diff options
576 files changed, 5264 insertions, 3160 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index eb112de1451..b2d75a829fc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -32,6 +32,7 @@ variables: GET_SOURCES_ATTEMPTS: "3" KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json + BUILD_ASSETS_IMAGE: "false" before_script: - bundle --version @@ -75,15 +76,17 @@ stages: - mysql:5.7 - redis:alpine -.rails5: &rails5 - allow_failure: true - only: +.rails4: &rails4 + allow_failure: false + except: variables: - - $CI_COMMIT_REF_NAME =~ /rails5/ - - $RAILS5_ENABLED + - $CI_COMMIT_REF_NAME =~ /(^docs[\/-].*|.*-docs$)/ + - $CI_COMMIT_REF_NAME =~ /(^qa[\/-].*|.*-qa$)/ + - $CI_COMMIT_REF_NAME =~ /norails4/ + - $RAILS5_DISABLED variables: - BUNDLE_GEMFILE: "Gemfile.rails5" - RAILS5: "true" + BUNDLE_GEMFILE: "Gemfile.rails4" + RAILS5: "false" # Skip all jobs except the ones that begin with 'docs/'. # Used for commits including ONLY documentation changes. @@ -148,13 +151,12 @@ stages: stage: test script: - JOB_NAME=( $CI_JOB_NAME ) - - export CI_NODE_INDEX=${JOB_NAME[-2]} - - export CI_NODE_TOTAL=${JOB_NAME[-1]} - - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json + - 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_${JOB_NAME[0]}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json - - export NEW_FLAKY_RSPEC_REPORT_PATH=rspec_flaky/new_${JOB_NAME[0]}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json + - 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} @@ -177,17 +179,17 @@ stages: <<: *rspec-metadata <<: *use-pg -.rspec-metadata-pg-rails5: &rspec-metadata-pg-rails5 +.rspec-metadata-pg-rails4: &rspec-metadata-pg-rails4 <<: *rspec-metadata-pg - <<: *rails5 + <<: *rails4 .rspec-metadata-mysql: &rspec-metadata-mysql <<: *rspec-metadata <<: *use-mysql -.rspec-metadata-mysql-rails5: &rspec-metadata-mysql-rails5 +.rspec-metadata-mysql-rails4: &rspec-metadata-mysql-rails4 <<: *rspec-metadata-mysql - <<: *rails5 + <<: *rails4 .only-canonical-masters: &only-canonical-masters only: @@ -321,7 +323,7 @@ cloud-native-image: image: ruby:2.5-alpine before_script: [] dependencies: [] - stage: test + stage: post-test allow_failure: true variables: GIT_DEPTH: "1" @@ -429,7 +431,7 @@ setup-test-env: script: - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' - scripts/gitaly-test-build # Do not use 'bundle exec' here - - BUNDLE_GEMFILE=Gemfile.rails5 bundle install $BUNDLE_INSTALL_FLAGS + - BUNDLE_GEMFILE=Gemfile.rails4 bundle install $BUNDLE_INSTALL_FLAGS artifacts: expire_in: 7d paths: @@ -459,129 +461,21 @@ danger-review: - yarn install --frozen-lockfile --cache-folder .yarn-cache - danger --fail-on-errors=true -rspec-pg 0 30: *rspec-metadata-pg -rspec-pg 1 30: *rspec-metadata-pg -rspec-pg 2 30: *rspec-metadata-pg -rspec-pg 3 30: *rspec-metadata-pg -rspec-pg 4 30: *rspec-metadata-pg -rspec-pg 5 30: *rspec-metadata-pg -rspec-pg 6 30: *rspec-metadata-pg -rspec-pg 7 30: *rspec-metadata-pg -rspec-pg 8 30: *rspec-metadata-pg -rspec-pg 9 30: *rspec-metadata-pg -rspec-pg 10 30: *rspec-metadata-pg -rspec-pg 11 30: *rspec-metadata-pg -rspec-pg 12 30: *rspec-metadata-pg -rspec-pg 13 30: *rspec-metadata-pg -rspec-pg 14 30: *rspec-metadata-pg -rspec-pg 15 30: *rspec-metadata-pg -rspec-pg 16 30: *rspec-metadata-pg -rspec-pg 17 30: *rspec-metadata-pg -rspec-pg 18 30: *rspec-metadata-pg -rspec-pg 19 30: *rspec-metadata-pg -rspec-pg 20 30: *rspec-metadata-pg -rspec-pg 21 30: *rspec-metadata-pg -rspec-pg 22 30: *rspec-metadata-pg -rspec-pg 23 30: *rspec-metadata-pg -rspec-pg 24 30: *rspec-metadata-pg -rspec-pg 25 30: *rspec-metadata-pg -rspec-pg 26 30: *rspec-metadata-pg -rspec-pg 27 30: *rspec-metadata-pg -rspec-pg 28 30: *rspec-metadata-pg -rspec-pg 29 30: *rspec-metadata-pg - -rspec-mysql 0 30: *rspec-metadata-mysql -rspec-mysql 1 30: *rspec-metadata-mysql -rspec-mysql 2 30: *rspec-metadata-mysql -rspec-mysql 3 30: *rspec-metadata-mysql -rspec-mysql 4 30: *rspec-metadata-mysql -rspec-mysql 5 30: *rspec-metadata-mysql -rspec-mysql 6 30: *rspec-metadata-mysql -rspec-mysql 7 30: *rspec-metadata-mysql -rspec-mysql 8 30: *rspec-metadata-mysql -rspec-mysql 9 30: *rspec-metadata-mysql -rspec-mysql 10 30: *rspec-metadata-mysql -rspec-mysql 11 30: *rspec-metadata-mysql -rspec-mysql 12 30: *rspec-metadata-mysql -rspec-mysql 13 30: *rspec-metadata-mysql -rspec-mysql 14 30: *rspec-metadata-mysql -rspec-mysql 15 30: *rspec-metadata-mysql -rspec-mysql 16 30: *rspec-metadata-mysql -rspec-mysql 17 30: *rspec-metadata-mysql -rspec-mysql 18 30: *rspec-metadata-mysql -rspec-mysql 19 30: *rspec-metadata-mysql -rspec-mysql 20 30: *rspec-metadata-mysql -rspec-mysql 21 30: *rspec-metadata-mysql -rspec-mysql 22 30: *rspec-metadata-mysql -rspec-mysql 23 30: *rspec-metadata-mysql -rspec-mysql 24 30: *rspec-metadata-mysql -rspec-mysql 25 30: *rspec-metadata-mysql -rspec-mysql 26 30: *rspec-metadata-mysql -rspec-mysql 27 30: *rspec-metadata-mysql -rspec-mysql 28 30: *rspec-metadata-mysql -rspec-mysql 29 30: *rspec-metadata-mysql - -rspec-pg-rails5 0 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 1 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 2 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 3 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 4 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 5 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 6 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 7 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 8 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 9 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 10 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 11 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 12 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 13 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 14 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 15 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 16 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 17 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 18 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 19 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 20 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 21 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 22 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 23 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 24 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 25 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 26 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 27 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 28 30: *rspec-metadata-pg-rails5 -rspec-pg-rails5 29 30: *rspec-metadata-pg-rails5 - -rspec-mysql-rails5 0 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 1 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 2 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 3 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 4 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 5 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 6 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 7 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 8 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 9 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 10 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 11 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 12 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 13 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 14 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 15 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 16 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 17 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 18 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 19 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 20 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 21 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 22 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 23 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 24 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 25 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 26 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 27 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 28 30: *rspec-metadata-mysql-rails5 -rspec-mysql-rails5 29 30: *rspec-metadata-mysql-rails5 +rspec-pg: + <<: *rspec-metadata-pg + parallel: 30 + +rspec-mysql: + <<: *rspec-metadata-mysql + parallel: 30 + +rspec-pg-rails4: + <<: *rspec-metadata-pg-rails4 + parallel: 30 + +rspec-mysql-rails4: + <<: *rspec-metadata-mysql-rails4 + parallel: 30 static-analysis: <<: *dedicated-no-docs-no-db-pull-cache-job @@ -627,11 +521,11 @@ downtime_check: - /(^docs[\/-].*|.*-docs$)/ - /(^qa[\/-].*|.*-qa$)/ -rails5_gemfile_lock_check: +rails4_gemfile_lock_check: <<: *dedicated-no-docs-no-db-pull-cache-job <<: *except-docs-and-qa script: - - scripts/rails5-gemfile-lock-check + - scripts/rails4-gemfile-lock-check ee_compat_check: <<: *rake-exec @@ -778,7 +672,8 @@ code_quality: --volume /var/run/docker.sock:/var/run/docker.sock "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code artifacts: - paths: [gl-code-quality-report.json] + reports: + codequality: gl-code-quality-report.json expire_in: 1 week sast: @@ -802,7 +697,8 @@ sast: --volume /var/run/docker.sock:/var/run/docker.sock "registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code artifacts: - paths: [gl-sast-report.json] + reports: + sast: gl-sast-report.json dependency_scanning: <<: *dedicated-no-docs-no-db-pull-cache-job @@ -824,7 +720,8 @@ dependency_scanning: --volume /var/run/docker.sock:/var/run/docker.sock "registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code artifacts: - paths: [gl-dependency-scanning-report.json] + reports: + dependency_scanning: gl-dependency-scanning-report.json qa:internal: <<: *dedicated-no-docs-no-db-pull-cache-job @@ -842,6 +739,39 @@ qa:selectors: - bundle install - bundle exec bin/qa Test::Sanity::Selectors +.qa-frontend-node: &qa-frontend-node + stage: test + variables: + NODE_OPTIONS: --max_old_space_size=3584 + cache: + key: "$CI_JOB_NAME" + paths: + - .yarn-cache/ + dependencies: [] + before_script: [] + script: + - date + - yarn install --frozen-lockfile --cache-folder .yarn-cache + - date + - yarn run webpack-prod + +qa-frontend-node:6: + <<: *qa-frontend-node + image: node:6-alpine + +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 + 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 @@ -891,6 +821,8 @@ pages: - 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 artifacts: paths: - public diff --git a/.gitlab/issue_templates/Test plan.md b/.gitlab/issue_templates/Test plan.md index db8e30c419c..a3c3f4a6509 100644 --- a/.gitlab/issue_templates/Test plan.md +++ b/.gitlab/issue_templates/Test plan.md @@ -64,7 +64,7 @@ Some features might be simple enough that they only involve one Component, while more complex features could involve multiple or even all. Example (from https://gitlab.com/gitlab-org/gitlab-ce/issues/50353): -* Respository is +* Repository is * Intuitive * It's easy to select the desired file template * It doesn't require unnecessary actions to save the change @@ -93,4 +93,4 @@ When adding new automated tests, please keep [testing levels](https://docs.gitla in mind. --> -/label ~Quality ~"test plan"
\ No newline at end of file +/label ~Quality ~"test plan" diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 4db8830b115..244fb7efb4c 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.129.0 +0.133.0 diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index a3fcc7121bb..21c8c7b46b8 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -7.1.0 +7.1.1 @@ -1,13 +1,12 @@ # --- Special code for migrating to Rails 5.0 --- def rails5? - %w[1 true].include?(ENV["RAILS5"]) + !%w[0 false].include?(ENV["RAILS5"]) end gem_versions = {} -gem_versions['activerecord_sane_schema_dumper'] = rails5? ? '1.0' : '0.2' -gem_versions['default_value_for'] = rails5? ? '~> 3.0.5' : '~> 3.0.0' -gem_versions['rails'] = rails5? ? '5.0.7' : '4.2.10' -gem_versions['rails-i18n'] = rails5? ? '~> 5.1' : '~> 4.0.9' +gem_versions['activerecord_sane_schema_dumper'] = rails5? ? '1.0' : '0.2' +gem_versions['rails'] = rails5? ? '5.0.7' : '4.2.10' +gem_versions['rails-i18n'] = rails5? ? '~> 5.1' : '~> 4.0.9' # --- The end of special code for migrating to Rails 5.0 --- source 'https://rubygems.org' @@ -15,13 +14,20 @@ source 'https://rubygems.org' gem 'rails', gem_versions['rails'] gem 'rails-deprecated_sanitizer', '~> 1.0.3' +# Improves copy-on-write performance for MRI +gem 'nakayoshi_fork', '~> 0.0.4' + # Responders respond_to and respond_with gem 'responders', '~> 2.0' gem 'sprockets', '~> 3.7.0' # Default values for AR models -gem 'default_value_for', gem_versions['default_value_for'] +if rails5? + gem 'gitlab-default_value_for', '~> 3.1.1', require: 'default_value_for' +else + gem 'default_value_for', '~> 3.0.0' +end # Supported DBs gem 'mysql2', '~> 0.4.10', group: :mysql @@ -133,7 +139,7 @@ gem 'rdoc', '~> 6.0' gem 'org-ruby', '~> 0.9.12' gem 'creole', '~> 0.5.0' gem 'wikicloth', '0.8.1' -gem 'asciidoctor', '~> 1.5.6' +gem 'asciidoctor', '~> 1.5.8' gem 'asciidoctor-plantuml', '0.0.8' gem 'rouge', '~> 3.1' gem 'truncato', '~> 0.7.9' @@ -223,7 +229,7 @@ gem 'slack-notifier', '~> 1.5.1' gem 'hangouts-chat', '~> 0.0.5' # Asana integration -gem 'asana', '~> 0.6.0' +gem 'asana', '~> 0.8.1' # FogBugz integration gem 'ruby-fogbugz', '~> 0.2.1' @@ -315,7 +321,7 @@ group :development do # Better errors handler gem 'better_errors', '~> 2.1.0' - gem 'binding_of_caller', '~> 0.7.2' + gem 'binding_of_caller', '~> 0.8.0' # thin instead webrick gem 'thin', '~> 1.7.0' @@ -364,7 +370,7 @@ group :development, :test do gem 'benchmark-ips', '~> 2.3.0', require: false gem 'license_finder', '~> 5.4', require: false - gem 'knapsack', '~> 1.16' + gem 'knapsack', '~> 1.17' gem 'activerecord_sane_schema_dumper', gem_versions['activerecord_sane_schema_dumper'] diff --git a/Gemfile.lock b/Gemfile.lock index 23261373c2b..975243f31d5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,41 +4,44 @@ GEM RedCloth (4.3.2) abstract_type (0.0.7) ace-rails-ap (4.1.2) - actionmailer (4.2.10) - actionpack (= 4.2.10) - actionview (= 4.2.10) - activejob (= 4.2.10) + actioncable (5.0.7) + actionpack (= 5.0.7) + nio4r (>= 1.2, < 3.0) + websocket-driver (~> 0.6.1) + actionmailer (5.0.7) + actionpack (= 5.0.7) + actionview (= 5.0.7) + activejob (= 5.0.7) mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.10) - actionview (= 4.2.10) - activesupport (= 4.2.10) - rack (~> 1.6) - rack-test (~> 0.6.2) - rails-dom-testing (~> 1.0, >= 1.0.5) + rails-dom-testing (~> 2.0) + actionpack (5.0.7) + actionview (= 5.0.7) + activesupport (= 5.0.7) + rack (~> 2.0) + rack-test (~> 0.6.3) + rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.10) - activesupport (= 4.2.10) + actionview (5.0.7) + activesupport (= 5.0.7) builder (~> 3.1) erubis (~> 2.7.0) - rails-dom-testing (~> 1.0, >= 1.0.5) + rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (4.2.10) - activesupport (= 4.2.10) - globalid (>= 0.3.0) - activemodel (4.2.10) - activesupport (= 4.2.10) - builder (~> 3.1) - activerecord (4.2.10) - activemodel (= 4.2.10) - activesupport (= 4.2.10) - arel (~> 6.0) - activerecord_sane_schema_dumper (0.2) - rails (>= 4, < 5) - activesupport (4.2.10) - i18n (~> 0.7) + activejob (5.0.7) + activesupport (= 5.0.7) + globalid (>= 0.3.6) + activemodel (5.0.7) + activesupport (= 5.0.7) + activerecord (5.0.7) + activemodel (= 5.0.7) + activesupport (= 5.0.7) + arel (~> 7.0) + activerecord_sane_schema_dumper (1.0) + rails (>= 5, < 6) + activesupport (5.0.7) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) acts-as-taggable-on (5.0.0) activerecord (>= 4.2.8) @@ -49,13 +52,13 @@ GEM public_suffix (>= 2.0.2, < 4.0) aes_key_wrap (1.0.1) akismet (2.0.0) - arel (6.0.4) - asana (0.6.0) + arel (7.1.4) + asana (0.8.1) faraday (~> 0.9) faraday_middleware (~> 0.9) faraday_middleware-multi_json (~> 0.0) oauth2 (~> 1.0) - asciidoctor (1.5.6.2) + asciidoctor (1.5.8) asciidoctor-plantuml (0.0.8) asciidoctor (~> 1.5) ast (2.4.0) @@ -79,7 +82,7 @@ GEM erubis (>= 2.6.6) rack (>= 0.9.0) bindata (2.4.3) - binding_of_caller (0.7.2) + binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) bootsnap (1.3.2) msgpack (~> 1.0) @@ -137,14 +140,12 @@ GEM addressable daemons (1.2.6) database_cleaner (1.5.3) - debug_inspector (0.0.2) + debug_inspector (0.0.3) debugger-ruby_core_source (1.3.8) deckar01-task_list (2.0.0) html-pipeline declarative (0.0.10) declarative-option (0.1.0) - default_value_for (3.0.2) - activerecord (>= 3.2.0, < 5.1) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) device_detector (1.0.0) @@ -274,6 +275,8 @@ GEM gitaly-proto (0.123.0) grpc (~> 1.0) github-markup (1.7.0) + gitlab-default_value_for (3.1.1) + activerecord (>= 3.2.0, < 6.0) gitlab-markup (1.6.5) gitlab-sidekiq-fetcher (0.3.0) sidekiq (~> 5) @@ -376,7 +379,7 @@ GEM json (~> 1.8) multi_xml (>= 0.5.2) httpclient (2.8.3) - i18n (0.9.5) + i18n (1.1.0) concurrent-ruby (~> 1.0) icalendar (2.4.1) ice_nine (0.11.2) @@ -412,7 +415,7 @@ GEM kaminari-core (= 1.0.1) kaminari-core (1.0.1) kgio (2.10.0) - knapsack (1.16.0) + knapsack (1.17.0) rake kubeclient (3.1.0) http (~> 2.2.2) @@ -467,9 +470,11 @@ GEM mustermann-grape (1.0.0) mustermann (~> 1.0.0) mysql2 (0.4.10) + nakayoshi_fork (0.0.4) net-ldap (0.16.0) net-ssh (5.0.1) netrc (0.11.0) + nio4r (2.3.1) nokogiri (1.8.4) mini_portile2 (~> 2.3.0) nokogumbo (1.5.0) @@ -598,7 +603,7 @@ GEM get_process_mem (~> 0.2) puma (>= 2.7, < 4) pyu-ruby-sasl (0.0.3.3) - rack (1.6.11) + rack (2.0.5) rack-accept (0.4.5) rack (>= 0.4) rack-attack (4.4.1) @@ -616,31 +621,36 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (4.2.10) - actionmailer (= 4.2.10) - actionpack (= 4.2.10) - actionview (= 4.2.10) - activejob (= 4.2.10) - activemodel (= 4.2.10) - activerecord (= 4.2.10) - activesupport (= 4.2.10) - bundler (>= 1.3.0, < 2.0) - railties (= 4.2.10) - sprockets-rails + rails (5.0.7) + actioncable (= 5.0.7) + actionmailer (= 5.0.7) + actionpack (= 5.0.7) + actionview (= 5.0.7) + activejob (= 5.0.7) + activemodel (= 5.0.7) + activerecord (= 5.0.7) + activesupport (= 5.0.7) + bundler (>= 1.3.0) + railties (= 5.0.7) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.2) + actionpack (~> 5.x, >= 5.0.1) + actionview (~> 5.x, >= 5.0.1) + activesupport (~> 5.x) rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.9) - activesupport (>= 4.2.0, < 5.0) - nokogiri (~> 1.6) - rails-deprecated_sanitizer (>= 1.0.1) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) rails-html-sanitizer (1.0.4) loofah (~> 2.2, >= 2.2.2) - rails-i18n (4.0.9) - i18n (~> 0.7) - railties (~> 4.0) - railties (4.2.10) - actionpack (= 4.2.10) - activesupport (= 4.2.10) + rails-i18n (5.1.1) + i18n (>= 0.7, < 2) + railties (>= 5.0, < 6) + railties (5.0.7) + actionpack (= 5.0.7) + activesupport (= 5.0.7) + method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (3.0.0) @@ -731,8 +741,7 @@ GEM rspec-core rspec-set (0.1.3) rspec-support (3.7.1) - rspec_junit_formatter (0.2.3) - builder (< 4) + rspec_junit_formatter (0.4.1) rspec-core (>= 2, < 4, != 2.12.0) rspec_profiling (0.0.5) activerecord @@ -849,8 +858,6 @@ GEM sysexits (1.2.0) temple (0.8.0) test-prof (0.2.5) - test_after_commit (1.1.0) - activerecord (>= 3.2) text (1.3.1) thin (1.7.2) daemons (~> 1.0, >= 1.0.9) @@ -913,6 +920,9 @@ GEM hashdiff webpack-rails (0.9.11) railties (>= 3.2.0) + websocket-driver (0.6.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.3) wikicloth (0.8.1) builder expression_parser @@ -928,12 +938,12 @@ PLATFORMS DEPENDENCIES RedCloth (~> 4.3.2) ace-rails-ap (~> 4.1.0) - activerecord_sane_schema_dumper (= 0.2) + activerecord_sane_schema_dumper (= 1.0) acts-as-taggable-on (~> 5.0) addressable (~> 2.5.2) akismet (~> 2.0) - asana (~> 0.6.0) - asciidoctor (~> 1.5.6) + asana (~> 0.8.1) + asciidoctor (~> 1.5.8) asciidoctor-plantuml (= 0.0.8) attr_encrypted (~> 3.1.0) awesome_print @@ -943,7 +953,7 @@ DEPENDENCIES bcrypt_pbkdf (~> 1.0) benchmark-ips (~> 2.3.0) better_errors (~> 2.1.0) - binding_of_caller (~> 0.7.2) + binding_of_caller (~> 0.8.0) bootsnap (~> 1.3) bootstrap_form (~> 2.7.0) brakeman (~> 4.2) @@ -962,7 +972,6 @@ DEPENDENCIES creole (~> 0.5.0) database_cleaner (~> 1.5.0) deckar01-task_list (= 2.0.0) - default_value_for (~> 3.0.0) device_detector devise (~> 4.4) devise-two-factor (~> 3.0.0) @@ -998,6 +1007,7 @@ DEPENDENCIES gettext_i18n_rails_js (~> 1.3) gitaly-proto (~> 0.123.0) github-markup (~> 1.7.0) + gitlab-default_value_for (~> 3.1.1) gitlab-markup (~> 1.6.5) gitlab-sidekiq-fetcher gitlab-styles (~> 2.4) @@ -1030,7 +1040,7 @@ DEPENDENCIES json-schema (~> 2.8.0) jwt (~> 1.5.6) kaminari (~> 1.0) - knapsack (~> 1.16) + knapsack (~> 1.17) kubeclient (~> 3.1.0) letter_opener_web (~> 1.3.0) license_finder (~> 5.4) @@ -1042,6 +1052,7 @@ DEPENDENCIES mini_magick minitest (~> 5.7.0) mysql2 (~> 0.4.10) + nakayoshi_fork (~> 0.0.4) net-ldap net-ssh (~> 5.0) nokogiri (~> 1.8.2) @@ -1080,9 +1091,10 @@ DEPENDENCIES rack-cors (~> 1.0.0) rack-oauth2 (~> 1.2.1) rack-proxy (~> 0.6.0) - rails (= 4.2.10) + rails (= 5.0.7) + rails-controller-testing rails-deprecated_sanitizer (~> 1.0.3) - rails-i18n (~> 4.0.9) + rails-i18n (~> 5.1) rainbow (~> 3.0) raindrops (~> 0.18) rblineprof (~> 0.3.6) @@ -1135,7 +1147,6 @@ DEPENDENCIES state_machines-activerecord (~> 0.5.1) sys-filesystem (~> 1.1.6) test-prof (~> 0.2.5) - test_after_commit (~> 1.1) thin (~> 1.7.0) timecop (~> 0.8.0) toml-rb (~> 1.0.0) diff --git a/Gemfile.rails5 b/Gemfile.rails4 index 2b526b19ba0..0ec00e702aa 100644 --- a/Gemfile.rails5 +++ b/Gemfile.rails4 @@ -1,6 +1,6 @@ -# BUNDLE_GEMFILE=Gemfile.rails5 bundle install +# BUNDLE_GEMFILE=Gemfile.rails4 bundle install -ENV["RAILS5"] = "true" +ENV["RAILS5"] = "false" gemfile = File.expand_path("../Gemfile", __FILE__) diff --git a/Gemfile.rails5.lock b/Gemfile.rails4.lock index 8893088446b..657975da2a4 100644 --- a/Gemfile.rails5.lock +++ b/Gemfile.rails4.lock @@ -4,44 +4,41 @@ GEM RedCloth (4.3.2) abstract_type (0.0.7) ace-rails-ap (4.1.2) - actioncable (5.0.7) - actionpack (= 5.0.7) - nio4r (>= 1.2, < 3.0) - websocket-driver (~> 0.6.1) - actionmailer (5.0.7) - actionpack (= 5.0.7) - actionview (= 5.0.7) - activejob (= 5.0.7) + actionmailer (4.2.10) + actionpack (= 4.2.10) + actionview (= 4.2.10) + activejob (= 4.2.10) mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (5.0.7) - actionview (= 5.0.7) - activesupport (= 5.0.7) - rack (~> 2.0) - rack-test (~> 0.6.3) - rails-dom-testing (~> 2.0) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.10) + actionview (= 4.2.10) + activesupport (= 4.2.10) + rack (~> 1.6) + rack-test (~> 0.6.2) + rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.0.7) - activesupport (= 5.0.7) + actionview (4.2.10) + activesupport (= 4.2.10) builder (~> 3.1) erubis (~> 2.7.0) - rails-dom-testing (~> 2.0) + rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.0.7) - activesupport (= 5.0.7) - globalid (>= 0.3.6) - activemodel (5.0.7) - activesupport (= 5.0.7) - activerecord (5.0.7) - activemodel (= 5.0.7) - activesupport (= 5.0.7) - arel (~> 7.0) - activerecord_sane_schema_dumper (1.0) - rails (>= 5, < 6) - activesupport (5.0.7) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) + activejob (4.2.10) + activesupport (= 4.2.10) + globalid (>= 0.3.0) + activemodel (4.2.10) + activesupport (= 4.2.10) + builder (~> 3.1) + activerecord (4.2.10) + activemodel (= 4.2.10) + activesupport (= 4.2.10) + arel (~> 6.0) + activerecord_sane_schema_dumper (0.2) + rails (>= 4, < 5) + activesupport (4.2.10) + i18n (~> 0.7) minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) acts-as-taggable-on (5.0.0) activerecord (>= 4.2.8) @@ -52,13 +49,13 @@ GEM public_suffix (>= 2.0.2, < 4.0) aes_key_wrap (1.0.1) akismet (2.0.0) - arel (7.1.4) - asana (0.6.0) + arel (6.0.4) + asana (0.8.1) faraday (~> 0.9) faraday_middleware (~> 0.9) faraday_middleware-multi_json (~> 0.0) oauth2 (~> 1.0) - asciidoctor (1.5.6.2) + asciidoctor (1.5.8) asciidoctor-plantuml (0.0.8) asciidoctor (~> 1.5) ast (2.4.0) @@ -82,7 +79,7 @@ GEM erubis (>= 2.6.6) rack (>= 0.9.0) bindata (2.4.3) - binding_of_caller (0.7.2) + binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) bootsnap (1.3.2) msgpack (~> 1.0) @@ -140,14 +137,14 @@ GEM addressable daemons (1.2.6) database_cleaner (1.5.3) - debug_inspector (0.0.2) + debug_inspector (0.0.3) debugger-ruby_core_source (1.3.8) deckar01-task_list (2.0.0) html-pipeline declarative (0.0.10) declarative-option (0.1.0) - default_value_for (3.0.5) - activerecord (>= 3.2.0, < 5.2) + default_value_for (3.0.2) + activerecord (>= 3.2.0, < 5.1) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) device_detector (1.0.0) @@ -379,7 +376,7 @@ GEM json (~> 1.8) multi_xml (>= 0.5.2) httpclient (2.8.3) - i18n (1.1.0) + i18n (0.9.5) concurrent-ruby (~> 1.0) icalendar (2.4.1) ice_nine (0.11.2) @@ -415,7 +412,7 @@ GEM kaminari-core (= 1.0.1) kaminari-core (1.0.1) kgio (2.10.0) - knapsack (1.16.0) + knapsack (1.17.0) rake kubeclient (3.1.0) http (~> 2.2.2) @@ -454,9 +451,9 @@ GEM memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) method_source (0.9.0) - mime-types (3.1) + mime-types (3.2.2) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0521) + mime-types-data (3.2018.0812) mimemagic (0.3.0) mini_magick (4.8.0) mini_mime (1.0.1) @@ -470,10 +467,10 @@ GEM mustermann-grape (1.0.0) mustermann (~> 1.0.0) mysql2 (0.4.10) + nakayoshi_fork (0.0.4) net-ldap (0.16.0) net-ssh (5.0.1) netrc (0.11.0) - nio4r (2.3.1) nokogiri (1.8.4) mini_portile2 (~> 2.3.0) nokogumbo (1.5.0) @@ -602,7 +599,7 @@ GEM get_process_mem (~> 0.2) puma (>= 2.7, < 4) pyu-ruby-sasl (0.0.3.3) - rack (2.0.5) + rack (1.6.11) rack-accept (0.4.5) rack (>= 0.4) rack-attack (4.4.1) @@ -620,36 +617,31 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (5.0.7) - actioncable (= 5.0.7) - actionmailer (= 5.0.7) - actionpack (= 5.0.7) - actionview (= 5.0.7) - activejob (= 5.0.7) - activemodel (= 5.0.7) - activerecord (= 5.0.7) - activesupport (= 5.0.7) - bundler (>= 1.3.0) - railties (= 5.0.7) - sprockets-rails (>= 2.0.0) - rails-controller-testing (1.0.2) - actionpack (~> 5.x, >= 5.0.1) - actionview (~> 5.x, >= 5.0.1) - activesupport (~> 5.x) + rails (4.2.10) + actionmailer (= 4.2.10) + actionpack (= 4.2.10) + actionview (= 4.2.10) + activejob (= 4.2.10) + activemodel (= 4.2.10) + activerecord (= 4.2.10) + activesupport (= 4.2.10) + bundler (>= 1.3.0, < 2.0) + railties (= 4.2.10) + sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) - nokogiri (>= 1.6) + rails-dom-testing (1.0.9) + activesupport (>= 4.2.0, < 5.0) + nokogiri (~> 1.6) + rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.4) loofah (~> 2.2, >= 2.2.2) - rails-i18n (5.1.1) - i18n (>= 0.7, < 2) - railties (>= 5.0, < 6) - railties (5.0.7) - actionpack (= 5.0.7) - activesupport (= 5.0.7) - method_source + rails-i18n (4.0.9) + i18n (~> 0.7) + railties (~> 4.0) + railties (4.2.10) + actionpack (= 4.2.10) + activesupport (= 4.2.10) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (3.0.0) @@ -740,7 +732,8 @@ GEM rspec-core rspec-set (0.1.3) rspec-support (3.7.1) - rspec_junit_formatter (0.4.1) + rspec_junit_formatter (0.2.3) + builder (< 4) rspec-core (>= 2, < 4, != 2.12.0) rspec_profiling (0.0.5) activerecord @@ -857,6 +850,8 @@ GEM sysexits (1.2.0) temple (0.8.0) test-prof (0.2.5) + test_after_commit (1.1.0) + activerecord (>= 3.2) text (1.3.1) thin (1.7.2) daemons (~> 1.0, >= 1.0.9) @@ -919,9 +914,6 @@ GEM hashdiff webpack-rails (0.9.11) railties (>= 3.2.0) - websocket-driver (0.6.5) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.3) wikicloth (0.8.1) builder expression_parser @@ -937,12 +929,12 @@ PLATFORMS DEPENDENCIES RedCloth (~> 4.3.2) ace-rails-ap (~> 4.1.0) - activerecord_sane_schema_dumper (= 1.0) + activerecord_sane_schema_dumper (= 0.2) acts-as-taggable-on (~> 5.0) addressable (~> 2.5.2) akismet (~> 2.0) - asana (~> 0.6.0) - asciidoctor (~> 1.5.6) + asana (~> 0.8.1) + asciidoctor (~> 1.5.8) asciidoctor-plantuml (= 0.0.8) attr_encrypted (~> 3.1.0) awesome_print @@ -952,7 +944,7 @@ DEPENDENCIES bcrypt_pbkdf (~> 1.0) benchmark-ips (~> 2.3.0) better_errors (~> 2.1.0) - binding_of_caller (~> 0.7.2) + binding_of_caller (~> 0.8.0) bootsnap (~> 1.3) bootstrap_form (~> 2.7.0) brakeman (~> 4.2) @@ -971,7 +963,7 @@ DEPENDENCIES creole (~> 0.5.0) database_cleaner (~> 1.5.0) deckar01-task_list (= 2.0.0) - default_value_for (~> 3.0.5) + default_value_for (~> 3.0.0) device_detector devise (~> 4.4) devise-two-factor (~> 3.0.0) @@ -1039,7 +1031,7 @@ DEPENDENCIES json-schema (~> 2.8.0) jwt (~> 1.5.6) kaminari (~> 1.0) - knapsack (~> 1.16) + knapsack (~> 1.17) kubeclient (~> 3.1.0) letter_opener_web (~> 1.3.0) license_finder (~> 5.4) @@ -1051,6 +1043,7 @@ DEPENDENCIES mini_magick minitest (~> 5.7.0) mysql2 (~> 0.4.10) + nakayoshi_fork (~> 0.0.4) net-ldap net-ssh (~> 5.0) nokogiri (~> 1.8.2) @@ -1089,10 +1082,9 @@ DEPENDENCIES rack-cors (~> 1.0.0) rack-oauth2 (~> 1.2.1) rack-proxy (~> 0.6.0) - rails (= 5.0.7) - rails-controller-testing + rails (= 4.2.10) rails-deprecated_sanitizer (~> 1.0.3) - rails-i18n (~> 5.1) + rails-i18n (~> 4.0.9) rainbow (~> 3.0) raindrops (~> 0.18) rblineprof (~> 0.3.6) @@ -1145,6 +1137,7 @@ DEPENDENCIES state_machines-activerecord (~> 0.5.1) sys-filesystem (~> 1.1.6) test-prof (~> 0.2.5) + test_after_commit (~> 1.1) thin (~> 1.7.0) timecop (~> 0.8.0) toml-rb (~> 1.0.0) diff --git a/app/assets/javascripts/badges/components/badge.vue b/app/assets/javascripts/badges/components/badge.vue index 8512bf9dd7b..ca1662313c2 100644 --- a/app/assets/javascripts/badges/components/badge.vue +++ b/app/assets/javascripts/badges/components/badge.vue @@ -1,7 +1,7 @@ <script> import Icon from '~/vue_shared/components/icon.vue'; import Tooltip from '~/vue_shared/directives/tooltip'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { name: 'Badge', diff --git a/app/assets/javascripts/badges/components/badge_form.vue b/app/assets/javascripts/badges/components/badge_form.vue index 47e6e618219..0eff922d93c 100644 --- a/app/assets/javascripts/badges/components/badge_form.vue +++ b/app/assets/javascripts/badges/components/badge_form.vue @@ -4,7 +4,7 @@ import { mapActions, mapState } from 'vuex'; import createFlash from '~/flash'; import { s__, sprintf } from '~/locale'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import createEmptyBadge from '../empty_badge'; import Badge from './badge.vue'; diff --git a/app/assets/javascripts/badges/components/badge_list.vue b/app/assets/javascripts/badges/components/badge_list.vue index ab518820378..5b64ea1080c 100644 --- a/app/assets/javascripts/badges/components/badge_list.vue +++ b/app/assets/javascripts/badges/components/badge_list.vue @@ -1,6 +1,6 @@ <script> import { mapState } from 'vuex'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import BadgeListRow from './badge_list_row.vue'; import { GROUP_BADGE } from '../constants'; diff --git a/app/assets/javascripts/badges/components/badge_list_row.vue b/app/assets/javascripts/badges/components/badge_list_row.vue index f28eff18f03..d01465232a7 100644 --- a/app/assets/javascripts/badges/components/badge_list_row.vue +++ b/app/assets/javascripts/badges/components/badge_list_row.vue @@ -2,7 +2,7 @@ import { mapActions, mapState } from 'vuex'; import { s__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import { PROJECT_BADGE } from '../constants'; import Badge from './badge.vue'; diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 5e28fc396ab..a04b828e277 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -1,6 +1,6 @@ <script> import Sortable from 'sortablejs'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import boardNewIssue from './board_new_issue.vue'; import boardCard from './board_card.vue'; import eventHub from '../eventhub'; diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue index ee3dc38bca6..2a96d1443e1 100644 --- a/app/assets/javascripts/boards/components/board_new_issue.vue +++ b/app/assets/javascripts/boards/components/board_new_issue.vue @@ -1,6 +1,6 @@ <script> import $ from 'jquery'; -import { GlButton } from '@gitlab-org/gitlab-ui'; +import { GlButton } from '@gitlab/ui'; import eventHub from '../eventhub'; import ProjectSelect from './project_select.vue'; import ListIssue from '../models/issue'; diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue index 2315a48a306..48c46ae32f1 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.vue +++ b/app/assets/javascripts/boards/components/issue_card_inner.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import { sprintf, __ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; @@ -231,7 +231,7 @@ export default { > <span class="js-assignee-tooltip"> <span class="bold d-block">Assignee</span> - {{ assignee.name }} + {{ assignee.name }} <span class="text-white-50">@{{ assignee.username }}</span> </span> </user-avatar-link> diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue index 025ef7e9743..d6c87132843 100644 --- a/app/assets/javascripts/boards/components/issue_due_date.vue +++ b/app/assets/javascripts/boards/components/issue_due_date.vue @@ -1,6 +1,6 @@ <script> import dateFormat from 'dateformat'; -import { GlTooltip } from '@gitlab-org/gitlab-ui'; +import { GlTooltip } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import { __ } from '~/locale'; import { getDayDifference, getTimeago, dateInWords } from '~/lib/utils/datetime_utility'; diff --git a/app/assets/javascripts/boards/components/issue_time_estimate.vue b/app/assets/javascripts/boards/components/issue_time_estimate.vue index efc7daf7812..a9803c8ab5d 100644 --- a/app/assets/javascripts/boards/components/issue_time_estimate.vue +++ b/app/assets/javascripts/boards/components/issue_time_estimate.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltip } from '@gitlab-org/gitlab-ui'; +import { GlTooltip } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility'; diff --git a/app/assets/javascripts/boards/components/modal/index.vue b/app/assets/javascripts/boards/components/modal/index.vue index fdd1346d4c7..fc0e3e46b88 100644 --- a/app/assets/javascripts/boards/components/modal/index.vue +++ b/app/assets/javascripts/boards/components/modal/index.vue @@ -6,7 +6,7 @@ import ModalList from './list.vue'; import ModalFooter from './footer.vue'; import EmptyState from './empty_state.vue'; import ModalStore from '../../stores/modal_store'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue index 20665f903d5..c502e32d169 100644 --- a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue +++ b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import ModalStore from '../../stores/modal_store'; import boardsStore from '../../stores/boards_store'; diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index 503417644fa..83e6e237757 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -2,7 +2,7 @@ import $ from 'jquery'; import _ from 'underscore'; import Icon from '~/vue_shared/components/icon.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import eventHub from '../eventhub'; import Api from '../../api'; diff --git a/app/assets/javascripts/deploy_keys/components/action_btn.vue b/app/assets/javascripts/deploy_keys/components/action_btn.vue index ea74fd27ff6..4acd21376bf 100644 --- a/app/assets/javascripts/deploy_keys/components/action_btn.vue +++ b/app/assets/javascripts/deploy_keys/components/action_btn.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import eventHub from '../eventhub'; export default { diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue index 631a9673b3e..1d2ac59e20a 100644 --- a/app/assets/javascripts/deploy_keys/components/app.vue +++ b/app/assets/javascripts/deploy_keys/components/app.vue @@ -6,7 +6,7 @@ import eventHub from '../eventhub'; import DeployKeysService from '../service'; import DeployKeysStore from '../store'; import KeysPanel from './keys_panel.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index f80e20a4391..881febedb7c 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -3,7 +3,7 @@ import { mapState, mapGetters, mapActions } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; import { __ } from '~/locale'; import createFlash from '~/flash'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import eventHub from '../../notes/event_hub'; import CompareVersions from './compare_versions.vue'; import DiffFile from './diff_file.vue'; @@ -94,7 +94,7 @@ export default { return __('Show latest version'); }, canCurrentUserFork() { - return this.currentUser.canFork === true && this.currentUser.canCreateMergeRequest; + return this.currentUser.can_fork === true && this.currentUser.can_create_merge_request; }, showCompareVersions() { return this.mergeRequestDiffs && this.mergeRequestDiff; diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue index 23d0bad2ecb..aa72aca1478 100644 --- a/app/assets/javascripts/diffs/components/commit_item.vue +++ b/app/assets/javascripts/diffs/components/commit_item.vue @@ -40,15 +40,17 @@ export default { }, computed: { authorName() { - return (this.commit.author && this.commit.author.name) || this.commit.authorName; + return (this.commit.author && this.commit.author.name) || this.commit.author_name; }, authorUrl() { return ( - (this.commit.author && this.commit.author.webUrl) || `mailto:${this.commit.authorEmail}` + (this.commit.author && this.commit.author.web_url) || `mailto:${this.commit.author_email}` ); }, authorAvatar() { - return (this.commit.author && this.commit.author.avatarUrl) || this.commit.authorGravatarUrl; + return ( + (this.commit.author && this.commit.author.avatar_url) || this.commit.author_gravatar_url + ); }, }, }; @@ -66,18 +68,18 @@ export default { <div class="commit-detail flex-list"> <div class="commit-content qa-commit-content"> <a - :href="commit.commitUrl" + :href="commit.commit_url" class="commit-row-message item-title" - v-html="commit.titleHtml" + v-html="commit.title_html" ></a> <span class="commit-row-message d-block d-sm-none"> · - {{ commit.shortId }} + {{ commit.short_id }} </span> <button - v-if="commit.descriptionHtml" + v-if="commit.description_html" class="text-expander js-toggle-button" type="button" :aria-label="__('Toggle commit description')" @@ -95,29 +97,29 @@ export default { ></a> {{ s__('CommitWidget|authored') }} <time-ago-tooltip - :time="commit.authoredDate" + :time="commit.authored_date" /> </div> <pre - v-if="commit.descriptionHtml" + v-if="commit.description_html" class="commit-row-description js-toggle-content append-bottom-8" - v-html="commit.descriptionHtml" + v-html="commit.description_html" ></pre> </div> <div class="commit-actions flex-row d-none d-sm-flex"> <div - v-if="commit.signatureHtml" - v-html="commit.signatureHtml" + v-if="commit.signature_html" + v-html="commit.signature_html" ></div> <commit-pipeline-status - v-if="commit.pipelineStatusPath" - :endpoint="commit.pipelineStatusPath" + v-if="commit.pipeline_status_path" + :endpoint="commit.pipeline_status_path" /> <div class="commit-sha-group"> <div class="label label-monospace" - v-text="commit.shortId" + v-text="commit.short_id" ></div> <clipboard-button :text="commit.id" diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue index a5b87dfc2d9..f50cb94a18f 100644 --- a/app/assets/javascripts/diffs/components/compare_versions.vue +++ b/app/assets/javascripts/diffs/components/compare_versions.vue @@ -1,6 +1,6 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; -import Tooltip from '@gitlab-org/gitlab-ui/dist/directives/tooltip'; +import Tooltip from '@gitlab/ui/dist/directives/tooltip'; import { __ } from '~/locale'; import { getParameterValues, mergeUrlParams } from '~/lib/utils/url_utility'; import Icon from '~/vue_shared/components/icon.vue'; diff --git a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue index f4b333f3700..112206e4ad6 100644 --- a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue +++ b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue @@ -56,16 +56,16 @@ export default { methods: { commitsText(version) { return n__( - `${version.commitsCount} commit,`, - `${version.commitsCount} commits,`, - version.commitsCount, + `${version.commits_count} commit,`, + `${version.commits_count} commits,`, + version.commits_count, ); }, href(version) { if (this.showCommitCount) { - return version.versionPath; + return version.version_path; } - return version.comparePath; + return version.compare_path; }, versionName(version) { if (this.isLatest(version)) { @@ -74,7 +74,7 @@ export default { if (this.targetBranch && (this.isBase(version) || !version)) { return this.targetBranch.branchName; } - return `version ${version.versionIndex}`; + return `version ${version.version_index}`; }, isActive(version) { if (!version) { @@ -84,11 +84,11 @@ export default { if (this.targetBranch) { return ( (this.isBase(version) && !this.startVersion) || - (this.startVersion && this.startVersion.versionIndex === version.versionIndex) + (this.startVersion && this.startVersion.version_index === version.version_index) ); } - return version.versionIndex === this.mergeRequestVersion.versionIndex; + return version.version_index === this.mergeRequestVersion.version_index; }, isBase(version) { if (!version || !this.targetBranch) { @@ -98,7 +98,7 @@ export default { }, isLatest(version) { return ( - this.mergeRequestVersion && version.versionIndex === this.targetVersions[0].versionIndex + this.mergeRequestVersion && version.version_index === this.targetVersions[0].version_index ); }, }, @@ -142,7 +142,7 @@ export default { </div> <div> <small class="commit-sha"> - {{ version.truncatedCommitSha }} + {{ version.truncated_commit_sha }} </small> </div> <div> @@ -151,8 +151,8 @@ export default { {{ commitsText(version) }} </template> <time-ago - v-if="version.createdAt" - :time="version.createdAt" + v-if="version.created_at" + :time="version.created_at" class="js-timeago js-timeago-render" /> </small> diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue index 547742a5ff4..5e5fda5fba6 100644 --- a/app/assets/javascripts/diffs/components/diff_content.vue +++ b/app/assets/javascripts/diffs/components/diff_content.vue @@ -39,7 +39,7 @@ export default { return this.diffFile.viewer.name === 'text'; }, diffFileCommentForm() { - return this.getCommentFormForDiffFile(this.diffFile.fileHash); + return this.getCommentFormForDiffFile(this.diffFile.file_hash); }, showNotesContainer() { return this.diffFile.discussions.length || this.diffFileCommentForm; @@ -73,28 +73,28 @@ export default { <inline-diff-view v-if="isInlineView" :diff-file="diffFile" - :diff-lines="diffFile.highlightedDiffLines || []" + :diff-lines="diffFile.highlighted_diff_lines || []" /> <parallel-diff-view v-if="isParallelView" :diff-file="diffFile" - :diff-lines="diffFile.parallelDiffLines || []" + :diff-lines="diffFile.parallel_diff_lines || []" /> </template> <diff-viewer v-else :diff-mode="diffMode" - :new-path="diffFile.newPath" - :new-sha="diffFile.diffRefs.headSha" - :old-path="diffFile.oldPath" - :old-sha="diffFile.diffRefs.baseSha" - :file-hash="diffFile.fileHash" + :new-path="diffFile.new_path" + :new-sha="diffFile.diff_refs.head_sha" + :old-path="diffFile.old_path" + :old-sha="diffFile.diff_refs.base_sha" + :file-hash="diffFile.file_hash" :project-path="projectPath" > <image-diff-overlay slot="image-overlay" :discussions="diffFile.discussions" - :file-hash="diffFile.fileHash" + :file-hash="diffFile.file_hash" :can-comment="getNoteableData.current_user.can_create_note" /> <div @@ -115,7 +115,7 @@ export default { :save-button-title="__('Comment')" class="diff-comment-form new-note discussion-form discussion-form-container" @handleFormUpdate="handleSaveNote" - @cancelForm="closeDiffFileCommentForm(diffFile.fileHash)" + @cancelForm="closeDiffFileCommentForm(diffFile.file_hash)" /> </div> </diff-viewer> diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index e76c7afd863..5da0bfb5bfe 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -3,7 +3,7 @@ import { mapActions, mapGetters, mapState } from 'vuex'; import _ from 'underscore'; import { __, sprintf } from '~/locale'; import createFlash from '~/flash'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import DiffFileHeader from './diff_file_header.vue'; import DiffContent from './diff_content.vue'; @@ -32,6 +32,7 @@ export default { computed: { ...mapState('diffs', ['currentDiffFileId']), ...mapGetters(['isNotesFetched']), + ...mapGetters('diffs', ['getDiffFileDiscussions']), isCollapsed() { return this.file.collapsed || false; }, @@ -39,7 +40,7 @@ export default { return sprintf( __('You can %{linkStart}view the blob%{linkEnd} instead.'), { - linkStart: `<a href="${_.escape(this.file.viewPath)}">`, + linkStart: `<a href="${_.escape(this.file.view_path)}">`, linkEnd: '</a>', }, false, @@ -48,21 +49,34 @@ export default { showExpandMessage() { return ( this.isCollapsed || - (!this.file.highlightedDiffLines && + (!this.file.highlighted_diff_lines && !this.isLoadingCollapsedDiff && - !this.file.tooLarge && + !this.file.too_large && this.file.text) ); }, showLoadingIcon() { return this.isLoadingCollapsedDiff || (!this.file.renderIt && !this.isCollapsed); }, + hasDiffLines() { + return ( + this.file.highlighted_diff_lines && + this.file.parallel_diff_lines && + this.file.parallel_diff_lines.length > 0 + ); + }, + }, + watch: { + 'file.collapsed': function fileCollapsedWatch(newVal, oldVal) { + if (!newVal && oldVal && !this.hasDiffLines) { + this.handleLoadCollapsedDiff(); + } + }, }, methods: { ...mapActions('diffs', ['loadCollapsedDiff', 'assignDiscussionsToDiff']), handleToggle() { - const { highlightedDiffLines, parallelDiffLines } = this.file; - if (!highlightedDiffLines && parallelDiffLines !== undefined && !parallelDiffLines.length) { + if (!this.hasDiffLines) { this.handleLoadCollapsedDiff(); } else { this.file.collapsed = !this.file.collapsed; @@ -81,7 +95,7 @@ export default { .then(() => { requestIdleCallback( () => { - this.assignDiscussionsToDiff(); + this.assignDiscussionsToDiff(this.getDiffFileDiscussions(this.file)); }, { timeout: 1000 }, ); @@ -103,9 +117,9 @@ export default { <template> <div - :id="file.fileHash" + :id="file.file_hash" :class="{ - 'is-active': currentDiffFileId === file.fileHash + 'is-active': currentDiffFileId === file.file_hash }" class="diff-file file-holder" > @@ -129,7 +143,7 @@ export default { make your changes there, and submit a merge request. </span> <a - :href="file.forkPath" + :href="file.fork_path" class="js-fork-suggestion-button btn btn-grouped btn-inverted btn-success" > Fork @@ -145,7 +159,7 @@ export default { <diff-content v-if="!isCollapsed && file.renderIt" - :class="{ hidden: isCollapsed || file.tooLarge }" + :class="{ hidden: isCollapsed || file.too_large }" :diff-file="file" /> <gl-loading-icon @@ -166,7 +180,7 @@ export default { </a> </div> <div - v-if="file.tooLarge" + v-if="file.too_large" class="nothing-here-block diff-collapsed js-too-large-diff" > {{ __('This source diff could not be displayed because it is too large.') }} diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index dcf1057eb84..af03cec6582 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -68,32 +68,32 @@ export default { }, titleLink() { if (this.diffFile.submodule) { - return this.diffFile.submoduleTreeUrl || this.diffFile.submoduleLink; + return this.diffFile.submodule_tree_url || this.diffFile.submodule_link; } return this.discussionPath; }, filePath() { if (this.diffFile.submodule) { - return `${this.diffFile.filePath} @ ${truncateSha(this.diffFile.blob.id)}`; + return `${this.diffFile.file_path} @ ${truncateSha(this.diffFile.blob.id)}`; } - if (this.diffFile.deletedFile) { - return sprintf(__('%{filePath} deleted'), { filePath: this.diffFile.filePath }, false); + if (this.diffFile.deleted_file) { + return sprintf(__('%{filePath} deleted'), { filePath: this.diffFile.file_path }, false); } - return this.diffFile.filePath; + return this.diffFile.file_path; }, titleTag() { - return this.diffFile.fileHash ? 'a' : 'span'; + return this.diffFile.file_hash ? 'a' : 'span'; }, isUsingLfs() { - return this.diffFile.storedExternally && this.diffFile.externalStorage === 'lfs'; + return this.diffFile.stored_externally && this.diffFile.external_storage === 'lfs'; }, collapseIcon() { return this.expanded ? 'chevron-down' : 'chevron-right'; }, viewFileButtonText() { - const truncatedContentSha = _.escape(truncateSha(this.diffFile.contentSha)); + const truncatedContentSha = _.escape(truncateSha(this.diffFile.content_sha)); return sprintf( s__('MergeRequests|View file @ %{commitId}'), { @@ -103,7 +103,7 @@ export default { ); }, viewReplacedFileButtonText() { - const truncatedBaseSha = _.escape(truncateSha(this.diffFile.diffRefs.baseSha)); + const truncatedBaseSha = _.escape(truncateSha(this.diffFile.diff_refs.base_sha)); return sprintf( s__('MergeRequests|View replaced file @ %{commitId}'), { @@ -113,7 +113,7 @@ export default { ); }, gfmCopyText() { - return `\`${this.diffFile.filePath}\``; + return `\`${this.diffFile.file_path}\``; }, }, methods: { @@ -164,21 +164,21 @@ export default { aria-hidden="true" css-classes="js-file-icon append-right-5" /> - <span v-if="diffFile.renamedFile"> + <span v-if="diffFile.renamed_file"> <strong v-tooltip - :title="diffFile.oldPath" + :title="diffFile.old_path" class="file-title-name" data-container="body" - v-html="diffFile.oldPathHtml" + v-html="diffFile.old_path_html" ></strong> → <strong v-tooltip - :title="diffFile.newPath" + :title="diffFile.new_path" class="file-title-name" data-container="body" - v-html="diffFile.newPathHtml" + v-html="diffFile.new_path_html" ></strong> </span> @@ -195,16 +195,16 @@ export default { <clipboard-button :title="__('Copy file path to clipboard')" - :text="diffFile.filePath" + :text="diffFile.file_path" :gfm="gfmCopyText" css-class="btn-default btn-transparent btn-clipboard" /> <small - v-if="diffFile.modeChanged" + v-if="diffFile.mode_changed" ref="fileMode" > - {{ diffFile.aMode }} → {{ diffFile.bMode }} + {{ diffFile.a_mode }} → {{ diffFile.b_mode }} </small> <span @@ -220,7 +220,7 @@ export default { class="file-actions d-none d-sm-block" > <template - v-if="diffFile.blob && diffFile.blob.readableText" + v-if="diffFile.blob && diffFile.blob.readable_text" > <button :disabled="!diffHasDiscussions(diffFile)" @@ -234,33 +234,33 @@ export default { </button> <edit-button - v-if="!diffFile.deletedFile" + v-if="!diffFile.deleted_file" :can-current-user-fork="canCurrentUserFork" - :edit-path="diffFile.editPath" - :can-modify-blob="diffFile.canModifyBlob" + :edit-path="diffFile.edit_path" + :can-modify-blob="diffFile.can_modify_blob" @showForkMessage="showForkMessage" /> </template> <a - v-if="diffFile.replacedViewPath" - :href="diffFile.replacedViewPath" + v-if="diffFile.replaced_view_path" + :href="diffFile.replaced_view_path" class="btn view-file js-view-file" v-html="viewReplacedFileButtonText" > </a> <a - :href="diffFile.viewPath" + :href="diffFile.view_path" class="btn view-file js-view-file" v-html="viewFileButtonText" > </a> <a - v-if="diffFile.externalUrl" + v-if="diffFile.external_url" v-tooltip - :href="diffFile.externalUrl" - :title="`View on ${diffFile.formattedExternalUrl}`" + :href="diffFile.external_url" + :title="`View on ${diffFile.formatted_external_url}`" target="_blank" rel="noopener noreferrer" class="btn btn-file-option" diff --git a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue index 254bc235691..8f8c2a31c71 100644 --- a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue +++ b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue @@ -3,7 +3,7 @@ import { mapActions } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; import { pluralize, truncate } from '~/lib/utils/text_utility'; import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import { COUNT_OF_AVATARS_IN_GUTTER, LENGTH_OF_AVATAR_TOOLTIP } from '../constants'; export default { diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue index f4a9be19496..8f037eeefc4 100644 --- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue +++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue @@ -73,7 +73,7 @@ export default { }), ...mapGetters(['isLoggedIn']), lineHref() { - return `#${this.line.lineCode || ''}`; + return `#${this.line.line_code || ''}`; }, shouldShowCommentButton() { return ( @@ -99,7 +99,7 @@ export default { methods: { ...mapActions('diffs', ['loadMoreLines', 'showCommentForm']), handleCommentButton() { - this.showCommentForm({ lineCode: this.line.lineCode }); + this.showCommentForm({ lineCode: this.line.line_code }); }, handleLoadMoreLines() { if (this.isRequesting) { @@ -108,8 +108,8 @@ export default { this.isRequesting = true; const endpoint = this.contextLinesPath; - const oldLineNumber = this.line.metaData.oldPos || 0; - const newLineNumber = this.line.metaData.newPos || 0; + const oldLineNumber = this.line.meta_data.old_pos || 0; + const newLineNumber = this.line.meta_data.new_pos || 0; const offset = newLineNumber - oldLineNumber; const bottom = this.isBottom; const { fileHash } = this; @@ -125,12 +125,12 @@ export default { to = lineNumber + UNFOLD_COUNT; } else { const diffFile = utils.findDiffFile(this.diffFiles, this.fileHash); - const indexForInline = utils.findIndexInInlineLines(diffFile.highlightedDiffLines, { + const indexForInline = utils.findIndexInInlineLines(diffFile.highlighted_diff_lines, { oldLineNumber, newLineNumber, }); - const prevLine = diffFile.highlightedDiffLines[indexForInline - 2]; - const prevLineNumber = (prevLine && prevLine.newLine) || 0; + const prevLine = diffFile.highlighted_diff_lines[indexForInline - 2]; + const prevLineNumber = (prevLine && prevLine.new_line) || 0; if (since <= prevLineNumber + 1) { since = prevLineNumber + 1; diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue index bb9bb821de3..07f38172575 100644 --- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue +++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue @@ -53,7 +53,7 @@ export default { this.noteableData.diff_head_sha, DIFF_NOTE_TYPE, this.noteableData.source_project_id, - this.line.lineCode, + this.line.line_code, ]; this.initAutoSave(this.noteableData, keys); @@ -72,7 +72,7 @@ export default { } this.cancelCommentForm({ - lineCode: this.line.lineCode, + lineCode: this.line.line_code, }); this.$nextTick(() => { this.resetAutoSave(); @@ -94,7 +94,7 @@ export default { <note-form ref="noteForm" :is-editing="true" - :line-code="line.lineCode" + :line-code="line.line_code" save-button-title="Comment" class="diff-comment-form" @cancelForm="handleCancelCommentForm" diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue index 5d9a0b123fe..0a893a57f07 100644 --- a/app/assets/javascripts/diffs/components/diff_table_cell.vue +++ b/app/assets/javascripts/diffs/components/diff_table_cell.vue @@ -96,9 +96,7 @@ export default { }; }, lineNumber() { - const { lineType } = this; - - return lineType === OLD_LINE_TYPE ? this.line.oldLine : this.line.newLine; + return this.lineType === OLD_LINE_TYPE ? this.line.old_line : this.line.new_line; }, }, }; diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue index 46a51859da5..b9e14c53d2c 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue @@ -48,7 +48,7 @@ export default { :discussions="line.discussions" /> <diff-line-note-form - v-if="diffLineCommentForms[line.lineCode]" + v-if="diffLineCommentForms[line.line_code]" :diff-file-hash="diffFileHash" :line="line" :note-target-line="line" diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue index 542acd3d930..1f4088066d1 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue @@ -52,9 +52,7 @@ export default { }; }, inlineRowId() { - const { lineCode, oldLine, newLine } = this.line; - - return lineCode || `${this.fileHash}_${oldLine}_${newLine}`; + return this.line.line_code || `${this.fileHash}_${this.line.old_line}_${this.line.new_line}`; }, }, created() { @@ -107,7 +105,7 @@ export default { <td :class="line.type" class="line_content" - v-html="line.richText" + v-html="line.rich_text" > </td> </tr> diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue index fbf9e77ac07..79efac89e98 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_view.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue @@ -43,16 +43,16 @@ export default { v-for="(line, index) in diffLines" > <inline-diff-table-row - :key="line.lineCode" - :file-hash="diffFile.fileHash" - :context-lines-path="diffFile.contextLinesPath" + :key="line.line_code" + :file-hash="diffFile.file_hash" + :context-lines-path="diffFile.context_lines_path" :line="line" :is-bottom="index + 1 === diffLinesLength" /> <inline-diff-comment-row v-if="shouldRenderInlineCommentRow(line)" :key="index" - :diff-file-hash="diffFile.fileHash" + :diff-file-hash="diffFile.file_hash" :line="line" :line-index="index" /> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue index 3b71c0a1fd4..00c2df4dac1 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue @@ -27,10 +27,10 @@ export default { diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), leftLineCode() { - return this.line.left && this.line.left.lineCode; + return this.line.left && this.line.left.line_code; }, rightLineCode() { - return this.line.right && this.line.right.lineCode; + return this.line.right && this.line.right.line_code; }, hasExpandedDiscussionOnLeft() { return this.line.left && this.line.left.discussions diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index fcc3b3e9117..2d87db12fd6 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -120,11 +120,11 @@ export default { class="diff-line-num old_line" /> <td - :id="line.left.lineCode" + :id="line.left.line_code" :class="parallelViewLeftLineType" class="line_content parallel left-side" @mousedown.native="handleParallelLineMouseDown" - v-html="line.left.richText" + v-html="line.left.rich_text" > </td> </template> @@ -146,11 +146,11 @@ export default { class="diff-line-num new_line" /> <td - :id="line.right.lineCode" + :id="line.right.line_code" :class="line.right.type" class="line_content parallel right-side" @mousedown.native="handleParallelLineMouseDown" - v-html="line.right.richText" + v-html="line.right.rich_text" > </td> </template> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue index 3452f0d2b00..6942f9b53e0 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue @@ -46,8 +46,8 @@ export default { > <parallel-diff-table-row :key="index" - :file-hash="diffFile.fileHash" - :context-lines-path="diffFile.contextLinesPath" + :file-hash="diffFile.file_hash" + :context-lines-path="diffFile.context_lines_path" :line="line" :is-bottom="index + 1 === diffLinesLength" /> @@ -55,7 +55,7 @@ export default { v-if="shouldRenderParallelCommentRow(line)" :key="`dcr-${index}`" :line="line" - :diff-file-hash="diffFile.fileHash" + :diff-file-hash="diffFile.file_hash" :line-index="index" /> </template> diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue index ff1eb23cea3..1f82eeae6cb 100644 --- a/app/assets/javascripts/diffs/components/tree_list.vue +++ b/app/assets/javascripts/diffs/components/tree_list.vue @@ -1,6 +1,6 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import { convertPermissionToBoolean } from '~/lib/utils/common_utils'; import Icon from '~/vue_shared/components/icon.vue'; import FileRow from '~/vue_shared/components/file_row.vue'; diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js index aae89109c27..06ef4207d85 100644 --- a/app/assets/javascripts/diffs/index.js +++ b/app/assets/javascripts/diffs/index.js @@ -1,6 +1,5 @@ import Vue from 'vue'; import { mapState } from 'vuex'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import diffsApp from './components/app.vue'; export default function initDiffsApp(store) { @@ -17,9 +16,7 @@ export default function initDiffsApp(store) { return { endpoint: dataset.endpoint, projectPath: dataset.projectPath, - currentUser: convertObjectPropsToCamelCase(JSON.parse(dataset.currentUserData), { - deep: true, - }), + currentUser: JSON.parse(dataset.currentUserData) || {}, }; }, computed: { diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 41256fdd27a..6354d3ce1e6 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -50,8 +50,8 @@ export const assignDiscussionsToDiff = ( }; export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => { - const { fileHash, line_code, id } = removeDiscussion; - commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash, lineCode: line_code, id }); + const { file_hash, line_code, id } = removeDiscussion; + commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash: file_hash, lineCode: line_code, id }); }; export const startRenderDiffsQueue = ({ state, commit }) => { @@ -167,7 +167,7 @@ export const expandAllFiles = ({ commit }) => { export const toggleFileDiscussions = ({ getters, dispatch }, diff) => { const discussions = getters.getDiffFileDiscussions(diff); const shouldCloseAll = getters.diffHasAllExpandedDiscussions(diff); - const shouldExpandAll = getters.diffHasAllCollpasedDiscussions(diff); + const shouldExpandAll = getters.diffHasAllCollapsedDiscussions(diff); discussions.forEach(discussion => { const data = { discussionId: discussion.id }; @@ -189,7 +189,7 @@ export const saveDiffDiscussion = ({ dispatch }, { note, formData }) => { return dispatch('saveNote', postData, { root: true }) .then(result => dispatch('updateDiscussion', result.discussion, { root: true })) .then(discussion => dispatch('assignDiscussionsToDiff', [discussion])) - .then(() => dispatch('closeDiffFileCommentForm', formData.diffFile.fileHash)) + .then(() => dispatch('closeDiffFileCommentForm', formData.diffFile.file_hash)) .then(() => dispatch('startTaskList', null, { root: true })) .catch(() => createFlash(s__('MergeRequests|Saving the comment failed'))); }; diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index bf490f9d78a..05e32e3c1f1 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -1,4 +1,3 @@ -import _ from 'underscore'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '../constants'; export const isParallelView = state => state.diffViewType === PARALLEL_DIFF_VIEW_TYPE; @@ -28,7 +27,7 @@ export const diffHasAllExpandedDiscussions = (state, getters) => diff => { * @param {Object} diff * @returns {Boolean} */ -export const diffHasAllCollpasedDiscussions = (state, getters) => diff => { +export const diffHasAllCollapsedDiscussions = (state, getters) => diff => { const discussions = getters.getDiffFileDiscussions(diff); return ( @@ -68,8 +67,7 @@ export const diffHasDiscussions = (state, getters) => diff => */ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) => diff => rootGetters.discussions.filter( - discussion => - discussion.diff_discussion && _.isEqual(discussion.diff_file.file_hash, diff.fileHash), + discussion => discussion.diff_discussion && discussion.diff_file.file_hash === diff.file_hash, ) || []; export const shouldRenderParallelCommentRow = state => line => { @@ -90,14 +88,14 @@ export const shouldRenderParallelCommentRow = state => line => { return true; } - const hasCommentFormOnLeft = line.left && state.diffLineCommentForms[line.left.lineCode]; - const hasCommentFormOnRight = line.right && state.diffLineCommentForms[line.right.lineCode]; + const hasCommentFormOnLeft = line.left && state.diffLineCommentForms[line.left.line_code]; + const hasCommentFormOnRight = line.right && state.diffLineCommentForms[line.right.line_code]; return hasCommentFormOnLeft || hasCommentFormOnRight; }; export const shouldRenderInlineCommentRow = state => line => { - if (state.diffLineCommentForms[line.lineCode]) return true; + if (state.diffLineCommentForms[line.line_code]) return true; if (!line.discussions || line.discussions.length === 0) { return false; @@ -108,7 +106,7 @@ export const shouldRenderInlineCommentRow = state => line => { // prevent babel-plugin-rewire from generating an invalid default during karma∂ tests export const getDiffFileByHash = state => fileHash => - state.diffFiles.find(file => file.fileHash === fileHash); + state.diffFiles.find(file => file.file_hash === fileHash); export const allBlobs = state => Object.values(state.treeEntries).filter(f => f.type === 'blob'); diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index e651c197968..2133cfe4825 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -23,12 +23,11 @@ export default { }, [types.SET_DIFF_DATA](state, data) { - const diffData = convertObjectPropsToCamelCase(data, { deep: true }); - prepareDiffData(diffData); - const { tree, treeEntries } = generateTreeList(diffData.diffFiles); + prepareDiffData(data); + const { tree, treeEntries } = generateTreeList(data.diff_files); Object.assign(state, { - ...diffData, + ...convertObjectPropsToCamelCase(data), tree: sortTree(tree), treeEntries, }); @@ -42,7 +41,7 @@ export default { [types.SET_MERGE_REQUEST_DIFFS](state, mergeRequestDiffs) { Object.assign(state, { - mergeRequestDiffs: convertObjectPropsToCamelCase(mergeRequestDiffs, { deep: true }), + mergeRequestDiffs, }); }, @@ -62,19 +61,18 @@ export default { const { lineNumbers, contextLines, fileHash } = options; const { bottom } = options.params; const diffFile = findDiffFile(state.diffFiles, fileHash); - const { highlightedDiffLines, parallelDiffLines } = diffFile; removeMatchLine(diffFile, lineNumbers, bottom); const lines = addLineReferences(contextLines, lineNumbers, bottom).map(line => ({ ...line, - lineCode: line.lineCode || `${fileHash}_${line.oldLine}_${line.newLine}`, + line_code: line.line_code || `${fileHash}_${line.old_line}_${line.new_line}`, discussions: line.discussions || [], })); addContextLines({ - inlineLines: highlightedDiffLines, - parallelLines: parallelDiffLines, + inlineLines: diffFile.highlighted_diff_lines, + parallelLines: diffFile.parallel_diff_lines, contextLines: lines, bottom, lineNumbers, @@ -82,10 +80,9 @@ export default { }, [types.ADD_COLLAPSED_DIFFS](state, { file, data }) { - const normalizedData = convertObjectPropsToCamelCase(data, { deep: true }); - prepareDiffData(normalizedData); - const [newFileData] = normalizedData.diffFiles.filter(f => f.fileHash === file.fileHash); - const selectedFile = state.diffFiles.find(f => f.fileHash === file.fileHash); + prepareDiffData(data); + const [newFileData] = data.diff_files.filter(f => f.file_hash === file.file_hash); + const selectedFile = state.diffFiles.find(f => f.file_hash === file.file_hash); Object.assign(selectedFile, { ...newFileData }); }, @@ -101,20 +98,20 @@ export default { const discussionLineCode = discussion.line_code; const fileHash = discussion.diff_file.file_hash; - const lineCheck = ({ lineCode }) => - lineCode === discussionLineCode && + const lineCheck = line => + line.line_code === discussionLineCode && isDiscussionApplicableToLine({ discussion, - diffPosition: diffPositionByLineCode[lineCode], + diffPosition: diffPositionByLineCode[line.line_code], latestDiff, }); state.diffFiles = state.diffFiles.map(diffFile => { - if (diffFile.fileHash === fileHash) { + if (diffFile.file_hash === fileHash) { const file = { ...diffFile }; - if (file.highlightedDiffLines) { - file.highlightedDiffLines = file.highlightedDiffLines.map(line => { + if (file.highlighted_diff_lines) { + file.highlighted_diff_lines = file.highlighted_diff_lines.map(line => { if (lineCheck(line)) { return { ...line, @@ -126,8 +123,8 @@ export default { }); } - if (file.parallelDiffLines) { - file.parallelDiffLines = file.parallelDiffLines.map(line => { + if (file.parallel_diff_lines) { + file.parallel_diff_lines = file.parallel_diff_lines.map(line => { const left = line.left && lineCheck(line.left); const right = line.right && lineCheck(line.right); @@ -148,7 +145,7 @@ export default { }); } - if (!file.parallelDiffLines || !file.highlightedDiffLines) { + if (!file.parallel_diff_lines || !file.highlighted_diff_lines) { file.discussions = file.discussions.concat(discussion); } @@ -160,16 +157,16 @@ export default { }, [types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode, id }) { - const selectedFile = state.diffFiles.find(f => f.fileHash === fileHash); + const selectedFile = state.diffFiles.find(f => f.file_hash === fileHash); if (selectedFile) { - if (selectedFile.parallelDiffLines) { - const targetLine = selectedFile.parallelDiffLines.find( + if (selectedFile.parallel_diff_lines) { + const targetLine = selectedFile.parallel_diff_lines.find( line => - (line.left && line.left.lineCode === lineCode) || - (line.right && line.right.lineCode === lineCode), + (line.left && line.left.line_code === lineCode) || + (line.right && line.right.line_code === lineCode), ); if (targetLine) { - const side = targetLine.left && targetLine.left.lineCode === lineCode ? 'left' : 'right'; + const side = targetLine.left && targetLine.left.line_code === lineCode ? 'left' : 'right'; Object.assign(targetLine[side], { discussions: [], @@ -177,9 +174,9 @@ export default { } } - if (selectedFile.highlightedDiffLines) { - const targetInlineLine = selectedFile.highlightedDiffLines.find( - line => line.lineCode === lineCode, + if (selectedFile.highlighted_diff_lines) { + const targetInlineLine = selectedFile.highlighted_diff_lines.find( + line => line.line_code === lineCode, ); if (targetInlineLine) { diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index a935b9b1ffa..d9d3c0f2ca2 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -1,5 +1,4 @@ import _ from 'underscore'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { diffModes } from '~/ide/constants'; import { LINE_POSITION_LEFT, @@ -15,7 +14,7 @@ import { } from '../constants'; export function findDiffFile(files, hash) { - return files.filter(file => file.fileHash === hash)[0]; + return files.filter(file => file.file_hash === hash)[0]; } export const getReversePosition = linePosition => { @@ -39,14 +38,14 @@ export function getFormData(params) { } = params; const position = JSON.stringify({ - base_sha: diffFile.diffRefs.baseSha, - start_sha: diffFile.diffRefs.startSha, - head_sha: diffFile.diffRefs.headSha, - old_path: diffFile.oldPath, - new_path: diffFile.newPath, + base_sha: diffFile.diff_refs.base_sha, + start_sha: diffFile.diff_refs.start_sha, + head_sha: diffFile.diff_refs.head_sha, + old_path: diffFile.old_path, + new_path: diffFile.new_path, position_type: positionType || TEXT_DIFF_POSITION_TYPE, - old_line: noteTargetLine ? noteTargetLine.oldLine : null, - new_line: noteTargetLine ? noteTargetLine.newLine : null, + old_line: noteTargetLine ? noteTargetLine.old_line : null, + new_line: noteTargetLine ? noteTargetLine.new_line : null, x: params.x, y: params.y, width: params.width, @@ -56,7 +55,7 @@ export function getFormData(params) { const postData = { view: diffViewType, line_type: linePosition === LINE_POSITION_RIGHT ? NEW_LINE_TYPE : OLD_LINE_TYPE, - merge_request_diff_head_sha: diffFile.diffRefs.headSha, + merge_request_diff_head_sha: diffFile.diff_refs.head_sha, in_reply_to_discussion_id: '', note_project_id: '', target_type: noteableData.targetType, @@ -69,10 +68,10 @@ export function getFormData(params) { noteable_id: noteableData.id, commit_id: '', type: - diffFile.diffRefs.startSha && diffFile.diffRefs.headSha + diffFile.diff_refs.start_sha && diffFile.diff_refs.head_sha ? DIFF_NOTE_TYPE : LEGACY_DIFF_NOTE_TYPE, - line_code: noteTargetLine ? noteTargetLine.lineCode : null, + line_code: noteTargetLine ? noteTargetLine.line_code : null, }, }; @@ -93,7 +92,7 @@ export const findIndexInInlineLines = (lines, lineNumbers) => { return _.findIndex( lines, - line => line.oldLine === oldLineNumber && line.newLine === newLineNumber, + line => line.old_line === oldLineNumber && line.new_line === newLineNumber, ); }; @@ -105,18 +104,18 @@ export const findIndexInParallelLines = (lines, lineNumbers) => { line => line.left && line.right && - line.left.oldLine === oldLineNumber && - line.right.newLine === newLineNumber, + line.left.old_line === oldLineNumber && + line.right.new_line === newLineNumber, ); }; export function removeMatchLine(diffFile, lineNumbers, bottom) { - const indexForInline = findIndexInInlineLines(diffFile.highlightedDiffLines, lineNumbers); - const indexForParallel = findIndexInParallelLines(diffFile.parallelDiffLines, lineNumbers); + const indexForInline = findIndexInInlineLines(diffFile.highlighted_diff_lines, lineNumbers); + const indexForParallel = findIndexInParallelLines(diffFile.parallel_diff_lines, lineNumbers); const factor = bottom ? 1 : -1; - diffFile.highlightedDiffLines.splice(indexForInline + factor, 1); - diffFile.parallelDiffLines.splice(indexForParallel + factor, 1); + diffFile.highlighted_diff_lines.splice(indexForInline + factor, 1); + diffFile.parallel_diff_lines.splice(indexForParallel + factor, 1); } export function addLineReferences(lines, lineNumbers, bottom) { @@ -125,18 +124,16 @@ export function addLineReferences(lines, lineNumbers, bottom) { let matchLineIndex = -1; const linesWithNumbers = lines.map((l, index) => { - const line = convertObjectPropsToCamelCase(l); - - if (line.type === MATCH_LINE_TYPE) { + if (l.type === MATCH_LINE_TYPE) { matchLineIndex = index; } else { - Object.assign(line, { - oldLine: bottom ? oldLineNumber + index + 1 : oldLineNumber + index - lineCount, - newLine: bottom ? newLineNumber + index + 1 : newLineNumber + index - lineCount, + Object.assign(l, { + old_line: bottom ? oldLineNumber + index + 1 : oldLineNumber + index - lineCount, + new_line: bottom ? newLineNumber + index + 1 : newLineNumber + index - lineCount, }); } - return line; + return l; }); if (matchLineIndex > -1) { @@ -146,9 +143,9 @@ export function addLineReferences(lines, lineNumbers, bottom) { : linesWithNumbers[matchLineIndex + 1]; Object.assign(line, { - metaData: { - oldPos: targetLine.oldLine, - newPos: targetLine.newLine, + meta_data: { + old_pos: targetLine.old_line, + new_pos: targetLine.new_line, }, }); } @@ -187,11 +184,11 @@ export function trimFirstCharOfLineContent(line = {}) { const parsedLine = Object.assign({}, line); - if (line.richText) { - const firstChar = parsedLine.richText.charAt(0); + if (line.rich_text) { + const firstChar = parsedLine.rich_text.charAt(0); if (firstChar === ' ' || firstChar === '+' || firstChar === '-') { - parsedLine.richText = line.richText.substring(1); + parsedLine.rich_text = line.rich_text.substring(1); } } @@ -201,15 +198,15 @@ export function trimFirstCharOfLineContent(line = {}) { // This prepares and optimizes the incoming diff data from the server // by setting up incremental rendering and removing unneeded data export function prepareDiffData(diffData) { - const filesLength = diffData.diffFiles.length; + const filesLength = diffData.diff_files.length; let showingLines = 0; for (let i = 0; i < filesLength; i += 1) { - const file = diffData.diffFiles[i]; + const file = diffData.diff_files[i]; - if (file.parallelDiffLines) { - const linesLength = file.parallelDiffLines.length; + if (file.parallel_diff_lines) { + const linesLength = file.parallel_diff_lines.length; for (let u = 0; u < linesLength; u += 1) { - const line = file.parallelDiffLines[u]; + const line = file.parallel_diff_lines[u]; if (line.left) { line.left = trimFirstCharOfLineContent(line.left); } @@ -219,13 +216,13 @@ export function prepareDiffData(diffData) { } } - if (file.highlightedDiffLines) { - const linesLength = file.highlightedDiffLines.length; + if (file.highlighted_diff_lines) { + const linesLength = file.highlighted_diff_lines.length; for (let u = 0; u < linesLength; u += 1) { - const line = file.highlightedDiffLines[u]; + const line = file.highlighted_diff_lines[u]; Object.assign(line, { ...trimFirstCharOfLineContent(line) }); } - showingLines += file.parallelDiffLines.length; + showingLines += file.parallel_diff_lines.length; } Object.assign(file, { @@ -238,26 +235,21 @@ export function prepareDiffData(diffData) { export function getDiffPositionByLineCode(diffFiles) { return diffFiles.reduce((acc, diffFile) => { - const { baseSha, headSha, startSha } = diffFile.diffRefs; - const { newPath, oldPath } = diffFile; - // We can only use highlightedDiffLines to create the map of diff lines because // highlightedDiffLines will also include every parallel diff line in it. - if (diffFile.highlightedDiffLines) { - diffFile.highlightedDiffLines.forEach(line => { - const { lineCode, oldLine, newLine } = line; - - if (lineCode) { - acc[lineCode] = { - baseSha, - headSha, - startSha, - newPath, - oldPath, - oldLine, - newLine, - lineCode, - positionType: 'text', + if (diffFile.highlighted_diff_lines) { + diffFile.highlighted_diff_lines.forEach(line => { + if (line.line_code) { + acc[line.line_code] = { + base_sha: diffFile.diff_refs.base_sha, + head_sha: diffFile.diff_refs.head_sha, + start_sha: diffFile.diff_refs.start_sha, + new_path: diffFile.new_path, + old_path: diffFile.old_path, + old_line: line.old_line, + new_line: line.new_line, + line_code: line.line_code, + position_type: 'text', }; } }); @@ -270,30 +262,30 @@ export function getDiffPositionByLineCode(diffFiles) { // This method will check whether the discussion is still applicable // to the diff line in question regarding different versions of the MR export function isDiscussionApplicableToLine({ discussion, diffPosition, latestDiff }) { - const { lineCode, ...diffPositionCopy } = diffPosition; + const { line_code, ...diffPositionCopy } = diffPosition; if (discussion.original_position && discussion.position) { - const originalRefs = convertObjectPropsToCamelCase(discussion.original_position); - const refs = convertObjectPropsToCamelCase(discussion.position); + const originalRefs = discussion.original_position; + const refs = discussion.position; return _.isEqual(refs, diffPositionCopy) || _.isEqual(originalRefs, diffPositionCopy); } - return latestDiff && discussion.active && lineCode === discussion.line_code; + // eslint-disable-next-line + return latestDiff && discussion.active && line_code === discussion.line_code; } export const generateTreeList = files => files.reduce( (acc, file) => { - const { fileHash, addedLines, removedLines, newFile, deletedFile, newPath } = file; - const split = newPath.split('/'); + const split = file.new_path.split('/'); split.forEach((name, i) => { const parent = acc.treeEntries[split.slice(0, i).join('/')]; const path = `${parent ? `${parent.path}/` : ''}${name}`; if (!acc.treeEntries[path]) { - const type = path === newPath ? 'blob' : 'tree'; + const type = path === file.new_path ? 'blob' : 'tree'; acc.treeEntries[path] = { key: path, path, @@ -307,11 +299,11 @@ export const generateTreeList = files => if (type === 'blob') { Object.assign(entry, { changed: true, - tempFile: newFile, - deleted: deletedFile, - fileHash, - addedLines, - removedLines, + tempFile: file.new_file, + deleted: file.deleted_file, + fileHash: file.file_hash, + addedLines: file.added_lines, + removedLines: file.removed_lines, }); } else { Object.assign(entry, { @@ -329,6 +321,6 @@ export const generateTreeList = files => ); export const getDiffMode = diffFile => { - const diffModeKey = Object.keys(diffModes).find(key => diffFile[`${key}File`]); + const diffModeKey = Object.keys(diffModes).find(key => diffFile[`${key}_file`]); return diffModes[diffModeKey] || diffModes.replaced; }; diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue index a48f5fcb7d6..6c0b5c1f427 100644 --- a/app/assets/javascripts/environments/components/container.vue +++ b/app/assets/javascripts/environments/components/container.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import tablePagination from '../../vue_shared/components/table_pagination.vue'; import environmentTable from '../components/environments_table.vue'; diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue index 03c3ad0401f..b849772a82e 100644 --- a/app/assets/javascripts/environments/components/environment_actions.vue +++ b/app/assets/javascripts/environments/components/environment_actions.vue @@ -4,7 +4,7 @@ import { formatTime } from '~/lib/utils/datetime_utility'; import Icon from '~/vue_shared/components/icon.vue'; import eventHub from '../event_hub'; import tooltip from '../../vue_shared/directives/tooltip'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { directives: { diff --git a/app/assets/javascripts/environments/components/environment_external_url.vue b/app/assets/javascripts/environments/components/environment_external_url.vue index 1e8a892c0b8..af537cfb991 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.vue +++ b/app/assets/javascripts/environments/components/environment_external_url.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import { s__ } from '~/locale'; diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index 50b0e9747ee..34d94490533 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -1,7 +1,7 @@ <script> import Timeago from 'timeago.js'; import _ from 'underscore'; -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import { humanize } from '~/lib/utils/text_utility'; import Icon from '~/vue_shared/components/icon.vue'; diff --git a/app/assets/javascripts/environments/components/environment_monitoring.vue b/app/assets/javascripts/environments/components/environment_monitoring.vue index 7c723fa8979..ae4f07a71cd 100644 --- a/app/assets/javascripts/environments/components/environment_monitoring.vue +++ b/app/assets/javascripts/environments/components/environment_monitoring.vue @@ -2,7 +2,7 @@ /** * Renders the Monitoring (Metrics) link in environments table. */ -import { GlButton, GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlButton, GlTooltipDirective } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; export default { diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue index 298469e6482..46c77dca871 100644 --- a/app/assets/javascripts/environments/components/environment_rollback.vue +++ b/app/assets/javascripts/environments/components/environment_rollback.vue @@ -6,7 +6,7 @@ * Makes a post request when the button is clicked. */ import { s__ } from '~/locale'; -import { GlTooltipDirective, GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import eventHub from '../event_hub'; @@ -63,7 +63,7 @@ export default { > <icon v-if="isLastDeployment" - name="repeat" + name="repeat" /> <icon v-else diff --git a/app/assets/javascripts/environments/components/environment_stop.vue b/app/assets/javascripts/environments/components/environment_stop.vue index 327c96a93e9..efecc128368 100644 --- a/app/assets/javascripts/environments/components/environment_stop.vue +++ b/app/assets/javascripts/environments/components/environment_stop.vue @@ -5,7 +5,7 @@ */ import $ from 'jquery'; -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import { s__ } from '~/locale'; import eventHub from '../event_hub'; diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue index b8b909f350c..83727caad16 100644 --- a/app/assets/javascripts/environments/components/environment_terminal_button.vue +++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue @@ -3,7 +3,7 @@ * Renders a terminal button to open a web terminal. * Used in environments table. */ -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; export default { diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue index c03d4f29ff9..4eae4eec394 100644 --- a/app/assets/javascripts/environments/components/environments_table.vue +++ b/app/assets/javascripts/environments/components/environments_table.vue @@ -2,7 +2,7 @@ /** * Render environments table. */ -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import environmentItem from './environment_item.vue'; export default { diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue index 6397f6caf1b..2ebc7b5b951 100644 --- a/app/assets/javascripts/environments/components/stop_environment_modal.vue +++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import GlModal from '~/vue_shared/components/gl_modal.vue'; import { s__, sprintf } from '~/locale'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; diff --git a/app/assets/javascripts/files_comment_button.js b/app/assets/javascripts/files_comment_button.js index 3233f5c4f71..aad5647c045 100644 --- a/app/assets/javascripts/files_comment_button.js +++ b/app/assets/javascripts/files_comment_button.js @@ -1,5 +1,5 @@ /* Developer beware! Do not add logic to showButton or hideButton - * that will force a reflow. Doing so will create a signficant performance + * that will force a reflow. Doing so will create a significant performance * bottleneck for pages with large diffs. For a comprehensive list of what * causes reflows, visit https://gist.github.com/paulirish/5d52fb081b3570c81e3a */ diff --git a/app/assets/javascripts/filtered_search/dropdown_emoji.js b/app/assets/javascripts/filtered_search/dropdown_emoji.js index af7936a92fb..d9a4d06b549 100644 --- a/app/assets/javascripts/filtered_search/dropdown_emoji.js +++ b/app/assets/javascripts/filtered_search/dropdown_emoji.js @@ -69,10 +69,13 @@ export default class DropdownEmoji extends FilteredSearchDropdown { // Replace empty gl-emoji tag to real content const dropdownItems = [...this.dropdown.querySelectorAll('.filter-dropdown-item')]; dropdownItems.forEach(dropdownItem => { - const name = dropdownItem.querySelector('.js-data-value').innerText; - const emojiTag = this.glEmojiTag(name); - const emojiElement = dropdownItem.querySelector('gl-emoji'); - emojiElement.outerHTML = emojiTag; + const valueElement = dropdownItem.querySelector('.js-data-value'); + if (valueElement !== null) { + const name = valueElement.innerText; + const emojiTag = this.glEmojiTag(name); + const emojiElement = dropdownItem.querySelector('gl-emoji'); + emojiElement.outerHTML = emojiTag; + } }); } diff --git a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js index c23d4c484a5..89dcff74d0e 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js +++ b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js @@ -135,10 +135,6 @@ export default class FilteredSearchVisualTokens { } static updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue) { - if (tokenValue === 'none') { - return Promise.resolve(); - } - const username = tokenValue.replace(/^@/, ''); return ( UsersCache.retrieve(username) @@ -184,7 +180,12 @@ export default class FilteredSearchVisualTokens { const tokenValueElement = tokenValueContainer.querySelector('.value'); tokenValueElement.innerText = tokenValue; + if (tokenValue === 'none' || tokenValue === 'any') { + return; + } + const tokenType = tokenName.toLowerCase(); + if (tokenType === 'label') { FilteredSearchVisualTokens.updateLabelTokenColor(tokenValueContainer, tokenValue); } else if (tokenType === 'author' || tokenType === 'assignee') { diff --git a/app/assets/javascripts/frequent_items/components/app.vue b/app/assets/javascripts/frequent_items/components/app.vue index 159c0bdc992..1ed8254bc58 100644 --- a/app/assets/javascripts/frequent_items/components/app.vue +++ b/app/assets/javascripts/frequent_items/components/app.vue @@ -1,7 +1,7 @@ <script> import { mapState, mapActions, mapGetters } from 'vuex'; import AccessorUtilities from '~/lib/utils/accessor'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import eventHub from '../event_hub'; import store from '../store/'; import { FREQUENT_ITEMS, STORAGE_KEY } from '../constants'; diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue index 2a4a39436e7..29dc2d6a8a3 100644 --- a/app/assets/javascripts/groups/components/app.vue +++ b/app/assets/javascripts/groups/components/app.vue @@ -8,7 +8,7 @@ import { HIDDEN_CLASS } from '~/lib/utils/constants'; import { getParameterByName } from '~/lib/utils/common_utils'; import { mergeUrlParams } from '~/lib/utils/url_utility'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import eventHub from '../event_hub'; import { COMMON_STR, CONTENT_LIST_CLASS } from '../constants'; import groupsComponent from './groups.vue'; diff --git a/app/assets/javascripts/ide/components/branches/search_list.vue b/app/assets/javascripts/ide/components/branches/search_list.vue index 358f1153de2..600e1063f89 100644 --- a/app/assets/javascripts/ide/components/branches/search_list.vue +++ b/app/assets/javascripts/ide/components/branches/search_list.vue @@ -2,7 +2,7 @@ import { mapActions, mapState } from 'vuex'; import _ from 'underscore'; import Icon from '~/vue_shared/components/icon.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import Item from './item.vue'; export default { diff --git a/app/assets/javascripts/ide/components/error_message.vue b/app/assets/javascripts/ide/components/error_message.vue index 2d9bd99e82a..11fc15871ac 100644 --- a/app/assets/javascripts/ide/components/error_message.vue +++ b/app/assets/javascripts/ide/components/error_message.vue @@ -1,6 +1,6 @@ <script> import { mapActions } from 'vuex'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/ide/components/file_templates/dropdown.vue b/app/assets/javascripts/ide/components/file_templates/dropdown.vue index 891f7d48b4c..81d8d0b5132 100644 --- a/app/assets/javascripts/ide/components/file_templates/dropdown.vue +++ b/app/assets/javascripts/ide/components/file_templates/dropdown.vue @@ -2,7 +2,7 @@ import $ from 'jquery'; import { mapActions, mapState } from 'vuex'; import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue index 364ab9426e0..6b4849eb6f9 100644 --- a/app/assets/javascripts/ide/components/ide_side_bar.vue +++ b/app/assets/javascripts/ide/components/ide_side_bar.vue @@ -1,6 +1,6 @@ <script> import { mapState, mapGetters } from 'vuex'; -import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui'; +import { GlSkeletonLoading } from '@gitlab/ui'; import IdeTree from './ide_tree.vue'; import ResizablePanel from './resizable_panel.vue'; import ActivityBar from './activity_bar.vue'; diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue index d2ff55a4ee3..12ed7f86b3d 100644 --- a/app/assets/javascripts/ide/components/ide_tree_list.vue +++ b/app/assets/javascripts/ide/components/ide_tree_list.vue @@ -1,7 +1,7 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; -import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui'; +import { GlSkeletonLoading } from '@gitlab/ui'; import FileRow from '~/vue_shared/components/file_row.vue'; import NavDropdown from './nav_dropdown.vue'; import FileRowExtra from './file_row_extra.vue'; diff --git a/app/assets/javascripts/ide/components/jobs/list.vue b/app/assets/javascripts/ide/components/jobs/list.vue index 57da8b4e2cb..e3626f60899 100644 --- a/app/assets/javascripts/ide/components/jobs/list.vue +++ b/app/assets/javascripts/ide/components/jobs/list.vue @@ -1,6 +1,6 @@ <script> import { mapActions } from 'vuex'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import Stage from './stage.vue'; export default { diff --git a/app/assets/javascripts/ide/components/jobs/stage.vue b/app/assets/javascripts/ide/components/jobs/stage.vue index 5644759d2f9..e4fc78afaf2 100644 --- a/app/assets/javascripts/ide/components/jobs/stage.vue +++ b/app/assets/javascripts/ide/components/jobs/stage.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import tooltip from '../../../vue_shared/directives/tooltip'; import Icon from '../../../vue_shared/components/icon.vue'; import CiIcon from '../../../vue_shared/components/ci_icon.vue'; diff --git a/app/assets/javascripts/ide/components/merge_requests/list.vue b/app/assets/javascripts/ide/components/merge_requests/list.vue index e4000f588bd..4df29590b85 100644 --- a/app/assets/javascripts/ide/components/merge_requests/list.vue +++ b/app/assets/javascripts/ide/components/merge_requests/list.vue @@ -3,7 +3,7 @@ import { mapActions, mapState } from 'vuex'; import _ from 'underscore'; import { __ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import Item from './item.vue'; import TokenedInput from '../shared/tokened_input.vue'; diff --git a/app/assets/javascripts/ide/components/pipelines/list.vue b/app/assets/javascripts/ide/components/pipelines/list.vue index 16aec1decd6..36cfcac4186 100644 --- a/app/assets/javascripts/ide/components/pipelines/list.vue +++ b/app/assets/javascripts/ide/components/pipelines/list.vue @@ -1,7 +1,7 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; import _ from 'underscore'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import { sprintf, __ } from '../../../locale'; import Icon from '../../../vue_shared/components/icon.vue'; import CiIcon from '../../../vue_shared/components/ci_icon.vue'; diff --git a/app/assets/javascripts/ide/components/preview/clientside.vue b/app/assets/javascripts/ide/components/preview/clientside.vue index 0bd56ff6e9b..afc0cfca7d8 100644 --- a/app/assets/javascripts/ide/components/preview/clientside.vue +++ b/app/assets/javascripts/ide/components/preview/clientside.vue @@ -3,7 +3,7 @@ import { mapActions, mapGetters, mapState } from 'vuex'; import _ from 'underscore'; import { Manager } from 'smooshpack'; import { listen } from 'codesandbox-api'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import Navigator from './navigator.vue'; import { packageJsonPath } from '../../constants'; import { createPathWithExt } from '../../utils'; diff --git a/app/assets/javascripts/ide/components/preview/navigator.vue b/app/assets/javascripts/ide/components/preview/navigator.vue index af8959186f9..cc6fc595b74 100644 --- a/app/assets/javascripts/ide/components/preview/navigator.vue +++ b/app/assets/javascripts/ide/components/preview/navigator.vue @@ -1,7 +1,7 @@ <script> import { listen } from 'codesandbox-api'; import Icon from '~/vue_shared/components/icon.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js index 8fa86995ef0..ea2525a2f0e 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js @@ -28,7 +28,7 @@ export const receiveLatestPipelineError = ({ commit, dispatch }, err) => { dispatch( 'setErrorMessage', { - text: __('An error occured whilst fetching the latest pipline.'), + text: __('An error occured whilst fetching the latest pipeline.'), action: () => dispatch('forcePipelineRequest').then(() => dispatch('setErrorMessage', null, { root: true }), diff --git a/app/assets/javascripts/init_legacy_filters.js b/app/assets/javascripts/init_legacy_filters.js deleted file mode 100644 index b6ff97d1279..00000000000 --- a/app/assets/javascripts/init_legacy_filters.js +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable no-new */ -import LabelsSelect from './labels_select'; -import subscriptionSelect from './subscription_select'; -import UsersSelect from './users_select'; -import issueStatusSelect from './issue_status_select'; -import MilestoneSelect from './milestone_select'; - -export default () => { - new UsersSelect(); - new LabelsSelect(); - new MilestoneSelect(); - issueStatusSelect(); - subscriptionSelect(); -}; diff --git a/app/assets/javascripts/jobs/components/artifacts_block.vue b/app/assets/javascripts/jobs/components/artifacts_block.vue index 93c89411b4a..932675c0fc6 100644 --- a/app/assets/javascripts/jobs/components/artifacts_block.vue +++ b/app/assets/javascripts/jobs/components/artifacts_block.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import timeagoMixin from '~/vue_shared/mixins/timeago'; diff --git a/app/assets/javascripts/jobs/components/commit_block.vue b/app/assets/javascripts/jobs/components/commit_block.vue index 06fe23fedce..9373dbebc8a 100644 --- a/app/assets/javascripts/jobs/components/commit_block.vue +++ b/app/assets/javascripts/jobs/components/commit_block.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; export default { diff --git a/app/assets/javascripts/jobs/components/empty_state.vue b/app/assets/javascripts/jobs/components/empty_state.vue index be7425c2d25..afc4d931a68 100644 --- a/app/assets/javascripts/jobs/components/empty_state.vue +++ b/app/assets/javascripts/jobs/components/empty_state.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/jobs/components/erased_block.vue b/app/assets/javascripts/jobs/components/erased_block.vue index d80e905c68e..712f564b065 100644 --- a/app/assets/javascripts/jobs/components/erased_block.vue +++ b/app/assets/javascripts/jobs/components/erased_block.vue @@ -1,6 +1,6 @@ <script> import _ from 'underscore'; -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; export default { diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue index 90216b04e92..ecb809ca4de 100644 --- a/app/assets/javascripts/jobs/components/job_app.vue +++ b/app/assets/javascripts/jobs/components/job_app.vue @@ -1,7 +1,7 @@ <script> import _ from 'underscore'; import { mapGetters, mapState, mapActions } from 'vuex'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import { isScrolledToBottom } from '~/lib/utils/scroll_utils'; import { polyfillSticky } from '~/lib/utils/sticky'; import bp from '~/breakpoints'; diff --git a/app/assets/javascripts/jobs/components/job_container_item.vue b/app/assets/javascripts/jobs/components/job_container_item.vue index 3ddcfd11dca..80cbed422a0 100644 --- a/app/assets/javascripts/jobs/components/job_container_item.vue +++ b/app/assets/javascripts/jobs/components/job_container_item.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; import tooltip from '~/vue_shared/directives/tooltip'; import CiIcon from '~/vue_shared/components/ci_icon.vue'; import Icon from '~/vue_shared/components/icon.vue'; diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue index 8b506b124ec..5e0495bb231 100644 --- a/app/assets/javascripts/jobs/components/job_log_controllers.vue +++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective, GlLink, GlButton } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui'; import { polyfillSticky } from '~/lib/utils/sticky'; import Icon from '~/vue_shared/components/icon.vue'; import { numberToHumanSize } from '~/lib/utils/number_utils'; diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue index f7b7b8f10f7..21f0a1435d7 100644 --- a/app/assets/javascripts/jobs/components/sidebar.vue +++ b/app/assets/javascripts/jobs/components/sidebar.vue @@ -1,7 +1,7 @@ <script> import _ from 'underscore'; import { mapActions, mapState } from 'vuex'; -import { GlLink, GlButton } from '@gitlab-org/gitlab-ui'; +import { GlLink, GlButton } from '@gitlab/ui'; import timeagoMixin from '~/vue_shared/mixins/timeago'; import { timeIntervalInWords } from '~/lib/utils/datetime_utility'; import Icon from '~/vue_shared/components/icon.vue'; diff --git a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue index cfedb38e17a..d143e9f586c 100644 --- a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue +++ b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; export default { name: 'SidebarDetailRow', diff --git a/app/assets/javascripts/jobs/components/stuck_block.vue b/app/assets/javascripts/jobs/components/stuck_block.vue index ca4bf471363..2b2ebe4c3f7 100644 --- a/app/assets/javascripts/jobs/components/stuck_block.vue +++ b/app/assets/javascripts/jobs/components/stuck_block.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; /** * Renders Stuck Runners block for job's view. */ diff --git a/app/assets/javascripts/jobs/components/trigger_block.vue b/app/assets/javascripts/jobs/components/trigger_block.vue index 1e62c05b4d1..4d18f76b7ea 100644 --- a/app/assets/javascripts/jobs/components/trigger_block.vue +++ b/app/assets/javascripts/jobs/components/trigger_block.vue @@ -1,5 +1,5 @@ <script> -import { GlButton } from '@gitlab-org/gitlab-ui'; +import { GlButton } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/jobs/store/getters.js b/app/assets/javascripts/jobs/store/getters.js index d440b2c9ef1..35e92b0b5d9 100644 --- a/app/assets/javascripts/jobs/store/getters.js +++ b/app/assets/javascripts/jobs/store/getters.js @@ -42,7 +42,7 @@ export const emptyStateIllustration = state => (state.job && state.job.status && state.job.status.illustration) || {}; export const emptyStateAction = state => - (state.job && state.job.status && state.job.status.action) || {}; + (state.job && state.job.status && state.job.status.action) || null; export const isScrollingDown = state => isScrolledToBottom() && !state.isTraceComplete; diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 90fe339e3de..dfb53c986fc 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -16,7 +16,7 @@ import 'vendor/jquery.atwho'; import AjaxCache from '~/lib/utils/ajax_cache'; import Vue from 'vue'; import syntaxHighlight from '~/syntax_highlight'; -import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui'; +import { GlSkeletonLoading } from '@gitlab/ui'; import axios from './lib/utils/axios_utils'; import { getLocationHash } from './lib/utils/url_utility'; import Flash from './flash'; diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue index b209f736c3f..30fcb895369 100644 --- a/app/assets/javascripts/notes/components/diff_with_note.vue +++ b/app/assets/javascripts/notes/components/diff_with_note.vue @@ -1,10 +1,9 @@ <script> import { mapState, mapActions } from 'vuex'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import DiffFileHeader from '~/diffs/components/diff_file_header.vue'; import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; import ImageDiffOverlay from '~/diffs/components/image_diff_overlay.vue'; -import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui'; +import { GlSkeletonLoading } from '@gitlab/ui'; import { trimFirstCharOfLineContent, getDiffMode } from '~/diffs/store/utils'; export default { @@ -34,7 +33,9 @@ export default { return getDiffMode(this.diffFile); }, hasTruncatedDiffLines() { - return this.discussion.truncatedDiffLines && this.discussion.truncatedDiffLines.length !== 0; + return ( + this.discussion.truncated_diff_lines && this.discussion.truncated_diff_lines.length !== 0 + ); }, isDiscussionsExpanded() { return true; // TODO: @fatihacet - Fix this. @@ -50,19 +51,17 @@ export default { return text ? 'text-file' : 'js-image-file'; }, diffFile() { - return convertObjectPropsToCamelCase(this.discussion.diffFile, { deep: true }); + return this.discussion.diff_file; }, imageDiffHtml() { - return this.discussion.imageDiffHtml; + return this.discussion.image_diff_html; }, userColorScheme() { return window.gon.user_color_scheme; }, normalizedDiffLines() { - if (this.discussion.truncatedDiffLines) { - return this.discussion.truncatedDiffLines.map(line => - trimFirstCharOfLineContent(convertObjectPropsToCamelCase(line)), - ); + if (this.discussion.truncated_diff_lines) { + return this.discussion.truncated_diff_lines.map(line => trimFirstCharOfLineContent(line)); } return []; @@ -97,7 +96,7 @@ export default { class="diff-file file-holder" > <diff-file-header - :discussion-path="discussion.discussionPath" + :discussion-path="discussion.discussion_path" :diff-file="diffFile" :can-current-user-fork="false" :discussions-expanded="isDiscussionsExpanded" @@ -111,15 +110,15 @@ export default { <table> <tr v-for="line in normalizedDiffLines" - :key="line.lineCode" + :key="line.line_code" class="line_holder" > - <td class="diff-line-num old_line">{{ line.oldLine }}</td> - <td class="diff-line-num new_line">{{ line.newLine }}</td> + <td class="diff-line-num old_line">{{ line.old_line }}</td> + <td class="diff-line-num new_line">{{ line.new_line }}</td> <td :class="line.type" class="line_content" - v-html="line.richText" + v-html="line.rich_text" > </td> </tr> @@ -165,17 +164,17 @@ export default { > <diff-viewer :diff-mode="diffMode" - :new-path="diffFile.newPath" - :new-sha="diffFile.diffRefs.headSha" - :old-path="diffFile.oldPath" - :old-sha="diffFile.diffRefs.baseSha" - :file-hash="diffFile.fileHash" + :new-path="diffFile.new_path" + :new-sha="diffFile.diff_refs.head_sha" + :old-path="diffFile.old_path" + :old-sha="diffFile.diff_refs.base_sha" + :file-hash="diffFile.file_hash" :project-path="projectPath" > <image-diff-overlay slot="image-overlay" :discussions="discussion" - :file-hash="diffFile.fileHash" + :file-hash="diffFile.file_hash" :show-comment-icon="true" :should-toggle-discussion="false" badge-class="image-comment-badge" diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue index f7a61fbfcd4..0f0d7f4661a 100644 --- a/app/assets/javascripts/notes/components/note_actions.vue +++ b/app/assets/javascripts/notes/components/note_actions.vue @@ -2,7 +2,7 @@ import { mapGetters } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { name: 'NoteActions', diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index c1dfa036678..7740967ccd5 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -1,6 +1,5 @@ <script> import { mapActions, mapGetters } from 'vuex'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { truncateSha } from '~/lib/utils/text_utility'; import { s__ } from '~/locale'; import systemNote from '~/vue_shared/components/notes/system_note.vue'; @@ -88,17 +87,16 @@ export default { transformedDiscussion() { return { ...this.discussion.notes[0], - truncatedDiffLines: this.discussion.truncated_diff_lines || [], - truncatedDiffLinesPath: this.discussion.truncated_diff_lines_path, - diffFile: this.discussion.diff_file, - diffDiscussion: this.discussion.diff_discussion, - imageDiffHtml: this.discussion.image_diff_html, + truncated_diff_lines: this.discussion.truncated_diff_lines || [], + truncated_diff_lines_path: this.discussion.truncated_diff_lines_path, + diff_file: this.discussion.diff_file, + diff_discussion: this.discussion.diff_discussion, active: this.discussion.active, - discussionPath: this.discussion.discussion_path, + discussion_path: this.discussion.discussion_path, resolved: this.discussion.resolved, - resolvedBy: this.discussion.resolved_by, - resolvedByPush: this.discussion.resolved_by_push, - resolvedAt: this.discussion.resolved_at, + resolved_by: this.discussion.resolved_by, + resolved_by_push: this.discussion.resolved_by_push, + resolved_at: this.discussion.resolved_at, }; }, author() { @@ -138,7 +136,7 @@ export default { return null; }, resolvedText() { - return this.transformedDiscussion.resolvedByPush ? 'Automatically resolved' : 'Resolved'; + return this.transformedDiscussion.resolved_by_push ? 'Automatically resolved' : 'Resolved'; }, hasMultipleUnresolvedDiscussions() { return this.unresolvedDiscussions.length > 1; @@ -150,12 +148,14 @@ export default { ); }, shouldRenderDiffs() { - const { diffDiscussion, diffFile } = this.transformedDiscussion; - - return diffDiscussion && diffFile && this.renderDiffFile; + return ( + this.transformedDiscussion.diff_discussion && + this.transformedDiscussion.diff_file && + this.renderDiffFile + ); }, shouldGroupReplies() { - return !this.shouldRenderDiffs && !this.transformedDiscussion.diffDiscussion; + return !this.shouldRenderDiffs && !this.transformedDiscussion.diff_discussion; }, shouldRenderHeader() { return this.shouldRenderDiffs; @@ -165,7 +165,7 @@ export default { }, wrapperComponentProps() { if (this.shouldRenderDiffs) { - return { discussion: convertObjectPropsToCamelCase(this.discussion) }; + return { discussion: this.discussion }; } return {}; @@ -184,8 +184,8 @@ export default { }, shouldShowDiscussions() { const isExpanded = this.discussion.expanded; - const { diffDiscussion, resolved } = this.transformedDiscussion; - const isResolvedNonDiffDiscussion = !diffDiscussion && resolved; + const { resolved } = this.transformedDiscussion; + const isResolvedNonDiffDiscussion = !this.transformedDiscussion.diff_discussion && resolved; return isExpanded || this.alwaysExpanded || isResolvedNonDiffDiscussion; }, @@ -333,9 +333,9 @@ Please check your network connection and try again.`; :expanded="discussion.expanded" @toggleHandler="toggleDiscussionHandler" > - <template v-if="transformedDiscussion.diffDiscussion"> + <template v-if="transformedDiscussion.diff_discussion"> started a discussion on - <a :href="transformedDiscussion.discussionPath"> + <a :href="transformedDiscussion.discussion_path"> <template v-if="transformedDiscussion.active"> the diff </template> @@ -356,8 +356,8 @@ Please check your network connection and try again.`; </note-header> <note-edited-text v-if="transformedDiscussion.resolved" - :edited-at="transformedDiscussion.resolvedAt" - :edited-by="transformedDiscussion.resolvedBy" + :edited-at="transformedDiscussion.resolved_at" + :edited-by="transformedDiscussion.resolved_by" :action-text="resolvedText" class-name="discussion-headline-light js-discussion-headline" /> diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index a4ab079d258..5b2f0540020 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -341,7 +341,7 @@ export const scrollToNoteIfNeeded = (context, el) => { }; export const fetchDiscussionDiffLines = ({ commit }, discussion) => - axios.get(discussion.truncatedDiffLinesPath).then(({ data }) => { + axios.get(discussion.truncated_diff_lines_path).then(({ data }) => { commit(types.SET_DISCUSSION_DIFF_LINES, { discussionId: discussion.id, diffLines: data.truncated_diff_lines, diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index c8d9e196103..f6054e0be87 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -102,7 +102,7 @@ export default { discussionsData.forEach(discussion => { if (discussion.diff_file) { Object.assign(discussion, { - fileHash: discussion.diff_file.file_hash, + file_hash: discussion.diff_file.file_hash, truncated_diff_lines: discussion.truncated_diff_lines || [], }); } @@ -195,7 +195,7 @@ export default { const selectedDiscussion = state.discussions.find(disc => disc.id === note.id); note.expanded = true; // override expand flag to prevent collapse if (note.diff_file) { - Object.assign(note, { fileHash: note.diff_file.file_hash }); + Object.assign(note, { file_hash: note.diff_file.file_hash }); } Object.assign(selectedDiscussion, { ...note }); }, diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js index c4901dd1cb6..9055738f86e 100644 --- a/app/assets/javascripts/pages/dashboard/issues/index.js +++ b/app/assets/javascripts/pages/dashboard/issues/index.js @@ -1,7 +1,13 @@ import projectSelect from '~/project_select'; -import initLegacyFilters from '~/init_legacy_filters'; +import initFilteredSearch from '~/pages/search/init_filtered_search'; +import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; +import { FILTERED_SEARCH } from '~/pages/constants'; document.addEventListener('DOMContentLoaded', () => { + initFilteredSearch({ + page: FILTERED_SEARCH.ISSUES, + filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, + }); + projectSelect(); - initLegacyFilters(); }); diff --git a/app/assets/javascripts/pages/dashboard/merge_requests/index.js b/app/assets/javascripts/pages/dashboard/merge_requests/index.js index c4901dd1cb6..260484726f3 100644 --- a/app/assets/javascripts/pages/dashboard/merge_requests/index.js +++ b/app/assets/javascripts/pages/dashboard/merge_requests/index.js @@ -1,7 +1,15 @@ import projectSelect from '~/project_select'; -import initLegacyFilters from '~/init_legacy_filters'; +import initFilteredSearch from '~/pages/search/init_filtered_search'; +import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; +import { FILTERED_SEARCH } from '~/pages/constants'; document.addEventListener('DOMContentLoaded', () => { + IssuableFilteredSearchTokenKeys.addExtraTokensForMergeRequests(); + + initFilteredSearch({ + page: FILTERED_SEARCH.MERGE_REQUESTS, + filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, + }); + projectSelect(); - initLegacyFilters(); }); diff --git a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue index f970a5ebb64..cbe85eaa590 100644 --- a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue +++ b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue @@ -1,7 +1,7 @@ <script> import _ from 'underscore'; import { s__, sprintf } from '~/locale'; -import { GlModal, GlModalDirective } from '@gitlab-org/gitlab-ui'; +import { GlModal, GlModalDirective } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/pipelines/components/empty_state.vue b/app/assets/javascripts/pipelines/components/empty_state.vue index 8a0259ed5a5..f756c651684 100644 --- a/app/assets/javascripts/pipelines/components/empty_state.vue +++ b/app/assets/javascripts/pipelines/components/empty_state.vue @@ -1,5 +1,5 @@ <script> -import { GlButton } from '@gitlab-org/gitlab-ui'; +import { GlButton } from '@gitlab/ui'; export default { name: 'PipelinesEmptyState', diff --git a/app/assets/javascripts/pipelines/components/graph/action_component.vue b/app/assets/javascripts/pipelines/components/graph/action_component.vue index b82e28a0735..3a39dfe181d 100644 --- a/app/assets/javascripts/pipelines/components/graph/action_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/action_component.vue @@ -1,10 +1,9 @@ <script> -import $ from 'jquery'; +import { GlTooltipDirective, GlButton } from '@gitlab/ui'; import axios from '~/lib/utils/axios_utils'; import { dasherize } from '~/lib/utils/text_utility'; import { __ } from '~/locale'; import createFlash from '~/flash'; -import tooltip from '~/vue_shared/directives/tooltip'; import Icon from '~/vue_shared/components/icon.vue'; /** @@ -20,23 +19,20 @@ import Icon from '~/vue_shared/components/icon.vue'; export default { components: { Icon, + GlButton, }, - directives: { - tooltip, + GlTooltip: GlTooltipDirective, }, - props: { tooltipText: { type: String, required: true, }, - link: { type: String, required: true, }, - actionIcon: { type: String, required: true, @@ -47,7 +43,6 @@ export default { isDisabled: false, }; }, - computed: { cssClass() { const actionIconDash = dasherize(this.actionIcon); @@ -62,8 +57,7 @@ export default { * */ onClickAction() { - $(this.$el).tooltip('hide'); - + this.$root.$emit('bv::hide::tooltip', `js-ci-action-${this.link}`); this.isDisabled = true; axios @@ -82,18 +76,16 @@ export default { }; </script> <template> - <button - v-tooltip + <gl-button + :id="`js-ci-action-${link}`" + v-gl-tooltip="{ boundary: 'viewport' }" :title="tooltipText" :class="cssClass" :disabled="isDisabled" - type="button" class="js-ci-action btn btn-blank btn-transparent ci-action-icon-container ci-action-icon-wrapper" - data-container="body" - data-boundary="viewport" @click="onClickAction" > <icon :name="actionIcon"/> - </button> + </gl-button> </template> diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index 4de8b3401e8..6c9a11c3829 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -1,6 +1,6 @@ <script> import _ from 'underscore'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import StageColumnComponent from './stage_column_component.vue'; export default { diff --git a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue index 34bada533df..2670ea29db6 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue @@ -1,8 +1,8 @@ <script> import $ from 'jquery'; +import { GlTooltipDirective } from '@gitlab/ui'; import CiIcon from '~/vue_shared/components/ci_icon.vue'; import JobItem from './job_item.vue'; -import tooltip from '../../../vue_shared/directives/tooltip'; /** * Renders the dropdown for the pipeline graph. @@ -12,32 +12,27 @@ import tooltip from '../../../vue_shared/directives/tooltip'; */ export default { directives: { - tooltip, + GlTooltip: GlTooltipDirective, }, - components: { JobItem, CiIcon, }, - props: { group: { type: Object, required: true, }, }, - computed: { tooltipText() { const { name, status } = this.group; return `${name} - ${status.label}`; }, }, - mounted() { this.stopDropdownClickPropagation(); }, - methods: { /** * When the user right clicks or cmd/ctrl + click in the group name or the action icon @@ -65,12 +60,10 @@ export default { <template> <div class="ci-job-dropdown-container dropdown dropright"> <button - v-tooltip + v-gl-tooltip.hover="{ boundary: 'viewport' }" :title="tooltipText" type="button" data-toggle="dropdown" - data-container="body" - data-boundary="viewport" data-display="static" class="dropdown-menu-toggle build-content" > diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue index 7cdde8a53b3..e6abf32decc 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_item.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue @@ -1,7 +1,7 @@ <script> import ActionComponent from './action_component.vue'; import JobNameComponent from './job_name_component.vue'; -import tooltip from '../../../vue_shared/directives/tooltip'; +import { GlTooltipDirective, GlLink } from '@gitlab/ui'; import { sprintf } from '~/locale'; import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin'; @@ -34,9 +34,10 @@ export default { components: { ActionComponent, JobNameComponent, + GlLink, }, directives: { - tooltip, + GlTooltip: GlTooltipDirective, }, mixins: [delayedJobMixin], props: { @@ -55,7 +56,6 @@ export default { default: Infinity, }, }, - computed: { status() { return this.job && this.job.status ? this.job.status : {}; @@ -88,7 +88,6 @@ export default { tooltipBoundary() { return this.dropdownLength < 5 ? 'viewport' : null; }, - /** * Verifies if the provided job has an action path * @@ -98,7 +97,6 @@ export default { return this.job.status && this.job.status.action && this.job.status.action.path; }, }, - methods: { pipelineActionRequestComplete() { this.$emit('pipelineActionRequestComplete'); @@ -108,30 +106,26 @@ export default { </script> <template> <div class="ci-job-component"> - <a + <gl-link v-if="status.has_details" - v-tooltip + v-gl-tooltip="{ boundary: tooltipBoundary }" :href="status.details_path" :title="tooltipText" :class="cssClassJobName" - :data-boundary="tooltipBoundary" - data-container="body" class="js-pipeline-graph-job-link" > - <job-name-component :name="job.name" :status="job.status" /> - </a> + </gl-link> <div v-else - v-tooltip + v-gl-tooltip :title="tooltipText" :class="cssClassJobName" class="js-job-component-tooltip non-details-job-component" - data-container="body" > <job-name-component diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue index efbab51d200..d5f931943d5 100644 --- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue @@ -13,34 +13,28 @@ export default { type: String, required: true, }, - groups: { type: Array, required: true, }, - isFirstColumn: { type: Boolean, required: false, default: false, }, - stageConnectorClass: { type: String, required: false, default: '', }, }, - methods: { groupId(group) { return `ci-badge-${_.escape(group.name)}`; }, - buildConnnectorClass(index) { return index === 0 && !this.isFirstColumn ? 'left-connector' : ''; }, - pipelineActionRequestComplete() { this.$emit('refreshPipelineGraph'); }, @@ -50,7 +44,8 @@ export default { <template> <li :class="stageConnectorClass" - class="stage-column"> + class="stage-column" + > <div class="stage-name"> {{ title }} </div> @@ -78,7 +73,6 @@ export default { :group="group" @pipelineActionRequestComplete="pipelineActionRequestComplete" /> - </li> </ul> </div> diff --git a/app/assets/javascripts/pipelines/components/header_component.vue b/app/assets/javascripts/pipelines/components/header_component.vue index 8f004b491c8..ac7fa4b195e 100644 --- a/app/assets/javascripts/pipelines/components/header_component.vue +++ b/app/assets/javascripts/pipelines/components/header_component.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import ciHeader from '../../vue_shared/components/header_ci_component.vue'; import eventHub from '../event_hub'; diff --git a/app/assets/javascripts/pipelines/components/nav_controls.vue b/app/assets/javascripts/pipelines/components/nav_controls.vue index 0911acbb131..5104fe36b42 100644 --- a/app/assets/javascripts/pipelines/components/nav_controls.vue +++ b/app/assets/javascripts/pipelines/components/nav_controls.vue @@ -1,5 +1,5 @@ <script> -import { GlLink, GlButton } from '@gitlab-org/gitlab-ui'; +import { GlLink, GlButton } from '@gitlab/ui'; import LoadingButton from '../../vue_shared/components/loading_button.vue'; export default { diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue index be4b37f3c8c..249f7b9f368 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_url.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue @@ -1,5 +1,5 @@ <script> -import { GlLink, GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlLink, GlTooltipDirective } from '@gitlab/ui'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import popover from '~/vue_shared/directives/popover'; diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue index 811495c45a9..112c1559f25 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue @@ -1,5 +1,5 @@ <script> -import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui'; import { s__, sprintf } from '~/locale'; import GlCountdown from '~/vue_shared/components/gl_countdown.vue'; import eventHub from '../event_hub'; diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue index 2abb24b87b6..d7d9eb00faa 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue @@ -1,5 +1,5 @@ <script> -import { GlLink, GlButton, GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlLink, GlButton, GlTooltipDirective } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; export default { diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue index 026d533d10f..fd674a8d447 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue @@ -308,7 +308,8 @@ export default { <div v-for="(stage, index) in pipeline.details.stages" :key="index" - class="stage-container dropdown js-mini-pipeline-graph"> + class="stage-container dropdown js-mini-pipeline-graph" + > <pipeline-stage :type="$options.pipelinesTable" :stage="stage" diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue index 3df8f7a6da6..1d62472671a 100644 --- a/app/assets/javascripts/pipelines/components/stage.vue +++ b/app/assets/javascripts/pipelines/components/stage.vue @@ -13,14 +13,13 @@ */ import $ from 'jquery'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui'; import { __ } from '../../locale'; import Flash from '../../flash'; import axios from '../../lib/utils/axios_utils'; import eventHub from '../event_hub'; import Icon from '../../vue_shared/components/icon.vue'; import JobItem from './graph/job_item.vue'; -import tooltip from '../../vue_shared/directives/tooltip'; import { PIPELINES_TABLE } from '../constants'; export default { @@ -31,7 +30,7 @@ export default { }, directives: { - tooltip, + GlTooltip: GlTooltipDirective, }, props: { @@ -159,11 +158,10 @@ export default { <button id="stageDropdown" ref="dropdown" - v-tooltip + v-gl-tooltip.hover :class="triggerButtonClass" :title="stage.title" class="mini-pipeline-graph-dropdown-toggle js-builds-dropdown-button" - data-placement="top" data-toggle="dropdown" data-display="static" type="button" diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js index 41bc5dcce5c..32bfa47e5f2 100644 --- a/app/assets/javascripts/pipelines/mixins/pipelines.js +++ b/app/assets/javascripts/pipelines/mixins/pipelines.js @@ -1,5 +1,5 @@ import Visibility from 'visibilityjs'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import { __ } from '../../locale'; import Flash from '../../flash'; import Poll from '../../lib/utils/poll'; diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js index f5dae5ad808..5a3407693e5 100644 --- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js +++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js @@ -2,7 +2,7 @@ import _ from 'underscore'; import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_search_input.vue'; import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import store from '../store'; diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue index 9a729ca9b91..7400b685c7e 100644 --- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue +++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue @@ -5,7 +5,7 @@ import Poll from '~/lib/utils/poll'; import Flash from '~/flash'; import { s__, sprintf } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import CommitPipelineService from '../services/commit_pipeline_service'; export default { diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue index 0a906f40f5a..6f94f5d6d2a 100644 --- a/app/assets/javascripts/registry/components/app.vue +++ b/app/assets/javascripts/registry/components/app.vue @@ -1,6 +1,6 @@ <script> import { mapGetters, mapActions } from 'vuex'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import Flash from '../../flash'; import store from '../stores'; import collapsibleContainer from './collapsible_container.vue'; diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue index be9816a55c4..d85de973740 100644 --- a/app/assets/javascripts/registry/components/collapsible_container.vue +++ b/app/assets/javascripts/registry/components/collapsible_container.vue @@ -1,6 +1,6 @@ <script> import { mapActions } from 'vuex'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import Flash from '../../flash'; import clipboardButton from '../../vue_shared/components/clipboard_button.vue'; import tooltip from '../../vue_shared/directives/tooltip'; diff --git a/app/assets/javascripts/reports/components/summary_row.vue b/app/assets/javascripts/reports/components/summary_row.vue index a44ba833b63..7e73ccb6c28 100644 --- a/app/assets/javascripts/reports/components/summary_row.vue +++ b/app/assets/javascripts/reports/components/summary_row.vue @@ -1,7 +1,7 @@ <script> import CiIcon from '~/vue_shared/components/ci_icon.vue'; import Popover from '~/vue_shared/components/help_popover.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; /** * Renders the summary row for each report diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js index 17def77b2d7..0a4583b5861 100644 --- a/app/assets/javascripts/search_autocomplete.js +++ b/app/assets/javascripts/search_autocomplete.js @@ -253,7 +253,6 @@ export class SearchAutocomplete { } getCategoryContents() { - const userId = gon.current_user_id; const userName = gon.current_username; const { projectOptions, groupOptions, dashboardOptions } = gl; @@ -279,21 +278,21 @@ export class SearchAutocomplete { const issueItems = [ { text: s__('SearchAutocomplete|Issues assigned to me'), - url: `${issuesPath}/?assignee_id=${userId}`, + url: `${issuesPath}/?assignee_username=${userName}`, }, { text: s__("SearchAutocomplete|Issues I've created"), - url: `${issuesPath}/?author_id=${userId}`, + url: `${issuesPath}/?author_username=${userName}`, }, ]; const mergeRequestItems = [ { text: s__('SearchAutocomplete|Merge requests assigned to me'), - url: `${mrPath}/?assignee_id=${userId}`, + url: `${mrPath}/?assignee_username=${userName}`, }, { text: s__("SearchAutocomplete|Merge requests I've created"), - url: `${mrPath}/?author_id=${userId}`, + url: `${mrPath}/?author_username=${userName}`, }, ]; diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue index 4d461baf74d..8a48eea5c89 100644 --- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue +++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue @@ -5,7 +5,7 @@ import Icon from '~/vue_shared/components/icon.vue'; import GfmAutoComplete from '~/gfm_auto_complete'; import { __, s__ } from '~/locale'; import Api from '~/api'; -import { GlModal, GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlModal, GlTooltipDirective } from '@gitlab/ui'; import eventHub from './event_hub'; import EmojiMenuInModal from './emoji_menu_in_modal'; diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue index fe73f6a0cef..43d2f754bac 100644 --- a/app/assets/javascripts/sidebar/components/participants/participants.vue +++ b/app/assets/javascripts/sidebar/components/participants/participants.vue @@ -2,7 +2,7 @@ import { __, n__, sprintf } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { directives: { diff --git a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue index b145e5dc5e2..87780411c26 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue @@ -1,7 +1,7 @@ <script> import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility'; import tooltip from '../../../vue_shared/directives/tooltip'; -import { GlProgressBar } from '@gitlab-org/gitlab-ui'; +import { GlProgressBar } from '@gitlab/ui'; export default { name: 'TimeTrackingComparisonPane', diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue index 913a616d9f1..7edef35461a 100644 --- a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue +++ b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue @@ -1,7 +1,7 @@ <script> import { __ } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue index 4ec925aa8a6..fe741dc60cb 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue @@ -33,6 +33,10 @@ export default { type: Object, required: true, }, + showMetrics: { + type: Boolean, + required: true, + }, }, deployedTextMap: { running: __('Deploying to'), @@ -74,6 +78,9 @@ export default { shouldRenderDropdown() { return this.deployment.changes && this.deployment.changes.length > 0; }, + showMemoryUsage() { + return this.hasMetrics && this.showMetrics; + }, }, methods: { stopEnvironment() { @@ -136,7 +143,7 @@ export default { {{ deployTimeago }} </span> <memory-usage - v-if="hasMetrics" + v-if="showMemoryUsage" :metrics-url="deployment.metrics_url" :metrics-monitoring-url="deployment.metrics_monitoring_url" /> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue index b3340290ed3..060361a6516 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import ciIcon from '../../vue_shared/components/ci_icon.vue'; export default { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue index 4bfbdcf1404..409fc2f2db4 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import eventHub from '../../event_hub'; import statusIcon from '../mr_widget_status_icon.vue'; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue index 7e33021e4b4..fb9ca897844 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue @@ -6,7 +6,7 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import MrWidgetAuthorTime from '../../components/mr_widget_author_time.vue'; import statusIcon from '../mr_widget_status_icon.vue'; import eventHub from '../../event_hub'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { name: 'MRWidgetMerged', diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue index 0e714cc2aa1..5a7f6cc36fa 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import simplePoll from '../../../lib/utils/simple_poll'; import eventHub from '../../event_hub'; import statusIcon from '../mr_widget_status_icon.vue'; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 063d1e15544..3b840540657 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -312,6 +312,7 @@ export default { :key="`pre-merge-deploy-${deployment.id}`" class="js-pre-merge-deploy" :deployment="deployment" + :show-metrics="false" /> <div class="mr-section-container"> <grouped-test-reports-app @@ -366,6 +367,7 @@ export default { v-for="postMergeDeployment in mr.postMergeDeployments" :key="`post-merge-deploy-${postMergeDeployment.id}`" :deployment="postMergeDeployment" + :show-metrics="true" class="js-post-deployment" /> </template> diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue index 766fc211bf5..c5fbaf87b00 100644 --- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import { pluralize } from '~/lib/utils/text_utility'; import { __, sprintf } from '~/locale'; diff --git a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue index 6780254827f..b0962684430 100644 --- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue +++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import CiIcon from './ci_icon.vue'; /** * Renders CI Badge link with CI icon and status text based on diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue index 6b90a1f540e..671b4909839 100644 --- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue +++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue @@ -12,7 +12,7 @@ * css-class="btn-transparent" * /> */ -import { GlButton, GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlButton, GlTooltipDirective } from '@gitlab/ui'; import Icon from '../components/icon.vue'; export default { diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue index b1139f34e41..420bd25b496 100644 --- a/app/assets/javascripts/vue_shared/components/commit.vue +++ b/app/assets/javascripts/vue_shared/components/commit.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import UserAvatarLink from './user_avatar/user_avatar_link.vue'; import Icon from '../../vue_shared/components/icon.vue'; diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue index c78b96695cf..97bdd9915c5 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; import Icon from '../../icon.vue'; import { numberToHumanSize } from '../../../../lib/utils/number_utils'; diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue index 419987d2c50..a084cfdf612 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue @@ -2,7 +2,7 @@ import axios from '~/lib/utils/axios_utils'; import { __ } from '~/locale'; import $ from 'jquery'; -import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui'; +import { GlSkeletonLoading } from '@gitlab/ui'; const { CancelToken } = axios; let axiosSource; diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue index 0e194eaaed5..0f4effda79f 100644 --- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue +++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue @@ -1,6 +1,6 @@ <script> import { __ } from '~/locale'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/vue_shared/components/file_icon.vue b/app/assets/javascripts/vue_shared/components/file_icon.vue index 03818be6a69..545be568ad3 100644 --- a/app/assets/javascripts/vue_shared/components/file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/file_icon.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import getIconForFile from './file_icon/file_icon_map'; import icon from '../../vue_shared/components/icon.vue'; diff --git a/app/assets/javascripts/vue_shared/components/gl_countdown.vue b/app/assets/javascripts/vue_shared/components/gl_countdown.vue index a35986b2d03..97f7998f461 100644 --- a/app/assets/javascripts/vue_shared/components/gl_countdown.vue +++ b/app/assets/javascripts/vue_shared/components/gl_countdown.vue @@ -1,6 +1,6 @@ <script> import { calculateRemainingMilliseconds, formatTime } from '~/lib/utils/datetime_utility'; -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; /** * Counts down to a given end date. diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue index 88e95c33b9b..1a91a8b81e3 100644 --- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue +++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective, GlLink, GlButton } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui'; import CiIconBadge from './ci_badge_link.vue'; import TimeagoTooltip from './time_ago_tooltip.vue'; import UserAvatarImage from './user_avatar/user_avatar_image.vue'; diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue index 69d7e5c46f5..9bae8a32a8c 100644 --- a/app/assets/javascripts/vue_shared/components/loading_button.vue +++ b/app/assets/javascripts/vue_shared/components/loading_button.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; /* eslint-disable vue/require-default-prop */ /* This is a re-usable vue component for rendering a button that will probably be sending off ajax requests and need diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 27e3f314dd3..ca9e57a9b00 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -1,6 +1,6 @@ <script> import $ from 'jquery'; -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import ToolbarButton from './toolbar_button.vue'; import Icon from '../icon.vue'; diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue index b0a93794013..3cb48023002 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue @@ -1,5 +1,5 @@ <script> -import { GlLink } from '@gitlab-org/gitlab-ui'; +import { GlLink } from '@gitlab/ui'; export default { components: { diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue index 91d0bbfc21c..13af4b627de 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlTooltipDirective } from '@gitlab/ui'; import Icon from '../icon.vue'; export default { diff --git a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue index 8cb72afcdc0..2dcd161b4fb 100644 --- a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue +++ b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue @@ -1,5 +1,5 @@ <script> -import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui'; +import { GlSkeletonLoading } from '@gitlab/ui'; export default { name: 'SkeletonNote', diff --git a/app/assets/javascripts/vue_shared/components/pagination_links.vue b/app/assets/javascripts/vue_shared/components/pagination_links.vue index 89dcf049f6e..0b44f8578cb 100644 --- a/app/assets/javascripts/vue_shared/components/pagination_links.vue +++ b/app/assets/javascripts/vue_shared/components/pagination_links.vue @@ -1,5 +1,5 @@ <script> -import { GlPagination } from '@gitlab-org/gitlab-ui'; +import { GlPagination } from '@gitlab/ui'; import { s__ } from '../../locale'; export default { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue index 5b12bb6b59e..6aa880603b9 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import datePicker from '../pikaday.vue'; import toggleSidebar from './toggle_sidebar.vue'; import collapsedCalendarIcon from './collapsed_calendar_icon.vue'; diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue index e50d612ce36..98b8b6460fe 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue @@ -4,7 +4,7 @@ import { __ } from '~/locale'; import LabelsSelect from '~/labels_select'; import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import DropdownTitle from './dropdown_title.vue'; import DropdownValue from './dropdown_value.vue'; import DropdownValueCollapsed from './dropdown_value_collapsed.vue'; diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue index e7cb5cfac12..5d1c92c3b3d 100644 --- a/app/assets/javascripts/vue_shared/components/toggle_button.vue +++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; +import { GlLoadingIcon } from '@gitlab/ui'; import { s__ } from '../../locale'; import icon from './icon.vue'; diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue index 4cfb1ded0a9..c78d98ccd9e 100644 --- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue +++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue @@ -15,7 +15,7 @@ */ -import { GlTooltip } from '@gitlab-org/gitlab-ui'; +import { GlTooltip } from '@gitlab/ui'; import defaultAvatarUrl from 'images/no_avatar.png'; import { placeholderImage } from '../../../lazy_loader'; diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue index 351a639c6e8..6dd519ea56d 100644 --- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue +++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue @@ -17,7 +17,7 @@ */ -import { GlLink, GlTooltipDirective } from '@gitlab-org/gitlab-ui'; +import { GlLink, GlTooltipDirective } from '@gitlab/ui'; import userAvatarImage from './user_avatar_image.vue'; export default { diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 6bdcb20210b..037a5adfb7e 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -415,7 +415,6 @@ span.idiff { } .preview-container { - height: 100%; overflow: auto; .file-container { diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 6d998fa1e07..3c7bf0b0e46 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -842,11 +842,15 @@ background-repeat: repeat; } - .diff-file-discussions + .discussion-form::before { - width: auto; - margin-left: -16px; - margin-right: -16px; - margin-bottom: 16px; + .diff-file-discussions + .discussion-form { + padding: $gl-padding; + + &::before { + width: auto; + margin-left: -$gl-padding; + margin-right: -$gl-padding; + margin-bottom: $gl-padding; + } } .notes { diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 3aa79bf2466..38851de6401 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -727,6 +727,10 @@ .issuable-main-info { flex: 1 auto; margin-right: 10px; + + .issue-weight-icon { + vertical-align: sub; + } } .issuable-meta { diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 45b921a2fbb..97b3f696139 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -241,7 +241,7 @@ table { .discussion-reply-holder { background-color: $white-light; padding: 10px 16px; - border-radius: 0 0 $border-radius-default $border-radius-default; + border-radius: 0 0 3px 3px; &.is-replying { padding-bottom: $gl-padding; diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 35e01c9c807..085ff27e6ef 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -28,7 +28,7 @@ $note-form-margin-left: 72px; } .main-notes-list { - @include vertical-line(39px); + @include vertical-line(36px); } .notes { @@ -272,7 +272,7 @@ $note-form-margin-left: 72px; } .system-note { - padding: 6px 20px; + padding: 6px 21px; margin: $gl-padding-24 0; background-color: transparent; @@ -407,6 +407,24 @@ $note-form-margin-left: 72px; } } +.tab-pane.notes { + .diff-file .notes .system-note { + margin: 0; + } +} + +.tab-pane.diffs { + .system-note { + padding: 0 $gl-padding; + margin-left: 20px; + } + + .notes > .note-discussion li.note.system-note { + border-bottom: 0; + padding: 0 $gl-padding; + } +} + .diff-file { .is-over { .add-diff-note { @@ -415,18 +433,12 @@ $note-form-margin-left: 72px; } .discussion-notes { - &:not(:first-child) { - border-top: 1px solid $white-normal; - margin-top: 20px; - } - &:not(:last-child) { - border-bottom: 1px solid $white-normal; - margin-bottom: 20px; + margin-bottom: 0; } .system-note { - margin: 0; + background-color: $white-light; padding: $gl-padding; } } @@ -485,6 +497,11 @@ $note-form-margin-left: 72px; .note-wrapper { @include outline-comment(); + + &.system-note { + border: 0; + margin-left: 20px; + } } .discussion-reply-holder { @@ -499,6 +516,10 @@ $note-form-margin-left: 72px; @include vertical-line(52px); } + .notes_content { + background-color: $white-light; + } + .discussion-reply-holder { border-top: 1px solid $border-color; } @@ -910,3 +931,23 @@ $note-form-margin-left: 72px; } } } + +//This needs to be deleted when Snippet/Commit comments are convered to Vue +// See https://gitlab.com/gitlab-org/gitlab-ce/issues/53918#note_117038785 +.unstyled-comments { + + .discussion-header { + padding: $gl-padding; + border-bottom: 1px solid $border-color; + } + + .note-wrapper.outlined { + margin: 0; + border: 0; + border-radius: 0; + } + + .discussion-form-container { + padding: $gl-padding; + } +} diff --git a/app/controllers/admin/background_jobs_controller.rb b/app/controllers/admin/background_jobs_controller.rb index 7701f2e645b..fc877142418 100644 --- a/app/controllers/admin/background_jobs_controller.rb +++ b/app/controllers/admin/background_jobs_controller.rb @@ -1,9 +1,4 @@ # frozen_string_literal: true class Admin::BackgroundJobsController < Admin::ApplicationController - def show - ps_output, _ = Gitlab::Popen.popen(%W(ps ww -U #{Gitlab.config.gitlab.user} -o pid,pcpu,pmem,stat,start,command)) - @sidekiq_processes = ps_output.split("\n").grep(/sidekiq \d+\.\d+\.\d+/) - @concurrency = Sidekiq.options[:concurrency] - end end diff --git a/app/controllers/admin/impersonation_tokens_controller.rb b/app/controllers/admin/impersonation_tokens_controller.rb index f5825ecb19a..706bcc1e549 100644 --- a/app/controllers/admin/impersonation_tokens_controller.rb +++ b/app/controllers/admin/impersonation_tokens_controller.rb @@ -11,6 +11,7 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController @impersonation_token = finder.build(impersonation_token_params) if @impersonation_token.save + PersonalAccessToken.redis_store!(current_user.id, @impersonation_token.token) redirect_to admin_user_impersonation_tokens_path, notice: "A new impersonation token has been created." else set_index_vars @@ -53,6 +54,8 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController @impersonation_token ||= finder.build @inactive_impersonation_tokens = finder(state: 'inactive').execute @active_impersonation_tokens = finder(state: 'active').execute.order(:expires_at) + + @new_impersonation_token = PersonalAccessToken.redis_getdel(current_user.id) end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 7f4aa8244ac..b839da7770d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -181,11 +181,11 @@ class ApplicationController < ActionController::Base Ability.allowed?(object, action, subject) end - def access_denied!(message = nil) + def access_denied!(message = nil, status = nil) # If we display a custom access denied message to the user, we don't want to # hide existence of the resource, rather tell them they cannot access it using # the provided message - status = message.present? ? :forbidden : :not_found + status ||= message.present? ? :forbidden : :not_found respond_to do |format| format.any { head status } diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index 5217b4be928..34a8c50fcbd 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -81,36 +81,36 @@ module IssuableCollections end def issuable_finder_for(finder_class) - finder_class.new(current_user, filter_params) + finder_class.new(current_user, finder_options) end # rubocop:disable Gitlab/ModuleWithInstanceVariables - # rubocop: disable CodeReuse/ActiveRecord - def filter_params - set_sort_order_from_cookie - set_default_state + def finder_options + params[:state] = default_state if params[:state].blank? - # Skip irrelevant Rails routing params - @filter_params = params.dup.except(:controller, :action, :namespace_id) - @filter_params[:sort] ||= default_sort_order + options = { + scope: params[:scope], + state: params[:state], + sort: set_sort_order_from_cookie || default_sort_order + } - @sort = @filter_params[:sort] + # Used by view to highlight active option + @sort = options[:sort] if @project - @filter_params[:project_id] = @project.id + options[:project_id] = @project.id elsif @group - @filter_params[:group_id] = @group.id - @filter_params[:include_subgroups] = true - @filter_params[:use_cte_for_search] = true + options[:group_id] = @group.id + options[:include_subgroups] = true + options[:use_cte_for_search] = true end - @filter_params.permit(finder_type.valid_params) + params.permit(finder_type.valid_params).merge(options) end - # rubocop: enable CodeReuse/ActiveRecord # rubocop:enable Gitlab/ModuleWithInstanceVariables - def set_default_state - params[:state] = 'opened' if params[:state].blank? + def default_state + 'opened' end def set_sort_order_from_cookie @@ -121,7 +121,7 @@ module IssuableCollections sort_value = update_cookie_value(sort_param) set_secure_cookie(remember_sorting_key, sort_value) - params[:sort] = sort_value + sort_value end def remember_sorting_key diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb index 285f2c3a8a0..ed10f32512e 100644 --- a/app/controllers/concerns/merge_requests_action.rb +++ b/app/controllers/concerns/merge_requests_action.rb @@ -19,7 +19,7 @@ module MergeRequestsAction (MergeRequestsFinder if action_name == 'merge_requests') end - def filter_params + def finder_options super.merge(non_archived: true) end end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index c032fb2efb5..4ce9be44403 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -4,13 +4,6 @@ class DashboardController < Dashboard::ApplicationController include IssuesAction include MergeRequestsAction - FILTER_PARAMS = [ - :author_id, - :assignee_id, - :milestone_title, - :label_name - ].freeze - before_action :event_filter, only: :activity before_action :projects, only: [:issues, :merge_requests] before_action :set_show_full_reference, only: [:issues, :merge_requests] @@ -51,10 +44,13 @@ class DashboardController < Dashboard::ApplicationController end def check_filters_presence! - @no_filters_set = FILTER_PARAMS.none? { |k| params.key?(k) } + @no_filters_set = finder_type.scalar_params.none? { |k| params.key?(k) } return unless @no_filters_set + # Call to set selected `state` and `sort` options in view + finder_options + respond_to do |format| format.html { render } format.atom { head :bad_request } diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 0718658cd48..2a6fe3b9c97 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -122,7 +122,7 @@ class Projects::BlobController < Projects::ApplicationController @lines.map! do |line| # These are marked as context lines but are loaded from blobs. # We also have context lines loaded from diffs in other places. - diff_line = Gitlab::Diff::Line.new(line, expanded_diff_line_type, nil, nil, nil) + diff_line = Gitlab::Diff::Line.new(line, nil, nil, nil, nil) diff_line.rich_text = line diff_line end @@ -132,11 +132,6 @@ class Projects::BlobController < Projects::ApplicationController render json: DiffLineSerializer.new.represent(@lines) end - def expanded_diff_line_type - # Context lines can't receive comments. - Feature.enabled?(:comment_in_any_diff_line, @project) ? nil : 'context' - end - def add_match_line return unless @form.unfold? diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb index 92ef10a9ef5..0a593bd35b6 100644 --- a/app/controllers/projects/deploy_keys_controller.rb +++ b/app/controllers/projects/deploy_keys_controller.rb @@ -46,7 +46,9 @@ class Projects::DeployKeysController < Projects::ApplicationController end def enable - Projects::EnableDeployKeyService.new(@project, current_user, params).execute + key = Projects::EnableDeployKeyService.new(@project, current_user, params).execute + + return render_404 unless key respond_to do |format| format.html { redirect_to_repository_settings(@project, anchor: 'js-deploy-keys-settings') } @@ -54,19 +56,16 @@ class Projects::DeployKeysController < Projects::ApplicationController end end - # rubocop: disable CodeReuse/ActiveRecord def disable - deploy_key_project = @project.deploy_keys_projects.find_by(deploy_key_id: params[:id]) - return render_404 unless deploy_key_project + deploy_key_project = Projects::DisableDeployKeyService.new(@project, current_user, params).execute - deploy_key_project.destroy! + return render_404 unless deploy_key_project respond_to do |format| format.html { redirect_to_repository_settings(@project, anchor: 'js-deploy-keys-settings') } format.json { head :ok } end end - # rubocop: enable CodeReuse/ActiveRecord protected diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb index ebf70f25bda..7b6657e1196 100644 --- a/app/controllers/root_controller.rb +++ b/app/controllers/root_controller.rb @@ -45,9 +45,9 @@ class RootController < Dashboard::ProjectsController when 'todos' redirect_to(dashboard_todos_path) when 'issues' - redirect_to(issues_dashboard_path(assignee_id: current_user.id)) + redirect_to(issues_dashboard_path(assignee_username: current_user.username)) when 'merge_requests' - redirect_to(merge_requests_dashboard_path(assignee_id: current_user.id)) + redirect_to(merge_requests_dashboard_path(assignee_username: current_user.username)) end end diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 93bef592c65..fdc630cbf72 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -14,7 +14,9 @@ # project_id: integer # milestone_title: string # author_id: integer +# author_username: string # assignee_id: integer or 'None' or 'Any' +# assignee_username: string # search: string # label_name: string # sort: string @@ -49,25 +51,15 @@ class IssuableFinder assignee_username author_id author_username - authorized_only - group_id - iids label_name milestone_title my_reaction_emoji - non_archived - project_id - scope search - sort - state - include_subgroups - use_cte_for_search ] end def self.array_params - @array_params ||= { label_name: [], iids: [], assignee_username: [] } + @array_params ||= { label_name: [], assignee_username: [] } end def self.valid_params diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 4f91e3e4117..74042f0bae8 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -173,17 +173,7 @@ module ApplicationHelper without = options.delete(:without) add_label = options.delete(:label) - exist_opts = { - state: params[:state], - scope: params[:scope], - milestone_title: params[:milestone_title], - assignee_id: params[:assignee_id], - author_id: params[:author_id], - search: params[:search], - label_name: params[:label_name] - } - - options = exist_opts.merge(options) + options = request.query_parameters.merge(options) if without.present? without.each do |key| diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index c158cf20dd6..44f85e9c0f8 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -24,6 +24,23 @@ module AuthHelper Gitlab::Auth::OAuth::Provider.label_for(name) end + def form_based_provider_priority + ['crowd', /^ldap/, 'kerberos'] + end + + def form_based_provider_with_highest_priority + @form_based_provider_with_highest_priority ||= begin + form_based_provider_priority.each do |provider_regexp| + highest_priority = form_based_providers.find { |provider| provider.match?(provider_regexp) } + break highest_priority unless highest_priority.nil? + end + end + end + + def form_based_auth_provider_has_active_class?(provider) + form_based_provider_with_highest_priority == provider + end + def form_based_provider?(name) [LDAP_PROVIDER, 'crowd'].any? { |pattern| pattern === name.to_s } end diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index 463f4145bdd..d90ef8903a7 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -2,11 +2,11 @@ module DashboardHelper def assigned_issues_dashboard_path - issues_dashboard_path(assignee_id: current_user.id) + issues_dashboard_path(assignee_username: current_user.username) end def assigned_mrs_dashboard_path - merge_requests_dashboard_path(assignee_id: current_user.id) + merge_requests_dashboard_path(assignee_username: current_user.username) end def dashboard_nav_links diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index 761f42f2f0f..a7fe8c3d59c 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -19,10 +19,7 @@ module NavHelper end def page_gutter_class - if current_path?('merge_requests#show') || - current_path?('projects/merge_requests/conflicts#show') || - current_path?('issues#show') || - current_path?('milestones#show') + if page_has_markdown? if cookies[:collapsed_gutter] == 'true' %w[page-gutter right-sidebar-collapsed] @@ -50,6 +47,17 @@ module NavHelper class_names end + def show_separator? + Gitlab::Sherlock.enabled? || can?(current_user, :read_instance_statistics) + end + + def page_has_markdown? + current_path?('merge_requests#show') || + current_path?('projects/merge_requests/conflicts#show') || + current_path?('issues#show') || + current_path?('milestones#show') + end + private def get_header_links diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb index 42f9a1213e9..df318de740a 100644 --- a/app/helpers/profiles_helper.rb +++ b/app/helpers/profiles_helper.rb @@ -7,7 +7,7 @@ module ProfilesHelper [ [s_("Profiles|Use a private email - %{email}").html_safe % { email: private_email }, Gitlab::PrivateCommitEmail::TOKEN], - verified_emails + *verified_emails ] end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 4f9e1322b56..80cc568820a 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -163,15 +163,26 @@ module SearchHelper if @project.present? opts[:data]['project-id'] = @project.id opts[:data]['base-endpoint'] = project_path(@project) - else - # Group context + elsif @group.present? opts[:data]['group-id'] = @group.id opts[:data]['base-endpoint'] = group_canonical_path(@group) + else + opts[:data]['base-endpoint'] = root_dashboard_path end opts end + def search_history_storage_prefix + if @project.present? + @project.full_path + elsif @group.present? + @group.full_path + else + 'dashboard' + end + end + # Sanitize a HTML field for search display. Most tags are stripped out and the # maximum length is set to 200 characters. def search_md_sanitize(object, field) diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 00000000000..71fbba5b328 --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 889f8ce27a6..9a28e245ebd 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -464,7 +464,9 @@ module Ci end def repo_url - auth = "gitlab-ci-token:#{ensure_token!}@" + return unless token + + auth = "gitlab-ci-token:#{token}@" project.http_url_to_repo.sub(%r{^https?://}) do |prefix| prefix + auth end @@ -725,7 +727,7 @@ module Ci trace = trace.dup Gitlab::Ci::MaskSecret.mask!(trace, project.runners_token) if project - Gitlab::Ci::MaskSecret.mask!(trace, token) + Gitlab::Ci::MaskSecret.mask!(trace, token) if token trace end @@ -814,12 +816,12 @@ module Ci .concat(pipeline.persisted_variables) .append(key: 'CI_JOB_ID', value: id.to_s) .append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self)) - .append(key: 'CI_JOB_TOKEN', value: token, public: false) + .append(key: 'CI_JOB_TOKEN', value: token.to_s, public: false) .append(key: 'CI_BUILD_ID', value: id.to_s) - .append(key: 'CI_BUILD_TOKEN', value: token, public: false) + .append(key: 'CI_BUILD_TOKEN', value: token.to_s, public: false) .append(key: 'CI_REGISTRY_USER', value: CI_REGISTRY_USER) - .append(key: 'CI_REGISTRY_PASSWORD', value: token, public: false) - .append(key: 'CI_REPOSITORY_URL', value: repo_url, public: false) + .append(key: 'CI_REGISTRY_PASSWORD', value: token.to_s, public: false) + .append(key: 'CI_REPOSITORY_URL', value: repo_url.to_s, public: false) .concat(deploy_token_variables) end end @@ -831,9 +833,9 @@ module Ci variables.append(key: 'GITLAB_FEATURES', value: project.licensed_features.join(',')) variables.append(key: 'CI_SERVER_NAME', value: 'GitLab') variables.append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION) - variables.append(key: 'CI_SERVER_VERSION_MAJOR', value: gitlab_version_info.major.to_s) - variables.append(key: 'CI_SERVER_VERSION_MINOR', value: gitlab_version_info.minor.to_s) - variables.append(key: 'CI_SERVER_VERSION_PATCH', value: gitlab_version_info.patch.to_s) + variables.append(key: 'CI_SERVER_VERSION_MAJOR', value: Gitlab.version_info.major.to_s) + variables.append(key: 'CI_SERVER_VERSION_MINOR', value: Gitlab.version_info.minor.to_s) + variables.append(key: 'CI_SERVER_VERSION_PATCH', value: Gitlab.version_info.patch.to_s) variables.append(key: 'CI_SERVER_REVISION', value: Gitlab.revision) variables.append(key: 'CI_JOB_NAME', value: name) variables.append(key: 'CI_JOB_STAGE', value: stage) @@ -850,10 +852,6 @@ module Ci end end - def gitlab_version_info - @gitlab_version_info ||= Gitlab::VersionInfo.parse(Gitlab::VERSION) - end - def legacy_variables Gitlab::Ci::Variables::Collection.new.tap do |variables| variables.append(key: 'CI_BUILD_REF', value: sha) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 56010e899a4..9512ba42f67 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -58,15 +58,9 @@ module Ci after_create :keep_around_commits, unless: :importing? - enum_with_nil source: { - unknown: nil, - push: 1, - web: 2, - trigger: 3, - schedule: 4, - api: 5, - external: 6 - } + # We use `Ci::PipelineEnums.sources` here so that EE can more easily extend + # this `Hash` with new values. + enum_with_nil source: ::Ci::PipelineEnums.sources enum_with_nil config_source: { unknown_source: nil, @@ -74,10 +68,9 @@ module Ci auto_devops_source: 2 } - enum failure_reason: { - unknown_failure: 0, - config_error: 1 - } + # We use `Ci::PipelineEnums.failure_reasons` here so that EE can more easily + # extend this `Hash` with new values. + enum failure_reason: ::Ci::PipelineEnums.failure_reasons state_machine :status, initial: :created do event :enqueue do diff --git a/app/models/ci/pipeline_enums.rb b/app/models/ci/pipeline_enums.rb new file mode 100644 index 00000000000..8d8d16e2ec1 --- /dev/null +++ b/app/models/ci/pipeline_enums.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Ci + module PipelineEnums + # Returns the `Hash` to use for creating the `failure_reason` enum for + # `Ci::Pipeline`. + def self.failure_reasons + { + unknown_failure: 0, + config_error: 1 + } + end + + # Returns the `Hash` to use for creating the `sources` enum for + # `Ci::Pipeline`. + def self.sources + { + unknown: nil, + push: 1, + web: 2, + trigger: 3, + schedule: 4, + api: 5, + external: 6 + } + end + end +end diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index a79a97576d1..c66d5ce54db 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -41,6 +41,10 @@ module Clusters ) end + def client + cluster.platform_kubernetes.kubeclient.knative_client + end + private def install_script diff --git a/app/models/clusters/concerns/application_status.rb b/app/models/clusters/concerns/application_status.rb index 93bdf9c223d..0e74cce29b7 100644 --- a/app/models/clusters/concerns/application_status.rb +++ b/app/models/clusters/concerns/application_status.rb @@ -64,6 +64,13 @@ module Clusters status_reason = transition.args.first app_status.status_reason = status_reason if status_reason end + + before_transition any => [:installed, :updated] do |app_status, _| + # When installing any application we are also performing an update + # of tiller (see Gitlab::Kubernetes::Helm::ClientCommand) so + # therefore we need to reflect that in the database. + app_status.cluster.application_helm.update!(version: Gitlab::Kubernetes::Helm::HELM_VERSION) + end end end diff --git a/app/models/clusters/kubernetes_namespace.rb b/app/models/clusters/kubernetes_namespace.rb index cbd52bfb48b..34f5e38ff79 100644 --- a/app/models/clusters/kubernetes_namespace.rb +++ b/app/models/clusters/kubernetes_namespace.rb @@ -11,9 +11,13 @@ module Clusters belongs_to :project, class_name: '::Project' has_one :platform_kubernetes, through: :cluster + before_validation :set_defaults + validates :namespace, presence: true validates :namespace, uniqueness: { scope: :cluster_id } + validates :service_account_name, presence: true + delegate :ca_pem, to: :platform_kubernetes, allow_nil: true delegate :api_url, to: :platform_kubernetes, allow_nil: true @@ -28,38 +32,43 @@ module Clusters "#{namespace}-token" end - def configure_predefined_credentials - self.namespace = kubernetes_or_project_namespace - self.service_account_name = default_service_account_name - end - def predefined_variables config = YAML.dump(kubeconfig) Gitlab::Ci::Variables::Collection.new.tap do |variables| variables - .append(key: 'KUBE_SERVICE_ACCOUNT', value: service_account_name) - .append(key: 'KUBE_NAMESPACE', value: namespace) - .append(key: 'KUBE_TOKEN', value: service_account_token, public: false) + .append(key: 'KUBE_SERVICE_ACCOUNT', value: service_account_name.to_s) + .append(key: 'KUBE_NAMESPACE', value: namespace.to_s) + .append(key: 'KUBE_TOKEN', value: service_account_token.to_s, public: false) .append(key: 'KUBECONFIG', value: config, public: false, file: true) end end - private - - def kubernetes_or_project_namespace - platform_kubernetes&.namespace.presence || project_namespace + def set_defaults + self.namespace ||= default_platform_kubernetes_namespace + self.namespace ||= default_project_namespace + self.service_account_name ||= default_service_account_name end + private + def default_service_account_name + return unless namespace + "#{namespace}-service-account" end - def project_namespace - Gitlab::NamespaceSanitizer.sanitize(project_slug) + def default_platform_kubernetes_namespace + platform_kubernetes&.namespace.presence + end + + def default_project_namespace + Gitlab::NamespaceSanitizer.sanitize(project_slug) if project_slug end def project_slug + return unless project + "#{project.path}-#{project.id}".downcase end diff --git a/app/models/commit.rb b/app/models/commit.rb index 9dd0cbacd9e..546fcc54a15 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -230,24 +230,13 @@ class Commit def lazy_author BatchLoader.for(author_email.downcase).batch do |emails, loader| - # A Hash that maps user Emails to the corresponding User objects. The - # Emails at this point are the _primary_ Emails of the Users. - users_for_emails = User - .by_any_email(emails) - .each_with_object({}) { |user, hash| hash[user.email] = user } - - users_for_ids = users_for_emails - .values - .each_with_object({}) { |user, hash| hash[user.id] = user } - - # Some commits may have used an alternative Email address. In this case we - # need to query the "emails" table to map those addresses to User objects. - Email - .where(email: emails - users_for_emails.keys) - .pluck(:email, :user_id) - .each { |(email, id)| users_for_emails[email] = users_for_ids[id] } - - users_for_emails.each { |email, user| loader.call(email, user) } + users = User.by_any_email(emails).includes(:emails) + + emails.each do |email| + user = users.find { |u| u.any_email?(email) } + + loader.call(email, user) + end end end diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 755f8bd4d06..0f50bd39131 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -42,18 +42,9 @@ class CommitStatus < ActiveRecord::Base scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) } scope :after_stage, -> (index) { where('stage_idx > ?', index) } - enum_with_nil failure_reason: { - unknown_failure: nil, - script_failure: 1, - api_failure: 2, - stuck_or_timeout_failure: 3, - runner_system_failure: 4, - missing_dependency_failure: 5, - runner_unsupported: 6, - stale_schedule: 7, - job_execution_timeout: 8, - archived_failure: 9 - } + # We use `CommitStatusEnums.failure_reasons` here so that EE can more easily + # extend this `Hash` with new values. + enum_with_nil failure_reason: ::CommitStatusEnums.failure_reasons ## # We still create some CommitStatuses outside of CreatePipelineService. diff --git a/app/models/commit_status_enums.rb b/app/models/commit_status_enums.rb new file mode 100644 index 00000000000..152105d9429 --- /dev/null +++ b/app/models/commit_status_enums.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module CommitStatusEnums + # Returns the Hash to use for creating the `failure_reason` enum for + # `CommitStatus`. + def self.failure_reasons + { + unknown_failure: nil, + script_failure: 1, + api_failure: 2, + stuck_or_timeout_failure: 3, + runner_system_failure: 4, + missing_dependency_failure: 5, + runner_unsupported: 6, + stale_schedule: 7, + job_execution_timeout: 8, + archived_failure: 9 + } + end +end diff --git a/app/models/concerns/deployable.rb b/app/models/concerns/deployable.rb index 85db01af18d..bc12b06b5af 100644 --- a/app/models/concerns/deployable.rb +++ b/app/models/concerns/deployable.rb @@ -13,6 +13,10 @@ module Deployable name: expanded_environment_name ) + # If we failed to persist envirionment record by validation error, such as name with invalid character, + # the job will fall back to a non-environment job. + return unless environment.persisted? + create_deployment!( project_id: environment.project_id, environment: environment, diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 83434276995..811e623b7f7 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -160,18 +160,18 @@ class Deployment < ActiveRecord::Base end def has_metrics? - prometheus_adapter&.can_query? + prometheus_adapter&.can_query? && success? end def metrics - return {} unless has_metrics? && success? + return {} unless has_metrics? metrics = prometheus_adapter.query(:deployment, self) metrics&.merge(deployment_time: finished_at.to_i) || {} end def additional_metrics - return {} unless has_metrics? && success? + return {} unless has_metrics? metrics = prometheus_adapter.query(:additional_metrics_deployment, self) metrics&.merge(deployment_time: finished_at.to_i) || {} diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb index 7d9f6d89d44..8f305dd7c22 100644 --- a/app/models/hooks/service_hook.rb +++ b/app/models/hooks/service_hook.rb @@ -5,8 +5,8 @@ class ServiceHook < WebHook validates :service, presence: true # rubocop: disable CodeReuse/ServiceClass - def execute(data) - WebHookService.new(self, data, 'service_hook').execute + def execute(data, hook_name = 'service_hook') + WebHookService.new(self, data, hook_name).execute end # rubocop: enable CodeReuse/ServiceClass end diff --git a/app/models/member.rb b/app/models/member.rb index 0696ea46c8b..bc8ac14d148 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -152,11 +152,13 @@ class Member < ActiveRecord::Base return member unless can_update_member?(current_user, member) - member.attributes = { - created_by: member.created_by || current_user, - access_level: access_level, - expires_at: expires_at - } + set_member_attributes( + member, + access_level, + current_user: current_user, + expires_at: expires_at, + ldap: ldap + ) if member.request? ::Members::ApproveAccessRequestService.new( @@ -175,6 +177,18 @@ class Member < ActiveRecord::Base # rubocop: enable CodeReuse/ServiceClass end + # Populates the attributes of a member. + # + # This logic resides in a separate method so that EE can extend this logic, + # without having to patch the `add_user` method directly. + def set_member_attributes(member, access_level, current_user: nil, expires_at: nil, ldap: false) + member.attributes = { + created_by: member.created_by || current_user, + access_level: access_level, + expires_at: expires_at + } + end + def add_users(source, users, access_level, current_user: nil, expires_at: nil) return [] unless users.present? diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index df5678ec2f1..92add079a02 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -966,7 +966,6 @@ class MergeRequest < ActiveRecord::Base def mergeable_ci_state? return true unless project.only_allow_merge_if_pipeline_succeeds? - return true unless head_pipeline actual_head_pipeline&.success? || actual_head_pipeline&.skipped? end diff --git a/app/models/project.rb b/app/models/project.rb index d87fc1e4b86..4d1917b9ab2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1903,10 +1903,6 @@ class Project < ActiveRecord::Base false end - def issue_board_milestone_available?(user = nil) - feature_available?(:issue_board_milestone, user) - end - def full_path_was File.join(namespace.full_path, previous_changes['path'].first) end @@ -1968,7 +1964,7 @@ class Project < ActiveRecord::Base end def migrate_to_hashed_storage! - return if hashed_storage?(:repository) + return unless storage_upgradable? update!(repository_read_only: true) diff --git a/app/models/project_services/chat_message/push_message.rb b/app/models/project_services/chat_message/push_message.rb index 82be33a12a1..5dd0414b7e6 100644 --- a/app/models/project_services/chat_message/push_message.rb +++ b/app/models/project_services/chat_message/push_message.rb @@ -26,16 +26,8 @@ module ChatMessage end def activity - action = if new_branch? - "created" - elsif removed_branch? - "removed" - else - "pushed to" - end - { - title: "#{user_combined_name} #{action} #{ref_type}", + title: humanized_action(short: true), subtitle: "in #{project_link}", text: compare_link, image: user_avatar @@ -44,32 +36,21 @@ module ChatMessage private + def humanized_action(short: false) + action, ref_link, target_link = compose_action_details + text = [user_combined_name, action, ref_type, ref_link] + text << target_link unless short + text.join(' ') + end + def message - if new_branch? - new_branch_message - elsif removed_branch? - removed_branch_message - else - push_message - end + humanized_action end def format(string) Slack::Notifier::LinkFormatter.format(string) end - def new_branch_message - "#{user_combined_name} pushed new #{ref_type} #{branch_link} to #{project_link}" - end - - def removed_branch_message - "#{user_combined_name} removed #{ref_type} #{ref} from #{project_link}" - end - - def push_message - "#{user_combined_name} pushed to #{ref_type} #{branch_link} of #{project_link} (#{compare_link})" - end - def commit_messages commits.map { |commit| compose_commit_message(commit) }.join("\n\n") end @@ -115,6 +96,16 @@ module ChatMessage "[Compare changes](#{compare_url})" end + def compose_action_details + if new_branch? + ['pushed new', branch_link, "to #{project_link}"] + elsif removed_branch? + ['removed', ref, "from #{project_link}"] + else + ['pushed to', branch_link, "of #{project_link} (#{compare_link})"] + end + end + def attachment_color '#345' end diff --git a/app/models/user.rb b/app/models/user.rb index a400058e87e..01eba7e0426 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -349,20 +349,28 @@ class User < ActiveRecord::Base def find_by_any_email(email, confirmed: false) return unless email - downcased = email.downcase - - find_by_private_commit_email(downcased) || by_any_email(downcased, confirmed: confirmed).take + by_any_email(email, confirmed: confirmed).take end - # Returns a relation containing all the users for the given Email address - def by_any_email(email, confirmed: false) - users = where(email: email) - users = users.confirmed if confirmed + # Returns a relation containing all the users for the given email addresses + # + # @param emails [String, Array<String>] email addresses to check + # @param confirmed [Boolean] Only return users where the email is confirmed + def by_any_email(emails, confirmed: false) + emails = Array(emails).map(&:downcase) + + from_users = where(email: emails) + from_users = from_users.confirmed if confirmed - emails = joins(:emails).where(emails: { email: email }) - emails = emails.confirmed if confirmed + from_emails = joins(:emails).where(emails: { email: emails }) + from_emails = from_emails.confirmed if confirmed - from_union([users, emails]) + items = [from_users, from_emails] + + user_ids = Gitlab::PrivateCommitEmail.user_ids_for_emails(emails) + items << where(id: user_ids) if user_ids.present? + + from_union(items) end def find_by_private_commit_email(email) @@ -1031,6 +1039,7 @@ class User < ActiveRecord::Base def all_emails all_emails = [] all_emails << email unless temp_oauth_email? + all_emails << private_commit_email all_emails.concat(emails.map(&:email)) all_emails end @@ -1043,16 +1052,24 @@ class User < ActiveRecord::Base verified_emails end + def any_email?(check_email) + downcased = check_email.downcase + + # handle the outdated private commit email case + return true if persisted? && + id == Gitlab::PrivateCommitEmail.user_id_for_email(downcased) + + all_emails.include?(check_email.downcase) + end + def verified_email?(check_email) downcased = check_email.downcase - if email == downcased - primary_email_verified? - else - user_id = Gitlab::PrivateCommitEmail.user_id_for_email(downcased) + # handle the outdated private commit email case + return true if persisted? && + id == Gitlab::PrivateCommitEmail.user_id_for_email(downcased) - user_id == id || emails.confirmed.where(email: downcased).exists? - end + verified_emails.include?(check_email.downcase) end def hook_attrs diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb index 1cd05cf3aac..76e7bc06b4e 100644 --- a/app/models/user_callout.rb +++ b/app/models/user_callout.rb @@ -3,11 +3,9 @@ class UserCallout < ActiveRecord::Base belongs_to :user - enum feature_name: { - gke_cluster_integration: 1, - gcp_signup_offer: 2, - cluster_security_warning: 3 - } + # We use `UserCalloutEnums.feature_names` here so that EE can more easily + # extend this `Hash` with new values. + enum feature_name: ::UserCalloutEnums.feature_names validates :user, presence: true validates :feature_name, diff --git a/app/models/user_callout_enums.rb b/app/models/user_callout_enums.rb new file mode 100644 index 00000000000..b9373ae6166 --- /dev/null +++ b/app/models/user_callout_enums.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module UserCalloutEnums + # Returns the `Hash` to use for the `feature_name` enum in the `UserCallout` + # model. + # + # This method is separate from the `UserCallout` model so that it can be + # extended by EE. + def self.feature_names + { + gke_cluster_integration: 1, + gcp_signup_offer: 2, + cluster_security_warning: 3 + } + end +end diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb index f9623587957..e42d78f47c5 100644 --- a/app/policies/ci/pipeline_policy.rb +++ b/app/policies/ci/pipeline_policy.rb @@ -16,6 +16,10 @@ module Ci enable :update_pipeline end + rule { can?(:owner_access) }.policy do + enable :destroy_pipeline + end + def ref_protected?(user, project, tag, ref) access = ::Gitlab::UserAccess.new(user, project: project) diff --git a/app/presenters/ci/pipeline_presenter.rb b/app/presenters/ci/pipeline_presenter.rb index 93a38f92073..57daf04efc6 100644 --- a/app/presenters/ci/pipeline_presenter.rb +++ b/app/presenters/ci/pipeline_presenter.rb @@ -4,9 +4,11 @@ module Ci class PipelinePresenter < Gitlab::View::Presenter::Delegated include Gitlab::Utils::StrongMemoize - FAILURE_REASONS = { - config_error: 'CI/CD YAML configuration error!' - }.freeze + # We use a class method here instead of a constant, allowing EE to redefine + # the returned `Hash` more easily. + def self.failure_reasons + { config_error: 'CI/CD YAML configuration error!' } + end presents :pipeline @@ -21,7 +23,7 @@ module Ci def failure_reason return unless pipeline.failure_reason? - FAILURE_REASONS[pipeline.failure_reason.to_sym] || + self.class.failure_reasons[pipeline.failure_reason.to_sym] || pipeline.failure_reason end diff --git a/app/serializers/environment_status_entity.rb b/app/serializers/environment_status_entity.rb index 4c6664e9e25..f6321b9e520 100644 --- a/app/serializers/environment_status_entity.rb +++ b/app/serializers/environment_status_entity.rb @@ -11,7 +11,7 @@ class EnvironmentStatusEntity < Grape::Entity project_environment_path(es.project, es.environment) end - expose :metrics_url, if: ->(*) { can_read_environment? && environment.has_metrics? } do |es| + expose :metrics_url, if: ->(*) { can_read_environment? && deployment.has_metrics? } do |es| metrics_project_environment_deployment_path(es.project, es.environment, es.deployment) end @@ -45,6 +45,10 @@ class EnvironmentStatusEntity < Grape::Entity object.environment end + def deployment + object.deployment + end + def project object.environment.project end diff --git a/app/services/ci/destroy_pipeline_service.rb b/app/services/ci/destroy_pipeline_service.rb new file mode 100644 index 00000000000..13f892aabb8 --- /dev/null +++ b/app/services/ci/destroy_pipeline_service.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Ci + class DestroyPipelineService < BaseService + def execute(pipeline) + raise Gitlab::Access::AccessDeniedError unless can?(current_user, :destroy_pipeline, pipeline) + + AuditEventService.new(current_user, pipeline).security_event + + pipeline.destroy! + end + end +end diff --git a/app/services/clusters/applications/check_installation_progress_service.rb b/app/services/clusters/applications/check_installation_progress_service.rb index 49b8825c3a4..ca0f7b30053 100644 --- a/app/services/clusters/applications/check_installation_progress_service.rb +++ b/app/services/clusters/applications/check_installation_progress_service.rb @@ -16,6 +16,7 @@ module Clusters end rescue Kubeclient::HttpError => e Rails.logger.error("Kubernetes error: #{e.error_code} #{e.message}") + Gitlab::Sentry.track_acceptable_exception(e, extra: { scope: 'kubernetes', app_id: app.id }) app.make_errored!("Kubernetes error: #{e.error_code}") unless app.errored? end diff --git a/app/services/clusters/applications/install_service.rb b/app/services/clusters/applications/install_service.rb index 947d22022bc..f4385748c43 100644 --- a/app/services/clusters/applications/install_service.rb +++ b/app/services/clusters/applications/install_service.rb @@ -14,9 +14,11 @@ module Clusters ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id) rescue Kubeclient::HttpError => e Rails.logger.error("Kubernetes error: #{e.error_code} #{e.message}") + Gitlab::Sentry.track_acceptable_exception(e, extra: { scope: 'kubernetes', app_id: app.id }) app.make_errored!("Kubernetes error: #{e.error_code}") rescue StandardError => e Rails.logger.error "Can't start installation process: #{e.class.name} #{e.message}" + Gitlab::Sentry.track_acceptable_exception(e, extra: { scope: 'kubernetes', app_id: app.id }) app.make_errored!("Can't start installation process.") end end diff --git a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb index 2b607681082..b31426556f6 100644 --- a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb +++ b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb @@ -23,7 +23,7 @@ module Clusters attr_reader :cluster, :kubernetes_namespace, :platform def configure_kubernetes_namespace - kubernetes_namespace.configure_predefined_credentials + kubernetes_namespace.set_defaults end def create_project_service_account diff --git a/app/services/projects/disable_deploy_key_service.rb b/app/services/projects/disable_deploy_key_service.rb new file mode 100644 index 00000000000..e483c0708c4 --- /dev/null +++ b/app/services/projects/disable_deploy_key_service.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Projects + class DisableDeployKeyService < BaseService + def execute + # rubocop: disable CodeReuse/ActiveRecord + deploy_key_project = project.deploy_keys_projects.find_by(deploy_key_id: params[:id]) + # rubocop: enable CodeReuse/ActiveRecord + + deploy_key_project&.destroy! + end + end +end diff --git a/app/services/projects/enable_deploy_key_service.rb b/app/services/projects/enable_deploy_key_service.rb index 102088e9557..38219cacee9 100644 --- a/app/services/projects/enable_deploy_key_service.rb +++ b/app/services/projects/enable_deploy_key_service.rb @@ -2,9 +2,10 @@ module Projects class EnableDeployKeyService < BaseService - # rubocop: disable CodeReuse/ActiveRecord def execute - key = accessible_keys.find_by(id: params[:key_id] || params[:id]) + key_id = params[:key_id] || params[:id] + key = find_accessible_key(key_id) + return unless key unless project.deploy_keys.include?(key) @@ -13,12 +14,15 @@ module Projects key end - # rubocop: enable CodeReuse/ActiveRecord private - def accessible_keys - current_user.accessible_deploy_keys + def find_accessible_key(key_id) + if current_user.admin? + DeployKey.find_by_id(key_id) + else + current_user.accessible_deploy_keys.find_by_id(key_id) + end end end end diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb index de6ff92d1da..3f503f3da28 100644 --- a/app/services/users/build_service.rb +++ b/app/services/users/build_service.rb @@ -28,7 +28,7 @@ module Users identity_attrs = params.slice(:extern_uid, :provider) - if identity_attrs.any? + unless identity_attrs.empty? user.identities.build(identity_attrs) end @@ -95,10 +95,6 @@ module Users if params[:reset_password] user_params.merge!(force_random_password: true, password_expires_at: nil) end - - if user_default_internal_regex_enabled? && !user_params.key?(:external) - user_params[:external] = user_external? - end else allowed_signup_params = signup_params allowed_signup_params << :skip_confirmation if skip_authorization @@ -109,6 +105,10 @@ module Users end end + if user_default_internal_regex_enabled? && !user_params.key?(:external) + user_params[:external] = user_external? + end + user_params end diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml index 9aa705d9fa6..a0a00ac5d96 100644 --- a/app/views/admin/background_jobs/show.html.haml +++ b/app/views/admin/background_jobs/show.html.haml @@ -6,43 +6,5 @@ %p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing %hr - - .card - .card-header Sidekiq running processes - .card-body - - if @sidekiq_processes.empty? - %h4.cred - %i.fa.fa-exclamation-triangle - There are no running sidekiq processes. Please restart GitLab - - else - .table-holder - %table.table - %thead - %th USER - %th PID - %th CPU - %th MEM - %th STATE - %th START - %th COMMAND - %tbody - - @sidekiq_processes.each do |process| - %tr - %td= gitlab_config.user - - parse_sidekiq_ps(process).each do |value| - %td= value - .clearfix - %p - %i.fa.fa-exclamation-circle - If '[#{@concurrency} of #{@concurrency} busy]' is shown, restart GitLab. - = link_to sprite_icon('question', size: 16), help_page_path('administration/restart_gitlab') - - %p - %i.fa.fa-exclamation-circle - If more than one sidekiq process is listed, stop GitLab, kill the remaining sidekiq processes (sudo pkill -u #{gitlab_config.user} -f sidekiq) and restart GitLab. - = link_to sprite_icon('question', size: 16), help_page_path('administration/restart_gitlab') - - - .card %iframe{ src: sidekiq_path, width: '100%', height: 970, style: "border: 0" } diff --git a/app/views/admin/impersonation_tokens/index.html.haml b/app/views/admin/impersonation_tokens/index.html.haml index 9e490713ef3..8e869fb4b71 100644 --- a/app/views/admin/impersonation_tokens/index.html.haml +++ b/app/views/admin/impersonation_tokens/index.html.haml @@ -5,6 +5,11 @@ .row.prepend-top-default .col-lg-12 + - if @new_impersonation_token + = render "shared/personal_access_tokens_created_container", new_token_value: @new_impersonation_token, + container_title: 'Your New Impersonation Token', + clipboard_button_title: 'Copy impersonation token to clipboard' + = render "shared/personal_access_tokens_form", path: admin_user_impersonation_tokens_path, impersonation: true, token: @impersonation_token, scopes: @scopes = render "shared/personal_access_tokens_table", impersonation: true, active_tokens: @active_impersonation_tokens, inactive_tokens: @inactive_impersonation_tokens diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index 832ba877558..fdd5c19d562 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true - page_title _("Issues") -- @breadcrumb_link = issues_dashboard_path(assignee_id: current_user.id) +- @breadcrumb_link = issues_dashboard_path(assignee_username: current_user.username) = content_for :meta_tags do = auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{current_user.name} issues") @@ -16,7 +16,7 @@ .nav-controls = render 'shared/issuable/feed_buttons' -= render 'shared/issuable/filter', type: :issues += render 'shared/issuable/search_bar', type: :issues - if current_user && @no_filters_set = render 'shared/dashboard/no_filter_selected' diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index fba8d1cf667..77cfa1271df 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true - page_title _("Merge Requests") -- @breadcrumb_link = merge_requests_dashboard_path(assignee_id: current_user.id) +- @breadcrumb_link = merge_requests_dashboard_path(assignee_username: current_user.username) .page-title-holder %h1.page-title= _('Merge Requests') @@ -12,7 +12,7 @@ .top-area = render 'shared/issuable/nav', type: :merge_requests, display_count: !@no_filters_set -= render 'shared/issuable/filter', type: :merge_requests += render 'shared/issuable/search_bar', type: :merge_requests - if current_user && @no_filters_set = render 'shared/dashboard/no_filter_selected' diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml index 5ddb3ece1cb..ec968e435cd 100644 --- a/app/views/devise/shared/_signin_box.html.haml +++ b/app/views/devise/shared/_signin_box.html.haml @@ -1,10 +1,10 @@ - if form_based_providers.any? - if crowd_enabled? - .login-box.tab-pane.active{ id: "crowd", role: 'tabpanel' } + .login-box.tab-pane{ id: "crowd", role: 'tabpanel', class: active_when(form_based_auth_provider_has_active_class?(:crowd)) } .login-body = render 'devise/sessions/new_crowd' - @ldap_servers.each_with_index do |server, i| - .login-box.tab-pane{ id: "#{server['provider_name']}", role: 'tabpanel', class: active_when(i.zero? && !crowd_enabled?) } + .login-box.tab-pane{ id: "#{server['provider_name']}", role: 'tabpanel', class: active_when(i.zero? && form_based_auth_provider_has_active_class?(:ldapmain)) } .login-body = render 'devise/sessions/new_ldap', server: server - if password_authentication_enabled_for_web? @@ -12,6 +12,8 @@ .login-body = render 'devise/sessions/new_base' + = render_if_exists 'devise/sessions/new_smartcard' + - elsif password_authentication_enabled_for_web? .login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' } .login-body diff --git a/app/views/devise/shared/_tabs_ldap.html.haml b/app/views/devise/shared/_tabs_ldap.html.haml index 7dced0942f5..aee05b6c81c 100644 --- a/app/views/devise/shared/_tabs_ldap.html.haml +++ b/app/views/devise/shared/_tabs_ldap.html.haml @@ -1,10 +1,13 @@ %ul.nav-links.new-session-tabs.nav-tabs.nav{ class: ('custom-provider-tabs' if form_based_providers.any?) } - if crowd_enabled? %li.nav-item - = link_to "Crowd", "#crowd", class: 'nav-link active', 'data-toggle' => 'tab' + = link_to "Crowd", "#crowd", class: "nav-link #{active_when(form_based_auth_provider_has_active_class?(:crowd))}", 'data-toggle' => 'tab' - @ldap_servers.each_with_index do |server, i| %li.nav-item - = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i.zero? && !crowd_enabled?)} qa-ldap-tab", 'data-toggle' => 'tab' + = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i.zero? && form_based_auth_provider_has_active_class?(:ldapmain))} qa-ldap-tab", 'data-toggle' => 'tab' + + = render_if_exists 'devise/shared/tab_smartcard' + - if password_authentication_enabled_for_web? %li.nav-item = link_to 'Standard', '#login-pane', class: 'nav-link qa-standard-tab', 'data-toggle' => 'tab' diff --git a/app/views/discussions/_discussion.html.haml b/app/views/discussions/_discussion.html.haml index 1765251c93d..10187129a33 100644 --- a/app/views/discussions/_discussion.html.haml +++ b/app/views/discussions/_discussion.html.haml @@ -1,12 +1,12 @@ - expanded = discussion.expanded? -%li.note.note-discussion.timeline-entry +%li.note.note-discussion.timeline-entry.unstyled-comments .timeline-entry-inner - .timeline-icon - = link_to user_path(discussion.author) do - = image_tag avatar_icon_for_user(discussion.author), class: "avatar s40" .timeline-content .discussion.js-toggle-container{ data: { discussion_id: discussion.id } } .discussion-header + .timeline-icon + = link_to user_path(discussion.author) do + = image_tag avatar_icon_for_user(discussion.author), class: "avatar s40" .discussion-actions %button.note-action-button.discussion-toggle-button.js-toggle-button{ type: "button", class: ("js-toggle-lazy-diff" unless expanded) } - if expanded diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml index 82693ec832e..69914fccc48 100644 --- a/app/views/events/event/_push.html.haml +++ b/app/views/events/event/_push.html.haml @@ -7,10 +7,10 @@ .event-title.d-flex.flex-wrap = inline_event_icon(event) %span.event-type.d-inline-block.append-right-4.pushed #{event.action_name} #{event.ref_type} - %span + %span.append-right-4 - commits_link = project_commits_path(project, event.ref_name) - should_link = event.tag? ? project.repository.tag_exists?(event.ref_name) : project.repository.branch_exists?(event.ref_name) - = link_to_if should_link, event.ref_name, commits_link, class: 'ref-name append-right-4' + = link_to_if should_link, event.ref_name, commits_link, class: 'ref-name' = render "events/event_scope", event: event diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 8f8b6b454d9..ea5f2b166b4 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -64,7 +64,7 @@ = link_to '#', class: 'dashboard-shortcuts-web-ide', title: _('Web IDE') do = _('Web IDE') - - if Gitlab::Sherlock.enabled? || can?(current_user, :read_instance_statistics) + - if show_separator? %li.line-separator.d-none.d-sm-block = render_if_exists 'dashboard/operations/nav_link' - if can?(current_user, :read_instance_statistics) diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml index c10d4ea1a4d..c1e1eaff942 100644 --- a/app/views/profiles/personal_access_tokens/index.html.haml +++ b/app/views/profiles/personal_access_tokens/index.html.haml @@ -14,17 +14,7 @@ .col-lg-8 - if @new_personal_access_token - .created-personal-access-token-container - %h5.prepend-top-0 - Your New Personal Access Token - .form-group - .input-group - = text_field_tag 'created-personal-access-token', @new_personal_access_token, readonly: true, class: "form-control js-select-on-focus", 'aria-describedby' => "created-personal-access-token-help-block" - %span.input-group-append - = clipboard_button(text: @new_personal_access_token, title: "Copy personal access token to clipboard", placement: "left", class: "input-group-text btn-default btn-clipboard") - %span#created-personal-access-token-help-block.form-text.text-muted.text-danger Make sure you save it - you won't be able to access it again. - - %hr + = render "shared/personal_access_tokens_created_container", new_token_value: @new_personal_access_token = render "shared/personal_access_tokens_form", path: profile_personal_access_tokens_path, impersonation: false, token: @personal_access_token, scopes: @scopes diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml index 71f34c0d85b..21ea188d7b3 100644 --- a/app/views/shared/_label.html.haml +++ b/app/views/shared/_label.html.haml @@ -23,28 +23,29 @@ %li.inline = link_to edit_label_path(label), class: 'btn btn-transparent label-action edit has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do = sprite_icon('pencil') - %li.inline - .dropdown - %button{ type: 'button', class: 'btn btn-transparent js-label-options-dropdown label-action', data: { toggle: 'dropdown' }, aria_label: _('Label actions dropdown') } - = sprite_icon('ellipsis_v') - .dropdown-menu.dropdown-open-left - %ul - - if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group) - %li - %button.js-promote-project-label-button.btn.btn-transparent.btn-action{ disabled: true, type: 'button', - data: { url: promote_project_label_path(label.project, label), - label_title: label.title, - label_color: label.color, - label_text_color: label.text_color, - group_name: label.project.group.name, - target: '#promote-label-modal', - container: 'body', - toggle: 'modal' } } - = _('Promote to group label') - - if can?(current_user, :admin_label, label) - %li - %span{ data: { toggle: 'modal', target: "#modal-delete-label-#{label.id}" } } - %button.text-danger.remove-row{ type: 'button' }= _('Delete') + - if can?(current_user, :admin_label, label) + %li.inline + .dropdown + %button{ type: 'button', class: 'btn btn-transparent js-label-options-dropdown label-action', data: { toggle: 'dropdown' }, aria_label: _('Label actions dropdown') } + = sprite_icon('ellipsis_v') + .dropdown-menu.dropdown-open-left + %ul + - if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group) + %li + %button.js-promote-project-label-button.btn.btn-transparent.btn-action{ disabled: true, type: 'button', + data: { url: promote_project_label_path(label.project, label), + label_title: label.title, + label_color: label.color, + label_text_color: label.text_color, + group_name: label.project.group.name, + target: '#promote-label-modal', + container: 'body', + toggle: 'modal' } } + = _('Promote to group label') + - if can?(current_user, :admin_label, label) + %li + %span{ data: { toggle: 'modal', target: "#modal-delete-label-#{label.id}" } } + %button.text-danger.remove-row{ type: 'button' }= _('Delete') - if current_user %li.inline.label-subscription - if can_subscribe_to_label_in_different_levels?(label) diff --git a/app/views/shared/_personal_access_tokens_created_container.html.haml b/app/views/shared/_personal_access_tokens_created_container.html.haml new file mode 100644 index 00000000000..3150d39b84a --- /dev/null +++ b/app/views/shared/_personal_access_tokens_created_container.html.haml @@ -0,0 +1,14 @@ +- container_title = local_assigns.fetch(:container_title, 'Your New Personal Access Token') +- clipboard_button_title = local_assigns.fetch(:clipboard_button_title, 'Copy personal access token to clipboard') + +.created-personal-access-token-container + %h5.prepend-top-0 + = container_title + .form-group + .input-group + = text_field_tag 'created-personal-access-token', new_token_value, readonly: true, class: "form-control js-select-on-focus", 'aria-describedby' => "created-token-help-block" + %span.input-group-append + = clipboard_button(text: new_token_value, title: clipboard_button_title, placement: "left", class: "input-group-text btn-default btn-clipboard") + %span#created-token-help-block.form-text.text-muted.text-danger Make sure you save it - you won't be able to access it again. + +%hr diff --git a/app/views/shared/_personal_access_tokens_table.html.haml b/app/views/shared/_personal_access_tokens_table.html.haml index cadac1cc99d..2efd03d4867 100644 --- a/app/views/shared/_personal_access_tokens_table.html.haml +++ b/app/views/shared/_personal_access_tokens_table.html.haml @@ -15,8 +15,6 @@ %th Created %th Expires %th Scopes - - if impersonation - %th Token %th %tbody - active_tokens.each do |token| @@ -30,10 +28,6 @@ - else %span.token-never-expires-label Never %td= token.scopes.present? ? token.scopes.join(", ") : "<no scopes selected>" - - if impersonation - %td.token-token-container - = text_field_tag 'impersonation-token-token', token.token, readonly: true, class: "form-control" - = clipboard_button(text: token.token) - path = impersonation ? revoke_admin_user_impersonation_token_path(token.user, token) : revoke_profile_personal_access_token_path(token) %td= link_to "Revoke", path, method: :put, class: "btn btn-danger float-right", data: { confirm: "Are you sure you want to revoke this #{type} Token? This action cannot be undone." } - else diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml deleted file mode 100644 index c7037335866..00000000000 --- a/app/views/shared/issuable/_filter.html.haml +++ /dev/null @@ -1,32 +0,0 @@ -.issues-filters - .issues-details-filters.row-content-block.second-block - = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :search]), method: :get, class: 'filter-form js-filter-form' do - - if params[:search].present? - = hidden_field_tag :search, params[:search] - .issues-other-filters - .filter-item.inline - - if params[:author_id].present? - = hidden_field_tag(:author_id, params[:author_id]) - = dropdown_tag(user_dropdown_label(params[:author_id], "Author"), options: { toggle_class: "js-user-search js-filter-submit js-author-search", title: "Filter by author", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit", - placeholder: "Search authors", data: { any_user: "Any Author", first_user: current_user&.username, current_user: true, project_id: @project&.id, group_id: @group&.id, selected: params[:author_id], field_name: "author_id", default_label: "Author" } }) - - .filter-item.inline - - if params[:assignee_id].present? - = hidden_field_tag(:assignee_id, params[:assignee_id]) - = dropdown_tag(user_dropdown_label(params[:assignee_id], "Assignee"), options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit", - placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: current_user&.username, null_user: true, current_user: true, project_id: @project&.id, group_id: @group&.id, selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } }) - - .filter-item.inline.milestone-filter - = render "shared/issuable/milestone_dropdown", selected: finder.milestones.try(:first), name: :milestone_title, show_any: true, show_upcoming: true, show_started: true - - .filter-item.inline.labels-filter - = render "shared/issuable/label_dropdown", selected: selected_labels, use_id: false, selected_toggle: params[:label_name], data_options: { field_name: "label_name[]" } - - - unless @no_filters_set - .float-right - = render 'shared/sort_dropdown' - - - has_labels = @labels && @labels.any? - .row-content-block.second-block.filtered-labels{ class: ("hidden" unless has_labels) } - - if has_labels - = render 'shared/labels_row', labels: @labels diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index 95f32bd0180..824bbe3524b 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -1,7 +1,6 @@ - type = local_assigns.fetch(:type) - board = local_assigns.fetch(:board, nil) - block_css_class = type != :boards_modal ? 'row-content-block second-block' : '' -- full_path = @project.present? ? @project.full_path : @group.full_path - user_can_admin_list = board && can?(current_user, :admin_list, board.parent) - show_sorting_dropdown = local_assigns.fetch(:show_sorting_dropdown, true) @@ -10,7 +9,7 @@ - if type == :boards #js-multiple-boards-switcher.inline.boards-switcher{ "v-cloak" => true } = render_if_exists "shared/boards/switcher", board: board - = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :search]), method: :get, class: 'filter-form js-filter-form' do + = form_tag page_filter_path, method: :get, class: 'filter-form js-filter-form' do - if params[:search].present? = hidden_field_tag :search, params[:search] - if @can_bulk_update @@ -25,7 +24,7 @@ dropdown_class: "filtered-search-history-dropdown", content_class: "filtered-search-history-dropdown-content", title: "Recent searches" }) do - .js-filtered-search-history-dropdown{ data: { full_path: full_path } } + .js-filtered-search-history-dropdown{ data: { full_path: search_history_storage_prefix } } .filtered-search-box-input-container.droplab-dropdown .scroll-container %ul.tokens-container.list-unstyled diff --git a/app/workers/build_finished_worker.rb b/app/workers/build_finished_worker.rb index 51cbbe8882e..61d866b1f02 100644 --- a/app/workers/build_finished_worker.rb +++ b/app/workers/build_finished_worker.rb @@ -13,7 +13,7 @@ class BuildFinishedWorker BuildTraceSectionsWorker.new.perform(build.id) BuildCoverageWorker.new.perform(build.id) - # We execute that async as this are two indepentent operations that can be executed after TraceSections and Coverage + # We execute that async as this are two independent operations that can be executed after TraceSections and Coverage BuildHooksWorker.perform_async(build.id) ArchiveTraceWorker.perform_async(build.id) end diff --git a/app/workers/process_commit_worker.rb b/app/workers/process_commit_worker.rb index 7b167c95c29..29a7f8e691a 100644 --- a/app/workers/process_commit_worker.rb +++ b/app/workers/process_commit_worker.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Worker for processing individiual commit messages pushed to a repository. +# Worker for processing individual commit messages pushed to a repository. # # Jobs for this worker are scheduled for every commit that is being pushed. As a # result of this the workload of this worker should be kept to a bare minimum. diff --git a/bin/rails b/bin/rails index 228f812ccaf..d21b64b3007 100755 --- a/bin/rails +++ b/bin/rails @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # Remove this block when upgraded to rails 5.0. -unless %w[1 true].include?(ENV["RAILS5"]) +if %w[0 false].include?(ENV["RAILS5"]) begin load File.expand_path('../spring', __FILE__) rescue LoadError => e @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # Remove this block when upgraded to rails 5.0. -unless %w[1 true].include?(ENV["RAILS5"]) +if %w[0 false].include?(ENV["RAILS5"]) begin load File.expand_path('../spring', __FILE__) rescue LoadError => e diff --git a/bin/rspec b/bin/rspec index 26583242051..b0770e30a70 100755 --- a/bin/rspec +++ b/bin/rspec @@ -2,7 +2,7 @@ # Remove these two lines below when upgraded to rails 5.0. # Allow run `rspec` command as `RAILS5=1 rspec ...` instead of `BUNDLE_GEMFILE=Gemfile.rails5 rspec ...` -gemfile = %w[1 true].include?(ENV["RAILS5"]) ? "Gemfile.rails5" : "Gemfile" +gemfile = %w[0 false].include?(ENV["RAILS5"]) ? "Gemfile.rails4" : "Gemfile" ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../#{gemfile}", __dir__) begin diff --git a/bin/setup b/bin/setup index ec1ebe02950..34bb667087a 100755 --- a/bin/setup +++ b/bin/setup @@ -1,7 +1,7 @@ #!/usr/bin/env ruby def rails5? - %w[1 true].include?(ENV["RAILS5"]) + !%w[0 false].include?(ENV["RAILS5"]) end require "pathname" diff --git a/changelogs/unreleased/28682-can-merge-branch-before-build-is-started.yml b/changelogs/unreleased/28682-can-merge-branch-before-build-is-started.yml new file mode 100644 index 00000000000..5ffd93e098f --- /dev/null +++ b/changelogs/unreleased/28682-can-merge-branch-before-build-is-started.yml @@ -0,0 +1,5 @@ +--- +title: Strictly require a pipeline to merge. +merge_request: 22911 +author: +type: changed diff --git a/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml b/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml new file mode 100644 index 00000000000..0662ff6f523 --- /dev/null +++ b/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml @@ -0,0 +1,5 @@ +--- +title: Allow deleting a Pipeline via the API. +merge_request: 22988 +author: +type: added diff --git a/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml b/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml new file mode 100644 index 00000000000..5118949f8a3 --- /dev/null +++ b/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml @@ -0,0 +1,5 @@ +--- +title: Don't show Memory Usage for unmerged MRs +merge_request: +author: +type: changed diff --git a/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml b/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml new file mode 100644 index 00000000000..dd26af875f5 --- /dev/null +++ b/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade helm to 2.11.0 and upgrade on every install +merge_request: 22693 +author: +type: added diff --git a/changelogs/unreleased/51959-branch-and-tag-name-links.yml b/changelogs/unreleased/51959-branch-and-tag-name-links.yml new file mode 100644 index 00000000000..64f1522c70d --- /dev/null +++ b/changelogs/unreleased/51959-branch-and-tag-name-links.yml @@ -0,0 +1,5 @@ +--- +title: Chat message push notifications now include links back to GitLab branches +merge_request: 22651 +author: Tony Castrogiovanni +type: added diff --git a/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml b/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml new file mode 100644 index 00000000000..a437ae560cb --- /dev/null +++ b/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml @@ -0,0 +1,5 @@ +--- +title: Use search bar for filtering in dashboard issues / MRs +merge_request: 22641 +author: Heinrich Lee Yu +type: changed diff --git a/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml b/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml new file mode 100644 index 00000000000..98e15a5cc0a --- /dev/null +++ b/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml @@ -0,0 +1,5 @@ +--- +title: Fix a bug where internal email pattern wasn't respected +merge_request: 22516 +author: +type: fixed diff --git a/changelogs/unreleased/53626-update-config-map-on-install-retry.yml b/changelogs/unreleased/53626-update-config-map-on-install-retry.yml new file mode 100644 index 00000000000..38e79c06c89 --- /dev/null +++ b/changelogs/unreleased/53626-update-config-map-on-install-retry.yml @@ -0,0 +1,5 @@ +--- +title: Update config map for gitlab managed application if already present on install +merge_request: 22969 +author: +type: other diff --git a/changelogs/unreleased/53636-fix-rendering-of-any-user-filter.yml b/changelogs/unreleased/53636-fix-rendering-of-any-user-filter.yml new file mode 100644 index 00000000000..a59a276a334 --- /dev/null +++ b/changelogs/unreleased/53636-fix-rendering-of-any-user-filter.yml @@ -0,0 +1,5 @@ +--- +title: Fix rendering of filter bar tokens for special values +merge_request: 22865 +author: Heinrich Lee Yu +type: fixed diff --git a/changelogs/unreleased/53700-hashed-storagemigration.yml b/changelogs/unreleased/53700-hashed-storagemigration.yml new file mode 100644 index 00000000000..899012ffd22 --- /dev/null +++ b/changelogs/unreleased/53700-hashed-storagemigration.yml @@ -0,0 +1,5 @@ +--- +title: 'Hashed Storage: allow migration to be retried in partially migrated projects' +merge_request: 23087 +author: +type: fixed diff --git a/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml b/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml new file mode 100644 index 00000000000..a9ca56303eb --- /dev/null +++ b/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml @@ -0,0 +1,5 @@ +--- +title: Removes promote to group label for anonymous user +merge_request: 23042 +author: Jacopo Beschi @jacopo-beschi +type: fixed diff --git a/changelogs/unreleased/54002-activity-feed-missing-padding-in-event-note-when-a-branch-is-deleted.yml b/changelogs/unreleased/54002-activity-feed-missing-padding-in-event-note-when-a-branch-is-deleted.yml new file mode 100644 index 00000000000..9f4f104a12c --- /dev/null +++ b/changelogs/unreleased/54002-activity-feed-missing-padding-in-event-note-when-a-branch-is-deleted.yml @@ -0,0 +1,5 @@ +--- +title: Adds margin after a deleted branch name in the activity feed. +merge_request: 23038 +author: +type: fixed diff --git a/changelogs/unreleased/54004-update-asana-to-0-8-1.yml b/changelogs/unreleased/54004-update-asana-to-0-8-1.yml new file mode 100644 index 00000000000..a47b4f3c4d9 --- /dev/null +++ b/changelogs/unreleased/54004-update-asana-to-0-8-1.yml @@ -0,0 +1,5 @@ +--- +title: Update asana to 0.8.1 +merge_request: 23039 +author: Takuya Noguchi +type: other diff --git a/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml b/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml new file mode 100644 index 00000000000..f0b0aa0ee1c --- /dev/null +++ b/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml @@ -0,0 +1,5 @@ +--- +title: Update asciidoctor to 1.5.8 +merge_request: 23047 +author: Takuya Noguchi +type: other diff --git a/changelogs/unreleased/54021-empty-button.yml b/changelogs/unreleased/54021-empty-button.yml new file mode 100644 index 00000000000..3b03665cf95 --- /dev/null +++ b/changelogs/unreleased/54021-empty-button.yml @@ -0,0 +1,5 @@ +--- +title: Prevent empty button being rendered in empty state +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml b/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml new file mode 100644 index 00000000000..3d6fd2d065a --- /dev/null +++ b/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml @@ -0,0 +1,7 @@ +--- +title: Fixes an issue where default values from models would override values set in + the interface (e.g. users would be set to external even though their emails matches + the internal email address pattern) +merge_request: 23114 +author: +type: fixed diff --git a/changelogs/unreleased/added-glob-for-ci-changes-detection.yml b/changelogs/unreleased/added-glob-for-ci-changes-detection.yml new file mode 100644 index 00000000000..887c6ef0346 --- /dev/null +++ b/changelogs/unreleased/added-glob-for-ci-changes-detection.yml @@ -0,0 +1,5 @@ +--- +title: Added glob for CI changes detection +merge_request: 23128 +author: Kirill Zaitsev +type: added diff --git a/changelogs/unreleased/an-gitaly-version-0-133-0.yml b/changelogs/unreleased/an-gitaly-version-0-133-0.yml new file mode 100644 index 00000000000..4f3943ceacb --- /dev/null +++ b/changelogs/unreleased/an-gitaly-version-0-133-0.yml @@ -0,0 +1,5 @@ +--- +title: Updated Gitaly to v0.133.0 +merge_request: 23148 +author: +type: other diff --git a/changelogs/unreleased/auto-devops-support-for-group-security-dashboard.yml b/changelogs/unreleased/auto-devops-support-for-group-security-dashboard.yml new file mode 100644 index 00000000000..7fb11f24902 --- /dev/null +++ b/changelogs/unreleased/auto-devops-support-for-group-security-dashboard.yml @@ -0,0 +1,5 @@ +--- +title: Auto DevOps support for Group Security Dashboard +merge_request: 23165 +author: +type: fixed diff --git a/changelogs/unreleased/auto_devops_kubernetes_active.yml b/changelogs/unreleased/auto_devops_kubernetes_active.yml new file mode 100644 index 00000000000..310d37128c9 --- /dev/null +++ b/changelogs/unreleased/auto_devops_kubernetes_active.yml @@ -0,0 +1,5 @@ +--- +title: Switch kubernetes:active with checking in Auto-DevOps.gitlab-ci.yml +merge_request: 22929 +author: +type: fixed diff --git a/changelogs/unreleased/ce-53347_fix_impersonation_tokens.yml b/changelogs/unreleased/ce-53347_fix_impersonation_tokens.yml new file mode 100644 index 00000000000..6cc743d6f3a --- /dev/null +++ b/changelogs/unreleased/ce-53347_fix_impersonation_tokens.yml @@ -0,0 +1,5 @@ +--- +title: Display impersonation token value only after creation +merge_request: 22916 +author: +type: fixed diff --git a/changelogs/unreleased/dm-commit-email-select-options.yml b/changelogs/unreleased/dm-commit-email-select-options.yml new file mode 100644 index 00000000000..90d5c8cf0c6 --- /dev/null +++ b/changelogs/unreleased/dm-commit-email-select-options.yml @@ -0,0 +1,5 @@ +--- +title: Fix bug causing not all emails to show up in commit email selectbox +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/drop-gcp-cluster-table.yml b/changelogs/unreleased/drop-gcp-cluster-table.yml new file mode 100644 index 00000000000..15964ec2eaf --- /dev/null +++ b/changelogs/unreleased/drop-gcp-cluster-table.yml @@ -0,0 +1,5 @@ +--- +title: Drop gcp_clusters table +merge_request: 22713 +author: +type: other diff --git a/changelogs/unreleased/fix-deployment-metrics-in-mr-widget.yml b/changelogs/unreleased/fix-deployment-metrics-in-mr-widget.yml new file mode 100644 index 00000000000..5427ead3d1b --- /dev/null +++ b/changelogs/unreleased/fix-deployment-metrics-in-mr-widget.yml @@ -0,0 +1,6 @@ +--- +title: Avoid returning deployment metrics url to MR widget when the deployment is + not successful +merge_request: 23010 +author: +type: fixed diff --git a/changelogs/unreleased/fix-not-render-emoji.yml b/changelogs/unreleased/fix-not-render-emoji.yml new file mode 100644 index 00000000000..857b97004f0 --- /dev/null +++ b/changelogs/unreleased/fix-not-render-emoji.yml @@ -0,0 +1,5 @@ +--- +title: Fix not render emoji in filter dropdown +merge_request: 23112 +author: Hiroyuki Sato +type: fixed diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml new file mode 100644 index 00000000000..cfbc4ced635 --- /dev/null +++ b/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml @@ -0,0 +1,5 @@ +--- +title: Enable even more frozen string in lib/gitlab/**/*.rb +merge_request: +author: gfyoung +type: performance diff --git a/changelogs/unreleased/gt-fix-typos-in-lib.yml b/changelogs/unreleased/gt-fix-typos-in-lib.yml new file mode 100644 index 00000000000..32ccd03b063 --- /dev/null +++ b/changelogs/unreleased/gt-fix-typos-in-lib.yml @@ -0,0 +1,5 @@ +--- +title: Fix typos in lib +merge_request: 23106 +author: George Tsiolis +type: other diff --git a/changelogs/unreleased/gt-remove-unused-project-method.yml b/changelogs/unreleased/gt-remove-unused-project-method.yml new file mode 100644 index 00000000000..2d60c2fe423 --- /dev/null +++ b/changelogs/unreleased/gt-remove-unused-project-method.yml @@ -0,0 +1,5 @@ +--- +title: Remove unused project method +merge_request: 54103 +author: George Tsiolis +type: other diff --git a/changelogs/unreleased/gt-rename-diffs-store-variable.yml b/changelogs/unreleased/gt-rename-diffs-store-variable.yml new file mode 100644 index 00000000000..0aed49f3d60 --- /dev/null +++ b/changelogs/unreleased/gt-rename-diffs-store-variable.yml @@ -0,0 +1,5 @@ +--- +title: Rename diffs store variable +merge_request: 23123 +author: George Tsiolis +type: other diff --git a/changelogs/unreleased/ignore-environment-validation-failure.yml b/changelogs/unreleased/ignore-environment-validation-failure.yml new file mode 100644 index 00000000000..1b61cf86dc4 --- /dev/null +++ b/changelogs/unreleased/ignore-environment-validation-failure.yml @@ -0,0 +1,5 @@ +--- +title: Ignore environment validation failure +merge_request: 23100 +author: +type: fixed diff --git a/changelogs/unreleased/osw-fallback-on-blank-refs.yml b/changelogs/unreleased/osw-fallback-on-blank-refs.yml new file mode 100644 index 00000000000..039179f5829 --- /dev/null +++ b/changelogs/unreleased/osw-fallback-on-blank-refs.yml @@ -0,0 +1,5 @@ +--- +title: Avoid Gitaly RPC errors when fetching diff stats +merge_request: 22995 +author: +type: fixed diff --git a/changelogs/unreleased/sh-fix-issue-53783-ce.yml b/changelogs/unreleased/sh-fix-issue-53783-ce.yml new file mode 100644 index 00000000000..10be1d81768 --- /dev/null +++ b/changelogs/unreleased/sh-fix-issue-53783-ce.yml @@ -0,0 +1,5 @@ +--- +title: Fix enabling project deploy key for admins +merge_request: 23043 +author: +type: fixed diff --git a/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml b/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml new file mode 100644 index 00000000000..3ec15908fc7 --- /dev/null +++ b/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml @@ -0,0 +1,5 @@ +--- +title: Remove display of local Sidekiq process in /admin/sidekiq +merge_request: 23118 +author: +type: fixed diff --git a/changelogs/unreleased/sh-use-nakayoshi-fork.yml b/changelogs/unreleased/sh-use-nakayoshi-fork.yml new file mode 100644 index 00000000000..5977d9b0974 --- /dev/null +++ b/changelogs/unreleased/sh-use-nakayoshi-fork.yml @@ -0,0 +1,5 @@ +--- +title: Improve memory performance by reducing dirty pages after fork() +merge_request: 23169 +author: +type: performance diff --git a/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml b/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml new file mode 100644 index 00000000000..6a82e32c416 --- /dev/null +++ b/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml @@ -0,0 +1,5 @@ +--- +title: Use Nokogiri as the ActiveSupport XML backend +merge_request: 23136 +author: +type: performance diff --git a/changelogs/unreleased/switch-rails.yml b/changelogs/unreleased/switch-rails.yml new file mode 100644 index 00000000000..4edf709dbd4 --- /dev/null +++ b/changelogs/unreleased/switch-rails.yml @@ -0,0 +1,5 @@ +--- +title: Switch to Rails 5 +merge_request: 21492 +author: +type: other diff --git a/changelogs/unreleased/triggermesh-phase2-serverless.yml b/changelogs/unreleased/triggermesh-phase2-serverless.yml new file mode 100644 index 00000000000..bee2b5e1e2c --- /dev/null +++ b/changelogs/unreleased/triggermesh-phase2-serverless.yml @@ -0,0 +1,5 @@ +--- +title: Add knative client to kubeclient library +merge_request: 22968 +author: cab105 +type: added diff --git a/changelogs/unreleased/validate-foreign-keys-being-indexed.yml b/changelogs/unreleased/validate-foreign-keys-being-indexed.yml new file mode 100644 index 00000000000..6608a93c08f --- /dev/null +++ b/changelogs/unreleased/validate-foreign-keys-being-indexed.yml @@ -0,0 +1,5 @@ +--- +title: Validate foreign keys being created and indexed for column with _id +merge_request: 22808 +author: +type: performance diff --git a/config/application.rb b/config/application.rb index 95b0f74a5a3..921baa5d617 100644 --- a/config/application.rb +++ b/config/application.rb @@ -8,7 +8,7 @@ module Gitlab # This method is used for smooth upgrading from the current Rails 4.x to Rails 5.0. # https://gitlab.com/gitlab-org/gitlab-ce/issues/14286 def self.rails5? - ENV["RAILS5"].in?(%w[1 true]) + !%w[0 false].include?(ENV["RAILS5"]) end class Application < Rails::Application @@ -158,6 +158,9 @@ module Gitlab config.action_view.sanitized_allowed_protocols = %w(smb) + # Nokogiri is significantly faster and uses less memory than REXML + ActiveSupport::XmlMini.backend = 'Nokogiri' + # This middleware needs to precede ActiveRecord::QueryCache and other middlewares that # connect to the database. config.middleware.insert_after Rails::Rack::Logger, ::Gitlab::Middleware::BasicHealthCheck diff --git a/config/boot.rb b/config/boot.rb index 655c54ddb84..1aeacdabbad 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,10 +1,10 @@ def rails5? - %w[1 true].include?(ENV["RAILS5"]) + !%w[0 false].include?(ENV["RAILS5"]) end require 'rubygems' unless rails5? -gemfile = rails5? ? "Gemfile.rails5" : "Gemfile" +gemfile = rails5? ? "Gemfile" : "Gemfile.rails4" ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../#{gemfile}", __dir__) # Set up gems listed in the Gemfile. diff --git a/config/dependency_decisions.yml b/config/dependency_decisions.yml index 488728e26ab..84d47bd52ad 100644 --- a/config/dependency_decisions.yml +++ b/config/dependency_decisions.yml @@ -544,13 +544,6 @@ :why: https://github.com/xtuc/webassemblyjs/blob/master/LICENSE :versions: [] :when: 2018-06-08 05:30:56.764116000 Z -- - :license - - "@gitlab-org/gitlab-ui" - - MIT - - :who: Clement Ho - :why: Our own library - :versions: [] - :when: 2018-07-17 21:02:54.529227000 Z - - :approve - lz-string - :who: Phil Hughes diff --git a/config/environment.rb b/config/environment.rb index 5d35937f7c6..3a52656a2c1 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,10 +1,10 @@ # Load the rails application # Remove this condition when upgraded to rails 5.0. -if %w[1 true].include?(ENV["RAILS5"]) - require_relative 'application' -else +if %w[0 false].include?(ENV["RAILS5"]) require File.expand_path('application', __dir__) +else + require_relative 'application' end # Initialize the rails application diff --git a/config/initializers/mysql_set_length_for_binary_indexes.rb b/config/initializers/mysql_set_length_for_binary_indexes.rb index 81ed2fb83de..0445d8fcae2 100644 --- a/config/initializers/mysql_set_length_for_binary_indexes.rb +++ b/config/initializers/mysql_set_length_for_binary_indexes.rb @@ -24,28 +24,46 @@ if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:prepend, MysqlSetLengthForBinaryIndex) end -if Gitlab.rails5? - module MysqlSetLengthForBinaryIndexAndIgnorePostgresOptionsForSchema - # This method is used in Rails 5 schema loading as t.index - def index(column_names, options = {}) - options[:length] ||= {} - Array(column_names).each do |column_name| - column = columns.find { |c| c.name == column_name } - - if column&.type == :binary - options[:length][column_name] = 20 - end - end +module MysqlSetLengthForBinaryIndexAndIgnorePostgresOptionsForSchema + # This method is used in Rails 5 schema loading as t.index + def index(column_names, options = {}) + # Ignore indexes that use opclasses, + # also see config/initializers/mysql_ignore_postgresql_options.rb + if options[:opclasses] + warn "WARNING: index on columns #{column_names} uses unsupported option, skipping." + return + end + + # when running rails 4 with rails 5 schema, rails 4 doesn't support multiple + # indexes on the same set of columns. Mysql doesn't support partial indexes, so if + # an index already exists and we add another index, skip it if it's partial: + # see https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21492#note_102821326 + if !Gitlab.rails5? && indexes[column_names] && options[:where] + warn "WARNING: index on columns #{column_names} already exists and partial index is not supported, skipping." + return + end + + options[:length] ||= {} + Array(column_names).each do |column_name| + column = columns.find { |c| c.name == column_name } - # Ignore indexes that use opclasses, - # also see config/initializers/mysql_ignore_postgresql_options.rb - unless options[:opclasses] - super(column_names, options) + if column&.type == :binary + options[:length][column_name] = 20 end end + + super(column_names, options) end +end +def mysql_adapter? + defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) && ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) +end + +if Gitlab.rails5? if defined?(ActiveRecord::ConnectionAdapters::MySQL::TableDefinition) ActiveRecord::ConnectionAdapters::MySQL::TableDefinition.send(:prepend, MysqlSetLengthForBinaryIndexAndIgnorePostgresOptionsForSchema) end +elsif mysql_adapter? && defined?(ActiveRecord::ConnectionAdapters::TableDefinition) + ActiveRecord::ConnectionAdapters::TableDefinition.send(:prepend, MysqlSetLengthForBinaryIndexAndIgnorePostgresOptionsForSchema) end diff --git a/db/migrate/20181030154446_add_missing_indexes_for_foreign_keys.rb b/db/migrate/20181030154446_add_missing_indexes_for_foreign_keys.rb new file mode 100644 index 00000000000..176d55565d8 --- /dev/null +++ b/db/migrate/20181030154446_add_missing_indexes_for_foreign_keys.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +class AddMissingIndexesForForeignKeys < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index(:application_settings, :usage_stats_set_by_user_id) + add_concurrent_index(:ci_pipeline_schedules, :owner_id) + add_concurrent_index(:ci_trigger_requests, :trigger_id) + add_concurrent_index(:ci_triggers, :owner_id) + add_concurrent_index(:clusters_applications_helm, :cluster_id, unique: true) + add_concurrent_index(:clusters_applications_ingress, :cluster_id, unique: true) + add_concurrent_index(:clusters_applications_jupyter, :cluster_id, unique: true) + add_concurrent_index(:clusters_applications_jupyter, :oauth_application_id) + add_concurrent_index(:clusters_applications_knative, :cluster_id, unique: true) + add_concurrent_index(:clusters_applications_prometheus, :cluster_id, unique: true) + add_concurrent_index(:fork_network_members, :forked_from_project_id) + add_concurrent_index(:internal_ids, :namespace_id) + add_concurrent_index(:internal_ids, :project_id) + add_concurrent_index(:issues, :closed_by_id) + add_concurrent_index(:label_priorities, :label_id) + add_concurrent_index(:merge_request_metrics, :merged_by_id) + add_concurrent_index(:merge_request_metrics, :latest_closed_by_id) + add_concurrent_index(:oauth_openid_requests, :access_grant_id) + add_concurrent_index(:project_deploy_tokens, :deploy_token_id) + add_concurrent_index(:protected_tag_create_access_levels, :group_id) + add_concurrent_index(:subscriptions, :project_id) + add_concurrent_index(:user_statuses, :user_id) + add_concurrent_index(:users, :accepted_term_id) + end + + def down + # MySQL requires index for FK, + # thus removal of indexes does fail + return if Gitlab::Database.mysql? + + remove_concurrent_index(:application_settings, :usage_stats_set_by_user_id) + remove_concurrent_index(:ci_pipeline_schedules, :owner_id) + remove_concurrent_index(:ci_trigger_requests, :trigger_id) + remove_concurrent_index(:ci_triggers, :owner_id) + remove_concurrent_index(:clusters_applications_helm, :cluster_id, unique: true) + remove_concurrent_index(:clusters_applications_ingress, :cluster_id, unique: true) + remove_concurrent_index(:clusters_applications_jupyter, :cluster_id, unique: true) + remove_concurrent_index(:clusters_applications_jupyter, :oauth_application_id) + remove_concurrent_index(:clusters_applications_knative, :cluster_id, unique: true) + remove_concurrent_index(:clusters_applications_prometheus, :cluster_id, unique: true) + remove_concurrent_index(:fork_network_members, :forked_from_project_id) + remove_concurrent_index(:internal_ids, :namespace_id) + remove_concurrent_index(:internal_ids, :project_id) + remove_concurrent_index(:issues, :closed_by_id) + remove_concurrent_index(:label_priorities, :label_id) + remove_concurrent_index(:merge_request_metrics, :merged_by_id) + remove_concurrent_index(:merge_request_metrics, :latest_closed_by_id) + remove_concurrent_index(:oauth_openid_requests, :access_grant_id) + remove_concurrent_index(:project_deploy_tokens, :deploy_token_id) + remove_concurrent_index(:protected_tag_create_access_levels, :group_id) + remove_concurrent_index(:subscriptions, :project_id) + remove_concurrent_index(:user_statuses, :user_id) + remove_concurrent_index(:users, :accepted_term_id) + end +end diff --git a/db/migrate/20181031190558_drop_fk_gcp_clusters_table.rb b/db/migrate/20181031190558_drop_fk_gcp_clusters_table.rb new file mode 100644 index 00000000000..a7106111f46 --- /dev/null +++ b/db/migrate/20181031190558_drop_fk_gcp_clusters_table.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class DropFkGcpClustersTable < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + remove_foreign_key_if_exists :gcp_clusters, column: :project_id + remove_foreign_key_if_exists :gcp_clusters, column: :user_id + remove_foreign_key_if_exists :gcp_clusters, column: :service_id + end + + def down + add_foreign_key_if_not_exists :gcp_clusters, :projects, column: :project_id, on_delete: :cascade + add_foreign_key_if_not_exists :gcp_clusters, :users, column: :user_id, on_delete: :nullify + add_foreign_key_if_not_exists :gcp_clusters, :services, column: :service_id, on_delete: :nullify + end + + private + + def add_foreign_key_if_not_exists(source, target, column:, on_delete:) + return unless table_exists?(source) + return if foreign_key_exists?(source, target, column: column) + + add_concurrent_foreign_key(source, target, column: column, on_delete: on_delete) + end + + def remove_foreign_key_if_exists(table, column:) + return unless table_exists?(table) + return unless foreign_key_exists?(table, column: column) + + remove_foreign_key(table, column: column) + end +end diff --git a/db/migrate/20181031190559_drop_gcp_clusters_table.rb b/db/migrate/20181031190559_drop_gcp_clusters_table.rb new file mode 100644 index 00000000000..808d474b4fc --- /dev/null +++ b/db/migrate/20181031190559_drop_gcp_clusters_table.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +class DropGcpClustersTable < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def up + drop_table :gcp_clusters + end + + def down + create_table :gcp_clusters do |t| + # Order columns by best align scheme + t.references :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade } + t.references :user, foreign_key: { on_delete: :nullify } + t.references :service, foreign_key: { on_delete: :nullify } + t.integer :status + t.integer :gcp_cluster_size, null: false + + # Timestamps + t.datetime_with_timezone :created_at, null: false + t.datetime_with_timezone :updated_at, null: false + + # Enable/disable + t.boolean :enabled, default: true + + # General + t.text :status_reason + + # k8s integration specific + t.string :project_namespace + + # Cluster details + t.string :endpoint + t.text :ca_cert + t.text :encrypted_kubernetes_token + t.string :encrypted_kubernetes_token_iv + t.string :username + t.text :encrypted_password + t.string :encrypted_password_iv + + # GKE + t.string :gcp_project_id, null: false + t.string :gcp_cluster_zone, null: false + t.string :gcp_cluster_name, null: false + t.string :gcp_machine_type + t.string :gcp_operation_id + t.text :encrypted_gcp_token + t.string :encrypted_gcp_token_iv + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 3772419b3c0..0c8b4c4c565 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1,4 +1,3 @@ -# encoding: UTF-8 # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. @@ -126,7 +125,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "unique_ips_limit_enabled", default: false, null: false t.string "default_artifacts_expire_in", default: "0", null: false t.string "uuid" - t.decimal "polling_interval_multiplier", default: 1.0, null: false + t.decimal "polling_interval_multiplier", default: "1.0", null: false t.integer "cached_markdown_version" t.boolean "clientside_sentry_enabled", default: false, null: false t.string "clientside_sentry_dsn" @@ -167,6 +166,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "diff_max_patch_bytes", default: 102400, null: false t.integer "archive_builds_in_seconds" t.string "commit_email_hostname" + t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id", using: :btree end create_table "audit_events", force: :cascade do |t| @@ -177,10 +177,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.text "details" t.datetime "created_at" t.datetime "updated_at" + t.index ["entity_id", "entity_type"], name: "index_audit_events_on_entity_id_and_entity_type", using: :btree end - add_index "audit_events", ["entity_id", "entity_type"], name: "index_audit_events_on_entity_id_and_entity_type", using: :btree - create_table "award_emoji", force: :cascade do |t| t.string "name" t.integer "user_id" @@ -188,11 +187,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "awardable_type" t.datetime "created_at" t.datetime "updated_at" + t.index ["awardable_type", "awardable_id"], name: "index_award_emoji_on_awardable_type_and_awardable_id", using: :btree + t.index ["user_id", "name"], name: "index_award_emoji_on_user_id_and_name", using: :btree end - add_index "award_emoji", ["awardable_type", "awardable_id"], name: "index_award_emoji_on_awardable_type_and_awardable_id", using: :btree - add_index "award_emoji", ["user_id", "name"], name: "index_award_emoji_on_user_id_and_name", using: :btree - create_table "badges", force: :cascade do |t| t.string "link_url", null: false t.string "image_url", null: false @@ -201,47 +199,43 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "type", null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false + t.index ["group_id"], name: "index_badges_on_group_id", using: :btree + t.index ["project_id"], name: "index_badges_on_project_id", using: :btree end - add_index "badges", ["group_id"], name: "index_badges_on_group_id", using: :btree - add_index "badges", ["project_id"], name: "index_badges_on_project_id", using: :btree - create_table "board_group_recent_visits", id: :bigserial, force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "user_id" t.integer "board_id" t.integer "group_id" + t.index ["board_id"], name: "index_board_group_recent_visits_on_board_id", using: :btree + t.index ["group_id"], name: "index_board_group_recent_visits_on_group_id", using: :btree + t.index ["user_id", "group_id", "board_id"], name: "index_board_group_recent_visits_on_user_group_and_board", unique: true, using: :btree + t.index ["user_id"], name: "index_board_group_recent_visits_on_user_id", using: :btree end - add_index "board_group_recent_visits", ["board_id"], name: "index_board_group_recent_visits_on_board_id", using: :btree - add_index "board_group_recent_visits", ["group_id"], name: "index_board_group_recent_visits_on_group_id", using: :btree - add_index "board_group_recent_visits", ["user_id", "group_id", "board_id"], name: "index_board_group_recent_visits_on_user_group_and_board", unique: true, using: :btree - add_index "board_group_recent_visits", ["user_id"], name: "index_board_group_recent_visits_on_user_id", using: :btree - create_table "board_project_recent_visits", id: :bigserial, force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "user_id" t.integer "project_id" t.integer "board_id" + t.index ["board_id"], name: "index_board_project_recent_visits_on_board_id", using: :btree + t.index ["project_id"], name: "index_board_project_recent_visits_on_project_id", using: :btree + t.index ["user_id", "project_id", "board_id"], name: "index_board_project_recent_visits_on_user_project_and_board", unique: true, using: :btree + t.index ["user_id"], name: "index_board_project_recent_visits_on_user_id", using: :btree end - add_index "board_project_recent_visits", ["board_id"], name: "index_board_project_recent_visits_on_board_id", using: :btree - add_index "board_project_recent_visits", ["project_id"], name: "index_board_project_recent_visits_on_project_id", using: :btree - add_index "board_project_recent_visits", ["user_id", "project_id", "board_id"], name: "index_board_project_recent_visits_on_user_project_and_board", unique: true, using: :btree - add_index "board_project_recent_visits", ["user_id"], name: "index_board_project_recent_visits_on_user_id", using: :btree - create_table "boards", force: :cascade do |t| t.integer "project_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "group_id" + t.index ["group_id"], name: "index_boards_on_group_id", using: :btree + t.index ["project_id"], name: "index_boards_on_project_id", using: :btree end - add_index "boards", ["group_id"], name: "index_boards_on_group_id", using: :btree - add_index "boards", ["project_id"], name: "index_boards_on_project_id", using: :btree - create_table "broadcast_messages", force: :cascade do |t| t.text "message", null: false t.datetime "starts_at", null: false @@ -252,10 +246,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "font" t.text "message_html", null: false t.integer "cached_markdown_version" + t.index ["starts_at", "ends_at", "id"], name: "index_broadcast_messages_on_starts_at_and_ends_at_and_id", using: :btree end - add_index "broadcast_messages", ["starts_at", "ends_at", "id"], name: "index_broadcast_messages_on_starts_at_and_ends_at_and_id", using: :btree - create_table "chat_names", force: :cascade do |t| t.integer "user_id", null: false t.integer "service_id", null: false @@ -266,51 +259,46 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "last_used_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["service_id", "team_id", "chat_id"], name: "index_chat_names_on_service_id_and_team_id_and_chat_id", unique: true, using: :btree + t.index ["user_id", "service_id"], name: "index_chat_names_on_user_id_and_service_id", unique: true, using: :btree end - add_index "chat_names", ["service_id", "team_id", "chat_id"], name: "index_chat_names_on_service_id_and_team_id_and_chat_id", unique: true, using: :btree - add_index "chat_names", ["user_id", "service_id"], name: "index_chat_names_on_user_id_and_service_id", unique: true, using: :btree - create_table "chat_teams", force: :cascade do |t| t.integer "namespace_id", null: false t.string "team_id" t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["namespace_id"], name: "index_chat_teams_on_namespace_id", unique: true, using: :btree end - add_index "chat_teams", ["namespace_id"], name: "index_chat_teams_on_namespace_id", unique: true, using: :btree - create_table "ci_build_trace_chunks", id: :bigserial, force: :cascade do |t| t.integer "build_id", null: false t.integer "chunk_index", null: false t.integer "data_store", null: false t.binary "raw_data" + t.index ["build_id", "chunk_index"], name: "index_ci_build_trace_chunks_on_build_id_and_chunk_index", unique: true, using: :btree end - add_index "ci_build_trace_chunks", ["build_id", "chunk_index"], name: "index_ci_build_trace_chunks_on_build_id_and_chunk_index", unique: true, using: :btree - create_table "ci_build_trace_section_names", force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false + t.index ["project_id", "name"], name: "index_ci_build_trace_section_names_on_project_id_and_name", unique: true, using: :btree end - add_index "ci_build_trace_section_names", ["project_id", "name"], name: "index_ci_build_trace_section_names_on_project_id_and_name", unique: true, using: :btree - create_table "ci_build_trace_sections", force: :cascade do |t| t.integer "project_id", null: false t.datetime_with_timezone "date_start", null: false t.datetime_with_timezone "date_end", null: false - t.integer "byte_start", limit: 8, null: false - t.integer "byte_end", limit: 8, null: false + t.bigint "byte_start", null: false + t.bigint "byte_end", null: false t.integer "build_id", null: false t.integer "section_name_id", null: false + t.index ["build_id", "section_name_id"], name: "index_ci_build_trace_sections_on_build_id_and_section_name_id", unique: true, using: :btree + t.index ["project_id"], name: "index_ci_build_trace_sections_on_project_id", using: :btree + t.index ["section_name_id"], name: "index_ci_build_trace_sections_on_section_name_id", using: :btree end - add_index "ci_build_trace_sections", ["build_id", "section_name_id"], name: "index_ci_build_trace_sections_on_build_id_and_section_name_id", unique: true, using: :btree - add_index "ci_build_trace_sections", ["project_id"], name: "index_ci_build_trace_sections_on_project_id", using: :btree - add_index "ci_build_trace_sections", ["section_name_id"], name: "index_ci_build_trace_sections_on_section_name_id", using: :btree - create_table "ci_builds", force: :cascade do |t| t.string "status" t.datetime "finished_at" @@ -341,7 +329,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "erased_at" t.datetime "artifacts_expire_at" t.string "environment" - t.integer "artifacts_size", limit: 8 + t.bigint "artifacts_size" t.string "when" t.text "yaml_variables" t.datetime "queued_at" @@ -356,45 +344,42 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "protected" t.integer "failure_reason" t.datetime_with_timezone "scheduled_at" + t.index ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)", using: :btree + t.index ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id", using: :btree + t.index ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree + t.index ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree + t.index ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree + t.index ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree + t.index ["id"], name: "partial_index_ci_builds_on_id_with_legacy_artifacts", where: "(artifacts_file <> ''::text)", using: :btree + t.index ["project_id", "id"], name: "index_ci_builds_on_project_id_and_id", using: :btree + t.index ["protected"], name: "index_ci_builds_on_protected", using: :btree + t.index ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree + t.index ["scheduled_at"], name: "partial_index_ci_builds_on_scheduled_at_with_scheduled_jobs", where: "((scheduled_at IS NOT NULL) AND ((type)::text = 'Ci::Build'::text) AND ((status)::text = 'scheduled'::text))", using: :btree + t.index ["stage_id", "stage_idx"], name: "tmp_build_stage_position_index", where: "(stage_idx IS NOT NULL)", using: :btree + t.index ["stage_id"], name: "index_ci_builds_on_stage_id", using: :btree + t.index ["status", "type", "runner_id"], name: "index_ci_builds_on_status_and_type_and_runner_id", using: :btree + t.index ["token"], name: "index_ci_builds_on_token", unique: true, using: :btree + t.index ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree + t.index ["user_id"], name: "index_ci_builds_on_user_id", using: :btree end - add_index "ci_builds", ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)", using: :btree - add_index "ci_builds", ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id", using: :btree - add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree - add_index "ci_builds", ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree - add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree - add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree - add_index "ci_builds", ["id"], name: "partial_index_ci_builds_on_id_with_legacy_artifacts", where: "(artifacts_file <> ''::text)", using: :btree - add_index "ci_builds", ["project_id", "id"], name: "index_ci_builds_on_project_id_and_id", using: :btree - add_index "ci_builds", ["protected"], name: "index_ci_builds_on_protected", using: :btree - add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree - add_index "ci_builds", ["scheduled_at"], name: "partial_index_ci_builds_on_scheduled_at_with_scheduled_jobs", where: "((scheduled_at IS NOT NULL) AND ((type)::text = 'Ci::Build'::text) AND ((status)::text = 'scheduled'::text))", using: :btree - add_index "ci_builds", ["stage_id", "stage_idx"], name: "tmp_build_stage_position_index", where: "(stage_idx IS NOT NULL)", using: :btree - add_index "ci_builds", ["stage_id"], name: "index_ci_builds_on_stage_id", using: :btree - add_index "ci_builds", ["status", "type", "runner_id"], name: "index_ci_builds_on_status_and_type_and_runner_id", using: :btree - add_index "ci_builds", ["token"], name: "index_ci_builds_on_token", unique: true, using: :btree - add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree - add_index "ci_builds", ["user_id"], name: "index_ci_builds_on_user_id", using: :btree - create_table "ci_builds_metadata", force: :cascade do |t| t.integer "build_id", null: false t.integer "project_id", null: false t.integer "timeout" t.integer "timeout_source", default: 1, null: false + t.index ["build_id"], name: "index_ci_builds_metadata_on_build_id", unique: true, using: :btree + t.index ["project_id"], name: "index_ci_builds_metadata_on_project_id", using: :btree end - add_index "ci_builds_metadata", ["build_id"], name: "index_ci_builds_metadata_on_build_id", unique: true, using: :btree - add_index "ci_builds_metadata", ["project_id"], name: "index_ci_builds_metadata_on_project_id", using: :btree - create_table "ci_builds_runner_session", id: :bigserial, force: :cascade do |t| t.integer "build_id", null: false t.string "url", null: false t.string "certificate" t.string "authorization" + t.index ["build_id"], name: "index_ci_builds_runner_session_on_build_id", unique: true, using: :btree end - add_index "ci_builds_runner_session", ["build_id"], name: "index_ci_builds_runner_session_on_build_id", unique: true, using: :btree - create_table "ci_group_variables", force: :cascade do |t| t.string "key", null: false t.text "value" @@ -405,16 +390,15 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "protected", default: false, null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false + t.index ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree end - add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree - create_table "ci_job_artifacts", force: :cascade do |t| t.integer "project_id", null: false t.integer "job_id", null: false t.integer "file_type", null: false t.integer "file_store" - t.integer "size", limit: 8 + t.bigint "size" t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.datetime_with_timezone "expire_at" @@ -422,13 +406,12 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.binary "file_sha256" t.integer "file_format", limit: 2 t.integer "file_location", limit: 2 + t.index ["expire_at", "job_id"], name: "index_ci_job_artifacts_on_expire_at_and_job_id", using: :btree + t.index ["file_store"], name: "index_ci_job_artifacts_on_file_store", using: :btree + t.index ["job_id", "file_type"], name: "index_ci_job_artifacts_on_job_id_and_file_type", unique: true, using: :btree + t.index ["project_id"], name: "index_ci_job_artifacts_on_project_id", using: :btree end - add_index "ci_job_artifacts", ["expire_at", "job_id"], name: "index_ci_job_artifacts_on_expire_at_and_job_id", using: :btree - add_index "ci_job_artifacts", ["file_store"], name: "index_ci_job_artifacts_on_file_store", using: :btree - add_index "ci_job_artifacts", ["job_id", "file_type"], name: "index_ci_job_artifacts_on_job_id_and_file_type", unique: true, using: :btree - add_index "ci_job_artifacts", ["project_id"], name: "index_ci_job_artifacts_on_project_id", using: :btree - create_table "ci_pipeline_schedule_variables", force: :cascade do |t| t.string "key", null: false t.text "value" @@ -438,10 +421,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "pipeline_schedule_id", null: false t.datetime_with_timezone "created_at" t.datetime_with_timezone "updated_at" + t.index ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree end - add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree - create_table "ci_pipeline_schedules", force: :cascade do |t| t.string "description" t.string "ref" @@ -453,11 +435,11 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "active", default: true t.datetime "created_at" t.datetime "updated_at" + t.index ["next_run_at", "active"], name: "index_ci_pipeline_schedules_on_next_run_at_and_active", using: :btree + t.index ["owner_id"], name: "index_ci_pipeline_schedules_on_owner_id", using: :btree + t.index ["project_id"], name: "index_ci_pipeline_schedules_on_project_id", using: :btree end - add_index "ci_pipeline_schedules", ["next_run_at", "active"], name: "index_ci_pipeline_schedules_on_next_run_at_and_active", using: :btree - add_index "ci_pipeline_schedules", ["project_id"], name: "index_ci_pipeline_schedules_on_project_id", using: :btree - create_table "ci_pipeline_variables", force: :cascade do |t| t.string "key", null: false t.text "value" @@ -465,10 +447,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "encrypted_value_salt" t.string "encrypted_value_iv" t.integer "pipeline_id", null: false + t.index ["pipeline_id", "key"], name: "index_ci_pipeline_variables_on_pipeline_id_and_key", unique: true, using: :btree end - add_index "ci_pipeline_variables", ["pipeline_id", "key"], name: "index_ci_pipeline_variables_on_pipeline_id_and_key", unique: true, using: :btree - create_table "ci_pipelines", force: :cascade do |t| t.string "ref" t.string "sha" @@ -492,37 +473,34 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "protected" t.integer "failure_reason" t.integer "iid" + t.index ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree + t.index ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree + t.index ["project_id", "iid"], name: "index_ci_pipelines_on_project_id_and_iid", unique: true, where: "(iid IS NOT NULL)", using: :btree + t.index ["project_id", "ref", "status", "id"], name: "index_ci_pipelines_on_project_id_and_ref_and_status_and_id", using: :btree + t.index ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree + t.index ["project_id", "source"], name: "index_ci_pipelines_on_project_id_and_source", using: :btree + t.index ["project_id", "status", "config_source"], name: "index_ci_pipelines_on_project_id_and_status_and_config_source", using: :btree + t.index ["project_id"], name: "index_ci_pipelines_on_project_id", using: :btree + t.index ["status"], name: "index_ci_pipelines_on_status", using: :btree + t.index ["user_id"], name: "index_ci_pipelines_on_user_id", using: :btree end - add_index "ci_pipelines", ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree - add_index "ci_pipelines", ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree - add_index "ci_pipelines", ["project_id", "iid"], name: "index_ci_pipelines_on_project_id_and_iid", unique: true, where: "(iid IS NOT NULL)", using: :btree - add_index "ci_pipelines", ["project_id", "ref", "status", "id"], name: "index_ci_pipelines_on_project_id_and_ref_and_status_and_id", using: :btree - add_index "ci_pipelines", ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree - add_index "ci_pipelines", ["project_id", "source"], name: "index_ci_pipelines_on_project_id_and_source", using: :btree - add_index "ci_pipelines", ["project_id", "status", "config_source"], name: "index_ci_pipelines_on_project_id_and_status_and_config_source", using: :btree - add_index "ci_pipelines", ["project_id"], name: "index_ci_pipelines_on_project_id", using: :btree - add_index "ci_pipelines", ["status"], name: "index_ci_pipelines_on_status", using: :btree - add_index "ci_pipelines", ["user_id"], name: "index_ci_pipelines_on_user_id", using: :btree - create_table "ci_runner_namespaces", force: :cascade do |t| t.integer "runner_id" t.integer "namespace_id" + t.index ["namespace_id"], name: "index_ci_runner_namespaces_on_namespace_id", using: :btree + t.index ["runner_id", "namespace_id"], name: "index_ci_runner_namespaces_on_runner_id_and_namespace_id", unique: true, using: :btree end - add_index "ci_runner_namespaces", ["namespace_id"], name: "index_ci_runner_namespaces_on_namespace_id", using: :btree - add_index "ci_runner_namespaces", ["runner_id", "namespace_id"], name: "index_ci_runner_namespaces_on_runner_id_and_namespace_id", unique: true, using: :btree - create_table "ci_runner_projects", force: :cascade do |t| t.integer "runner_id", null: false t.datetime "created_at" t.datetime "updated_at" t.integer "project_id" + t.index ["project_id"], name: "index_ci_runner_projects_on_project_id", using: :btree + t.index ["runner_id"], name: "index_ci_runner_projects_on_runner_id", using: :btree end - add_index "ci_runner_projects", ["project_id"], name: "index_ci_runner_projects_on_project_id", using: :btree - add_index "ci_runner_projects", ["runner_id"], name: "index_ci_runner_projects_on_runner_id", using: :btree - create_table "ci_runners", force: :cascade do |t| t.string "token" t.datetime "created_at" @@ -542,14 +520,13 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "ip_address" t.integer "maximum_timeout" t.integer "runner_type", limit: 2, null: false + t.index ["contacted_at"], name: "index_ci_runners_on_contacted_at", using: :btree + t.index ["is_shared"], name: "index_ci_runners_on_is_shared", using: :btree + t.index ["locked"], name: "index_ci_runners_on_locked", using: :btree + t.index ["runner_type"], name: "index_ci_runners_on_runner_type", using: :btree + t.index ["token"], name: "index_ci_runners_on_token", using: :btree end - add_index "ci_runners", ["contacted_at"], name: "index_ci_runners_on_contacted_at", using: :btree - add_index "ci_runners", ["is_shared"], name: "index_ci_runners_on_is_shared", using: :btree - add_index "ci_runners", ["locked"], name: "index_ci_runners_on_locked", using: :btree - add_index "ci_runners", ["runner_type"], name: "index_ci_runners_on_runner_type", using: :btree - add_index "ci_runners", ["token"], name: "index_ci_runners_on_token", using: :btree - create_table "ci_stages", force: :cascade do |t| t.integer "project_id" t.integer "pipeline_id" @@ -559,23 +536,22 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "status" t.integer "lock_version" t.integer "position" + t.index ["pipeline_id", "name"], name: "index_ci_stages_on_pipeline_id_and_name", unique: true, using: :btree + t.index ["pipeline_id", "position"], name: "index_ci_stages_on_pipeline_id_and_position", using: :btree + t.index ["pipeline_id"], name: "index_ci_stages_on_pipeline_id", using: :btree + t.index ["project_id"], name: "index_ci_stages_on_project_id", using: :btree end - add_index "ci_stages", ["pipeline_id", "name"], name: "index_ci_stages_on_pipeline_id_and_name", unique: true, using: :btree - add_index "ci_stages", ["pipeline_id", "position"], name: "index_ci_stages_on_pipeline_id_and_position", using: :btree - add_index "ci_stages", ["pipeline_id"], name: "index_ci_stages_on_pipeline_id", using: :btree - add_index "ci_stages", ["project_id"], name: "index_ci_stages_on_project_id", using: :btree - create_table "ci_trigger_requests", force: :cascade do |t| t.integer "trigger_id", null: false t.text "variables" t.datetime "created_at" t.datetime "updated_at" t.integer "commit_id" + t.index ["commit_id"], name: "index_ci_trigger_requests_on_commit_id", using: :btree + t.index ["trigger_id"], name: "index_ci_trigger_requests_on_trigger_id", using: :btree end - add_index "ci_trigger_requests", ["commit_id"], name: "index_ci_trigger_requests_on_commit_id", using: :btree - create_table "ci_triggers", force: :cascade do |t| t.string "token" t.datetime "created_at" @@ -584,10 +560,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "owner_id" t.string "description" t.string "ref" + t.index ["owner_id"], name: "index_ci_triggers_on_owner_id", using: :btree + t.index ["project_id"], name: "index_ci_triggers_on_project_id", using: :btree end - add_index "ci_triggers", ["project_id"], name: "index_ci_triggers_on_project_id", using: :btree - create_table "ci_variables", force: :cascade do |t| t.string "key", null: false t.text "value" @@ -597,18 +573,16 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "project_id", null: false t.boolean "protected", default: false, null: false t.string "environment_scope", default: "*", null: false + t.index ["project_id", "key", "environment_scope"], name: "index_ci_variables_on_project_id_and_key_and_environment_scope", unique: true, using: :btree end - add_index "ci_variables", ["project_id", "key", "environment_scope"], name: "index_ci_variables_on_project_id_and_key_and_environment_scope", unique: true, using: :btree - create_table "cluster_groups", force: :cascade do |t| t.integer "cluster_id", null: false t.integer "group_id", null: false + t.index ["cluster_id", "group_id"], name: "index_cluster_groups_on_cluster_id_and_group_id", unique: true, using: :btree + t.index ["group_id"], name: "index_cluster_groups_on_group_id", using: :btree end - add_index "cluster_groups", ["cluster_id", "group_id"], name: "index_cluster_groups_on_cluster_id_and_group_id", unique: true, using: :btree - add_index "cluster_groups", ["group_id"], name: "index_cluster_groups_on_group_id", using: :btree - create_table "cluster_platforms_kubernetes", force: :cascade do |t| t.integer "cluster_id", null: false t.datetime_with_timezone "created_at", null: false @@ -622,20 +596,18 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.text "encrypted_token" t.string "encrypted_token_iv" t.integer "authorization_type", limit: 2 + t.index ["cluster_id"], name: "index_cluster_platforms_kubernetes_on_cluster_id", unique: true, using: :btree end - add_index "cluster_platforms_kubernetes", ["cluster_id"], name: "index_cluster_platforms_kubernetes_on_cluster_id", unique: true, using: :btree - create_table "cluster_projects", force: :cascade do |t| t.integer "project_id", null: false t.integer "cluster_id", null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false + t.index ["cluster_id"], name: "index_cluster_projects_on_cluster_id", using: :btree + t.index ["project_id"], name: "index_cluster_projects_on_project_id", using: :btree end - add_index "cluster_projects", ["cluster_id"], name: "index_cluster_projects_on_cluster_id", using: :btree - add_index "cluster_projects", ["project_id"], name: "index_cluster_projects_on_project_id", using: :btree - create_table "cluster_providers_gcp", force: :cascade do |t| t.integer "cluster_id", null: false t.integer "status" @@ -651,10 +623,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.text "encrypted_access_token" t.string "encrypted_access_token_iv" t.boolean "legacy_abac", default: true, null: false + t.index ["cluster_id"], name: "index_cluster_providers_gcp_on_cluster_id", unique: true, using: :btree end - add_index "cluster_providers_gcp", ["cluster_id"], name: "index_cluster_providers_gcp_on_cluster_id", unique: true, using: :btree - create_table "clusters", force: :cascade do |t| t.integer "user_id" t.integer "provider_type" @@ -665,19 +636,8 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "name", null: false t.string "environment_scope", default: "*", null: false t.integer "cluster_type", limit: 2, default: 3, null: false - end - - add_index "clusters", ["enabled"], name: "index_clusters_on_enabled", using: :btree - add_index "clusters", ["user_id"], name: "index_clusters_on_user_id", using: :btree - - create_table "clusters_applications_cert_managers", force: :cascade do |t| - t.integer "cluster_id", null: false - t.integer "status", null: false - t.string "version", null: false - t.string "email", null: false - t.datetime_with_timezone "created_at", null: false - t.datetime_with_timezone "updated_at", null: false - t.text "status_reason" + t.index ["enabled"], name: "index_clusters_on_enabled", using: :btree + t.index ["user_id"], name: "index_clusters_on_user_id", using: :btree end create_table "clusters_applications_helm", force: :cascade do |t| @@ -690,6 +650,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.text "encrypted_ca_key" t.text "encrypted_ca_key_iv" t.text "ca_cert" + t.index ["cluster_id"], name: "index_clusters_applications_helm_on_cluster_id", unique: true, using: :btree end create_table "clusters_applications_ingress", force: :cascade do |t| @@ -702,6 +663,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "cluster_ip" t.text "status_reason" t.string "external_ip" + t.index ["cluster_id"], name: "index_clusters_applications_ingress_on_cluster_id", unique: true, using: :btree end create_table "clusters_applications_jupyter", force: :cascade do |t| @@ -713,6 +675,8 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.text "status_reason" + t.index ["cluster_id"], name: "index_clusters_applications_jupyter_on_cluster_id", unique: true, using: :btree + t.index ["oauth_application_id"], name: "index_clusters_applications_jupyter_on_oauth_application_id", using: :btree end create_table "clusters_applications_knative", force: :cascade do |t| @@ -723,6 +687,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "version", null: false t.string "hostname" t.text "status_reason" + t.index ["cluster_id"], name: "index_clusters_applications_knative_on_cluster_id", unique: true, using: :btree end create_table "clusters_applications_prometheus", force: :cascade do |t| @@ -732,6 +697,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.text "status_reason" t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false + t.index ["cluster_id"], name: "index_clusters_applications_prometheus_on_cluster_id", unique: true, using: :btree end create_table "clusters_applications_runners", force: :cascade do |t| @@ -743,11 +709,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "version", null: false t.text "status_reason" t.boolean "privileged", default: true, null: false + t.index ["cluster_id"], name: "index_clusters_applications_runners_on_cluster_id", unique: true, using: :btree + t.index ["runner_id"], name: "index_clusters_applications_runners_on_runner_id", using: :btree end - add_index "clusters_applications_runners", ["cluster_id"], name: "index_clusters_applications_runners_on_cluster_id", unique: true, using: :btree - add_index "clusters_applications_runners", ["runner_id"], name: "index_clusters_applications_runners_on_runner_id", using: :btree - create_table "clusters_kubernetes_namespaces", id: :bigserial, force: :cascade do |t| t.integer "cluster_id", null: false t.integer "project_id" @@ -758,23 +723,21 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "encrypted_service_account_token_iv" t.string "namespace", null: false t.string "service_account_name" + t.index ["cluster_id", "namespace"], name: "kubernetes_namespaces_cluster_and_namespace", unique: true, using: :btree + t.index ["cluster_id"], name: "index_clusters_kubernetes_namespaces_on_cluster_id", using: :btree + t.index ["cluster_project_id"], name: "index_clusters_kubernetes_namespaces_on_cluster_project_id", using: :btree + t.index ["project_id"], name: "index_clusters_kubernetes_namespaces_on_project_id", using: :btree end - add_index "clusters_kubernetes_namespaces", ["cluster_id", "namespace"], name: "kubernetes_namespaces_cluster_and_namespace", unique: true, using: :btree - add_index "clusters_kubernetes_namespaces", ["cluster_id"], name: "index_clusters_kubernetes_namespaces_on_cluster_id", using: :btree - add_index "clusters_kubernetes_namespaces", ["cluster_project_id"], name: "index_clusters_kubernetes_namespaces_on_cluster_project_id", using: :btree - add_index "clusters_kubernetes_namespaces", ["project_id"], name: "index_clusters_kubernetes_namespaces_on_project_id", using: :btree - create_table "container_repositories", force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["project_id", "name"], name: "index_container_repositories_on_project_id_and_name", unique: true, using: :btree + t.index ["project_id"], name: "index_container_repositories_on_project_id", using: :btree end - add_index "container_repositories", ["project_id", "name"], name: "index_container_repositories_on_project_id_and_name", unique: true, using: :btree - add_index "container_repositories", ["project_id"], name: "index_container_repositories_on_project_id", using: :btree - create_table "conversational_development_index_metrics", force: :cascade do |t| t.float "leader_issues", null: false t.float "instance_issues", null: false @@ -816,10 +779,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "created_at" t.datetime "updated_at" t.boolean "can_push", default: false, null: false + t.index ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree end - add_index "deploy_keys_projects", ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree - create_table "deploy_tokens", force: :cascade do |t| t.boolean "revoked", default: false t.boolean "read_repository", default: false, null: false @@ -828,11 +790,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime_with_timezone "created_at", null: false t.string "name", null: false t.string "token", null: false + t.index ["token", "expires_at", "id"], name: "index_deploy_tokens_on_token_and_expires_at_and_id", where: "(revoked IS FALSE)", using: :btree + t.index ["token"], name: "index_deploy_tokens_on_token", unique: true, using: :btree end - add_index "deploy_tokens", ["token", "expires_at", "id"], name: "index_deploy_tokens_on_token_and_expires_at_and_id", where: "(revoked IS FALSE)", using: :btree - add_index "deploy_tokens", ["token"], name: "index_deploy_tokens_on_token", unique: true, using: :btree - create_table "deployments", force: :cascade do |t| t.integer "iid", null: false t.integer "project_id", null: false @@ -848,18 +809,17 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "on_stop" t.integer "status", limit: 2, default: 2, null: false t.datetime_with_timezone "finished_at" + t.index ["created_at"], name: "index_deployments_on_created_at", using: :btree + t.index ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id", using: :btree + t.index ["environment_id", "id"], name: "index_deployments_on_environment_id_and_id", using: :btree + t.index ["environment_id", "iid", "project_id"], name: "index_deployments_on_environment_id_and_iid_and_project_id", using: :btree + t.index ["environment_id", "status"], name: "index_deployments_on_environment_id_and_status", using: :btree + t.index ["id"], name: "partial_index_deployments_for_legacy_successful_deployments", where: "((finished_at IS NULL) AND (status = 2))", using: :btree + t.index ["project_id", "iid"], name: "index_deployments_on_project_id_and_iid", unique: true, using: :btree + t.index ["project_id", "status", "created_at"], name: "index_deployments_on_project_id_and_status_and_created_at", using: :btree + t.index ["project_id", "status"], name: "index_deployments_on_project_id_and_status", using: :btree end - add_index "deployments", ["created_at"], name: "index_deployments_on_created_at", using: :btree - add_index "deployments", ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id", using: :btree - add_index "deployments", ["environment_id", "id"], name: "index_deployments_on_environment_id_and_id", using: :btree - add_index "deployments", ["environment_id", "iid", "project_id"], name: "index_deployments_on_environment_id_and_iid_and_project_id", using: :btree - add_index "deployments", ["environment_id", "status"], name: "index_deployments_on_environment_id_and_status", using: :btree - add_index "deployments", ["id"], name: "partial_index_deployments_for_legacy_successful_deployments", where: "((finished_at IS NULL) AND (status = 2))", using: :btree - add_index "deployments", ["project_id", "iid"], name: "index_deployments_on_project_id_and_iid", unique: true, using: :btree - add_index "deployments", ["project_id", "status", "created_at"], name: "index_deployments_on_project_id_and_status_and_created_at", using: :btree - add_index "deployments", ["project_id", "status"], name: "index_deployments_on_project_id_and_status", using: :btree - create_table "emails", force: :cascade do |t| t.integer "user_id", null: false t.string "email", null: false @@ -868,12 +828,11 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "confirmation_token" t.datetime_with_timezone "confirmed_at" t.datetime_with_timezone "confirmation_sent_at" + t.index ["confirmation_token"], name: "index_emails_on_confirmation_token", unique: true, using: :btree + t.index ["email"], name: "index_emails_on_email", unique: true, using: :btree + t.index ["user_id"], name: "index_emails_on_user_id", using: :btree end - add_index "emails", ["confirmation_token"], name: "index_emails_on_confirmation_token", unique: true, using: :btree - add_index "emails", ["email"], name: "index_emails_on_email", unique: true, using: :btree - add_index "emails", ["user_id"], name: "index_emails_on_user_id", using: :btree - create_table "environments", force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false @@ -883,11 +842,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "environment_type" t.string "state", default: "available", null: false t.string "slug", null: false + t.index ["project_id", "name"], name: "index_environments_on_project_id_and_name", unique: true, using: :btree + t.index ["project_id", "slug"], name: "index_environments_on_project_id_and_slug", unique: true, using: :btree end - add_index "environments", ["project_id", "name"], name: "index_environments_on_project_id_and_name", unique: true, using: :btree - add_index "environments", ["project_id", "slug"], name: "index_environments_on_project_id_and_slug", unique: true, using: :btree - create_table "events", force: :cascade do |t| t.integer "project_id" t.integer "author_id", null: false @@ -896,95 +854,60 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime_with_timezone "updated_at", null: false t.integer "action", limit: 2, null: false t.string "target_type" + t.index ["action"], name: "index_events_on_action", using: :btree + t.index ["author_id", "project_id"], name: "index_events_on_author_id_and_project_id", using: :btree + t.index ["project_id", "id"], name: "index_events_on_project_id_and_id", using: :btree + t.index ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id", using: :btree end - add_index "events", ["action"], name: "index_events_on_action", using: :btree - add_index "events", ["author_id", "project_id"], name: "index_events_on_author_id_and_project_id", using: :btree - add_index "events", ["project_id", "id"], name: "index_events_on_project_id_and_id", using: :btree - add_index "events", ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id", using: :btree - create_table "feature_gates", force: :cascade do |t| t.string "feature_key", null: false t.string "key", null: false t.string "value" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["feature_key", "key", "value"], name: "index_feature_gates_on_feature_key_and_key_and_value", unique: true, using: :btree end - add_index "feature_gates", ["feature_key", "key", "value"], name: "index_feature_gates_on_feature_key_and_key_and_value", unique: true, using: :btree - create_table "features", force: :cascade do |t| t.string "key", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["key"], name: "index_features_on_key", unique: true, using: :btree end - add_index "features", ["key"], name: "index_features_on_key", unique: true, using: :btree - create_table "fork_network_members", force: :cascade do |t| t.integer "fork_network_id", null: false t.integer "project_id", null: false t.integer "forked_from_project_id" + t.index ["fork_network_id"], name: "index_fork_network_members_on_fork_network_id", using: :btree + t.index ["forked_from_project_id"], name: "index_fork_network_members_on_forked_from_project_id", using: :btree + t.index ["project_id"], name: "index_fork_network_members_on_project_id", unique: true, using: :btree end - add_index "fork_network_members", ["fork_network_id"], name: "index_fork_network_members_on_fork_network_id", using: :btree - add_index "fork_network_members", ["project_id"], name: "index_fork_network_members_on_project_id", unique: true, using: :btree - create_table "fork_networks", force: :cascade do |t| t.integer "root_project_id" t.string "deleted_root_project_name" + t.index ["root_project_id"], name: "index_fork_networks_on_root_project_id", unique: true, using: :btree end - add_index "fork_networks", ["root_project_id"], name: "index_fork_networks_on_root_project_id", unique: true, using: :btree - create_table "forked_project_links", force: :cascade do |t| t.integer "forked_to_project_id", null: false t.integer "forked_from_project_id", null: false t.datetime "created_at" t.datetime "updated_at" + t.index ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree end - add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree - - create_table "gcp_clusters", force: :cascade do |t| - t.integer "project_id", null: false - t.integer "user_id" - t.integer "service_id" - t.integer "status" - t.integer "gcp_cluster_size", null: false - t.datetime_with_timezone "created_at", null: false - t.datetime_with_timezone "updated_at", null: false - t.boolean "enabled", default: true - t.text "status_reason" - t.string "project_namespace" - t.string "endpoint" - t.text "ca_cert" - t.text "encrypted_kubernetes_token" - t.string "encrypted_kubernetes_token_iv" - t.string "username" - t.text "encrypted_password" - t.string "encrypted_password_iv" - t.string "gcp_project_id", null: false - t.string "gcp_cluster_zone", null: false - t.string "gcp_cluster_name", null: false - t.string "gcp_machine_type" - t.string "gcp_operation_id" - t.text "encrypted_gcp_token" - t.string "encrypted_gcp_token_iv" - end - - add_index "gcp_clusters", ["project_id"], name: "index_gcp_clusters_on_project_id", unique: true, using: :btree - create_table "gpg_key_subkeys", force: :cascade do |t| t.integer "gpg_key_id", null: false t.binary "keyid" t.binary "fingerprint" + t.index ["fingerprint"], name: "index_gpg_key_subkeys_on_fingerprint", unique: true, using: :btree + t.index ["gpg_key_id"], name: "index_gpg_key_subkeys_on_gpg_key_id", using: :btree + t.index ["keyid"], name: "index_gpg_key_subkeys_on_keyid", unique: true, using: :btree end - add_index "gpg_key_subkeys", ["fingerprint"], name: "index_gpg_key_subkeys_on_fingerprint", unique: true, using: :btree - add_index "gpg_key_subkeys", ["gpg_key_id"], name: "index_gpg_key_subkeys_on_gpg_key_id", using: :btree - add_index "gpg_key_subkeys", ["keyid"], name: "index_gpg_key_subkeys_on_keyid", unique: true, using: :btree - create_table "gpg_keys", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -992,12 +915,11 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.binary "primary_keyid" t.binary "fingerprint" t.text "key" + t.index ["fingerprint"], name: "index_gpg_keys_on_fingerprint", unique: true, using: :btree + t.index ["primary_keyid"], name: "index_gpg_keys_on_primary_keyid", unique: true, using: :btree + t.index ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree end - add_index "gpg_keys", ["fingerprint"], name: "index_gpg_keys_on_fingerprint", unique: true, using: :btree - add_index "gpg_keys", ["primary_keyid"], name: "index_gpg_keys_on_primary_keyid", unique: true, using: :btree - add_index "gpg_keys", ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree - create_table "gpg_signatures", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -1009,63 +931,59 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.text "gpg_key_user_email" t.integer "verification_status", limit: 2, default: 0, null: false t.integer "gpg_key_subkey_id" + t.index ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", unique: true, using: :btree + t.index ["gpg_key_id"], name: "index_gpg_signatures_on_gpg_key_id", using: :btree + t.index ["gpg_key_primary_keyid"], name: "index_gpg_signatures_on_gpg_key_primary_keyid", using: :btree + t.index ["gpg_key_subkey_id"], name: "index_gpg_signatures_on_gpg_key_subkey_id", using: :btree + t.index ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree end - add_index "gpg_signatures", ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", unique: true, using: :btree - add_index "gpg_signatures", ["gpg_key_id"], name: "index_gpg_signatures_on_gpg_key_id", using: :btree - add_index "gpg_signatures", ["gpg_key_primary_keyid"], name: "index_gpg_signatures_on_gpg_key_primary_keyid", using: :btree - add_index "gpg_signatures", ["gpg_key_subkey_id"], name: "index_gpg_signatures_on_gpg_key_subkey_id", using: :btree - add_index "gpg_signatures", ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree - create_table "group_custom_attributes", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "group_id", null: false t.string "key", null: false t.string "value", null: false + t.index ["group_id", "key"], name: "index_group_custom_attributes_on_group_id_and_key", unique: true, using: :btree + t.index ["key", "value"], name: "index_group_custom_attributes_on_key_and_value", using: :btree end - add_index "group_custom_attributes", ["group_id", "key"], name: "index_group_custom_attributes_on_group_id_and_key", unique: true, using: :btree - add_index "group_custom_attributes", ["key", "value"], name: "index_group_custom_attributes_on_key_and_value", using: :btree - create_table "identities", force: :cascade do |t| t.string "extern_uid" t.string "provider" t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" + t.index ["user_id"], name: "index_identities_on_user_id", using: :btree end - add_index "identities", ["user_id"], name: "index_identities_on_user_id", using: :btree - create_table "import_export_uploads", force: :cascade do |t| t.datetime_with_timezone "updated_at", null: false t.integer "project_id" t.text "import_file" t.text "export_file" + t.index ["project_id"], name: "index_import_export_uploads_on_project_id", using: :btree + t.index ["updated_at"], name: "index_import_export_uploads_on_updated_at", using: :btree end - add_index "import_export_uploads", ["project_id"], name: "index_import_export_uploads_on_project_id", using: :btree - add_index "import_export_uploads", ["updated_at"], name: "index_import_export_uploads_on_updated_at", using: :btree - create_table "internal_ids", id: :bigserial, force: :cascade do |t| t.integer "project_id" t.integer "usage", null: false t.integer "last_value", null: false t.integer "namespace_id" + t.index ["namespace_id"], name: "index_internal_ids_on_namespace_id", using: :btree + t.index ["project_id"], name: "index_internal_ids_on_project_id", using: :btree + t.index ["usage", "namespace_id"], name: "index_internal_ids_on_usage_and_namespace_id", unique: true, where: "(namespace_id IS NOT NULL)", using: :btree + t.index ["usage", "project_id"], name: "index_internal_ids_on_usage_and_project_id", unique: true, where: "(project_id IS NOT NULL)", using: :btree end - add_index "internal_ids", ["usage", "namespace_id"], name: "index_internal_ids_on_usage_and_namespace_id", unique: true, where: "(namespace_id IS NOT NULL)", using: :btree - add_index "internal_ids", ["usage", "project_id"], name: "index_internal_ids_on_usage_and_project_id", unique: true, where: "(project_id IS NOT NULL)", using: :btree - create_table "issue_assignees", id: false, force: :cascade do |t| t.integer "user_id", null: false t.integer "issue_id", null: false + t.index ["issue_id", "user_id"], name: "index_issue_assignees_on_issue_id_and_user_id", unique: true, using: :btree + t.index ["user_id"], name: "index_issue_assignees_on_user_id", using: :btree end - add_index "issue_assignees", ["issue_id", "user_id"], name: "index_issue_assignees_on_issue_id_and_user_id", unique: true, using: :btree - add_index "issue_assignees", ["user_id"], name: "index_issue_assignees_on_user_id", using: :btree - create_table "issue_metrics", force: :cascade do |t| t.integer "issue_id", null: false t.datetime "first_mentioned_in_commit_at" @@ -1073,10 +991,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "first_added_to_board_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["issue_id"], name: "index_issue_metrics", using: :btree end - add_index "issue_metrics", ["issue_id"], name: "index_issue_metrics", using: :btree - create_table "issues", force: :cascade do |t| t.string "title" t.integer "author_id" @@ -1102,23 +1019,23 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "discussion_locked" t.datetime_with_timezone "closed_at" t.integer "closed_by_id" + t.index ["author_id"], name: "index_issues_on_author_id", using: :btree + t.index ["closed_by_id"], name: "index_issues_on_closed_by_id", using: :btree + t.index ["confidential"], name: "index_issues_on_confidential", using: :btree + t.index ["description"], name: "index_issues_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} + t.index ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree + t.index ["moved_to_id"], name: "index_issues_on_moved_to_id", where: "(moved_to_id IS NOT NULL)", using: :btree + t.index ["project_id", "created_at", "id", "state"], name: "index_issues_on_project_id_and_created_at_and_id_and_state", using: :btree + t.index ["project_id", "due_date", "id", "state"], name: "idx_issues_on_project_id_and_due_date_and_id_and_state_partial", where: "(due_date IS NOT NULL)", using: :btree + t.index ["project_id", "iid"], name: "index_issues_on_project_id_and_iid", unique: true, using: :btree + t.index ["project_id", "updated_at", "id", "state"], name: "index_issues_on_project_id_and_updated_at_and_id_and_state", using: :btree + t.index ["relative_position"], name: "index_issues_on_relative_position", using: :btree + t.index ["state"], name: "index_issues_on_state", using: :btree + t.index ["title"], name: "index_issues_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} + t.index ["updated_at"], name: "index_issues_on_updated_at", using: :btree + t.index ["updated_by_id"], name: "index_issues_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree end - add_index "issues", ["author_id"], name: "index_issues_on_author_id", using: :btree - add_index "issues", ["confidential"], name: "index_issues_on_confidential", using: :btree - add_index "issues", ["description"], name: "index_issues_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} - add_index "issues", ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree - add_index "issues", ["moved_to_id"], name: "index_issues_on_moved_to_id", where: "(moved_to_id IS NOT NULL)", using: :btree - add_index "issues", ["project_id", "created_at", "id", "state"], name: "index_issues_on_project_id_and_created_at_and_id_and_state", using: :btree - add_index "issues", ["project_id", "due_date", "id", "state"], name: "idx_issues_on_project_id_and_due_date_and_id_and_state_partial", where: "(due_date IS NOT NULL)", using: :btree - add_index "issues", ["project_id", "iid"], name: "index_issues_on_project_id_and_iid", unique: true, using: :btree - add_index "issues", ["project_id", "updated_at", "id", "state"], name: "index_issues_on_project_id_and_updated_at_and_id_and_state", using: :btree - add_index "issues", ["relative_position"], name: "index_issues_on_relative_position", using: :btree - add_index "issues", ["state"], name: "index_issues_on_state", using: :btree - add_index "issues", ["title"], name: "index_issues_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} - add_index "issues", ["updated_at"], name: "index_issues_on_updated_at", using: :btree - add_index "issues", ["updated_by_id"], name: "index_issues_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree - create_table "keys", force: :cascade do |t| t.integer "user_id" t.datetime "created_at" @@ -1129,33 +1046,31 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "fingerprint" t.boolean "public", default: false, null: false t.datetime "last_used_at" + t.index ["fingerprint"], name: "index_keys_on_fingerprint", unique: true, using: :btree + t.index ["user_id"], name: "index_keys_on_user_id", using: :btree end - add_index "keys", ["fingerprint"], name: "index_keys_on_fingerprint", unique: true, using: :btree - add_index "keys", ["user_id"], name: "index_keys_on_user_id", using: :btree - create_table "label_links", force: :cascade do |t| t.integer "label_id" t.integer "target_id" t.string "target_type" t.datetime "created_at" t.datetime "updated_at" + t.index ["label_id"], name: "index_label_links_on_label_id", using: :btree + t.index ["target_id", "target_type"], name: "index_label_links_on_target_id_and_target_type", using: :btree end - add_index "label_links", ["label_id"], name: "index_label_links_on_label_id", using: :btree - add_index "label_links", ["target_id", "target_type"], name: "index_label_links_on_target_id_and_target_type", using: :btree - create_table "label_priorities", force: :cascade do |t| t.integer "project_id", null: false t.integer "label_id", null: false t.integer "priority", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["label_id"], name: "index_label_priorities_on_label_id", using: :btree + t.index ["priority"], name: "index_label_priorities_on_priority", using: :btree + t.index ["project_id", "label_id"], name: "index_label_priorities_on_project_id_and_label_id", unique: true, using: :btree end - add_index "label_priorities", ["priority"], name: "index_label_priorities_on_priority", using: :btree - add_index "label_priorities", ["project_id", "label_id"], name: "index_label_priorities_on_project_id_and_label_id", unique: true, using: :btree - create_table "labels", force: :cascade do |t| t.string "title" t.string "color" @@ -1168,45 +1083,41 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "type" t.integer "group_id" t.integer "cached_markdown_version" + t.index ["group_id", "project_id", "title"], name: "index_labels_on_group_id_and_project_id_and_title", unique: true, using: :btree + t.index ["project_id"], name: "index_labels_on_project_id", using: :btree + t.index ["template"], name: "index_labels_on_template", where: "template", using: :btree + t.index ["title"], name: "index_labels_on_title", using: :btree + t.index ["type", "project_id"], name: "index_labels_on_type_and_project_id", using: :btree end - add_index "labels", ["group_id", "project_id", "title"], name: "index_labels_on_group_id_and_project_id_and_title", unique: true, using: :btree - add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree - add_index "labels", ["template"], name: "index_labels_on_template", where: "template", using: :btree - add_index "labels", ["title"], name: "index_labels_on_title", using: :btree - add_index "labels", ["type", "project_id"], name: "index_labels_on_type_and_project_id", using: :btree - create_table "lfs_file_locks", force: :cascade do |t| t.integer "project_id", null: false t.integer "user_id", null: false t.datetime "created_at", null: false t.string "path", limit: 511 + t.index ["project_id", "path"], name: "index_lfs_file_locks_on_project_id_and_path", unique: true, using: :btree + t.index ["user_id"], name: "index_lfs_file_locks_on_user_id", using: :btree end - add_index "lfs_file_locks", ["project_id", "path"], name: "index_lfs_file_locks_on_project_id_and_path", unique: true, using: :btree - add_index "lfs_file_locks", ["user_id"], name: "index_lfs_file_locks_on_user_id", using: :btree - create_table "lfs_objects", force: :cascade do |t| t.string "oid", null: false - t.integer "size", limit: 8, null: false + t.bigint "size", null: false t.datetime "created_at" t.datetime "updated_at" t.string "file" t.integer "file_store" + t.index ["file_store"], name: "index_lfs_objects_on_file_store", using: :btree + t.index ["oid"], name: "index_lfs_objects_on_oid", unique: true, using: :btree end - add_index "lfs_objects", ["file_store"], name: "index_lfs_objects_on_file_store", using: :btree - add_index "lfs_objects", ["oid"], name: "index_lfs_objects_on_oid", unique: true, using: :btree - create_table "lfs_objects_projects", force: :cascade do |t| t.integer "lfs_object_id", null: false t.integer "project_id", null: false t.datetime "created_at" t.datetime "updated_at" + t.index ["project_id"], name: "index_lfs_objects_projects_on_project_id", using: :btree end - add_index "lfs_objects_projects", ["project_id"], name: "index_lfs_objects_projects_on_project_id", using: :btree - create_table "lists", force: :cascade do |t| t.integer "board_id", null: false t.integer "label_id" @@ -1214,12 +1125,11 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "position" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["board_id", "label_id"], name: "index_lists_on_board_id_and_label_id", unique: true, using: :btree + t.index ["label_id"], name: "index_lists_on_label_id", using: :btree + t.index ["list_type"], name: "index_lists_on_list_type", using: :btree end - add_index "lists", ["board_id", "label_id"], name: "index_lists_on_board_id_and_label_id", unique: true, using: :btree - add_index "lists", ["label_id"], name: "index_lists_on_label_id", using: :btree - add_index "lists", ["list_type"], name: "index_lists_on_list_type", using: :btree - create_table "members", force: :cascade do |t| t.integer "access_level", null: false t.integer "source_id", null: false @@ -1235,14 +1145,13 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "invite_accepted_at" t.datetime "requested_at" t.date "expires_at" + t.index ["access_level"], name: "index_members_on_access_level", using: :btree + t.index ["invite_token"], name: "index_members_on_invite_token", unique: true, using: :btree + t.index ["requested_at"], name: "index_members_on_requested_at", using: :btree + t.index ["source_id", "source_type"], name: "index_members_on_source_id_and_source_type", using: :btree + t.index ["user_id"], name: "index_members_on_user_id", using: :btree end - add_index "members", ["access_level"], name: "index_members_on_access_level", using: :btree - add_index "members", ["invite_token"], name: "index_members_on_invite_token", unique: true, using: :btree - add_index "members", ["requested_at"], name: "index_members_on_requested_at", using: :btree - add_index "members", ["source_id", "source_type"], name: "index_members_on_source_id_and_source_type", using: :btree - add_index "members", ["user_id"], name: "index_members_on_user_id", using: :btree - create_table "merge_request_diff_commits", id: false, force: :cascade do |t| t.datetime_with_timezone "authored_date" t.datetime_with_timezone "committed_date" @@ -1254,11 +1163,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.text "committer_name" t.text "committer_email" t.text "message" + t.index ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_commits_on_mr_diff_id_and_order", unique: true, using: :btree + t.index ["sha"], name: "index_merge_request_diff_commits_on_sha", using: :btree end - add_index "merge_request_diff_commits", ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_commits_on_mr_diff_id_and_order", unique: true, using: :btree - add_index "merge_request_diff_commits", ["sha"], name: "index_merge_request_diff_commits_on_sha", using: :btree - create_table "merge_request_diff_files", id: false, force: :cascade do |t| t.integer "merge_request_diff_id", null: false t.integer "relative_order", null: false @@ -1272,10 +1180,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.text "old_path", null: false t.text "diff", null: false t.boolean "binary" + t.index ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_files_on_mr_diff_id_and_order", unique: true, using: :btree end - add_index "merge_request_diff_files", ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_files_on_mr_diff_id_and_order", unique: true, using: :btree - create_table "merge_request_diffs", force: :cascade do |t| t.string "state" t.integer "merge_request_id", null: false @@ -1286,10 +1193,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "head_commit_sha" t.string "start_commit_sha" t.integer "commits_count" + t.index ["merge_request_id", "id"], name: "index_merge_request_diffs_on_merge_request_id_and_id", using: :btree end - add_index "merge_request_diffs", ["merge_request_id", "id"], name: "index_merge_request_diffs_on_merge_request_id_and_id", using: :btree - create_table "merge_request_metrics", force: :cascade do |t| t.integer "merge_request_id", null: false t.datetime "latest_build_started_at" @@ -1302,12 +1208,13 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "merged_by_id" t.integer "latest_closed_by_id" t.datetime_with_timezone "latest_closed_at" + t.index ["first_deployed_to_production_at"], name: "index_merge_request_metrics_on_first_deployed_to_production_at", using: :btree + t.index ["latest_closed_by_id"], name: "index_merge_request_metrics_on_latest_closed_by_id", using: :btree + t.index ["merge_request_id"], name: "index_merge_request_metrics", using: :btree + t.index ["merged_by_id"], name: "index_merge_request_metrics_on_merged_by_id", using: :btree + t.index ["pipeline_id"], name: "index_merge_request_metrics_on_pipeline_id", using: :btree end - add_index "merge_request_metrics", ["first_deployed_to_production_at"], name: "index_merge_request_metrics_on_first_deployed_to_production_at", using: :btree - add_index "merge_request_metrics", ["merge_request_id"], name: "index_merge_request_metrics", using: :btree - add_index "merge_request_metrics", ["pipeline_id"], name: "index_merge_request_metrics_on_pipeline_id", using: :btree - create_table "merge_requests", force: :cascade do |t| t.string "target_branch", null: false t.string "source_branch", null: false @@ -1344,38 +1251,36 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "rebase_commit_sha" t.boolean "squash", default: false, null: false t.boolean "allow_maintainer_to_push" + t.index ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree + t.index ["author_id"], name: "index_merge_requests_on_author_id", using: :btree + t.index ["created_at"], name: "index_merge_requests_on_created_at", using: :btree + t.index ["description"], name: "index_merge_requests_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} + t.index ["head_pipeline_id"], name: "index_merge_requests_on_head_pipeline_id", using: :btree + t.index ["id", "merge_jid"], name: "index_merge_requests_on_id_and_merge_jid", where: "((merge_jid IS NOT NULL) AND ((state)::text = 'locked'::text))", using: :btree + t.index ["latest_merge_request_diff_id"], name: "index_merge_requests_on_latest_merge_request_diff_id", using: :btree + t.index ["merge_user_id"], name: "index_merge_requests_on_merge_user_id", where: "(merge_user_id IS NOT NULL)", using: :btree + t.index ["milestone_id"], name: "index_merge_requests_on_milestone_id", using: :btree + t.index ["source_branch"], name: "index_merge_requests_on_source_branch", using: :btree + t.index ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_and_branch_state_opened", where: "((state)::text = 'opened'::text)", using: :btree + t.index ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_id_and_source_branch", using: :btree + t.index ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree + t.index ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid", unique: true, using: :btree + t.index ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid_opened", where: "((state)::text = 'opened'::text)", using: :btree + t.index ["target_project_id", "merge_commit_sha", "id"], name: "index_merge_requests_on_tp_id_and_merge_commit_sha_and_id", using: :btree + t.index ["title"], name: "index_merge_requests_on_title", using: :btree + t.index ["title"], name: "index_merge_requests_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} + t.index ["updated_by_id"], name: "index_merge_requests_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree end - add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree - add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree - add_index "merge_requests", ["created_at"], name: "index_merge_requests_on_created_at", using: :btree - add_index "merge_requests", ["description"], name: "index_merge_requests_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} - add_index "merge_requests", ["head_pipeline_id"], name: "index_merge_requests_on_head_pipeline_id", using: :btree - add_index "merge_requests", ["id", "merge_jid"], name: "index_merge_requests_on_id_and_merge_jid", where: "((merge_jid IS NOT NULL) AND ((state)::text = 'locked'::text))", using: :btree - add_index "merge_requests", ["latest_merge_request_diff_id"], name: "index_merge_requests_on_latest_merge_request_diff_id", using: :btree - add_index "merge_requests", ["merge_user_id"], name: "index_merge_requests_on_merge_user_id", where: "(merge_user_id IS NOT NULL)", using: :btree - add_index "merge_requests", ["milestone_id"], name: "index_merge_requests_on_milestone_id", using: :btree - add_index "merge_requests", ["source_branch"], name: "index_merge_requests_on_source_branch", using: :btree - add_index "merge_requests", ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_and_branch_state_opened", where: "((state)::text = 'opened'::text)", using: :btree - add_index "merge_requests", ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_id_and_source_branch", using: :btree - add_index "merge_requests", ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree - add_index "merge_requests", ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid", unique: true, using: :btree - add_index "merge_requests", ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid_opened", where: "((state)::text = 'opened'::text)", using: :btree - add_index "merge_requests", ["target_project_id", "merge_commit_sha", "id"], name: "index_merge_requests_on_tp_id_and_merge_commit_sha_and_id", using: :btree - add_index "merge_requests", ["title"], name: "index_merge_requests_on_title", using: :btree - add_index "merge_requests", ["title"], name: "index_merge_requests_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} - add_index "merge_requests", ["updated_by_id"], name: "index_merge_requests_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree - create_table "merge_requests_closing_issues", force: :cascade do |t| t.integer "merge_request_id", null: false t.integer "issue_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["issue_id"], name: "index_merge_requests_closing_issues_on_issue_id", using: :btree + t.index ["merge_request_id"], name: "index_merge_requests_closing_issues_on_merge_request_id", using: :btree end - add_index "merge_requests_closing_issues", ["issue_id"], name: "index_merge_requests_closing_issues_on_issue_id", using: :btree - add_index "merge_requests_closing_issues", ["merge_request_id"], name: "index_merge_requests_closing_issues_on_merge_request_id", using: :btree - create_table "milestones", force: :cascade do |t| t.string "title", null: false t.integer "project_id" @@ -1390,15 +1295,14 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.date "start_date" t.integer "cached_markdown_version" t.integer "group_id" + t.index ["description"], name: "index_milestones_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} + t.index ["due_date"], name: "index_milestones_on_due_date", using: :btree + t.index ["group_id"], name: "index_milestones_on_group_id", using: :btree + t.index ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree + t.index ["title"], name: "index_milestones_on_title", using: :btree + t.index ["title"], name: "index_milestones_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} end - add_index "milestones", ["description"], name: "index_milestones_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} - add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree - add_index "milestones", ["group_id"], name: "index_milestones_on_group_id", using: :btree - add_index "milestones", ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree - add_index "milestones", ["title"], name: "index_milestones_on_title", using: :btree - add_index "milestones", ["title"], name: "index_milestones_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} - create_table "namespaces", force: :cascade do |t| t.string "name", null: false t.string "path", null: false @@ -1418,19 +1322,18 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "two_factor_grace_period", default: 48, null: false t.integer "cached_markdown_version" t.string "runners_token" + t.index ["created_at"], name: "index_namespaces_on_created_at", using: :btree + t.index ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree + t.index ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} + t.index ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree + t.index ["parent_id", "id"], name: "index_namespaces_on_parent_id_and_id", unique: true, using: :btree + t.index ["path"], name: "index_namespaces_on_path", using: :btree + t.index ["path"], name: "index_namespaces_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"} + t.index ["require_two_factor_authentication"], name: "index_namespaces_on_require_two_factor_authentication", using: :btree + t.index ["runners_token"], name: "index_namespaces_on_runners_token", unique: true, using: :btree + t.index ["type"], name: "index_namespaces_on_type", using: :btree end - add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree - add_index "namespaces", ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree - add_index "namespaces", ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} - add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree - add_index "namespaces", ["parent_id", "id"], name: "index_namespaces_on_parent_id_and_id", unique: true, using: :btree - add_index "namespaces", ["path"], name: "index_namespaces_on_path", using: :btree - add_index "namespaces", ["path"], name: "index_namespaces_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"} - add_index "namespaces", ["require_two_factor_authentication"], name: "index_namespaces_on_require_two_factor_authentication", using: :btree - add_index "namespaces", ["runners_token"], name: "index_namespaces_on_runners_token", unique: true, using: :btree - add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree - create_table "note_diff_files", force: :cascade do |t| t.integer "diff_note_id", null: false t.text "diff", null: false @@ -1441,10 +1344,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "b_mode", null: false t.text "new_path", null: false t.text "old_path", null: false + t.index ["diff_note_id"], name: "index_note_diff_files_on_diff_note_id", unique: true, using: :btree end - add_index "note_diff_files", ["diff_note_id"], name: "index_note_diff_files_on_diff_note_id", unique: true, using: :btree - create_table "notes", force: :cascade do |t| t.text "note" t.string "noteable_type" @@ -1469,19 +1371,18 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "cached_markdown_version" t.text "change_position" t.boolean "resolved_by_push" + t.index ["author_id"], name: "index_notes_on_author_id", using: :btree + t.index ["commit_id"], name: "index_notes_on_commit_id", using: :btree + t.index ["created_at"], name: "index_notes_on_created_at", using: :btree + t.index ["discussion_id"], name: "index_notes_on_discussion_id", using: :btree + t.index ["line_code"], name: "index_notes_on_line_code", using: :btree + t.index ["note"], name: "index_notes_on_note_trigram", using: :gin, opclasses: {"note"=>"gin_trgm_ops"} + t.index ["noteable_id", "noteable_type"], name: "index_notes_on_noteable_id_and_noteable_type", using: :btree + t.index ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree + t.index ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree + t.index ["updated_at"], name: "index_notes_on_updated_at", using: :btree end - add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree - add_index "notes", ["commit_id"], name: "index_notes_on_commit_id", using: :btree - add_index "notes", ["created_at"], name: "index_notes_on_created_at", using: :btree - add_index "notes", ["discussion_id"], name: "index_notes_on_discussion_id", using: :btree - add_index "notes", ["line_code"], name: "index_notes_on_line_code", using: :btree - add_index "notes", ["note"], name: "index_notes_on_note_trigram", using: :gin, opclasses: {"note"=>"gin_trgm_ops"} - add_index "notes", ["noteable_id", "noteable_type"], name: "index_notes_on_noteable_id_and_noteable_type", using: :btree - add_index "notes", ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree - add_index "notes", ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree - add_index "notes", ["updated_at"], name: "index_notes_on_updated_at", using: :btree - create_table "notification_settings", force: :cascade do |t| t.integer "user_id", null: false t.integer "source_id" @@ -1503,12 +1404,11 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "success_pipeline" t.boolean "push_to_merge_request" t.boolean "issue_due" + t.index ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree + t.index ["user_id", "source_id", "source_type"], name: "index_notifications_on_user_id_and_source_id_and_source_type", unique: true, using: :btree + t.index ["user_id"], name: "index_notification_settings_on_user_id", using: :btree end - add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree - add_index "notification_settings", ["user_id", "source_id", "source_type"], name: "index_notifications_on_user_id_and_source_id_and_source_type", unique: true, using: :btree - add_index "notification_settings", ["user_id"], name: "index_notification_settings_on_user_id", using: :btree - create_table "oauth_access_grants", force: :cascade do |t| t.integer "resource_owner_id", null: false t.integer "application_id", null: false @@ -1518,10 +1418,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "created_at", null: false t.datetime "revoked_at" t.string "scopes" + t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree end - add_index "oauth_access_grants", ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree - create_table "oauth_access_tokens", force: :cascade do |t| t.integer "resource_owner_id" t.integer "application_id" @@ -1531,12 +1430,11 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "revoked_at" t.datetime "created_at", null: false t.string "scopes" + t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree + t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree + t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree end - add_index "oauth_access_tokens", ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree - add_index "oauth_access_tokens", ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree - add_index "oauth_access_tokens", ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree - create_table "oauth_applications", force: :cascade do |t| t.string "name", null: false t.string "uid", null: false @@ -1548,14 +1446,14 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "owner_id" t.string "owner_type" t.boolean "trusted", default: false, null: false + t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree + t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree end - add_index "oauth_applications", ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree - add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree - create_table "oauth_openid_requests", force: :cascade do |t| t.integer "access_grant_id", null: false t.string "nonce", null: false + t.index ["access_grant_id"], name: "index_oauth_openid_requests_on_access_grant_id", using: :btree end create_table "pages_domains", force: :cascade do |t| @@ -1568,14 +1466,13 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime_with_timezone "verified_at" t.string "verification_code", null: false t.datetime_with_timezone "enabled_until" + t.index ["domain"], name: "index_pages_domains_on_domain", unique: true, using: :btree + t.index ["project_id", "enabled_until"], name: "index_pages_domains_on_project_id_and_enabled_until", using: :btree + t.index ["project_id"], name: "index_pages_domains_on_project_id", using: :btree + t.index ["verified_at", "enabled_until"], name: "index_pages_domains_on_verified_at_and_enabled_until", using: :btree + t.index ["verified_at"], name: "index_pages_domains_on_verified_at", using: :btree end - add_index "pages_domains", ["domain"], name: "index_pages_domains_on_domain", unique: true, using: :btree - add_index "pages_domains", ["project_id", "enabled_until"], name: "index_pages_domains_on_project_id_and_enabled_until", using: :btree - add_index "pages_domains", ["project_id"], name: "index_pages_domains_on_project_id", using: :btree - add_index "pages_domains", ["verified_at", "enabled_until"], name: "index_pages_domains_on_verified_at_and_enabled_until", using: :btree - add_index "pages_domains", ["verified_at"], name: "index_pages_domains_on_verified_at", using: :btree - create_table "personal_access_tokens", force: :cascade do |t| t.integer "user_id", null: false t.string "token" @@ -1587,29 +1484,26 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "scopes", default: "--- []\n", null: false t.boolean "impersonation", default: false, null: false t.string "token_digest" + t.index ["token"], name: "index_personal_access_tokens_on_token", unique: true, using: :btree + t.index ["token_digest"], name: "index_personal_access_tokens_on_token_digest", unique: true, using: :btree + t.index ["user_id"], name: "index_personal_access_tokens_on_user_id", using: :btree end - add_index "personal_access_tokens", ["token"], name: "index_personal_access_tokens_on_token", unique: true, using: :btree - add_index "personal_access_tokens", ["token_digest"], name: "index_personal_access_tokens_on_token_digest", unique: true, using: :btree - add_index "personal_access_tokens", ["user_id"], name: "index_personal_access_tokens_on_user_id", using: :btree - create_table "programming_languages", force: :cascade do |t| t.string "name", null: false t.string "color", null: false t.datetime_with_timezone "created_at", null: false + t.index ["name"], name: "index_programming_languages_on_name", unique: true, using: :btree end - add_index "programming_languages", ["name"], name: "index_programming_languages_on_name", unique: true, using: :btree - create_table "project_authorizations", id: false, force: :cascade do |t| t.integer "user_id", null: false t.integer "project_id", null: false t.integer "access_level", null: false + t.index ["project_id"], name: "index_project_authorizations_on_project_id", using: :btree + t.index ["user_id", "project_id", "access_level"], name: "index_project_authorizations_on_user_id_project_id_access_level", unique: true, using: :btree end - add_index "project_authorizations", ["project_id"], name: "index_project_authorizations_on_project_id", using: :btree - add_index "project_authorizations", ["user_id", "project_id", "access_level"], name: "index_project_authorizations_on_user_id_project_id_access_level", unique: true, using: :btree - create_table "project_auto_devops", force: :cascade do |t| t.integer "project_id", null: false t.datetime_with_timezone "created_at", null: false @@ -1617,37 +1511,33 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "enabled" t.string "domain" t.integer "deploy_strategy", default: 0, null: false + t.index ["project_id"], name: "index_project_auto_devops_on_project_id", unique: true, using: :btree end - add_index "project_auto_devops", ["project_id"], name: "index_project_auto_devops_on_project_id", unique: true, using: :btree - create_table "project_ci_cd_settings", force: :cascade do |t| t.integer "project_id", null: false t.boolean "group_runners_enabled", default: true, null: false + t.index ["project_id"], name: "index_project_ci_cd_settings_on_project_id", unique: true, using: :btree end - add_index "project_ci_cd_settings", ["project_id"], name: "index_project_ci_cd_settings_on_project_id", unique: true, using: :btree - create_table "project_custom_attributes", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "project_id", null: false t.string "key", null: false t.string "value", null: false + t.index ["key", "value"], name: "index_project_custom_attributes_on_key_and_value", using: :btree + t.index ["project_id", "key"], name: "index_project_custom_attributes_on_project_id_and_key", unique: true, using: :btree end - add_index "project_custom_attributes", ["key", "value"], name: "index_project_custom_attributes_on_key_and_value", using: :btree - add_index "project_custom_attributes", ["project_id", "key"], name: "index_project_custom_attributes_on_project_id_and_key", unique: true, using: :btree - create_table "project_deploy_tokens", force: :cascade do |t| t.integer "project_id", null: false t.integer "deploy_token_id", null: false t.datetime_with_timezone "created_at", null: false + t.index ["deploy_token_id"], name: "index_project_deploy_tokens_on_deploy_token_id", using: :btree + t.index ["project_id", "deploy_token_id"], name: "index_project_deploy_tokens_on_project_id_and_deploy_token_id", unique: true, using: :btree end - add_index "project_deploy_tokens", ["deploy_token_id"], name: "index_project_deploy_tokens_on_deploy_token_id", using: :btree - add_index "project_deploy_tokens", ["project_id", "deploy_token_id"], name: "index_project_deploy_tokens_on_project_id_and_deploy_token_id", unique: true, using: :btree - create_table "project_features", force: :cascade do |t| t.integer "project_id", null: false t.integer "merge_requests_access_level" @@ -1659,10 +1549,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "updated_at" t.integer "repository_access_level", default: 20, null: false t.integer "pages_access_level", default: 20, null: false + t.index ["project_id"], name: "index_project_features_on_project_id", unique: true, using: :btree end - add_index "project_features", ["project_id"], name: "index_project_features_on_project_id", unique: true, using: :btree - create_table "project_group_links", force: :cascade do |t| t.integer "project_id", null: false t.integer "group_id", null: false @@ -1670,45 +1559,41 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "updated_at" t.integer "group_access", default: 30, null: false t.date "expires_at" + t.index ["group_id"], name: "index_project_group_links_on_group_id", using: :btree + t.index ["project_id"], name: "index_project_group_links_on_project_id", using: :btree end - add_index "project_group_links", ["group_id"], name: "index_project_group_links_on_group_id", using: :btree - add_index "project_group_links", ["project_id"], name: "index_project_group_links_on_project_id", using: :btree - create_table "project_import_data", force: :cascade do |t| t.integer "project_id" t.text "data" t.text "encrypted_credentials" t.string "encrypted_credentials_iv" t.string "encrypted_credentials_salt" + t.index ["project_id"], name: "index_project_import_data_on_project_id", using: :btree end - add_index "project_import_data", ["project_id"], name: "index_project_import_data_on_project_id", using: :btree - create_table "project_mirror_data", force: :cascade do |t| t.integer "project_id", null: false t.string "status" t.string "jid" t.text "last_error" + t.index ["jid"], name: "index_project_mirror_data_on_jid", using: :btree + t.index ["project_id"], name: "index_project_mirror_data_on_project_id", unique: true, using: :btree + t.index ["status"], name: "index_project_mirror_data_on_status", using: :btree end - add_index "project_mirror_data", ["jid"], name: "index_project_mirror_data_on_jid", using: :btree - add_index "project_mirror_data", ["project_id"], name: "index_project_mirror_data_on_project_id", unique: true, using: :btree - add_index "project_mirror_data", ["status"], name: "index_project_mirror_data_on_status", using: :btree - create_table "project_statistics", force: :cascade do |t| t.integer "project_id", null: false t.integer "namespace_id", null: false - t.integer "commit_count", limit: 8, default: 0, null: false - t.integer "storage_size", limit: 8, default: 0, null: false - t.integer "repository_size", limit: 8, default: 0, null: false - t.integer "lfs_objects_size", limit: 8, default: 0, null: false - t.integer "build_artifacts_size", limit: 8, default: 0, null: false + t.bigint "commit_count", default: 0, null: false + t.bigint "storage_size", default: 0, null: false + t.bigint "repository_size", default: 0, null: false + t.bigint "lfs_objects_size", default: 0, null: false + t.bigint "build_artifacts_size", default: 0, null: false + t.index ["namespace_id"], name: "index_project_statistics_on_namespace_id", using: :btree + t.index ["project_id"], name: "index_project_statistics_on_project_id", unique: true, using: :btree end - add_index "project_statistics", ["namespace_id"], name: "index_project_statistics_on_namespace_id", using: :btree - add_index "project_statistics", ["project_id"], name: "index_project_statistics_on_project_id", unique: true, using: :btree - create_table "projects", force: :cascade do |t| t.string "name" t.string "path" @@ -1761,29 +1646,28 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "jobs_cache_index" t.boolean "pages_https_only", default: true t.boolean "remote_mirror_available_overridden" - t.integer "pool_repository_id", limit: 8 - end - - add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree - add_index "projects", ["created_at"], name: "index_projects_on_created_at", using: :btree - add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree - add_index "projects", ["description"], name: "index_projects_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} - add_index "projects", ["id"], name: "index_projects_on_id_partial_for_visibility", unique: true, where: "(visibility_level = ANY (ARRAY[10, 20]))", using: :btree - add_index "projects", ["last_activity_at"], name: "index_projects_on_last_activity_at", using: :btree - add_index "projects", ["last_repository_check_at"], name: "index_projects_on_last_repository_check_at", where: "(last_repository_check_at IS NOT NULL)", using: :btree - add_index "projects", ["last_repository_check_failed"], name: "index_projects_on_last_repository_check_failed", using: :btree - add_index "projects", ["last_repository_updated_at"], name: "index_projects_on_last_repository_updated_at", using: :btree - add_index "projects", ["name"], name: "index_projects_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} - add_index "projects", ["namespace_id"], name: "index_projects_on_namespace_id", using: :btree - add_index "projects", ["path"], name: "index_projects_on_path", using: :btree - add_index "projects", ["path"], name: "index_projects_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"} - add_index "projects", ["pending_delete"], name: "index_projects_on_pending_delete", using: :btree - add_index "projects", ["pool_repository_id"], name: "index_projects_on_pool_repository_id", where: "(pool_repository_id IS NOT NULL)", using: :btree - add_index "projects", ["repository_storage", "created_at"], name: "idx_project_repository_check_partial", where: "(last_repository_check_at IS NULL)", using: :btree - add_index "projects", ["repository_storage"], name: "index_projects_on_repository_storage", using: :btree - add_index "projects", ["runners_token"], name: "index_projects_on_runners_token", using: :btree - add_index "projects", ["star_count"], name: "index_projects_on_star_count", using: :btree - add_index "projects", ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree + t.bigint "pool_repository_id" + t.index ["ci_id"], name: "index_projects_on_ci_id", using: :btree + t.index ["created_at"], name: "index_projects_on_created_at", using: :btree + t.index ["creator_id"], name: "index_projects_on_creator_id", using: :btree + t.index ["description"], name: "index_projects_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} + t.index ["id"], name: "index_projects_on_id_partial_for_visibility", unique: true, where: "(visibility_level = ANY (ARRAY[10, 20]))", using: :btree + t.index ["last_activity_at"], name: "index_projects_on_last_activity_at", using: :btree + t.index ["last_repository_check_at"], name: "index_projects_on_last_repository_check_at", where: "(last_repository_check_at IS NOT NULL)", using: :btree + t.index ["last_repository_check_failed"], name: "index_projects_on_last_repository_check_failed", using: :btree + t.index ["last_repository_updated_at"], name: "index_projects_on_last_repository_updated_at", using: :btree + t.index ["name"], name: "index_projects_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} + t.index ["namespace_id"], name: "index_projects_on_namespace_id", using: :btree + t.index ["path"], name: "index_projects_on_path", using: :btree + t.index ["path"], name: "index_projects_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"} + t.index ["pending_delete"], name: "index_projects_on_pending_delete", using: :btree + t.index ["pool_repository_id"], name: "index_projects_on_pool_repository_id", where: "(pool_repository_id IS NOT NULL)", using: :btree + t.index ["repository_storage", "created_at"], name: "idx_project_repository_check_partial", where: "(last_repository_check_at IS NULL)", using: :btree + t.index ["repository_storage"], name: "index_projects_on_repository_storage", using: :btree + t.index ["runners_token"], name: "index_projects_on_runners_token", using: :btree + t.index ["star_count"], name: "index_projects_on_star_count", using: :btree + t.index ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree + end create_table "prometheus_metrics", force: :cascade do |t| t.integer "project_id" @@ -1797,40 +1681,36 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime_with_timezone "updated_at", null: false t.boolean "common", default: false, null: false t.string "identifier" + t.index ["common"], name: "index_prometheus_metrics_on_common", using: :btree + t.index ["group"], name: "index_prometheus_metrics_on_group", using: :btree + t.index ["identifier"], name: "index_prometheus_metrics_on_identifier", unique: true, using: :btree + t.index ["project_id"], name: "index_prometheus_metrics_on_project_id", using: :btree end - add_index "prometheus_metrics", ["common"], name: "index_prometheus_metrics_on_common", using: :btree - add_index "prometheus_metrics", ["group"], name: "index_prometheus_metrics_on_group", using: :btree - add_index "prometheus_metrics", ["identifier"], name: "index_prometheus_metrics_on_identifier", unique: true, using: :btree - add_index "prometheus_metrics", ["project_id"], name: "index_prometheus_metrics_on_project_id", using: :btree - create_table "protected_branch_merge_access_levels", force: :cascade do |t| t.integer "protected_branch_id", null: false t.integer "access_level", default: 40, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["protected_branch_id"], name: "index_protected_branch_merge_access", using: :btree end - add_index "protected_branch_merge_access_levels", ["protected_branch_id"], name: "index_protected_branch_merge_access", using: :btree - create_table "protected_branch_push_access_levels", force: :cascade do |t| t.integer "protected_branch_id", null: false t.integer "access_level", default: 40, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["protected_branch_id"], name: "index_protected_branch_push_access", using: :btree end - add_index "protected_branch_push_access_levels", ["protected_branch_id"], name: "index_protected_branch_push_access", using: :btree - create_table "protected_branches", force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false t.datetime "created_at" t.datetime "updated_at" + t.index ["project_id"], name: "index_protected_branches_on_project_id", using: :btree end - add_index "protected_branches", ["project_id"], name: "index_protected_branches_on_project_id", using: :btree - create_table "protected_tag_create_access_levels", force: :cascade do |t| t.integer "protected_tag_id", null: false t.integer "access_level", default: 40 @@ -1838,23 +1718,22 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "group_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["group_id"], name: "index_protected_tag_create_access_levels_on_group_id", using: :btree + t.index ["protected_tag_id"], name: "index_protected_tag_create_access", using: :btree + t.index ["user_id"], name: "index_protected_tag_create_access_levels_on_user_id", using: :btree end - add_index "protected_tag_create_access_levels", ["protected_tag_id"], name: "index_protected_tag_create_access", using: :btree - add_index "protected_tag_create_access_levels", ["user_id"], name: "index_protected_tag_create_access_levels_on_user_id", using: :btree - create_table "protected_tags", force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["project_id", "name"], name: "index_protected_tags_on_project_id_and_name", unique: true, using: :btree + t.index ["project_id"], name: "index_protected_tags_on_project_id", using: :btree end - add_index "protected_tags", ["project_id", "name"], name: "index_protected_tags_on_project_id_and_name", unique: true, using: :btree - add_index "protected_tags", ["project_id"], name: "index_protected_tags_on_project_id", using: :btree - create_table "push_event_payloads", id: false, force: :cascade do |t| - t.integer "commit_count", limit: 8, null: false + t.bigint "commit_count", null: false t.integer "event_id", null: false t.integer "action", limit: 2, null: false t.integer "ref_type", limit: 2, null: false @@ -1862,21 +1741,19 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.binary "commit_to" t.text "ref" t.string "commit_title", limit: 70 + t.index ["event_id"], name: "index_push_event_payloads_on_event_id", unique: true, using: :btree end - add_index "push_event_payloads", ["event_id"], name: "index_push_event_payloads_on_event_id", unique: true, using: :btree - create_table "redirect_routes", force: :cascade do |t| t.integer "source_id", null: false t.string "source_type", null: false t.string "path", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["path"], name: "index_redirect_routes_on_path", unique: true, using: :btree + t.index ["source_type", "source_id"], name: "index_redirect_routes_on_source_type_and_source_id", using: :btree end - add_index "redirect_routes", ["path"], name: "index_redirect_routes_on_path", unique: true, using: :btree - add_index "redirect_routes", ["source_type", "source_id"], name: "index_redirect_routes_on_source_type_and_source_id", using: :btree - create_table "releases", force: :cascade do |t| t.string "tag" t.text "description" @@ -1885,11 +1762,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "updated_at" t.text "description_html" t.integer "cached_markdown_version" + t.index ["project_id", "tag"], name: "index_releases_on_project_id_and_tag", using: :btree + t.index ["project_id"], name: "index_releases_on_project_id", using: :btree end - add_index "releases", ["project_id", "tag"], name: "index_releases_on_project_id_and_tag", using: :btree - add_index "releases", ["project_id"], name: "index_releases_on_project_id", using: :btree - create_table "remote_mirrors", force: :cascade do |t| t.integer "project_id" t.string "url" @@ -1906,27 +1782,24 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "encrypted_credentials_salt" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["last_successful_update_at"], name: "index_remote_mirrors_on_last_successful_update_at", using: :btree + t.index ["project_id"], name: "index_remote_mirrors_on_project_id", using: :btree end - add_index "remote_mirrors", ["last_successful_update_at"], name: "index_remote_mirrors_on_last_successful_update_at", using: :btree - add_index "remote_mirrors", ["project_id"], name: "index_remote_mirrors_on_project_id", using: :btree - create_table "repositories", id: :bigserial, force: :cascade do |t| t.integer "shard_id", null: false t.string "disk_path", null: false + t.index ["disk_path"], name: "index_repositories_on_disk_path", unique: true, using: :btree + t.index ["shard_id"], name: "index_repositories_on_shard_id", using: :btree end - add_index "repositories", ["disk_path"], name: "index_repositories_on_disk_path", unique: true, using: :btree - add_index "repositories", ["shard_id"], name: "index_repositories_on_shard_id", using: :btree - create_table "repository_languages", id: false, force: :cascade do |t| t.integer "project_id", null: false t.integer "programming_language_id", null: false t.float "share", null: false + t.index ["project_id", "programming_language_id"], name: "index_repository_languages_on_project_and_languages_id", unique: true, using: :btree end - add_index "repository_languages", ["project_id", "programming_language_id"], name: "index_repository_languages_on_project_and_languages_id", unique: true, using: :btree - create_table "resource_label_events", id: :bigserial, force: :cascade do |t| t.integer "action", null: false t.integer "issue_id" @@ -1937,13 +1810,12 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "cached_markdown_version" t.text "reference" t.text "reference_html" + t.index ["issue_id"], name: "index_resource_label_events_on_issue_id", using: :btree + t.index ["label_id"], name: "index_resource_label_events_on_label_id", using: :btree + t.index ["merge_request_id"], name: "index_resource_label_events_on_merge_request_id", using: :btree + t.index ["user_id"], name: "index_resource_label_events_on_user_id", using: :btree end - add_index "resource_label_events", ["issue_id"], name: "index_resource_label_events_on_issue_id", using: :btree - add_index "resource_label_events", ["label_id"], name: "index_resource_label_events_on_label_id", using: :btree - add_index "resource_label_events", ["merge_request_id"], name: "index_resource_label_events_on_merge_request_id", using: :btree - add_index "resource_label_events", ["user_id"], name: "index_resource_label_events_on_user_id", using: :btree - create_table "routes", force: :cascade do |t| t.integer "source_id", null: false t.string "source_type", null: false @@ -1951,12 +1823,11 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "created_at" t.datetime "updated_at" t.string "name" + t.index ["path"], name: "index_routes_on_path", unique: true, using: :btree + t.index ["path"], name: "index_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"} + t.index ["source_type", "source_id"], name: "index_routes_on_source_type_and_source_id", unique: true, using: :btree end - add_index "routes", ["path"], name: "index_routes_on_path", unique: true, using: :btree - add_index "routes", ["path"], name: "index_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"} - add_index "routes", ["source_type", "source_id"], name: "index_routes_on_source_type_and_source_id", unique: true, using: :btree - create_table "sent_notifications", force: :cascade do |t| t.integer "project_id" t.integer "noteable_id" @@ -1968,10 +1839,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "note_type" t.text "position" t.string "in_reply_to_discussion_id" + t.index ["reply_key"], name: "index_sent_notifications_on_reply_key", unique: true, using: :btree end - add_index "sent_notifications", ["reply_key"], name: "index_sent_notifications_on_reply_key", unique: true, using: :btree - create_table "services", force: :cascade do |t| t.string "type" t.string "title" @@ -1994,17 +1864,15 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "commit_events", default: true, null: false t.boolean "job_events", default: false, null: false t.boolean "confidential_note_events", default: true + t.index ["project_id"], name: "index_services_on_project_id", using: :btree + t.index ["template"], name: "index_services_on_template", using: :btree end - add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree - add_index "services", ["template"], name: "index_services_on_template", using: :btree - create_table "shards", force: :cascade do |t| t.string "name", null: false + t.index ["name"], name: "index_shards_on_name", unique: true, using: :btree end - add_index "shards", ["name"], name: "index_shards_on_name", unique: true, using: :btree - create_table "site_statistics", force: :cascade do |t| t.integer "repositories_count", default: 0, null: false end @@ -2024,15 +1892,14 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "cached_markdown_version" t.text "description" t.text "description_html" + t.index ["author_id"], name: "index_snippets_on_author_id", using: :btree + t.index ["file_name"], name: "index_snippets_on_file_name_trigram", using: :gin, opclasses: {"file_name"=>"gin_trgm_ops"} + t.index ["project_id"], name: "index_snippets_on_project_id", using: :btree + t.index ["title"], name: "index_snippets_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} + t.index ["updated_at"], name: "index_snippets_on_updated_at", using: :btree + t.index ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree end - add_index "snippets", ["author_id"], name: "index_snippets_on_author_id", using: :btree - add_index "snippets", ["file_name"], name: "index_snippets_on_file_name_trigram", using: :gin, opclasses: {"file_name"=>"gin_trgm_ops"} - add_index "snippets", ["project_id"], name: "index_snippets_on_project_id", using: :btree - add_index "snippets", ["title"], name: "index_snippets_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} - add_index "snippets", ["updated_at"], name: "index_snippets_on_updated_at", using: :btree - add_index "snippets", ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree - create_table "spam_logs", force: :cascade do |t| t.integer "user_id" t.string "source_ip" @@ -2055,20 +1922,19 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "created_at" t.datetime "updated_at" t.integer "project_id" + t.index ["project_id"], name: "index_subscriptions_on_project_id", using: :btree + t.index ["subscribable_id", "subscribable_type", "user_id", "project_id"], name: "index_subscriptions_on_subscribable_and_user_id_and_project_id", unique: true, using: :btree end - add_index "subscriptions", ["subscribable_id", "subscribable_type", "user_id", "project_id"], name: "index_subscriptions_on_subscribable_and_user_id_and_project_id", unique: true, using: :btree - create_table "system_note_metadata", force: :cascade do |t| t.integer "note_id", null: false t.integer "commit_count" t.string "action" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["note_id"], name: "index_system_note_metadata_on_note_id", unique: true, using: :btree end - add_index "system_note_metadata", ["note_id"], name: "index_system_note_metadata_on_note_id", unique: true, using: :btree - create_table "taggings", force: :cascade do |t| t.integer "tag_id" t.integer "taggable_id" @@ -2077,32 +1943,29 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "tagger_type" t.string "context" t.datetime "created_at" + t.index ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree + t.index ["tag_id"], name: "index_taggings_on_tag_id", using: :btree + t.index ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree + t.index ["taggable_id", "taggable_type"], name: "index_taggings_on_taggable_id_and_taggable_type", using: :btree end - add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree - add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree - add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree - add_index "taggings", ["taggable_id", "taggable_type"], name: "index_taggings_on_taggable_id_and_taggable_type", using: :btree - create_table "tags", force: :cascade do |t| t.string "name" t.integer "taggings_count", default: 0 + t.index ["name"], name: "index_tags_on_name", unique: true, using: :btree end - add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree - create_table "term_agreements", force: :cascade do |t| t.integer "term_id", null: false t.integer "user_id", null: false t.boolean "accepted", default: false, null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false + t.index ["term_id"], name: "index_term_agreements_on_term_id", using: :btree + t.index ["user_id", "term_id"], name: "term_agreements_unique_index", unique: true, using: :btree + t.index ["user_id"], name: "index_term_agreements_on_user_id", using: :btree end - add_index "term_agreements", ["term_id"], name: "index_term_agreements_on_term_id", using: :btree - add_index "term_agreements", ["user_id", "term_id"], name: "term_agreements_unique_index", unique: true, using: :btree - add_index "term_agreements", ["user_id"], name: "index_term_agreements_on_user_id", using: :btree - create_table "timelogs", force: :cascade do |t| t.integer "time_spent", null: false t.integer "user_id" @@ -2111,12 +1974,11 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "issue_id" t.integer "merge_request_id" t.datetime_with_timezone "spent_at" + t.index ["issue_id"], name: "index_timelogs_on_issue_id", using: :btree + t.index ["merge_request_id"], name: "index_timelogs_on_merge_request_id", using: :btree + t.index ["user_id"], name: "index_timelogs_on_user_id", using: :btree end - add_index "timelogs", ["issue_id"], name: "index_timelogs_on_issue_id", using: :btree - add_index "timelogs", ["merge_request_id"], name: "index_timelogs_on_merge_request_id", using: :btree - add_index "timelogs", ["user_id"], name: "index_timelogs_on_user_id", using: :btree - create_table "todos", force: :cascade do |t| t.integer "user_id", null: false t.integer "project_id" @@ -2130,24 +1992,22 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.integer "note_id" t.string "commit_id" t.integer "group_id" + t.index ["author_id"], name: "index_todos_on_author_id", using: :btree + t.index ["commit_id"], name: "index_todos_on_commit_id", using: :btree + t.index ["group_id"], name: "index_todos_on_group_id", using: :btree + t.index ["note_id"], name: "index_todos_on_note_id", using: :btree + t.index ["project_id"], name: "index_todos_on_project_id", using: :btree + t.index ["target_type", "target_id"], name: "index_todos_on_target_type_and_target_id", using: :btree + t.index ["user_id", "id"], name: "index_todos_on_user_id_and_id_done", where: "((state)::text = 'done'::text)", using: :btree + t.index ["user_id", "id"], name: "index_todos_on_user_id_and_id_pending", where: "((state)::text = 'pending'::text)", using: :btree + t.index ["user_id"], name: "index_todos_on_user_id", using: :btree end - add_index "todos", ["author_id"], name: "index_todos_on_author_id", using: :btree - add_index "todos", ["commit_id"], name: "index_todos_on_commit_id", using: :btree - add_index "todos", ["group_id"], name: "index_todos_on_group_id", using: :btree - add_index "todos", ["note_id"], name: "index_todos_on_note_id", using: :btree - add_index "todos", ["project_id"], name: "index_todos_on_project_id", using: :btree - add_index "todos", ["target_type", "target_id"], name: "index_todos_on_target_type_and_target_id", using: :btree - add_index "todos", ["user_id", "id"], name: "index_todos_on_user_id_and_id_done", where: "((state)::text = 'done'::text)", using: :btree - add_index "todos", ["user_id", "id"], name: "index_todos_on_user_id_and_id_pending", where: "((state)::text = 'pending'::text)", using: :btree - add_index "todos", ["user_id"], name: "index_todos_on_user_id", using: :btree - create_table "trending_projects", force: :cascade do |t| t.integer "project_id", null: false + t.index ["project_id"], name: "index_trending_projects_on_project_id", unique: true, using: :btree end - add_index "trending_projects", ["project_id"], name: "index_trending_projects_on_project_id", unique: true, using: :btree - create_table "u2f_registrations", force: :cascade do |t| t.text "certificate" t.string "key_handle" @@ -2157,13 +2017,12 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "name" + t.index ["key_handle"], name: "index_u2f_registrations_on_key_handle", using: :btree + t.index ["user_id"], name: "index_u2f_registrations_on_user_id", using: :btree end - add_index "u2f_registrations", ["key_handle"], name: "index_u2f_registrations_on_key_handle", using: :btree - add_index "u2f_registrations", ["user_id"], name: "index_u2f_registrations_on_user_id", using: :btree - create_table "uploads", force: :cascade do |t| - t.integer "size", limit: 8, null: false + t.bigint "size", null: false t.string "path", limit: 511, null: false t.string "checksum", limit: 64 t.integer "model_id" @@ -2173,13 +2032,12 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "mount_point" t.string "secret" t.integer "store" + t.index ["checksum"], name: "index_uploads_on_checksum", using: :btree + t.index ["model_id", "model_type"], name: "index_uploads_on_model_id_and_model_type", using: :btree + t.index ["store"], name: "index_uploads_on_store", using: :btree + t.index ["uploader", "path"], name: "index_uploads_on_uploader_and_path", using: :btree end - add_index "uploads", ["checksum"], name: "index_uploads_on_checksum", using: :btree - add_index "uploads", ["model_id", "model_type"], name: "index_uploads_on_model_id_and_model_type", using: :btree - add_index "uploads", ["store"], name: "index_uploads_on_store", using: :btree - add_index "uploads", ["uploader", "path"], name: "index_uploads_on_uploader_and_path", using: :btree - create_table "user_agent_details", force: :cascade do |t| t.string "user_agent", null: false t.string "ip_address", null: false @@ -2188,52 +2046,48 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "submitted", default: false, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree end - add_index "user_agent_details", ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree - create_table "user_callouts", force: :cascade do |t| t.integer "feature_name", null: false t.integer "user_id", null: false + t.index ["user_id", "feature_name"], name: "index_user_callouts_on_user_id_and_feature_name", unique: true, using: :btree + t.index ["user_id"], name: "index_user_callouts_on_user_id", using: :btree end - add_index "user_callouts", ["user_id", "feature_name"], name: "index_user_callouts_on_user_id_and_feature_name", unique: true, using: :btree - add_index "user_callouts", ["user_id"], name: "index_user_callouts_on_user_id", using: :btree - create_table "user_custom_attributes", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "user_id", null: false t.string "key", null: false t.string "value", null: false + t.index ["key", "value"], name: "index_user_custom_attributes_on_key_and_value", using: :btree + t.index ["user_id", "key"], name: "index_user_custom_attributes_on_user_id_and_key", unique: true, using: :btree end - add_index "user_custom_attributes", ["key", "value"], name: "index_user_custom_attributes_on_key_and_value", using: :btree - add_index "user_custom_attributes", ["user_id", "key"], name: "index_user_custom_attributes_on_user_id_and_key", unique: true, using: :btree - create_table "user_interacted_projects", id: false, force: :cascade do |t| t.integer "user_id", null: false t.integer "project_id", null: false + t.index ["project_id", "user_id"], name: "index_user_interacted_projects_on_project_id_and_user_id", unique: true, using: :btree + t.index ["user_id"], name: "index_user_interacted_projects_on_user_id", using: :btree end - add_index "user_interacted_projects", ["project_id", "user_id"], name: "index_user_interacted_projects_on_project_id_and_user_id", unique: true, using: :btree - add_index "user_interacted_projects", ["user_id"], name: "index_user_interacted_projects_on_user_id", using: :btree - create_table "user_preferences", force: :cascade do |t| t.integer "user_id", null: false t.integer "issue_notes_filter", limit: 2, default: 0, null: false t.integer "merge_request_notes_filter", limit: 2, default: 0, null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false + t.index ["user_id"], name: "index_user_preferences_on_user_id", unique: true, using: :btree end - add_index "user_preferences", ["user_id"], name: "index_user_preferences_on_user_id", unique: true, using: :btree - create_table "user_statuses", primary_key: "user_id", force: :cascade do |t| t.integer "cached_markdown_version" t.string "emoji", default: "speech_balloon", null: false t.string "message", limit: 100 t.string "message_html" + t.index ["user_id"], name: "index_user_statuses_on_user_id", using: :btree end create_table "user_synced_attributes_metadata", force: :cascade do |t| @@ -2242,10 +2096,9 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "location_synced", default: false t.integer "user_id", null: false t.string "provider" + t.index ["user_id"], name: "index_user_synced_attributes_metadata_on_user_id", unique: true, using: :btree end - add_index "user_synced_attributes_metadata", ["user_id"], name: "index_user_synced_attributes_metadata_on_user_id", unique: true, using: :btree - create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false @@ -2315,33 +2168,32 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.boolean "private_profile" t.boolean "include_private_contributions" t.string "commit_email" + t.index ["accepted_term_id"], name: "index_users_on_accepted_term_id", using: :btree + t.index ["admin"], name: "index_users_on_admin", using: :btree + t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree + t.index ["created_at"], name: "index_users_on_created_at", using: :btree + t.index ["email"], name: "index_users_on_email", unique: true, using: :btree + t.index ["email"], name: "index_users_on_email_trigram", using: :gin, opclasses: {"email"=>"gin_trgm_ops"} + t.index ["feed_token"], name: "index_users_on_feed_token", using: :btree + t.index ["ghost"], name: "index_users_on_ghost", using: :btree + t.index ["incoming_email_token"], name: "index_users_on_incoming_email_token", using: :btree + t.index ["name"], name: "index_users_on_name", using: :btree + t.index ["name"], name: "index_users_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} + t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree + t.index ["state"], name: "index_users_on_state", using: :btree + t.index ["username"], name: "index_users_on_username", using: :btree + t.index ["username"], name: "index_users_on_username_trigram", using: :gin, opclasses: {"username"=>"gin_trgm_ops"} end - add_index "users", ["admin"], name: "index_users_on_admin", using: :btree - add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree - add_index "users", ["created_at"], name: "index_users_on_created_at", using: :btree - add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree - add_index "users", ["email"], name: "index_users_on_email_trigram", using: :gin, opclasses: {"email"=>"gin_trgm_ops"} - add_index "users", ["feed_token"], name: "index_users_on_feed_token", using: :btree - add_index "users", ["ghost"], name: "index_users_on_ghost", using: :btree - add_index "users", ["incoming_email_token"], name: "index_users_on_incoming_email_token", using: :btree - add_index "users", ["name"], name: "index_users_on_name", using: :btree - add_index "users", ["name"], name: "index_users_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} - add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree - add_index "users", ["state"], name: "index_users_on_state", using: :btree - add_index "users", ["username"], name: "index_users_on_username", using: :btree - add_index "users", ["username"], name: "index_users_on_username_trigram", using: :gin, opclasses: {"username"=>"gin_trgm_ops"} - create_table "users_star_projects", force: :cascade do |t| t.integer "project_id", null: false t.integer "user_id", null: false t.datetime "created_at" t.datetime "updated_at" + t.index ["project_id"], name: "index_users_star_projects_on_project_id", using: :btree + t.index ["user_id", "project_id"], name: "index_users_star_projects_on_user_id_and_project_id", unique: true, using: :btree end - add_index "users_star_projects", ["project_id"], name: "index_users_star_projects_on_project_id", using: :btree - add_index "users_star_projects", ["user_id", "project_id"], name: "index_users_star_projects_on_user_id_and_project_id", unique: true, using: :btree - create_table "web_hook_logs", force: :cascade do |t| t.integer "web_hook_id", null: false t.string "trigger" @@ -2355,11 +2207,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "internal_error_message" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["created_at", "web_hook_id"], name: "index_web_hook_logs_on_created_at_and_web_hook_id", using: :btree + t.index ["web_hook_id"], name: "index_web_hook_logs_on_web_hook_id", using: :btree end - add_index "web_hook_logs", ["created_at", "web_hook_id"], name: "index_web_hook_logs_on_created_at_and_web_hook_id", using: :btree - add_index "web_hook_logs", ["web_hook_id"], name: "index_web_hook_logs_on_web_hook_id", using: :btree - create_table "web_hooks", force: :cascade do |t| t.integer "project_id" t.datetime "created_at" @@ -2383,11 +2234,10 @@ ActiveRecord::Schema.define(version: 20181107054254) do t.string "encrypted_token_iv" t.string "encrypted_url" t.string "encrypted_url_iv" + t.index ["project_id"], name: "index_web_hooks_on_project_id", using: :btree + t.index ["type"], name: "index_web_hooks_on_type", using: :btree end - add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree - add_index "web_hooks", ["type"], name: "index_web_hooks_on_type", using: :btree - add_foreign_key "application_settings", "users", column: "usage_stats_set_by_user_id", name: "fk_964370041d", on_delete: :nullify add_foreign_key "badges", "namespaces", column: "group_id", on_delete: :cascade add_foreign_key "badges", "projects", on_delete: :cascade @@ -2461,9 +2311,6 @@ ActiveRecord::Schema.define(version: 20181107054254) do add_foreign_key "fork_network_members", "projects", on_delete: :cascade add_foreign_key "fork_networks", "projects", column: "root_project_id", name: "fk_e7b436b2b5", on_delete: :nullify add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade - add_foreign_key "gcp_clusters", "projects", on_delete: :cascade - add_foreign_key "gcp_clusters", "services", on_delete: :nullify - add_foreign_key "gcp_clusters", "users", on_delete: :nullify add_foreign_key "gpg_key_subkeys", "gpg_keys", on_delete: :cascade add_foreign_key "gpg_keys", "users", on_delete: :cascade add_foreign_key "gpg_signatures", "gpg_key_subkeys", on_delete: :nullify diff --git a/doc/administration/git_protocol.md b/doc/administration/git_protocol.md index b1be078d672..341a00009e5 100644 --- a/doc/administration/git_protocol.md +++ b/doc/administration/git_protocol.md @@ -19,7 +19,15 @@ and the [protocol documentation](https://github.com/git/git/blob/master/Document From the client side, `git` `v2.18.0` or newer must be installed. From the server side, if we want to configure SSH we need to set the `sshd` -server to accept the `GIT_PROTOCOL` environment, +server to accept the `GIT_PROTOCOL` environment. + +In installations using [GitLab Helm Charts](../install/kubernetes/gitlab_chart.md) +and [All-in-one docker image](https://docs.gitlab.com/omnibus/docker/), the SSH +service is already configured to accept the `GIT_PROTOCOL` environment and users +need not do anything more. + +For Omnibus GitLab and installations from source, you have to manually update +the SSH configuration of your server: ``` # /etc/ssh/sshd_config diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md index 7c1ef43499d..a9ba40c870c 100644 --- a/doc/administration/high_availability/redis.md +++ b/doc/administration/high_availability/redis.md @@ -684,7 +684,7 @@ cache, queues, and shared_state. To make this work with Sentinel: ``` 1. Note that for each persistence class, GitLab will default to using the configuration specified in `gitlab_rails['redis_sentinels']` unless - overriden by the settings above. + overridden by the settings above. 1. Be sure to include BOTH configuration options for each persistent classes. For example, if you choose to configure a cache instance, you must specify both `gitlab_rails['redis_cache_instance']` and `gitlab_rails['redis_cache_sentinels']` for GitLab to generate the proper configuration files. diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md index b1b670c3b42..2d9fdedcbeb 100644 --- a/doc/administration/monitoring/prometheus/index.md +++ b/doc/administration/monitoring/prometheus/index.md @@ -1,4 +1,4 @@ -# GitLab Prometheus +# Monitoring GitLab with Prometheus > **Notes:** > - Prometheus and the various exporters listed in this page are bundled in the @@ -24,10 +24,10 @@ dashboard tool like [Grafana]. ## Configuring Prometheus ->**Note:** +NOTE: **Note:** For installations from source you'll have to install and configure it yourself. -Prometheus and it's exporters are on by default, starting with GitLab 9.0. +Prometheus and its exporters are on by default, starting with GitLab 9.0. Prometheus will run as the `gitlab-prometheus` user and listen on `http://localhost:9090`. By default Prometheus is only accessible from the GitLab server itself. Each exporter will be automatically set up as a @@ -43,17 +43,17 @@ To disable Prometheus and all of its exporters, as well as any added in the futu ``` 1. Save the file and [reconfigure GitLab][reconfigure] for the changes to - take effect + take effect. -## Changing the port and address Prometheus listens on +### Changing the port and address Prometheus listens on ->**Note:** +NOTE: **Note:** The following change was added in [GitLab Omnibus 8.17][1261]. Although possible, it's not recommended to change the port Prometheus listens on as this might affect or conflict with other services running on the GitLab server. Proceed at your own risk. -In order to access Prometheus from outside the GitLab server you will need to +In order to access Prometheus from outside the GitLab server you will need to set a FQDN or IP in `prometheus['listen_address']`. To change the address/port that Prometheus listens on: @@ -77,6 +77,60 @@ To change the address/port that Prometheus listens on: 1. Save the file and [reconfigure GitLab][reconfigure] for the changes to take effect +### Using an external Prometheus server + +NOTE: **Note:** +Prometheus and most exporters do not support authentication. We do not recommend exposing them outside the local network. + +A few configuration changes are required to allow GitLab to be monitored by an external Prometheus server. External servers are recommended for highly available deployments of GitLab with multiple nodes. + +To use an external Prometheus server: + +1. Edit `/etc/gitlab/gitlab.rb`. +1. Disable the bundled Prometheus: + + ```ruby + prometheus['enable'] = false + ``` + +1. Set each bundled service's [exporter](#bundled-software-metrics) to listen on a network address, for example: + + ```ruby + gitlab_monitor['listen_address'] = '0.0.0.0' + gitlab_monitor['listen_port'] = '9168' + gitaly['prometheus_listen_addr'] = "0.0.0.0:9236" + node_exporter['listen_address'] = '0.0.0.0:9100' + redis_exporter['listen_address'] = '0.0.0.0:9121' + postgres_exporter['listen_address'] = '0.0.0.0:9187' + ``` + +1. Install and set up a dedicated Prometheus instance, if necessary, using the [official installation instructions](https://prometheus.io/docs/prometheus/latest/installation/). +1. Add the Prometheus server IP address to the [monitoring IP whitelist](../ip_whitelist.html). For example: + + ```ruby + gitlab_rails['monitoring_whitelist'] = ['127.0.0.0/8', '192.168.0.1'] + ``` + +1. [Reconfigure GitLab][reconfigure] to apply the changes +1. Edit the Prometheus server's configuration file. +1. Add each node's exporters to the Prometheus server's + [scrape target configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#%3Cscrape_config%3E). + For example, a sample snippet using `static_configs`: + + ```yaml + scrape_configs: + - job_name: 'gitlab_exporters' + static_configs: + - targets: ['1.1.1.1:9168', '1.1.1.1:9236', '1.1.1.1:9236', '1.1.1.1:9100', '1.1.1.1:9121', '1.1.1.1:9187'] + + - job_name: 'gitlab_metrics' + metrics_path: /-/metrics + static_configs: + - targets: ['1.1.1.1:443'] + ``` + +1. Restart the Prometheus server. + ## Viewing performance metrics You can visit `http://localhost:9090` for the dashboard that Prometheus offers by default. @@ -86,7 +140,7 @@ If SSL has been enabled on your GitLab instance, you may not be able to access Prometheus on the same browser as GitLab if using the same FQDN due to [HSTS][hsts]. We plan to [provide access via GitLab][multi-user-prometheus], but in the interim there are some workarounds: using a separate FQDN, using server IP, using a separate browser for Prometheus, resetting HSTS, or -having [Nginx proxy it][nginx-custom-config]. +having [NGINX proxy it][nginx-custom-config]. The performance data collected by Prometheus can be viewed directly in the Prometheus console or through a compatible dashboard tool. @@ -102,26 +156,7 @@ Sample Prometheus queries: - **Data transmitted:** `rate(node_network_transmit_bytes_total{device!="lo"}[5m])` - **Data received:** `rate(node_network_receive_bytes_total{device!="lo"}[5m])` -## Configuring Prometheus to monitor Kubernetes - -> Introduced in GitLab 9.0. -> Pod monitoring introduced in GitLab 9.4. - -If your GitLab server is running within Kubernetes, Prometheus will collect metrics from the Nodes and [annotated Pods](https://prometheus.io/docs/operating/configuration/#kubernetes_sd_config) in the cluster, including performance data on each container. This is particularly helpful if your CI/CD environments run in the same cluster, as you can use the [Prometheus project integration][] to monitor them. - -To disable the monitoring of Kubernetes: - -1. Edit `/etc/gitlab/gitlab.rb` -1. Add or find and uncomment the following line and set it to `false`: - - ```ruby - prometheus['monitor_kubernetes'] = false - ``` - -1. Save the file and [reconfigure GitLab][reconfigure] for the changes to - take effect - -## GitLab Prometheus metrics +## GitLab metrics > Introduced in GitLab 9.3. @@ -129,17 +164,10 @@ GitLab monitors its own internal service metrics, and makes them available at th [➔ Read more about the GitLab Metrics.](gitlab_metrics.md) -## Prometheus exporters - -There are a number of libraries and servers which help in exporting existing -metrics from third-party systems as Prometheus metrics. This is useful for cases -where it is not feasible to instrument a given system with Prometheus metrics -directly (for example, HAProxy or Linux system stats). You can read more in the -[Prometheus exporters and integrations upstream documentation][prom-exporters]. +## Bundled software metrics -While you can use any exporter you like with your GitLab installation, the -following ones documented here are bundled in the Omnibus GitLab packages -making it easy to configure and use. +Many of the GitLab dependencies bundled in Omnibus GitLab are preconfigured to +export Prometheus metrics. ### Node exporter @@ -166,6 +194,25 @@ The GitLab monitor exporter allows you to measure various GitLab metrics, pulled [➔ Read more about the GitLab monitor exporter.](gitlab_monitor_exporter.md) +## Configuring Prometheus to monitor Kubernetes + +> Introduced in GitLab 9.0. +> Pod monitoring introduced in GitLab 9.4. + +If your GitLab server is running within Kubernetes, Prometheus will collect metrics from the Nodes and [annotated Pods](https://prometheus.io/docs/operating/configuration/#kubernetes_sd_config) in the cluster, including performance data on each container. This is particularly helpful if your CI/CD environments run in the same cluster, as you can use the [Prometheus project integration][prometheus integration] to monitor them. + +To disable the monitoring of Kubernetes: + +1. Edit `/etc/gitlab/gitlab.rb`. +1. Add or find and uncomment the following line and set it to `false`: + + ```ruby + prometheus['monitor_kubernetes'] = false + ``` + +1. Save the file and [reconfigure GitLab][reconfigure] for the changes to + take effect. + [grafana]: https://grafana.net [hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security [multi-user-prometheus]: https://gitlab.com/gitlab-org/multi-user-prometheus diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md index aec9a359ada..f85a1f791f9 100644 --- a/doc/administration/uploads.md +++ b/doc/administration/uploads.md @@ -48,11 +48,12 @@ _The uploads are stored by default in 1. Save the file and [restart GitLab][] for the changes to take effect. -### Using object storage +### Using object storage **[CORE ONLY]** > **Notes:** > -> - [Introduced][ee-3867] in [GitLab Enterprise Edition Premium][eep] 10.5. +> - [Introduced][ee-3867] in [GitLab Premium][eep] 10.5. +> - [Introduced][ce17358] in [GitLab Core][ce] 10.7. > - Since version 11.1, we support direct_upload to S3. If you don't want to use the local disk where GitLab is installed to store the @@ -197,4 +198,6 @@ _The uploads are stored by default in [reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure "How to reconfigure Omnibus GitLab" [restart gitlab]: restart_gitlab.md#installations-from-source "How to restart GitLab" [eep]: https://about.gitlab.com/gitlab-ee/ "GitLab Enterprise Edition Premium" +[ce]: https://about.gitlab.com/gitlab-ce/ "GitLab Community Edition" [ee-3867]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3867 +[ce-17358]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17358 diff --git a/doc/api/avatar.md b/doc/api/avatar.md index 7faed893066..aa6f7c185ae 100644 --- a/doc/api/avatar.md +++ b/doc/api/avatar.md @@ -4,7 +4,7 @@ ## Get a single avatar URL -Get a single avatar URL for a given email addres. If user with matching public +Get a single avatar URL for a given email address. If user with matching public email address is not found, results from external avatar services are returned. This endpoint can be accessed without authentication. In case public visibility is restricted, response will be `403 Forbidden` when unauthenticated. diff --git a/doc/api/commits.md b/doc/api/commits.md index 994eefa423f..7d9b52ec24f 100644 --- a/doc/api/commits.md +++ b/doc/api/commits.md @@ -290,7 +290,7 @@ Example response: ## Revert a commit -> [Introduced][ce-22919] in GitLab 11.6. +> [Introduced][ce-22919] in GitLab 11.5. Reverts a commit in a given branch. diff --git a/doc/api/events.md b/doc/api/events.md index ccac5b8bb60..e1c6b801a77 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -71,7 +71,7 @@ Parameters: Example request: ``` -curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/events&target_type=issue&action=created&after=2017-01-31&before=2017-03-01 +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01 ``` Example response: @@ -276,7 +276,7 @@ Parameters: Example request: ``` -curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:project_id/events&target_type=issue&action=created&after=2017-01-31&before=2017-03-01 +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:project_id/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01 ``` Example response: diff --git a/doc/api/pipelines.md b/doc/api/pipelines.md index 574be52801c..7b4c9a8fbb3 100644 --- a/doc/api/pipelines.md +++ b/doc/api/pipelines.md @@ -235,5 +235,22 @@ Response: } ``` +## Delete a pipeline + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22988) in GitLab 11.6. + +``` +DELETE /projects/:id/pipelines/:pipeline_id +``` + +| Attribute | Type | Required | Description | +|------------|---------|----------|---------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `pipeline_id` | integer | yes | The ID of a pipeline | + +``` +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --request "DELETE" "https://gitlab.example.com/api/v4/projects/1/pipelines/46" +``` + [ce-5837]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5837 [ce-7209]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7209 diff --git a/doc/api/users.md b/doc/api/users.md index ee24aa09156..e3633c46041 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -1072,7 +1072,6 @@ Example response: [ { "active" : true, - "token" : "EsMo-vhKfXGwX9RKrwiy", "scopes" : [ "api" ], @@ -1089,7 +1088,6 @@ Example response: "read_user" ], "revoked" : true, - "token" : "ZcZRpLeEuQRprkRjYydY", "name" : "mytoken2", "created_at" : "2017-03-17T17:19:28.697Z", "id" : 3, @@ -1125,7 +1123,6 @@ Example response: ```json { "active" : true, - "token" : "EsMo-vhKfXGwX9RKrwiy", "scopes" : [ "api" ], @@ -1142,6 +1139,8 @@ Example response: > Requires admin permissions. +> Token values are returned once. Make sure you save it - you won't be able to access it again. + It creates a new impersonation token. Note that only administrators can do this. You are only able to create impersonation tokens to impersonate the user and perform both API calls and Git reads and writes. The user will not see these tokens in their profile diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png Binary files differdeleted file mode 100644 index a56c07a0da7..00000000000 --- a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png +++ /dev/null diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md index b6989d229d1..b090ea014dc 100644 --- a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md +++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md @@ -444,9 +444,7 @@ On your GitLab project repository navigate to the **Registry** tab. ![container registry page empty image](img/container_registry_page_empty_image.png) -You may need to [enable Container Registry](../../../user/project/container_registry.md#enable-the-container-registry-for-your-project) to your project to see this tab. You'll find it under your project's **Settings > General > Sharing and permissions**. - -![container registry checkbox](img/container_registry_checkbox.png) +You may need to [enable Container Registry](../../../user/project/container_registry.md#enable-the-container-registry-for-your-project) to your project to see this tab. You'll find it under your project's **Settings > General > Permissions**. To start using Container Registry on our machine, we first need to login to the GitLab registry using our GitLab username and password: diff --git a/doc/ci/pipelines.md b/doc/ci/pipelines.md index 371703a12c8..c628895ee1a 100644 --- a/doc/ci/pipelines.md +++ b/doc/ci/pipelines.md @@ -294,7 +294,7 @@ runners will not use regular runners, they must be tagged accordingly. [jobs]: #jobs [jobs-yaml]: yaml/README.md#jobs -[manual]: yaml/README.md#manual +[manual]: yaml/README.md#whenmanual [env-manual]: environments.md#manually-deploying-to-environments [stages]: yaml/README.md#stages [runners]: runners/README.html diff --git a/doc/ci/variables/where_variables_can_be_used.md b/doc/ci/variables/where_variables_can_be_used.md index 4e8ce10c9cb..1d98e8426fe 100644 --- a/doc/ci/variables/where_variables_can_be_used.md +++ b/doc/ci/variables/where_variables_can_be_used.md @@ -17,7 +17,7 @@ There are two places defined variables can be used. On the: | Definition | Can be expanded? | Expansion place | Description | |--------------------------------------|-------------------|-----------------|--------------| -| `environment:url` | yes | GitLab | The variable expansion is made by GitLab's [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism).<ul><li>Supported: all variables defined for a job (project/group variables, variables from `.gitlab-ci.yml`, variables from triggers, variables from pipeline schedules)</li><li>Not suported: variables defined in Runner's `config.toml` and variables created in job's `script`</li></ul> | +| `environment:url` | yes | GitLab | The variable expansion is made by GitLab's [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism).<ul><li>Supported: all variables defined for a job (project/group variables, variables from `.gitlab-ci.yml`, variables from triggers, variables from pipeline schedules)</li><li>Not supported: variables defined in Runner's `config.toml` and variables created in job's `script`</li></ul> | | `environment:name` | yes | GitLab | Similar to `environment:url`, but the variables expansion doesn't support: <ul><li>variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`)</li><li>any other variables related to environment (currently only `CI_ENVIRONMENT_URL`)</li><li>[persisted variables](#persisted-variables)</li></ul> | | `variables` | yes | Runner | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism) | | `image` | yes | Runner | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism) | diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index aab5f268ef9..ec709280085 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -476,6 +476,7 @@ docker build: - Dockerfile - docker/scripts/* - dockerfiles/**/* + - more_scripts/*.{rb,py,sh} ``` In the scenario above, if you are pushing multiple commits to GitLab to an @@ -485,6 +486,7 @@ one of the commits contains changes to either: - The `Dockerfile` file. - Any of the files inside `docker/scripts/` directory. - Any of the files and subfolders inside `dockerfiles` directory. +- Any of the files with `rb`, `py`, `sh` extensions inside `more_scripts` directory. CAUTION: **Warning:** There are some caveats when using this feature with new branches and tags. See @@ -1602,10 +1604,11 @@ test: ## `include` -> Introduced in [GitLab Edition Premium][ee] 10.5. -> Available for Starter, Premium and Ultimate [versions][gitlab-versions] since 10.6. +> Introduced in [GitLab Premium](https://about.gitlab.com/pricing/) 10.5. +> Available for Starter, Premium and Ultimate since 10.6. > Behaviour expanded in GitLab 10.8 to allow more flexible overriding. -> Available for Libre since [11.4](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21603) +> [Moved](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21603) +to GitLab Core in 11.4 Using the `include` keyword, you can allow the inclusion of external YAML files. @@ -1767,7 +1770,7 @@ stages: production: script: - - install_depedencies + - install_dependencies - deploy - notify_owner ``` diff --git a/doc/development/README.md b/doc/development/README.md index 14dfe8eb1f3..d2dd62ecac5 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -30,6 +30,7 @@ description: 'Learn how to contribute to GitLab.' ## Backend guides - [GitLab utilities](utilities.md) +- [Logging](logging.md) - [API styleguide](api_styleguide.md) Use this styleguide if you are contributing to the API. - [GraphQL API styleguide](api_graphql_styleguide.md) Use this @@ -51,6 +52,7 @@ description: 'Learn how to contribute to GitLab.' - [Prometheus metrics](prometheus_metrics.md) - [Guidelines for reusing abstractions](reusing_abstractions.md) - [DeclarativePolicy framework](policies.md) +- [Switching to Rails 5](switching_to_rails5.md) ## Performance guides diff --git a/doc/development/architecture.md b/doc/development/architecture.md index 66d8a4f2f6e..01d99c46f89 100644 --- a/doc/development/architecture.md +++ b/doc/development/architecture.md @@ -10,39 +10,182 @@ For information, see the [GitLab Release Process](https://gitlab.com/gitlab-org/ Both EE and CE require some add-on components called gitlab-shell and Gitaly. These components are available from the [gitlab-shell](https://gitlab.com/gitlab-org/gitlab-shell/tree/master) and [gitaly](https://gitlab.com/gitlab-org/gitaly/tree/master) repositories respectively. New versions are usually tags but staying on the master branch will give you the latest stable version. New releases are generally around the same time as GitLab CE releases with exception for informal security updates deemed critical. -## Physical office analogy +## GitLab Omnibus Component by Component -You can imagine GitLab as a physical office. +This document is designed to be consumed by systems adminstrators and GitLab Support Engineers who want to understand more about the internals of GitLab and how they work together. -**The repositories** are the goods GitLab handles. -They can be stored in a warehouse. -This can be either a hard disk, or something more complex, such as a NFS filesystem; +When deployed, GitLab should be considered the amalgamation of the below processes. When troubleshooting or debugging, be as specific as possible as to which component you are referencing. That should increase clarity and reduce confusion. -**Nginx** acts like the front-desk. -Users come to Nginx and request actions to be done by workers in the office; +### GitLab Process Descriptions -**The database** is a series of metal file cabinets with information on: - - The goods in the warehouse (metadata, issues, merge requests etc); - - The users coming to the front desk (permissions) +As of this writing, a fresh GitLab 11.3.0 install will show the following processes with `gitlab-ctl status`: -**Redis** is a communication board with “cubby holes” that can contain tasks for office workers; +``` +run: alertmanager: (pid 30829) 14207s; run: log: (pid 13906) 2432044s +run: gitaly: (pid 30771) 14210s; run: log: (pid 13843) 2432046s +run: gitlab-monitor: (pid 30788) 14209s; run: log: (pid 13868) 2432045s +run: gitlab-workhorse: (pid 30758) 14210s; run: log: (pid 13855) 2432046s +run: logrotate: (pid 30246) 3407s; run: log: (pid 13825) 2432047s +run: nginx: (pid 30849) 14207s; run: log: (pid 13856) 2432046s +run: node-exporter: (pid 30929) 14206s; run: log: (pid 13877) 2432045s +run: postgres-exporter: (pid 30935) 14206s; run: log: (pid 13931) 2432044s +run: postgresql: (pid 13133) 2432214s; run: log: (pid 13848) 2432046s +run: prometheus: (pid 30807) 14209s; run: log: (pid 13884) 2432045s +run: redis: (pid 30560) 14274s; run: log: (pid 13807) 2432047s +run: redis-exporter: (pid 30946) 14205s; run: log: (pid 13869) 2432045s +run: sidekiq: (pid 30953) 14205s; run: log: (pid 13810) 2432047s +run: unicorn: (pid 30960) 14204s; run: log: (pid 13809) 2432047s +``` + +### Layers + +GitLab can be considered to have two layers from a process perspective: + +- **Monitoring**: Anything from this layer is not required to deliver GitLab the application, but will allow administrators more insight into their infrastructure and what the service as a whole is doing. +- **Core**: Any process that is vital for the delivery of GitLab as as platform. If any of these processes halt there will be a GitLab outage. For the Core layer, you can further divide into: + - **Processors**: These processes are responsible for actually performing operations and presenting the service. + - **Data**: These services store/expose structured data for the GitLab service. + +### alertmanager + +- Omnibus configuration options +- Layer: Monitoring + +[Alert manager](https://prometheus.io/docs/alerting/alertmanager/) is a tool provided by prometheus that _"handles alerts sent by client applications such as the Prometheus server. It takes care of deduplicating, grouping, and routing them to the correct receiver integration such as email, PagerDuty, or OpsGenie. It also takes care of silencing and inhibition of alerts."_ You can read more in [issue gitlab-ce#45740](https://gitlab.com/gitlab-org/gitlab-ce/issues/45740) about what we will be alerting on. + +### gitaly + +- [Omnibus confiugration options](https://gitlab.com/gitlab-org/gitaly/tree/master/doc/configuration) +- Layer: Core Service (Data) + +Gitaly is a service designed by GitLab to remove our need for NFS for Git storage in distributed deployments of GitLab. (Think GitLab.com or High Availablity Deployments) As of 11.3.0, This service handles all Git level access in GitLab. You can read more about the project [in the project's readme](https://gitlab.com/gitlab-org/gitaly). + +### gitlab-monitor + +- Omnibus configuration options +- Layer: Monitoring + +GitLab Monitor is a process disigned in house that allows us to export metrics about GitLab application internals to prometheus. You can read more [in the project's readme](https://gitlab.com/gitlab-org/gitlab-monitor) + +### gitlab-workhorse + +- Omnibus configuration options +- Layer: Core Service (Processor) + +[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse) is a program designed at GitLab to help alieviate pressure from unicorn. You can read more about the [historical reasons for developing](https://about.gitlab.com/2016/04/12/a-brief-history-of-gitlab-workhorse/). It's designed to act as a smart reverse proxy to help speed up GitLab as a whole. + +### logrotate + +- [Omnibus configuration options](https://docs.gitlab.com/omnibus/settings/logs.html#logrotate) +- Layer: Core Service + +GitLab is comprised of a large number of services that all log. We started bundling our own logrotate as of 7.4 to make sure we were logging responsibly. This is just a packaged version of the common opensource offering. + +### nginx + +- [Omnibus configuration options](https://docs.gitlab.com/omnibus/settings/nginx.html) +- Layer: Core Service (Processor) + +Nginx as as an ingress port for all HTTP requests and routes them to the approriate sub-systems within GitLab. We are bundling an unmodified version of the popular open source webserver. + +### node-exporter + +- [Omnibus configuration options](https://docs.gitlab.com/ee/administration/monitoring/prometheus/node_exporter.html) +- Layer: Monitoring + +[Node Exporter](https://github.com/prometheus/node_exporter) is a Prometheus tool that gives us metrics on the underlying machine. (Think CPU/Disk/Load) It's just a packaged version of the common open source offering from the Prometheus project. + +### postgres-exporter + +- [Omnibus configuration options](https://docs.gitlab.com/ee/administration/monitoring/prometheus/postgres_exporter.html) +- Layer: Monitoring + +[Postgres-exporter](https://github.com/wrouesnel/postgres_exporter) is the community provided Prometheus exporter that will deliver data about Postgres to prometheus for use in Grafana Dashboards. + +### postgresql + +- [Omnibus configuration options](https://docs.gitlab.com/omnibus/settings/database.html) +- Layer: Core Service (Data) + +GitLab packages the popular Database to provide storage for Application meta data and user information. + +### prometheus + +- [Omnibus configuration options](https://docs.gitlab.com/ee/administration/monitoring/prometheus/) +- Layer: Monitoring + +Prometheus is a time-series tool that helps GitLab administrators expose metrics about the individual processes used to provide GitLab the service. + +### redis + +- [Omnibus configuration options](https://docs.gitlab.com/omnibus/settings/redis.html) +- Layer: Core Service (Data) + +Redis is packaged to provide a place to store: + +- session data +- temporary cache information +- background job queues. + +### redis-exporter + +- [Omnibus configuration options](https://docs.gitlab.com/ee/administration/monitoring/prometheus/redis_exporter.html) +- Layer: Monitoring + +[Redis Exporter](https://github.com/oliver006/redis_exporter) is designed to give specific metrics about the Redis process to Prometheus so that we can graph these metrics in Graphana. + +### sidekiq + +- Omnibus configuration options +- Layer: Core Service (Processor) + +Sidekiq is a Ruby background job processor that pulls jobs from the redis queue and processes them. Background jobs allow GitLab to provide a faster request/response cycle by moving work into the background. + +### unicorn + +- [Omnibus configuration options](https://docs.gitlab.com/omnibus/settings/unicorn.html) +- Layer: Core Service (Processor) + +[Unicorn](https://bogomips.org/unicorn/) is a Ruby application server that is used to run the core Rails Application that provides the user facing features in GitLab. Often process output you will see this as `bundle` or `config.ru` depending on the GitLab version. + +### Additional Processes + +### GitLab Pages + +TODO + +### Mattermost + +TODO + +## GitLab by Request Type + +GitLab provides two "interfaces" for end users to access the service: + +- Web HTTP Requests (Viewing the UI/API) +- Git HTTP/SSH Requests (Pushing/Pulling Git Data) + +It's important to understand the distinction as some processes are used in both and others are exclusive to a specific request type. + +### GitLab Web HTTP Request Cycle + +When making a request to an HTTP Endpoint (Think `/users/sign_in`) the request will take the following path through the GitLab Service: + +- nginx - Acts as our first line reverse proxy +- gitlab-workhorse - This determines if it needs to go to the Rails application or somewhere else to reduce load on unicorn. +- unicorn - Since this is a web request, and it needs to access the application it will go to Unicorn. +- Postgres/Gitaly/Redis - Depending on the type of request, it may hit these services to store or retreive data. -**Sidekiq** is a worker that primarily handles sending out emails. -It takes tasks from the Redis communication board; -**A Unicorn worker** is a worker that handles quick/mundane tasks. -They work with the communication board (Redis). -Their job description: - - check permissions by checking the user session stored in a Redis “cubby hole”; - - make tasks for Sidekiq; - - fetch stuff from the warehouse or move things around in there; +### GitLab Git Request Cycle -**GitLab-shell** is a third kind of worker that takes orders from a fax machine (SSH) instead of the front desk (HTTP). -GitLab-shell communicates with Sidekiq via the “communication board” (Redis), and asks quick questions of the Unicorn workers either directly or via the front desk. +Below we describe the different pathing that HTTP vs. SSH Git requests will take. There is some overlap with the Web Request Cycle but also some differences. -**Gitaly** is a back desk that is specialized on reaching the disks to perform git operations efficiently and keep a copy of the result of costly operations. All git operations go through Gitaly. +### Web Request (80/443) +TODO -**GitLab Enterprise Edition (the application)** is the collection of processes and business practices that the office is run by. +### SSH Request (22) +TODO ## System Layout diff --git a/doc/development/changelog.md b/doc/development/changelog.md index f06d40d1dbb..cd0a1f46d27 100644 --- a/doc/development/changelog.md +++ b/doc/development/changelog.md @@ -133,15 +133,15 @@ If you're working on the GitLab EE repository, the entry will be added to ### Arguments -| Argument | Shorthand | Purpose | -| ----------------- | --------- | ---------------------------------------------------------------------------------------------------------- | -| [`--amend`] | | Amend the previous commit | -| [`--force`] | `-f` | Overwrite an existing entry | -| [`--merge-request`] | `-m` | Set merge request ID | -| [`--dry-run`] | `-n` | Don't actually write anything, just print | -| [`--git-username`] | `-u` | Use Git user.name configuration as the author | -| [`--type`] | `-t` | The category of the change, valid options are: added, fixed, changed, deprecated, removed, security, other | -| [`--help`] | `-h` | Print help message | +| Argument | Shorthand | Purpose | +| ----------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| [`--amend`] | | Amend the previous commit | +| [`--force`] | `-f` | Overwrite an existing entry | +| [`--merge-request`] | `-m` | Set merge request ID | +| [`--dry-run`] | `-n` | Don't actually write anything, just print | +| [`--git-username`] | `-u` | Use Git user.name configuration as the author | +| [`--type`] | `-t` | The category of the change, valid options are: `added`, `fixed`, `changed`, `deprecated`, `removed`, `security`, `performance`, `other` | +| [`--help`] | `-h` | Print help message | [`--amend`]: #-amend [`--force`]: #-force-or-f diff --git a/doc/development/feature_flags.md b/doc/development/feature_flags.md index 350593cc813..1019a1fd0e2 100644 --- a/doc/development/feature_flags.md +++ b/doc/development/feature_flags.md @@ -33,7 +33,7 @@ You can follow the progress on that [in the issue on our issue tracker](https:// In general, it's better to have a group- or user-based gate, and you should prefer it over the use of percentage gates. This would make debugging easier, as you -filter for example logs and errors based on actors too. Futhermore, this allows +filter for example logs and errors based on actors too. Furthermore, this allows for enabling for the `gitlab-org` group first, while the rest of the users aren't impacted. diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md index f58d79fccf1..c4ac53f45ac 100644 --- a/doc/development/i18n/proofreader.md +++ b/doc/development/i18n/proofreader.md @@ -41,6 +41,7 @@ are very appreciative of the work done by translators and proofreaders! - Nikita Grylov - [GitLab](https://gitlab.com/nixel2007), [Crowdin](https://crowdin.com/profile/nixel2007) - Alexy Lustin - [GitLab](https://gitlab.com/allustin), [Crowdin](https://crowdin.com/profile/lustin) - Spanish + - Pedro Garcia - [GitLab](https://gitlab.com/pedgarrod), [Crowdin](https://crowdin.com/profile/breaking_pitt) - Ukrainian - Volodymyr Sobotovych - [GitLab](https://gitlab.com/wheleph), [Crowdin](https://crowdin.com/profile/wheleph) - Andrew Vityuk - [GitLab](https://gitlab.com/3_1_3_u), [Crowdin](https://crowdin.com/profile/andruwa13) diff --git a/doc/development/logging.md b/doc/development/logging.md new file mode 100644 index 00000000000..abd08c420da --- /dev/null +++ b/doc/development/logging.md @@ -0,0 +1,144 @@ +# GitLab Developers Guide to Logging + +[GitLab Logs](../administration/logs.md) play a critical role for both +administrators and GitLab team members to diagnose problems in the field. + +## Don't use `Rails.logger` + +Currently `Rails.logger` calls all get saved into `production.log`, which contains +a mix of Rails' logs and other calls developers have inserted in the code base. +For example: + +``` +Started GET "/gitlabhq/yaml_db/tree/master" for 168.111.56.1 at 2015-02-12 19:34:53 +0200 +Processing by Projects::TreeController#show as HTML + Parameters: {"project_id"=>"gitlabhq/yaml_db", "id"=>"master"} + + ... + + Namespaces"."created_at" DESC, "namespaces"."id" DESC LIMIT 1 [["id", 26]] + CACHE (0.0ms) SELECT "members".* FROM "members" WHERE "members"."source_type" = 'Project' AND "members"."type" IN ('ProjectMember') AND "members"."source_id" = $1 AND "members"."source_type" = $2 AND "members"."user_id" = 1 ORDER BY "members"."created_at" DESC, "members"."id" DESC LIMIT 1 [["source_id", 18], ["source_type", "Project"]] + CACHE (0.0ms) SELECT "members".* FROM "members" WHERE "members"."source_type" = 'Project' AND "members". + (1.4ms) SELECT COUNT(*) FROM "merge_requests" WHERE "merge_requests"."target_project_id" = $1 AND ("merge_requests"."state" IN ('opened','reopened')) [["target_project_id", 18]] + Rendered layouts/nav/_project.html.haml (28.0ms) + Rendered layouts/_collapse_button.html.haml (0.2ms) + Rendered layouts/_flash.html.haml (0.1ms) + Rendered layouts/_page.html.haml (32.9ms) +Completed 200 OK in 166ms (Views: 117.4ms | ActiveRecord: 27.2ms) +``` + +These logs suffer from a number of problems: + +1. They often lack timestamps or other contextual information (e.g. project ID, user) +2. They may span multiple lines, which make them hard to find via Elasticsearch. +3. They lack a common structure, which make them hard to parse by log +forwarders, such as Logstash or Fluentd. This also makes them hard to +search. + +Note that currently on GitLab.com, any messages in `production.log` will +NOT get indexed by Elasticsearch due to the sheer volume and noise. They +do end up in Google Stackdriver, but it is still harder to search for +logs there. See the [GitLab.com logging +documentation](https://gitlab.com/gitlab-com/runbooks/blob/master/howto/logging.md) +for more details. + +## Use structured (JSON) logging + +Structured logging solves these problems. Consider the example from an API request: + +```json +{"time":"2018-10-29T12:49:42.123Z","severity":"INFO","duration":709.08,"db":14.59,"view":694.49,"status":200,"method":"GET","path":"/api/v4/projects","params":[{"key":"action","value":"git-upload-pack"},{"key":"changes","value":"_any"},{"key":"key_id","value":"secret"},{"key":"secret_token","value":"[FILTERED]"}],"host":"localhost","ip":"::1","ua":"Ruby","route":"/api/:version/projects","user_id":1,"username":"root","queue_duration":100.31,"gitaly_calls":30} +``` + +In a single line, we've included all the information that a user needs +to understand what happened: the timestamp, HTTP method and path, user +ID, etc. + +### How to use JSON logging + +Suppose you want to log the events that happen in a project +importer. You want to log issues created, merge requests, etc. as the +importer progresses. Here's what to do: + +1. Look at [the list of GitLab Logs](../administration/logs.md) to see +if your log message might belong with one of the existing log files. +1. If there isn't a good place, consider creating a new filename, but +check with a maintainer if it makes sense to do so. A log file should +make it easy for people to search pertinent logs in one place. For +example, `geo.log` contains all logs pertaining to GitLab Geo. +To create a new file: + 1. Choose a filename (e.g. `importer_json.log`). + 1. Create a new subclass of `Gitlab::JsonLogger`: + + ```ruby + module Gitlab + module Import + class Logger < ::Gitlab::JsonLogger + def self.file_name_noext + 'importer_json' + end + end + end + end + ``` + + 1. In your class where you want to log, you might initialize the logger as an instance variable: + + ```ruby + attr_accessor :logger + + def initialize + @logger = Gitlab::Import::Logger.build + end + ``` + + Note that it's useful to memoize this because creating a new logger + each time you log will open a file, adding unnecessary overhead. + +1. Now insert log messages into your code. When adding logs, + make sure to include all the context as key-value pairs: + + ```ruby + # BAD + logger.info("Unable to create project #{project.id}") + ``` + + ```ruby + # GOOD + logger.info("Unable to create project", project_id: project.id) + ``` + +1. Be sure to create a common base structure of your log messages. For example, + all messages might have `current_user_id` and `project_id` to make it easier + to search for activities by user for a given time. + +1. Do NOT mix and match types. Elasticsearch won't be able to index your + logs properly if you [mix integer and string + types](https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping.html#_avoiding_type_gotchas): + + ```ruby + # BAD + logger.info("Import error", error: 1) + logger.info("Import error", error: "I/O failure") + ``` + + ```ruby + # GOOD + logger.info("Import error", error_code: 1, error: "I/O failure") + ``` + +## Additional steps with new log files + +1. Consider log retention settings. By default, Omnibus will rotate any +logs in `/var/log/gitlab/gitlab-rails/*.log` every hour and [keep at +most 30 compressed files](https://docs.gitlab.com/omnibus/settings/logs.html#logrotate). +On GitLab.com, that setting is only 6 compressed files. These settings should suffice +for most users, but you may need to tweak them in [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab). + +1. If you add a new file, submit an issue to the [production +tracker](https://gitlab.com/gitlab-com/gl-infra/production/issues) or +a merge request to the [gitlab_fluentd](https://gitlab.com/gitlab-cookbooks/gitlab_fluentd) +project. See [this example](https://gitlab.com/gitlab-cookbooks/gitlab_fluentd/merge_requests/51/diffs). + +1. Be sure to update the [GitLab CE/EE documentation](../administration/logs.md) and the [GitLab.com +runbooks](https://gitlab.com/gitlab-com/runbooks/blob/master/howto/logging.md). diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md index 6f31e5b82e5..e4e532bb4ed 100644 --- a/doc/development/migration_style_guide.md +++ b/doc/development/migration_style_guide.md @@ -187,12 +187,7 @@ end When adding a foreign-key constraint to either an existing or new column remember to also add a index on the column. -This is _required_ if the foreign-key constraint specifies -`ON DELETE CASCADE` or `ON DELETE SET NULL` behavior. On a cascading -delete, the [corresponding record needs to be retrieved using an -index](https://www.cybertec-postgresql.com/en/postgresql-indexes-and-foreign-keys/) -(otherwise, we'd need to scan the whole table) for subsequent update or -deletion. +This is _required_ for all foreign-keys. Here's an example where we add a new column with a foreign key constraint. Note it includes `index: true` to create an index for it. diff --git a/doc/development/new_fe_guide/development/testing.md b/doc/development/new_fe_guide/development/testing.md index 748478768de..082acbedcd2 100644 --- a/doc/development/new_fe_guide/development/testing.md +++ b/doc/development/new_fe_guide/development/testing.md @@ -231,7 +231,7 @@ Their abstraction level is comparable to how a user would interact with the UI. <details> <summary>Vuex stores</summary> When testing the frontend code of a page as a whole, the interaction between Vue components and Vuex stores is covered as well. -<details> +</details> ## Feature tests diff --git a/doc/development/switching_to_rails5.md b/doc/development/switching_to_rails5.md new file mode 100644 index 00000000000..c9a4ce1a1d1 --- /dev/null +++ b/doc/development/switching_to_rails5.md @@ -0,0 +1,27 @@ +# Switching to Rails 5 + +GitLab switched recently to Rails 5. This is a big change (especially for backend development) and it introduces couple of temporary inconveniences. + +## After the switch, I found a broken feature. What do I do? + +Many fixes and tweaks were done to make our codebase compatible with Rails 5, but it's possible that not all issues were found. If you find an bug, please create an issue and assign it the ~rails5 label. + +## It takes much longer to run CI pipelines that build GitLab. Why? + +We are temporarily running CI pipelines with Rails 4 and 5 so that we ensure we remain compatible with Rails 4 in case we must revert back to Rails 4 from Rails 5 (this can double the duration of CI pipelines). + +We might revert back to Rails 4 if we found a major issue we were unable to quickly fix. + +Once we are sure we can stay with Rails 5, we will stop running CI pipelines with Rails 4. + +## Can I skip running Rails 4 tests? + +If you are sure that your merge request doesn't introduce any incompatibility, you can just include `norails4` anywhere in your branch name and Rails 4 tests will be skipped. + +## CI is failing on my test with Rails 4. How can I debug it? + +You can run specs locally with Rails 4 using the following command: + +```sh +BUNDLE_GEMFILE=Gemfile.rails4 RAILS5=0 bundle exec rspec ... +``` diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md index 36d150c8a5b..1830641431e 100644 --- a/doc/development/testing_guide/review_apps.md +++ b/doc/development/testing_guide/review_apps.md @@ -24,7 +24,7 @@ Review Apps are automatically deployed by each pipeline, both in [`scripts/review_apps/review-apps.sh`][review-apps.sh] - These scripts are basically [our official Auto DevOps scripts][Auto-DevOps.gitlab-ci.yml] where the - default CNG images are overriden with the images built and stored in the + default CNG images are overridden with the images built and stored in the [`CNG-mirror` project's registry][cng-mirror-registry]. - Since we're using [the official GitLab Helm chart][helm-chart], this means you get a dedicated environment for your branch that's very close to what it @@ -33,7 +33,7 @@ Review Apps are automatically deployed by each pipeline, both in thanks to the direct link to it from the MR widget. The default username is `root` and its password can be found in the 1Password secure note named **gitlab-{ce,ee} Review App's root password** (note that there's currently - [a bug where the default password seems to be overriden][password-bug]). + [a bug where the default password seems to be overridden][password-bug]). **Additional notes:** diff --git a/doc/install/requirements.md b/doc/install/requirements.md index dcc6d75724e..1b7e0d1d0ab 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -104,7 +104,7 @@ features of GitLab work with MySQL/MariaDB: 1. MySQL support for subgroups was [dropped with GitLab 9.3][post]. See [issue #30472][30472] for more information. 1. Geo does [not support MySQL](https://docs.gitlab.com/ee/administration/geo/replication/database.html#mysql-replication). This means no supported Disaster Recovery solution if using MySQL. **[PREMIUM ONLY]** -1. [Zero downtime migrations][../update/README.md#upgrading-without-downtime] do not work with MySQL. +1. [Zero downtime migrations](../update/README.md#upgrading-without-downtime) do not work with MySQL. 1. GitLab [optimizes the loading of dashboard events](https://gitlab.com/gitlab-org/gitlab-ce/issues/31806) using [PostgreSQL LATERAL JOINs](https://blog.heapanalytics.com/postgresqls-powerful-new-join-type-lateral/). 1. In general, SQL optimized for PostgreSQL may run much slower in MySQL due to differences in query planners. For example, subqueries that work well in PostgreSQL @@ -197,7 +197,13 @@ use the CI features. ## Supported web browsers -We support the current and the previous major release of Firefox, Chrome/Chromium, Safari and Microsoft browsers (Microsoft Edge and Internet Explorer 11). +We support the current and the previous major release of: + +- Firefox +- Chrome/Chromium +- Safari +- Microsoft Edge +- Internet Explorer 11 Each time a new browser version is released, we begin supporting that version and stop supporting the third most recent version. diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 3647f600b21..6bb2e236dc1 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -657,6 +657,8 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac | `REVIEW_DISABLED` | From GitLab 11.0, this variable can be used to disable the `review` and the manual `review:stop` job. If the variable is present, these jobs will not be created. | | `DAST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `dast` job. If the variable is present, the job will not be created. | | `PERFORMANCE_DISABLED` | From GitLab 11.0, this variable can be used to disable the `performance` job. If the variable is present, the job will not be created. | +| `OLD_REPORTS_DISABLED` | From GitLab 11.5, this variable can be used to disable the `sast` job. If the variable is present, the job will not be created. | +| `NEW_REPORTS_DISABLED` | From GitLab 11.5, this variable can be used to disable the `sast_dashboard` job. If the variable is present, the job will not be created. | TIP: **Tip:** Set up the replica variables using a diff --git a/doc/topics/git/troubleshooting_git.md b/doc/topics/git/troubleshooting_git.md index 8555c5e91ea..d1729d70158 100644 --- a/doc/topics/git/troubleshooting_git.md +++ b/doc/topics/git/troubleshooting_git.md @@ -78,5 +78,20 @@ git push In case you're running an older version of Git (< 2.9), consider upgrading to >= 2.9 (see [Broken pipe when pushing to Git repository][Broken-Pipe]). +## Timeout during git push/pull + +If pulling/pushing from/to your repository ends up taking more than 50 seconds, +a timeout will be issued with a log of the number of operations performed +and their respective timings, like the example below: + +``` +remote: Running checks for branch: master +remote: Scanning for LFS objects... (153ms) +remote: Calculating new repository size... (cancelled after 729ms) +``` + +This could be used to further investigate what operation is performing poorly +and provide GitLab with more information on how to improve the service. + [SSH troubleshooting]: ../../ssh/README.md#troubleshooting "SSH Troubleshooting" [Broken-Pipe]: https://stackoverflow.com/questions/19120120/broken-pipe-when-pushing-to-git-repository/36971469#36971469 "StackOverflow: 'Broken pipe when pushing to Git repository'" diff --git a/doc/university/training/topics/tags.md b/doc/university/training/topics/tags.md index 9526bcbfb82..14c39457838 100644 --- a/doc/university/training/topics/tags.md +++ b/doc/university/training/topics/tags.md @@ -22,7 +22,7 @@ comments: false **Additional resources** -<http://git-scm.com/book/en/Git-Basics-Tagging> +<https://git-scm.com/book/en/Git-Basics-Tagging> ---------- diff --git a/doc/user/project/clusters/eks_and_gitlab/img/new_project.png b/doc/user/project/clusters/eks_and_gitlab/img/new_project.png Binary files differdeleted file mode 100644 index 02afc099f10..00000000000 --- a/doc/user/project/clusters/eks_and_gitlab/img/new_project.png +++ /dev/null diff --git a/doc/user/project/clusters/eks_and_gitlab/img/rbac.png b/doc/user/project/clusters/eks_and_gitlab/img/rbac.png Binary files differindex c8adaad13c2..517e4f7ca44 100644 --- a/doc/user/project/clusters/eks_and_gitlab/img/rbac.png +++ b/doc/user/project/clusters/eks_and_gitlab/img/rbac.png diff --git a/doc/user/project/clusters/eks_and_gitlab/index.md b/doc/user/project/clusters/eks_and_gitlab/index.md index 45d77e075f1..fa2ed21f980 100644 --- a/doc/user/project/clusters/eks_and_gitlab/index.md +++ b/doc/user/project/clusters/eks_and_gitlab/index.md @@ -1,123 +1,139 @@ # Connecting and deploying to an Amazon EKS cluster -## Introduction +In this tutorial, we will show how to integrate an +[Amazon EKS](https://aws.amazon.com/eks/) cluster with GitLab and begin +deploying applications. -In this tutorial, we will show how to integrate an [Amazon EKS](https://aws.amazon.com/eks/) cluster with GitLab, and begin deploying applications. +## Introduction For an end-to-end walkthrough we will: -1. Start with a new project based on the sample Ruby on Rails template -1. Integrate an EKS cluster -1. Utilize [Auto DevOps](../../../../topics/autodevops/) to build, test, and deploy our application +1. Start with a new project based on the sample Ruby on Rails template. +1. Integrate an EKS cluster. +1. Utilize [Auto DevOps](../../../../topics/autodevops/) to build, test, and deploy our application. You will need: -1. An account on GitLab, like [GitLab.com](https://gitlab.com) -1. An Amazon EKS cluster (with worker nodes properly configured) -1. `kubectl` [installed and configured for access to the EKS cluster](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html#get-started-kubectl) +1. An account on GitLab, like [GitLab.com](https://gitlab.com). +1. An Amazon EKS cluster (with worker nodes properly configured). +1. `kubectl` [installed and configured for access to the EKS cluster](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html#get-started-kubectl). -If you don't have an Amazon EKS cluster, one can be created by following [the EKS getting started guide](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html). +If you don't have an Amazon EKS cluster, one can be created by following the +[EKS getting started guide](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html). ## Creating a new project -On GitLab, create a new project by clicking on the `+` icon in the top navigation bar, and selecting `New project`. - -![New Project](img/new_project.png) +On GitLab, create a new project by clicking on the `+` icon in the top navigation +bar and selecting **New project**. -On the new project screen, click on the `Create from template` tab, and select `Use template` for the Ruby on Rails sample project. +On the new project screen, click on the **Create from template** tab, and select +"Use template" for the Ruby on Rails sample project. -Give the project a name, and then select `Create project`. +Give the project a name, and then select **Create project**. ![Create Project](img/create_project.png) ## Configuring and connecting the EKS cluster -From the left side bar, hover over `Operations` and select `Kubernetes`, then click on `Add Kubernetes cluster`, and finally `Add an existing Kubernetes cluster`. +From the left side bar, hover over **Operations > Kubernetes > Add Kubernetes cluster**, +then click **Add an existing Kubernetes cluster**. -A few details from the EKS cluster will be required to connect it to GitLab. +A few details from the EKS cluster will be required to connect it to GitLab: -1. **Retrieve the certificate**: A valid Kubernetes certificate is needed to authenticate to the EKS cluster. We will use the certificate created by default. Open a shell and use `kubectl` to retrieve it: - - List the secrets with `kubectl get secrets`, and one should named similar to `default-token-xxxxx`. Copy that token name for use below. - - Get the certificate with `kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 -D` +1. **Retrieve the certificate**: A valid Kubernetes certificate is needed to + authenticate to the EKS cluster. We will use the certificate created by default. + Open a shell and use `kubectl` to retrieve it: -1. **Create admin token**: A `cluster-admin` token is required to install and manage Helm Tiller. GitLab establishes mutual SSL auth with Helm Tiller and creates limited service accounts for each application. To create the token we will create an admin service account as follows: + - List the secrets with `kubectl get secrets`, and one should named similar to + `default-token-xxxxx`. Copy that token name for use below. + - Get the certificate with: - 1. Create a file called `eks-admin-service-account.yaml` with the text below: + ```sh + kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 -D + ``` - ```yaml - apiVersion: v1 - kind: ServiceAccount - metadata: - name: eks-admin - namespace: kube-system - ``` +1. **Create admin token**: A `cluster-admin` token is required to install and + manage Helm Tiller. GitLab establishes mutual SSL auth with Helm Tiller + and creates limited service accounts for each application. To create the + token we will create an admin service account as follows: - 2. Apply the service account to your cluster: + 2.1. Create a file called `eks-admin-service-account.yaml` with contents: - ```bash - kubectl apply -f eks-admin-service-account.yaml - ``` + ```yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: eks-admin + namespace: kube-system + ``` - Output: + 2.2. Apply the service account to your cluster: - ```bash - serviceaccount "eks-admin" created - ``` + ```bash + kubectl apply -f eks-admin-service-account.yaml + ``` - 3. Create a file called `eks-admin-cluster-role-binding.yaml` with the text below: + Output: - ```yaml - apiVersion: rbac.authorization.k8s.io/v1beta1 - kind: ClusterRoleBinding - metadata: - name: eks-admin - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin - subjects: - - kind: ServiceAccount - name: eks-admin - namespace: kube-system - ``` + ```bash + serviceaccount "eks-admin" created + ``` - 4. Apply the cluster role binding to your cluster: + 2.3. Create a file called `eks-admin-cluster-role-binding.yaml` with contents: - ```bash - kubectl apply -f eks-admin-cluster-role-binding.yaml - ``` + ```yaml + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: ClusterRoleBinding + metadata: + name: eks-admin + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin + subjects: + - kind: ServiceAccount + name: eks-admin + namespace: kube-system + ``` - Output: + 2.4. Apply the cluster role binding to your cluster: - ```bash - clusterrolebinding "eks-admin" created - ``` + ```bash + kubectl apply -f eks-admin-cluster-role-binding.yaml + ``` - 5. Retrieve the token for the `eks-admin` service account. Copy the `<authentication_token>` value from the output. + Output: - ```bash - kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}') - ``` + ```bash + clusterrolebinding "eks-admin" created + ``` - Output: - - ```yaml - Name: eks-admin-token-b5zv4 - Namespace: kube-system - Labels: <none> - Annotations: kubernetes.io/service-account.name=eks-admin - kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8 + 2.5. Retrieve the token for the `eks-admin` service account: - Type: kubernetes.io/service-account-token + ```bash + kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}') + ``` - Data - ==== - ca.crt: 1025 bytes - namespace: 11 bytes - token: <authentication_token> - ``` + Copy the `<authentication_token>` value from the output: + + ```yaml + Name: eks-admin-token-b5zv4 + Namespace: kube-system + Labels: <none> + Annotations: kubernetes.io/service-account.name=eks-admin + kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8 -1. The API server endpoint is also required, so GitLab can connect to the cluster. This is displayed on the AWS EKS console, when viewing the EKS cluster details. + Type: kubernetes.io/service-account-token + + Data + ==== + ca.crt: 1025 bytes + namespace: 11 bytes + token: <authentication_token> + ``` + +1. The API server endpoint is also required, so GitLab can connect to the cluster. + This is displayed on the AWS EKS console, when viewing the EKS cluster details. You now have all the information needed to connect the EKS cluster: @@ -130,17 +146,26 @@ You now have all the information needed to connect the EKS cluster: ![Add Cluster](img/add_cluster.png) -Click on `Add Kubernetes cluster`, the cluster is now connected to GitLab. At this point, [Kubernetes deployment variables](../#deployment-variables) will automatically be available during CI jobs, making it easy to interact with the cluster. +Click on **Add Kubernetes cluster**, the cluster is now connected to GitLab. +At this point, [Kubernetes deployment variables](../#deployment-variables) will +automatically be available during CI/CD jobs, making it easy to interact with the cluster. If you would like to utilize your own CI/CD scripts to deploy to the cluster, you can stop here. -## Disable Role-Based Access Control (RBAC) - Optional +## Disable Role-Based Access Control (RBAC) (optional) -When connecting a cluster via GitLab integration, you may specify whether the cluster is RBAC-enabled or not. This will affect how GitLab interacts with the cluster for certain operations. If you **did not** check the "RBAC-enabled cluster" checkbox at creation time, GitLab will assume RBAC is disabled for your cluster when interacting with it. If so, you must disable RBAC on your cluster for the integration to work properly. +When connecting a cluster via GitLab integration, you may specify whether the +cluster is RBAC-enabled or not. This will affect how GitLab interacts with the +cluster for certain operations. If you **did not** check the "RBAC-enabled cluster" +checkbox at creation time, GitLab will assume RBAC is disabled for your cluster +when interacting with it. If so, you must disable RBAC on your cluster for the +integration to work properly. ![rbac](img/rbac.png) -> **Note**: Disabling RBAC means that any application running in the cluster, or user who can authenticate to the cluster, has full API access. This is a [security concern](https://docs.gitlab.com/ee/user/project/clusters/#security-implications), and may not be desirable. +NOTE: **Note**: Disabling RBAC means that any application running in the cluster, +or user who can authenticate to the cluster, has full API access. This is a +[security concern](../index.md#security-implications), and may not be desirable. To effectively disable RBAC, global permissions can be applied granting full access: @@ -154,56 +179,100 @@ kubectl create clusterrolebinding permissive-binding \ ## Deploy services to the cluster -GitLab supports one-click deployment of helpful services to the cluster, many of which support Auto DevOps. Back on the Kubernetes cluster screen in GitLab, a list of applications is now available to deploy. +GitLab supports one-click deployment of helpful services to the cluster, many of +which support Auto DevOps. Back on the Kubernetes cluster screen in GitLab, a +list of applications is now available to deploy. -First install Helm Tiller, a package manager for Kubernetes. This enables deployment of the other applications. +First, install Helm Tiller, a package manager for Kubernetes. This enables +deployment of the other applications. ![Deploy Apps](img/deploy_apps.png) ### Deploying NGINX Ingress (optional) -Next, if you would like the deployed app to be reachable on the internet, deploy the Ingress. Note that this will also cause an [Elastic Load Balancer](https://aws.amazon.com/documentation/elastic-load-balancing/) to be created, which will incur additional AWS costs. +Next, if you would like the deployed app to be reachable on the internet, deploy +the Ingress. Note that this will also cause an +[Elastic Load Balancer](https://aws.amazon.com/documentation/elastic-load-balancing/) +to be created, which will incur additional AWS costs. + +Once installed, you may see a `?` for "Ingress IP Address". This is because the +created ELB is available at a DNS name, not an IP address. To get the DNS name, +run: -Once installed, you may see a `?` for `Ingress IP Address`. This is because the created ELB is available at a DNS name, not an IP address. To get the DNS name, run: `kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -o jsonpath="{.status.loadBalancer.ingress[0].hostname}"`. Note, you may see a trailing `%` on some Kubernetes versions, do not include it. +```sh +kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -o jsonpath="{.status.loadBalancer.ingress[0].hostname}" +``` + +Note that you may see a trailing `%` on some Kubernetes versions, **do not include it**. -The Ingress is now available at this address, and will route incoming requests to the proper service based on the DNS name in the request. To support this, a wildcard DNS CNAME record should be created for the desired domain name. For example `*.myekscluster.com` would point to the Ingress hostname obtained earlier. +The Ingress is now available at this address and will route incoming requests to +the proper service based on the DNS name in the request. To support this, a +wildcard DNS CNAME record should be created for the desired domain name. For example, +`*.myekscluster.com` would point to the Ingress hostname obtained earlier. ![Create DNS](img/create_dns.png) ### Deploying the GitLab Runner (optional) -If the project is on GitLab.com, free shared runners are available and you do not have to deploy one. If a project specific runner is desired, or there are no shared runners, it is easy to deploy one. +If the project is on GitLab.com, free shared Runners are available and you do +not have to deploy one. If a project specific Runner is desired, or there are no +shared Runners, it is easy to deploy one. -Simply click on the `Install` button for the GitLab Runner. It is important to note that the runner deployed is set as **privileged**, which means it essentially has root access to the underlying machine. This is required to build docker images, and so is on by default. +Simply click on the **Install** button for the GitLab Runner. It is important to +note that the Runner deployed is set as **privileged**, which means it essentially +has root access to the underlying machine. This is required to build docker images, +and so is on by default. ### Deploying Prometheus (optional) -GitLab is able to monitor applications automatically, utilizing [Prometheus](../../integrations/prometheus.html). Kubernetes container CPU and memory metrics are automatically collected, and response metrics are retrieved from NGINX Ingress as well. +GitLab is able to monitor applications automatically, utilizing +[Prometheus](../../integrations/prometheus.html). Kubernetes container CPU and +memory metrics are automatically collected, and response metrics are retrieved +from NGINX Ingress as well. -To enable monitoring, simply install Prometheus into the cluster with the `Install` button. +To enable monitoring, simply install Prometheus into the cluster with the +**Install** button. ## Create a default Storage Class -Amazon EKS does not have a default Storage Class out of the box, which means requests for persistent volumes will not be automatically fulfilled. As part of Auto DevOps, the deployed Postgres instance requests persistent storage, and without a default storage class it will fail to start. +Amazon EKS doesn't have a default Storage Class out of the box, which means +requests for persistent volumes will not be automatically fulfilled. As part +of Auto DevOps, the deployed Postgres instance requests persistent storage, +and without a default storage class it will fail to start. -If a default Storage Class does not already exist and is desired, follow Amazon's [short guide](https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html) to create one. +If a default Storage Class doesn't already exist and is desired, follow Amazon's +[guide on storage classes](https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html) +to create one. -Alternatively, disable Postgres by setting the project variable [`POSTGRES_ENABLED`](../../../../topics/autodevops/#environment-variables) to `false`. +Alternatively, disable Postgres by setting the project variable +[`POSTGRES_ENABLED`](../../../../topics/autodevops/#environment-variables) to `false`. ## Deploy the app to EKS -With RBAC disabled and services deployed, [Auto DevOps](https://docs.gitlab.com/ee/topics/autodevops/) can now be leveraged to build, test, and deploy the app. To enable, click on `Settings` in the left sidebar, then `CI/CD`. You will see a section for `Auto DevOps`, expand it. Click on the radio button to `Enable Auto DevOps`. +With RBAC disabled and services deployed, +[Auto DevOps](../../../../topics/autodevops/index.md) can now be leveraged +to build, test, and deploy the app. -If a wildcard DNS entry was created resolving to the Load Balancer, enter it in the `domain` field. Otherwise, the deployed app will not be externally available outside of the cluster. To save, click `Save changes`. +[Enable Auto DevOps](../../../../topics/autodevops/index.md##enablingdisabling-auto-devops-at-the-project-level) +if not already enabled. If a wildcard DNS entry was created resolving to the +Load Balancer, enter it in the `domain` field under the Auto DevOps settings. +Otherwise, the deployed app will not be externally available outside of the cluster. ![Deploy Pipeline](img/pipeline.png) -A new pipeline will automatically be created, which will begin to build, test, and deploy the app. +A new pipeline will automatically be created, which will begin to build, test, +and deploy the app. -After the pipeline has finished, your app will be running in EKS and available to users. Click on `CI/CD` tab in the left navigation bar, and choose `Environments`. +After the pipeline has finished, your app will be running in EKS and available +to users. Click on **CI/CD > Environments**. ![Deployed Environment](img/environment.png) -You will see a list of the environments and their deploy status, as well as options to browse to the app, view monitoring metrics, and even access a shell on the running pod. +You will see a list of the environments and their deploy status, as well as +options to browse to the app, view monitoring metrics, and even access a shell +on the running pod. + +## Learn more -To learn more about Auto DevOps, review our [documentation](../../../../topics/autodevops/). +To learn more on automatically deploying your applications, +read about [Auto DevOps](../../../../topics/autodevops/index.md). diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index 3fbd4c21eab..ca262e4b76e 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -49,8 +49,8 @@ new Kubernetes cluster to your project: NOTE: **Note:** You need Maintainer [permissions] and above to access the Kubernetes page. -1. Click on **Add Kubernetes cluster**. -1. Click on **Create with Google Kubernetes Engine**. +1. Click **Add Kubernetes cluster**. +1. Click **Create with Google Kubernetes Engine**. 1. Connect your Google account if you haven't done already by clicking the **Sign in with Google** button. 1. From there on, choose your cluster's settings: @@ -78,8 +78,8 @@ To add an existing Kubernetes cluster to your project: NOTE: **Note:** You need Maintainer [permissions] and above to access the Kubernetes page. -1. Click on **Add Kubernetes cluster**. -1. Click on **Add an existing Kubernetes cluster** and fill in the details: +1. Click **Add Kubernetes cluster**. +1. Click **Add an existing Kubernetes cluster** and fill in the details: - **Kubernetes cluster name** (required) - The name you wish to give the cluster. - **Environment scope** (required)- The [associated environment](#setting-the-environment-scope) to this cluster. @@ -228,7 +228,11 @@ twice, which can lead to confusion during deployments. | [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications. | [stable/prometheus](https://github.com/helm/charts/tree/master/stable/prometheus) | | [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) | | [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use [this](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) custom Jupyter image that installs additional useful packages on top of the base Jupyter. You will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/amit1rrr/rubix). More information on creating executable runbooks can be found at [Nurtch Documentation](http://docs.nurtch.com/en/latest). **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) | -| [Knative](https://cloud.google.com/knative) | 0.1.2 | Knative provides a platform to create, deploy, and manage serverless workloads from a Kubernetes cluster. It is used in conjunction with, and includes [Istio](https://istio.io) to provide an external IP address for all programs hosted by Knative. You will be prompted to enter a wildcard domain where your applications will be exposed. Configure your DNS server to use the external IP address for that domain. For any application created and installed, they will be accessible as <program_name>.<kubernetes_namespace>.<domain_name>. **Note**: This will require your kubernetes cluster to have RBAC enabled. | [knative/knative](https://storage.googleapis.com/triggermesh-charts) +| [Knative](https://cloud.google.com/knative) | 11.5+ | Knative provides a platform to create, deploy, and manage serverless workloads from a Kubernetes cluster. It is used in conjunction with, and includes [Istio](https://istio.io) to provide an external IP address for all programs hosted by Knative. You will be prompted to enter a wildcard domain where your applications will be exposed. Configure your DNS server to use the external IP address for that domain. For any application created and installed, they will be accessible as `<program_name>.<kubernetes_namespace>.<domain_name>`. This will require your kubernetes cluster to have [RBAC enabled](#role-based-access-control-rbac). | [knative/knative](https://storage.googleapis.com/triggermesh-charts) + +NOTE: **Note:** +As of GitLab 11.6 Helm Tiller will be upgraded to the latest version supported +by GitLab before installing any of the above applications. ## Getting the external IP address @@ -255,14 +259,17 @@ your ingress application in which case you should manually determine it. ### Manually determining the IP address -If the cluster is on GKE, click on the **Google Kubernetes Engine** link in the +If the cluster is on GKE, click the **Google Kubernetes Engine** link in the **Advanced settings**, or go directly to the [Google Kubernetes Engine dashboard](https://console.cloud.google.com/kubernetes/) -and select the proper project and cluster. Then click on **Connect** and execute +and select the proper project and cluster. Then click **Connect** and execute the `gcloud` command in a local terminal or using the **Cloud Shell**. If the cluster is not on GKE, follow the specific instructions for your Kubernetes provider to configure `kubectl` with the right credentials. +The output of the following examples will show the external IP address of your +cluster. This information can then be used to set up DNS entries and forwarding +rules that allow external access to your deployed applications. If you installed the Ingress [via the **Applications**](#installing-applications), run the following command: @@ -271,26 +278,23 @@ run the following command: kubectl get svc --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip} ' ``` -NOTE: **Note:** For Istio/Knative, the command will be different: + ```bash kubectl get svc --namespace=istio-system knative-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} ' ``` -Otherwise, you can list the IP addresses of all load balancers: +Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run: ```bash -kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} ' +kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -o jsonpath="{.status.loadBalancer.ingress[0].hostname}". ``` -> **Note**: Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run: -> ```bash -> kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -o jsonpath="{.status.loadBalancer.ingress[0].hostname}". -> ``` +Otherwise, you can list the IP addresses of all load balancers: -The output is the external IP address of your cluster. This information can then -be used to set up DNS entries and forwarding rules that allow external access to -your deployed applications. +```bash +kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} ' +``` ### Using a static IP @@ -300,7 +304,7 @@ your apps will not be able to be reached, and you'd have to change the DNS record again. In order to avoid that, you should change it into a static reserved IP. -[Read how to promote an ephemeral external IP address in GKE.](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip) +Read how to [promote an ephemeral external IP address in GKE](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip). ### Pointing your DNS at the cluster IP @@ -406,7 +410,7 @@ service account of the cluster integration. After you have successfully added your cluster information, you can enable the Kubernetes cluster integration: -1. Click the "Enabled/Disabled" switch +1. Click the **Enabled/Disabled** switch 1. Hit **Save** for the changes to take effect You can now start using your Kubernetes cluster for your deployments. @@ -423,7 +427,7 @@ When you remove a cluster, you only remove its relation to GitLab, not the cluster itself. To remove the cluster, you can do so by visiting the GKE dashboard or using `kubectl`. -To remove the Kubernetes cluster integration from your project, simply click on the +To remove the Kubernetes cluster integration from your project, simply click the **Remove integration** button. You will then be able to follow the procedure and add a Kubernetes cluster again. @@ -486,7 +490,13 @@ the deployment variables above, ensuring any pods you create are labelled with ## Read more -- [Connecting and deploying to an Amazon EKS cluster](eks_and_gitlab/index.md) +### Integrating Amazon EKS cluster with GitLab + +- Learn how to [connect and deploy to an Amazon EKS cluster](eks_and_gitlab/index.md). + +### Serverless + +- [Run serverless workloads on Kubernetes with Knative.](serverless/index.md) [permissions]: ../../permissions.md [ee]: https://about.gitlab.com/pricing/ diff --git a/doc/user/project/clusters/serverless/img/deploy-stage.png b/doc/user/project/clusters/serverless/img/deploy-stage.png Binary files differnew file mode 100644 index 00000000000..dc2f8af9c63 --- /dev/null +++ b/doc/user/project/clusters/serverless/img/deploy-stage.png diff --git a/doc/user/project/clusters/serverless/img/dns-entry.png b/doc/user/project/clusters/serverless/img/dns-entry.png Binary files differnew file mode 100644 index 00000000000..2e7655c6041 --- /dev/null +++ b/doc/user/project/clusters/serverless/img/dns-entry.png diff --git a/doc/user/project/clusters/serverless/img/install-knative.png b/doc/user/project/clusters/serverless/img/install-knative.png Binary files differnew file mode 100644 index 00000000000..dd576a9df35 --- /dev/null +++ b/doc/user/project/clusters/serverless/img/install-knative.png diff --git a/doc/user/project/clusters/serverless/img/knative-app.png b/doc/user/project/clusters/serverless/img/knative-app.png Binary files differnew file mode 100644 index 00000000000..54301e1786f --- /dev/null +++ b/doc/user/project/clusters/serverless/img/knative-app.png diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md new file mode 100644 index 00000000000..bdbc4f7f09d --- /dev/null +++ b/doc/user/project/clusters/serverless/index.md @@ -0,0 +1,137 @@ +# Serverless + +> Introduced in GitLab 11.5. + +Run serverless workloads on Kubernetes using [Knative](https://cloud.google.com/knative/). + +## Overview + +Knative extends Kubernetes to provide a set of middleware components that are useful to build modern, source-centric, container-based applications. Knative brings some significant benefits out of the box through its main components: + +- [Build:](https://github.com/knative/build) Source-to-container build orchestration +- [Eventing:](https://github.com/knative/eventing) Management and delivery of events +- [Serving:](https://github.com/knative/serving) Request-driven compute that can scale to zero + +For more information on Knative, visit the [Knative docs repo](https://github.com/knative/docs). + +## Requirements + +To run Knative on Gitlab, you will need: + +1. **Kubernetes:** An RBAC-enabled Kubernetes cluster is required to deploy Knative. + The simplest way to get started is to add a cluster using [GitLab's GKE integration](https://docs.gitlab.com/ee/user/project/clusters/#adding-and-creating-a-new-gke-cluster-via-gitlab). + GitLab recommends +1. **Helm Tiller:** Helm is a package manager for Kubernetes and is required to install + all the other applications. +1. **Domain Name:** Knative will provide its own load balancer using Istio. It will provide an + external IP address for all the applications served by Knative. You will be prompted to enter a + wildcard domain where your applications will be served. Configure your DNS server to use the + external IP address for that domain. +1. **Serverless `gitlab-ci.yml` Template:** GitLab uses [Kaniko](https://github.com/GoogleContainerTools/kaniko) + to build the application and the [TriggerMesh CLI](https://github.com/triggermesh/tm), to simplify the + deployment of knative services and functions. + + Add the following `.gitlab-ci.yml` to the root of your repository (you may skip this step if using the sample + [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) mentioned below). + + ```yaml + stages: + - build + - deploy + + build: + stage: build + image: + name: gcr.io/kaniko-project/executor:debug + entrypoint: [""] + only: + - master + script: + - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json + - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE + + deploy: + stage: deploy + image: gcr.io/triggermesh/tm@sha256:e3ee74db94d215bd297738d93577481f3e4db38013326c90d57f873df7ab41d5 + only: + - master + environment: production + script: + - echo "$CI_REGISTRY_IMAGE" + - tm -n "$KUBE_NAMESPACE" --config "$KUBECONFIG" deploy service "$CI_PROJECT_NAME" --from-image "$CI_REGISTRY_IMAGE" --wait + ``` + +1. **Dockerfile:** Knative requires a Dockerfile in order to build your application. It should be included + at the root of your project's repo and expose port 8080. + +## Installing Knative via GitLab's Kubernetes integration + +NOTE: **Note:** +Minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.50 GB memory. RBAC must be enabled. + +You may download the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started. + +1. [Add a Kubernetes cluster](https://docs.gitlab.com/ce/user/project/clusters/) and install Helm. + +1. Once Helm has been successfully installed, on the Knative app section, enter the domain to be used with + your application and click "Install". + + ![install-knative](img/install-knative.png) + +1. After the Knative installation has finished, retrieve the Istio Ingress IP address by running the following command: + + ```bash + kubectl get svc --namespace=istio-system knative-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} ' + ``` + + Output: + + ```bash + 35.161.143.124 my-machine-name:~ my-user$ + ``` + +1. The ingress is now available at this address and will route incoming requests to the proper service based on the DNS + name in the request. To support this, a wildcard DNS A record should be created for the desired domain name. For example, + if your Knative base domain is `knative.example.com` then you need to create an A record with domain `*.knative.example.com` + pointing the ip address of the ingress. + + ![dns entry](img/dns-entry.png) + +## Deploy the application with Knative + +With all the pieces in place, you can simply create a new CI pipeline to deploy the Knative application. Navigate to +**CI/CD >> Pipelines** and click the **Run Pipeline** button at the upper-right part of the screen. Then, on the +Pipelines page, click **Create pipeline**. + +## Obtain the URL for the Knative deployment + +Once all the stages of the pipeline finish, click the **deploy** stage. + +![deploy stage](img/deploy-stage.png) + +The output will look like this: + +```bash +Running with gitlab-runner 11.5.0~beta.844.g96d88322 (96d88322) + on docker-auto-scale 72989761 +Using Docker executor with image gcr.io/triggermesh/tm@sha256:e3ee74db94d215bd297738d93577481f3e4db38013326c90d57f873df7ab41d5 ... +Pulling docker image gcr.io/triggermesh/tm@sha256:e3ee74db94d215bd297738d93577481f3e4db38013326c90d57f873df7ab41d5 ... +Using docker image sha256:6b3f6590a9b30bd7aafb9573f047d930c70066e43955b4beb18a1eee175f6de1 for gcr.io/triggermesh/tm@sha256:e3ee74db94d215bd297738d93577481f3e4db38013326c90d57f873df7ab41d5 ... +Running on runner-72989761-project-4342902-concurrent-0 via runner-72989761-stg-srm-1541795796-27929c96... +Cloning repository... +Cloning into '/builds/danielgruesso/knative'... +Checking out 8671ad20 as master... +Skipping Git submodules setup +$ echo "$CI_REGISTRY_IMAGE" +registry.staging.gitlab.com/danielgruesso/knative +$ tm -n "$KUBE_NAMESPACE" --config "$KUBECONFIG" deploy service "$CI_PROJECT_NAME" --from-image "$CI_REGISTRY_IMAGE" --wait +Deployment started. Run "tm -n knative-4342902 describe service knative" to see the details +Waiting for ready state....... +Service domain: knative.knative-4342902.knative.info +Job succeeded +``` + +The second to last line, labeled **Service domain** contains the URL for the deployment. Copy and paste the domain into your +browser to see the app live. + +![knative app](img/knative-app.png)
\ No newline at end of file diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md index 3e4be043199..42da2210fab 100644 --- a/doc/user/project/import/github.md +++ b/doc/user/project/import/github.md @@ -17,6 +17,7 @@ the [GitHub rake task](../../../administration/raketasks/github_import.md) to im GitHub without the constraints of a Sidekiq worker. The following aspects of a project are imported: + * Repository description (GitLab.com & 7.7+) * Git repository data (GitLab.com & 7.7+) * Issues (GitLab.com & 7.7+) diff --git a/doc/user/project/merge_requests/img/comment-on-any-diff-line.png b/doc/user/project/merge_requests/img/comment-on-any-diff-line.png Binary files differnew file mode 100644 index 00000000000..856ede41527 --- /dev/null +++ b/doc/user/project/merge_requests/img/comment-on-any-diff-line.png diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 6de2ab07fc4..8a68185798b 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -141,6 +141,15 @@ you hide discussions that are no longer relevant. [Read more about resolving discussion comments in merge requests reviews.](../../discussions/index.md) +## Commenting on any file line in merge requests + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/13950) in GitLab 11.5. + +GitLab provides a way of leaving comments in any part of the file being changed +in a Merge Request. To do so, click the **...** button in the gutter of the Merge Request diff UI to expand the diff lines and leave a comment, just as you would for a changed line. + +![Comment on any diff file line](img/comment-on-any-diff-line.png) + ## Resolve conflicts When a merge request has conflicts, GitLab may provide the option to resolve @@ -168,11 +177,11 @@ administrator to do so. ### Adding patches when creating a merge request via e-mail -> **Note**: This feature was [implemented in GitLab 11.5](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22723) +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22723) in GitLab 11.5. You can add commits to the merge request being created by adding -patches as attachments to the email, all attachments with a filename -ending in `.patch` will be considered patches. The patches will be processed +patches as attachments to the email. All attachments with a filename +ending in `.patch` will be considered patches and they will be processed ordered by name. The combined size of the patches can be 2MB. @@ -185,7 +194,7 @@ branch already exists, the patches will be applied on top of it. ## Find the merge request that introduced a change -> **Note**: this feature was [implemented in GitLab 10.5](https://gitlab.com/gitlab-org/gitlab-ce/issues/2383). +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/2383) in GitLab 10.5. When viewing the commit details page, GitLab will link to the merge request (or merge requests, if it's in more than one) containing that commit. diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md index 3cf46231a9d..7168fe63887 100644 --- a/doc/user/project/milestones/index.md +++ b/doc/user/project/milestones/index.md @@ -6,6 +6,26 @@ Milestones in GitLab are a way to track issues and merge requests created to ach Milestones allow you to organize issues and merge requests into a cohesive group, with an optional start date and an optional due date. +## Milestones as Agile sprints + +Milestones can be used as Agile sprints. +Set the milestone start date and due date to represent +the start and end of your Agile sprint. +Set the milestone title to the name of your Agile sprint, +such as `November 2018 sprint`. +Add an issue to your Agile sprint by associating +the milestone to the issue. + +## Milestones as releases + +Milestones can be used as releases. +Set the milestone due date to represent the release date of your release. +(And leave the milestone start date blank.) +Set the the milestone title to the version of your release, +such as `Version 9.4`. +Add an issue to your release by associating +the milestone to the issue. + ## Project milestones and group milestones - **Project milestones** can be assigned to issues or merge requests in that project only. diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md index 6d822d3f7f2..1710bba2fd0 100644 --- a/doc/user/project/repository/index.md +++ b/doc/user/project/repository/index.md @@ -53,17 +53,35 @@ To get started with the command line, please read through the Use GitLab's [file finder](../../../workflow/file_finder.md) to search for files in a repository. +### Supported markup languages and extensions + +GitLab supports a number of markup languages (sometimes called [lightweight +markup languages](https://en.wikipedia.org/wiki/Lightweight_markup_language)) +that you can use for the content of your files in a repository. They are mostly +used for documentation purposes. + +Just pick the right extension for your files and GitLab will render them +according to the markup language. + +| Markup language | Extensions | +| --------------- | ---------- | +| Plain text | `txt` | +| [Markdown](../../markdown.md) | `mdown`, `mkd`, `mkdn`, `md`, `markdown` | +| [reStructuredText](http://docutils.sourceforge.net/rst.html) | `rst` | +| [Asciidoc](https://asciidoctor.org/docs/what-is-asciidoc/) | `adoc`, `ad`, `asciidoc` | +| [Textile](https://txstyle.org/) | `textile` | +| [rdoc](http://rdoc.sourceforge.net/doc/index.html) | `rdoc` | +| [Orgmode](https://orgmode.org/) | `org` | +| [creole](http://www.wikicreole.org/) | `creole` | +| [Mediawiki](https://www.mediawiki.org/wiki/MediaWiki) | `wiki`, `mediawiki` | + ### Repository README and index files When a `README` or `index` file is present in a repository, its contents will be automatically pre-rendered by GitLab without opening it. -They can either be plain text or have an extension of a supported markup language: - -- Asciidoc: `README.adoc` or `index.adoc` -- Markdown: `README.md` or `index.md` -- reStructuredText: `README.rst` or `index.rst` -- Text: `README.txt` or `index.txt` +They can either be plain text or have an extension of a +[supported markup language](#supported-markup-languages-and-extensions): Some things to note about precedence: @@ -75,10 +93,6 @@ Some things to note about precedence: precedence over `README.md`, and `README.rst` will take precedence over `README`. -NOTE: **Note:** -`index` files without an extension will not automatically pre-render. You'll -have to explicitly open them to see their contents. - ### Jupyter Notebook files > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/2508) in GitLab 9.1 diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md index 084d1161633..d6754372816 100644 --- a/doc/user/project/settings/index.md +++ b/doc/user/project/settings/index.md @@ -18,6 +18,8 @@ Adjust your project's name, description, avatar, [default branch](../repository/ ![general project settings](img/general_settings.png) +The project description also partially supports [standard markdown](../../markdown.md#standard-markdown). You can use [emphasis](../../markdown.md#emphasis), [links](../../markdown.md#links), and [line-breaks](../../markdown.md#line-breaks) to add more context to the project description. + ### Sharing and permissions Set up your project's access, [visibility](../../../public_access/public_access.md), and enable [Container Registry](../container_registry.md) for your projects: diff --git a/doc/user/search/img/dashboard_links.png b/doc/user/search/img/dashboard_links.png Binary files differnew file mode 100644 index 00000000000..2c472c7e464 --- /dev/null +++ b/doc/user/search/img/dashboard_links.png diff --git a/doc/user/search/img/issues_assigned_to_you.png b/doc/user/search/img/issues_assigned_to_you.png Binary files differindex 36c670eedd5..d2fff5e9a67 100644 --- a/doc/user/search/img/issues_assigned_to_you.png +++ b/doc/user/search/img/issues_assigned_to_you.png diff --git a/doc/user/search/img/left_menu_bar.png b/doc/user/search/img/left_menu_bar.png Binary files differdeleted file mode 100644 index d68a71cba8e..00000000000 --- a/doc/user/search/img/left_menu_bar.png +++ /dev/null diff --git a/doc/user/search/index.md b/doc/user/search/index.md index 3f9d07dacaa..78c1294346b 100644 --- a/doc/user/search/index.md +++ b/doc/user/search/index.md @@ -2,27 +2,27 @@ ## Issues and merge requests -To search through issues and merge requests in multiple projects, you can use the left-sidebar. +To search through issues and merge requests in multiple projects, you can use the **Issues** or **Merge Requests** links +in the top-right part of your screen. -Click the menu bar, then **Issues** or **Merge Requests**, which work in the same way, -therefore, the following notes are valid for both. +Both of them work in the same way, therefore, the following notes are valid for both. The number displayed on their right represents the number of issues and merge requests assigned to you. -![menu bar - issues and MRs assigned to you](img/left_menu_bar.png) +![issues and MRs dashboard links](img/dashboard_links.png) When you click **Issues**, you'll see the opened issues assigned to you straight away: ![Issues assigned to you](img/issues_assigned_to_you.png) -You can filter them by **Author**, **Assignee**, **Milestone**, and **Labels**, -searching through **Open**, **Closed**, and **All** issues. +You can search through **Open**, **Closed**, or **All** issues. -Of course, you can combine all filters together. +You can also filter the results using the search and filter field. This works in the same way as the ones found in the +per project pages described below. ### Issues and MRs assigned to you or created by you -You'll find a shortcut to issues and merge requests create by you or assigned to you +You'll also find shortcuts to issues and merge requests created by you or assigned to you on the search field on the top-right of your screen: ![shortcut to your issues and mrs](img/issues_mrs_shortcut.png) diff --git a/doc/workflow/shortcuts.md b/doc/workflow/shortcuts.md index b2f1cbec204..7863dd8c242 100644 --- a/doc/workflow/shortcuts.md +++ b/doc/workflow/shortcuts.md @@ -93,4 +93,4 @@ You can see GitLab's keyboard shortcuts by using 'shift + ?' | Keyboard Shortcut | Description | | ----------------- | ----------- | -| <kbd>⌘</kbd> + <kbd>p</kbd> | Go to file | +| <kbd>Cmd</kbd>/<kbd>Ctrl</kbd> + <kbd>p</kbd> | Go to file | diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 3b8f3fedccf..337b92a6183 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -207,7 +207,7 @@ module API end desc 'Revert a commit in a branch' do - detail 'This feature was introduced in GitLab 11.6' + detail 'This feature was introduced in GitLab 11.5' success Entities::Commit end params do diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 61d57c643f0..5572e86985c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1263,7 +1263,11 @@ module API expose :token end - class ImpersonationToken < PersonalAccessTokenWithToken + class ImpersonationToken < PersonalAccessToken + expose :impersonation + end + + class ImpersonationTokenWithToken < PersonalAccessTokenWithToken expose :impersonation end diff --git a/lib/api/pipelines.rb b/lib/api/pipelines.rb index 1cfb982c04b..cba1e3a6684 100644 --- a/lib/api/pipelines.rb +++ b/lib/api/pipelines.rb @@ -81,6 +81,21 @@ module API present pipeline, with: Entities::Pipeline end + desc 'Deletes a pipeline' do + detail 'This feature was introduced in GitLab 11.6' + http_codes [[204, 'Pipeline was deleted'], [403, 'Forbidden']] + end + params do + requires :pipeline_id, type: Integer, desc: 'The pipeline ID' + end + delete ':id/pipelines/:pipeline_id' do + authorize! :destroy_pipeline, pipeline + + destroy_conditionally!(pipeline) do + ::Ci::DestroyPipelineService.new(user_project, current_user).execute(pipeline) + end + end + desc 'Retry builds in the pipeline' do detail 'This feature was introduced in GitLab 8.11.' success Entities::Pipeline diff --git a/lib/api/users.rb b/lib/api/users.rb index 2a56506f3a5..b41fce76df0 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -531,7 +531,7 @@ module API desc 'Create a impersonation token. Available only for admins.' do detail 'This feature was introduced in GitLab 9.0' - success Entities::ImpersonationToken + success Entities::ImpersonationTokenWithToken end params do requires :name, type: String, desc: 'The name of the impersonation token' @@ -542,7 +542,7 @@ module API impersonation_token = finder.build(declared_params(include_missing: false)) if impersonation_token.save - present impersonation_token, with: Entities::ImpersonationToken + present impersonation_token, with: Entities::ImpersonationTokenWithToken else render_validation_error!(impersonation_token) end diff --git a/lib/gitlab.rb b/lib/gitlab.rb index 2bb09684441..2ef54658a11 100644 --- a/lib/gitlab.rb +++ b/lib/gitlab.rb @@ -53,4 +53,8 @@ module Gitlab def self.pre_release? VERSION.include?('pre') end + + def self.version_info + Gitlab::VersionInfo.parse(Gitlab::VERSION) + end end diff --git a/lib/gitlab/checks/commit_check.rb b/lib/gitlab/checks/commit_check.rb index 6dd74e8fb74..58267b6752f 100644 --- a/lib/gitlab/checks/commit_check.rb +++ b/lib/gitlab/checks/commit_check.rb @@ -10,8 +10,8 @@ module Gitlab def initialize(project, user, newrev, oldrev) @project = project @user = user - @newrev = user - @oldrev = user + @newrev = newrev + @oldrev = oldrev @file_paths = [] end diff --git a/lib/gitlab/ci/build/policy/changes.rb b/lib/gitlab/ci/build/policy/changes.rb index 7bf51519752..1663c875426 100644 --- a/lib/gitlab/ci/build/policy/changes.rb +++ b/lib/gitlab/ci/build/policy/changes.rb @@ -14,7 +14,7 @@ module Gitlab pipeline.modified_paths.any? do |path| @globs.any? do |glob| - File.fnmatch?(glob, path, File::FNM_PATHNAME | File::FNM_DOTMATCH) + File.fnmatch?(glob, path, File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB) end end end diff --git a/lib/gitlab/ci/parsers/test/junit.rb b/lib/gitlab/ci/parsers/test/junit.rb index ed5a79d9b9b..2791730fd26 100644 --- a/lib/gitlab/ci/parsers/test/junit.rb +++ b/lib/gitlab/ci/parsers/test/junit.rb @@ -14,7 +14,7 @@ module Gitlab test_case = create_test_case(test_case) test_suite.add_test_case(test_case) end - rescue REXML::ParseException + rescue Nokogiri::XML::SyntaxError raise JunitParserError, "XML parsing failed" rescue raise JunitParserError, "JUnit parsing failed" diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml index ec949c290bd..c90976b2040 100644 --- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @@ -19,6 +19,15 @@ # * review: REVIEW_DISABLED # * stop_review: REVIEW_DISABLED # +# The sast and sast_dashboard jobs are executed to guarantee full compatibility +# with the group security dashboard and the security reports with old runners. +# If you use only runners with version 11.5 or above, you can disable the sast +# job by setting the OLD_REPORTS_DISABLED environment variable. If you use only +# runners with version below 11.5, you can disable the sast_dashboard job by +# setting the NEW_REPORTS_DISABLED environment variable. +# The sast_dashboard job will be removed in the future, when the sast job will +# use the new reports syntax. +# # In order to deploy, you must have a Kubernetes cluster configured either # via a project integration, or via group/project variables. # AUTO_DEVOPS_DOMAIN must also be set as a variable at the group or project @@ -27,7 +36,7 @@ # Continuous deployment to production is enabled by default. # If you want to deploy to staging first, set STAGING_ENABLED environment variable. # If you want to enable incremental rollout, either manual or time based, -# set INCREMENTAL_ROLLOUT_TYPE environment variable to "manual" or "timed". +# set INCREMENTAL_ROLLOUT_MODE environment variable to "manual" or "timed". # If you want to use canary deployments, set CANARY_ENABLED environment variable. # # If Auto DevOps fails to detect the proper buildpack, or if you want to @@ -149,10 +158,10 @@ performance: only: refs: - branches - kubernetes: active except: variables: - $PERFORMANCE_DISABLED + - $KUBECONFIG == null sast: stage: test @@ -173,6 +182,29 @@ sast: except: variables: - $SAST_DISABLED + - $OLD_REPORTS_DISABLED + +sast_dashboard: + stage: test + image: docker:stable + allow_failure: true + services: + - docker:stable-dind + script: + - setup_docker + - sast + artifacts: + reports: + sast: gl-sast-report.json + only: + refs: + - branches + variables: + - $GITLAB_FEATURES =~ /\bsast\b/ + except: + variables: + - $SAST_DISABLED + - $NEW_REPORTS_DISABLED dependency_scanning: stage: test @@ -227,7 +259,6 @@ dast: only: refs: - branches - kubernetes: active variables: - $GITLAB_FEATURES =~ /\bdast\b/ except: @@ -235,6 +266,7 @@ dast: - master variables: - $DAST_DISABLED + - $KUBECONFIG == null review: stage: review @@ -256,12 +288,12 @@ review: only: refs: - branches - kubernetes: active except: refs: - master variables: - $REVIEW_DISABLED + - $KUBECONFIG == null stop_review: stage: cleanup @@ -279,12 +311,12 @@ stop_review: only: refs: - branches - kubernetes: active except: refs: - master variables: - $REVIEW_DISABLED + - $KUBECONFIG == null # Staging deploys are disabled by default since # continuous deployment to production is enabled by default @@ -308,9 +340,11 @@ staging: only: refs: - master - kubernetes: active variables: - $STAGING_ENABLED + except: + variables: + - $KUBECONFIG == null # Canaries are also disabled by default, but if you want them, # and know what the downsides are, you can enable this by setting @@ -333,9 +367,11 @@ canary: only: refs: - master - kubernetes: active variables: - $CANARY_ENABLED + except: + variables: + - $KUBECONFIG == null .production: &production_template stage: production @@ -361,13 +397,13 @@ production: only: refs: - master - kubernetes: active except: variables: - $STAGING_ENABLED - $CANARY_ENABLED - $INCREMENTAL_ROLLOUT_ENABLED - $INCREMENTAL_ROLLOUT_MODE + - $KUBECONFIG == null production_manual: <<: *production_template @@ -376,7 +412,6 @@ production_manual: only: refs: - master - kubernetes: active variables: - $STAGING_ENABLED - $CANARY_ENABLED @@ -384,6 +419,7 @@ production_manual: variables: - $INCREMENTAL_ROLLOUT_ENABLED - $INCREMENTAL_ROLLOUT_MODE + - $KUBECONFIG == null # This job implements incremental rollout on for every push to `master`. @@ -413,13 +449,13 @@ production_manual: only: refs: - master - kubernetes: active variables: - $INCREMENTAL_ROLLOUT_MODE == "manual" - $INCREMENTAL_ROLLOUT_ENABLED except: variables: - $INCREMENTAL_ROLLOUT_MODE == "timed" + - $KUBECONFIG == null .timed_rollout_template: &timed_rollout_template <<: *rollout_template @@ -428,9 +464,11 @@ production_manual: only: refs: - master - kubernetes: active variables: - $INCREMENTAL_ROLLOUT_MODE == "timed" + except: + variables: + - $KUBECONFIG == null timed rollout 10%: <<: *timed_rollout_template diff --git a/lib/gitlab/ci/variables/collection/item.rb b/lib/gitlab/ci/variables/collection/item.rb index fdf852e8788..cf8958e34c2 100644 --- a/lib/gitlab/ci/variables/collection/item.rb +++ b/lib/gitlab/ci/variables/collection/item.rb @@ -6,8 +6,8 @@ module Gitlab class Collection class Item def initialize(key:, value:, public: true, file: false) - raise ArgumentError, "`value` must be of type String, while it was: #{value.class}" unless - value.is_a?(String) || value.nil? + raise ArgumentError, "`#{key}` must be of type String, while it was: #{value.class}" unless + value.is_a?(String) @variable = { key: key, value: value, public: public, file: file diff --git a/lib/gitlab/file_detector.rb b/lib/gitlab/file_detector.rb index d6338b09e3d..2770469ca9f 100644 --- a/lib/gitlab/file_detector.rb +++ b/lib/gitlab/file_detector.rb @@ -8,7 +8,7 @@ module Gitlab module FileDetector PATTERNS = { # Project files - readme: %r{\A(readme|index)[^/]*\z}i, + readme: /\A(#{Regexp.union(*Gitlab::MarkupHelper::PLAIN_FILENAMES).source})(\.(#{Regexp.union(*Gitlab::MarkupHelper::EXTENSIONS).source}))?\z/i, changelog: %r{\A(changelog|history|changes|news)[^/]*\z}i, license: %r{\A((un)?licen[sc]e|copying)(\.[^/]+)?\z}i, contributing: %r{\Acontributing[^/]*\z}i, diff --git a/lib/gitlab/fogbugz_import/client.rb b/lib/gitlab/fogbugz_import/client.rb index acb000e3e23..dd747a79673 100644 --- a/lib/gitlab/fogbugz_import/client.rb +++ b/lib/gitlab/fogbugz_import/client.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fogbugz' module Gitlab diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index 98ea5b309a1..431911d1eee 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module FogbugzImport class Importer diff --git a/lib/gitlab/fogbugz_import/project_creator.rb b/lib/gitlab/fogbugz_import/project_creator.rb index 1918d5b208d..3c71031a8d9 100644 --- a/lib/gitlab/fogbugz_import/project_creator.rb +++ b/lib/gitlab/fogbugz_import/project_creator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module FogbugzImport class ProjectCreator diff --git a/lib/gitlab/fogbugz_import/repository.rb b/lib/gitlab/fogbugz_import/repository.rb index d1dc63db2b2..b958dcf6cbf 100644 --- a/lib/gitlab/fogbugz_import/repository.rb +++ b/lib/gitlab/fogbugz_import/repository.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module FogbugzImport class Repository diff --git a/lib/gitlab/gfm/reference_rewriter.rb b/lib/gitlab/gfm/reference_rewriter.rb index 641446b52a5..08d7db49ad7 100644 --- a/lib/gitlab/gfm/reference_rewriter.rb +++ b/lib/gitlab/gfm/reference_rewriter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Gfm ## diff --git a/lib/gitlab/gfm/uploads_rewriter.rb b/lib/gitlab/gfm/uploads_rewriter.rb index b767c8a278d..3f06badf5d9 100644 --- a/lib/gitlab/gfm/uploads_rewriter.rb +++ b/lib/gitlab/gfm/uploads_rewriter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fileutils' module Gitlab diff --git a/lib/gitlab/git/attributes_at_ref_parser.rb b/lib/gitlab/git/attributes_at_ref_parser.rb index 26b5bd520d5..cbddf836ce8 100644 --- a/lib/gitlab/git/attributes_at_ref_parser.rb +++ b/lib/gitlab/git/attributes_at_ref_parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git # Parses root .gitattributes file at a given ref diff --git a/lib/gitlab/git/attributes_parser.rb b/lib/gitlab/git/attributes_parser.rb index 08f4d7d4f5c..8b9d74ae8e7 100644 --- a/lib/gitlab/git/attributes_parser.rb +++ b/lib/gitlab/git/attributes_parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git # Class for parsing Git attribute files and extracting the attributes for diff --git a/lib/gitlab/git/blame.rb b/lib/gitlab/git/blame.rb index e25e15f5c80..b118eda37f8 100644 --- a/lib/gitlab/git/blame.rb +++ b/lib/gitlab/git/blame.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class Blame diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb index 0bd1d3420a2..9dd1c484d59 100644 --- a/lib/gitlab/git/blob.rb +++ b/lib/gitlab/git/blob.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitaly note: JV: seems to be completely migrated (behind feature flags). module Gitlab diff --git a/lib/gitlab/git/branch.rb b/lib/gitlab/git/branch.rb index 6351cfb83e3..9447cfa0fb6 100644 --- a/lib/gitlab/git/branch.rb +++ b/lib/gitlab/git/branch.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class Branch < Ref diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 2820491b65d..4f05c4b73a1 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitlab::Git::Commit is a wrapper around Gitaly::GitCommit module Gitlab module Git diff --git a/lib/gitlab/git/commit_stats.rb b/lib/gitlab/git/commit_stats.rb index 83a9fd5f81a..8815088d23c 100644 --- a/lib/gitlab/git/commit_stats.rb +++ b/lib/gitlab/git/commit_stats.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitlab::Git::CommitStats counts the additions, deletions, and total changes # in a commit. module Gitlab diff --git a/lib/gitlab/git/compare.rb b/lib/gitlab/git/compare.rb index 7cb842256d0..ab5245ba7cb 100644 --- a/lib/gitlab/git/compare.rb +++ b/lib/gitlab/git/compare.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitaly note: JV: no RPC's here. module Gitlab diff --git a/lib/gitlab/git/conflict/file.rb b/lib/gitlab/git/conflict/file.rb index f08dab59ce4..7ffe4a7ae81 100644 --- a/lib/gitlab/git/conflict/file.rb +++ b/lib/gitlab/git/conflict/file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git module Conflict diff --git a/lib/gitlab/git/conflict/parser.rb b/lib/gitlab/git/conflict/parser.rb index fb5717dd556..20de8ebde4e 100644 --- a/lib/gitlab/git/conflict/parser.rb +++ b/lib/gitlab/git/conflict/parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git module Conflict diff --git a/lib/gitlab/git/conflict/resolution.rb b/lib/gitlab/git/conflict/resolution.rb index ab9be683e15..04299a2d10c 100644 --- a/lib/gitlab/git/conflict/resolution.rb +++ b/lib/gitlab/git/conflict/resolution.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git module Conflict diff --git a/lib/gitlab/git/conflict/resolver.rb b/lib/gitlab/git/conflict/resolver.rb index 307f1b8cb66..26e82643a4c 100644 --- a/lib/gitlab/git/conflict/resolver.rb +++ b/lib/gitlab/git/conflict/resolver.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git module Conflict diff --git a/lib/gitlab/git/diff.rb b/lib/gitlab/git/diff.rb index b2e2d49dd0b..74a4633424f 100644 --- a/lib/gitlab/git/diff.rb +++ b/lib/gitlab/git/diff.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class Diff diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb index 47ebca7c4a2..5c70cb6c66c 100644 --- a/lib/gitlab/git/diff_collection.rb +++ b/lib/gitlab/git/diff_collection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitaly note: JV: no RPC's here. module Gitlab diff --git a/lib/gitlab/git/gitmodules_parser.rb b/lib/gitlab/git/gitmodules_parser.rb index 4b505312f60..575e12390cd 100644 --- a/lib/gitlab/git/gitmodules_parser.rb +++ b/lib/gitlab/git/gitmodules_parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitaly note: JV: no RPC's here. module Gitlab diff --git a/lib/gitlab/git/hook_env.rb b/lib/gitlab/git/hook_env.rb index 620568d8817..892a069a3b7 100644 --- a/lib/gitlab/git/hook_env.rb +++ b/lib/gitlab/git/hook_env.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitaly note: JV: no RPC's here. module Gitlab diff --git a/lib/gitlab/git/index.rb b/lib/gitlab/git/index.rb index c2e4274e3ee..3b9b516308f 100644 --- a/lib/gitlab/git/index.rb +++ b/lib/gitlab/git/index.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class Index diff --git a/lib/gitlab/git/lfs_changes.rb b/lib/gitlab/git/lfs_changes.rb index d7148165408..8e2a925dfea 100644 --- a/lib/gitlab/git/lfs_changes.rb +++ b/lib/gitlab/git/lfs_changes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class LfsChanges diff --git a/lib/gitlab/git/lfs_pointer_file.rb b/lib/gitlab/git/lfs_pointer_file.rb index 2ae0a889590..b7019a221ac 100644 --- a/lib/gitlab/git/lfs_pointer_file.rb +++ b/lib/gitlab/git/lfs_pointer_file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class LfsPointerFile diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb index 0584629ac84..8797d3dce24 100644 --- a/lib/gitlab/git/operation_service.rb +++ b/lib/gitlab/git/operation_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class OperationService diff --git a/lib/gitlab/git/path_helper.rb b/lib/gitlab/git/path_helper.rb index 57b82a37d6c..e3a2031eeca 100644 --- a/lib/gitlab/git/path_helper.rb +++ b/lib/gitlab/git/path_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitaly note: JV: no RPC's here. module Gitlab diff --git a/lib/gitlab/git/pre_receive_error.rb b/lib/gitlab/git/pre_receive_error.rb index ac1ab7c39d5..03caace6fce 100644 --- a/lib/gitlab/git/pre_receive_error.rb +++ b/lib/gitlab/git/pre_receive_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git # diff --git a/lib/gitlab/git/raw_diff_change.rb b/lib/gitlab/git/raw_diff_change.rb index 98de9328071..e1002af40f6 100644 --- a/lib/gitlab/git/raw_diff_change.rb +++ b/lib/gitlab/git/raw_diff_change.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git # This class behaves like a struct with fields :blob_id, :blob_size, :operation, :old_path, :new_path diff --git a/lib/gitlab/git/ref.rb b/lib/gitlab/git/ref.rb index 31a280155bd..eec91194949 100644 --- a/lib/gitlab/git/ref.rb +++ b/lib/gitlab/git/ref.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class Ref diff --git a/lib/gitlab/git/remote_mirror.rb b/lib/gitlab/git/remote_mirror.rb index 7f9520de5ce..e992d522e7f 100644 --- a/lib/gitlab/git/remote_mirror.rb +++ b/lib/gitlab/git/remote_mirror.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class RemoteMirror diff --git a/lib/gitlab/git/remote_repository.rb b/lib/gitlab/git/remote_repository.rb index f40e59a8dd0..234541d8145 100644 --- a/lib/gitlab/git/remote_repository.rb +++ b/lib/gitlab/git/remote_repository.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git # diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 1642c4c5687..993955d1a6b 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'tempfile' require 'forwardable' require "rubygems/package" @@ -419,13 +421,17 @@ module Gitlab end def diff_stats(left_id, right_id) + if [left_id, right_id].any? { |ref| ref.blank? || Gitlab::Git.blank_ref?(ref) } + return empty_diff_stats + end + stats = wrapped_gitaly_errors do gitaly_commit_client.diff_stats(left_id, right_id) end Gitlab::Git::DiffStatsCollection.new(stats) rescue CommandError, TypeError - Gitlab::Git::DiffStatsCollection.new([]) + empty_diff_stats end # Returns a RefName for a given SHA @@ -962,6 +968,10 @@ module Gitlab private + def empty_diff_stats + Gitlab::Git::DiffStatsCollection.new([]) + end + def uncached_has_local_branches? wrapped_gitaly_errors do gitaly_repository_client.has_local_branches? diff --git a/lib/gitlab/git/repository_mirroring.rb b/lib/gitlab/git/repository_mirroring.rb index 752a91fbb60..7e63a6dc7cb 100644 --- a/lib/gitlab/git/repository_mirroring.rb +++ b/lib/gitlab/git/repository_mirroring.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git module RepositoryMirroring diff --git a/lib/gitlab/git/tag.rb b/lib/gitlab/git/tag.rb index bbf2ecdb1fa..ade708d0541 100644 --- a/lib/gitlab/git/tag.rb +++ b/lib/gitlab/git/tag.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class Tag < Ref diff --git a/lib/gitlab/git/tree.rb b/lib/gitlab/git/tree.rb index b5b701699f0..51542bcaaa2 100644 --- a/lib/gitlab/git/tree.rb +++ b/lib/gitlab/git/tree.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class Tree diff --git a/lib/gitlab/git/user.rb b/lib/gitlab/git/user.rb index 338e1a30c45..2c798844798 100644 --- a/lib/gitlab/git/user.rb +++ b/lib/gitlab/git/user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class User diff --git a/lib/gitlab/git/util.rb b/lib/gitlab/git/util.rb index 4708f22dcb3..03c2c1367b0 100644 --- a/lib/gitlab/git/util.rb +++ b/lib/gitlab/git/util.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Gitaly note: JV: no RPC's here. module Gitlab diff --git a/lib/gitlab/git/version.rb b/lib/gitlab/git/version.rb index 4bd91898457..64c89656167 100644 --- a/lib/gitlab/git/version.rb +++ b/lib/gitlab/git/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git module Version diff --git a/lib/gitlab/git/wiki.rb b/lib/gitlab/git/wiki.rb index 02c643d0da0..c43331bed60 100644 --- a/lib/gitlab/git/wiki.rb +++ b/lib/gitlab/git/wiki.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class Wiki diff --git a/lib/gitlab/git/wiki_file.rb b/lib/gitlab/git/wiki_file.rb index 64313bb04e8..c05a5adc00c 100644 --- a/lib/gitlab/git/wiki_file.rb +++ b/lib/gitlab/git/wiki_file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class WikiFile diff --git a/lib/gitlab/git/wiki_page.rb b/lib/gitlab/git/wiki_page.rb index c4087c9ebdc..f6cac398548 100644 --- a/lib/gitlab/git/wiki_page.rb +++ b/lib/gitlab/git/wiki_page.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class WikiPage diff --git a/lib/gitlab/git/wiki_page_version.rb b/lib/gitlab/git/wiki_page_version.rb index d5e7e70fd31..475a9d4d1b9 100644 --- a/lib/gitlab/git/wiki_page_version.rb +++ b/lib/gitlab/git/wiki_page_version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git class WikiPageVersion diff --git a/lib/gitlab/git/wraps_gitaly_errors.rb b/lib/gitlab/git/wraps_gitaly_errors.rb index 4b161f7e6ce..9963bcfbf1c 100644 --- a/lib/gitlab/git/wraps_gitaly_errors.rb +++ b/lib/gitlab/git/wraps_gitaly_errors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Git module WrapsGitalyErrors diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb index d99a9f15371..8b455dc7696 100644 --- a/lib/gitlab/gitaly_client.rb +++ b/lib/gitlab/gitaly_client.rb @@ -139,7 +139,7 @@ module Gitlab ensure duration = Gitlab::Metrics::System.monotonic_time - start - # Keep track, seperately, for the performance bar + # Keep track, separately, for the performance bar self.query_time += duration gitaly_controller_action_duration_seconds.observe( current_transaction_labels.merge(gitaly_service: service.to_s, rpc: rpc.to_s), diff --git a/lib/gitlab/gitaly_client/attributes_bag.rb b/lib/gitlab/gitaly_client/attributes_bag.rb index 198a1de91c7..3f1a0ef4888 100644 --- a/lib/gitlab/gitaly_client/attributes_bag.rb +++ b/lib/gitlab/gitaly_client/attributes_bag.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient # This module expects an `ATTRS` const to be defined on the subclass diff --git a/lib/gitlab/gitaly_client/blob_service.rb b/lib/gitlab/gitaly_client/blob_service.rb index 086ce31e678..39547328210 100644 --- a/lib/gitlab/gitaly_client/blob_service.rb +++ b/lib/gitlab/gitaly_client/blob_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class BlobService @@ -15,7 +17,7 @@ module Gitlab ) response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_blob, request, timeout: GitalyClient.fast_timeout) - data = '' + data = [] blob = nil response.each do |msg| if blob.nil? @@ -27,6 +29,8 @@ module Gitlab return nil if blob.oid.blank? + data = data.join + Gitlab::Git::Blob.new( id: blob.oid, size: blob.size, diff --git a/lib/gitlab/gitaly_client/blobs_stitcher.rb b/lib/gitlab/gitaly_client/blobs_stitcher.rb index 5ca592ff812..01bab854082 100644 --- a/lib/gitlab/gitaly_client/blobs_stitcher.rb +++ b/lib/gitlab/gitaly_client/blobs_stitcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class BlobsStitcher diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index 085b2a127a5..4e46cb9f05c 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class CommitService @@ -93,7 +95,7 @@ module Gitlab response = GitalyClient.call(@repository.storage, :commit_service, :tree_entry, request, timeout: GitalyClient.medium_timeout) entry = nil - data = '' + data = [] response.each do |msg| if entry.nil? entry = msg @@ -103,7 +105,7 @@ module Gitlab data << msg.data end - entry.data = data + entry.data = data.join entry unless entry.oid.blank? end @@ -254,7 +256,7 @@ module Gitlab ) response = GitalyClient.call(@repository.storage, :commit_service, :raw_blame, request, timeout: GitalyClient.medium_timeout) - response.reduce("") { |memo, msg| memo << msg.data } + response.reduce([]) { |memo, msg| memo << msg.data }.join end def find_commit(revision) @@ -345,8 +347,8 @@ module Gitlab request = Gitaly::ExtractCommitSignatureRequest.new(repository: @gitaly_repo, commit_id: commit_id) response = GitalyClient.call(@repository.storage, :commit_service, :extract_commit_signature, request) - signature = ''.b - signed_text = ''.b + signature = +''.b + signed_text = +''.b response.each do |message| signature << message.signature @@ -364,7 +366,7 @@ module Gitlab request = Gitaly::GetCommitSignaturesRequest.new(repository: @gitaly_repo, commit_ids: commit_ids) response = GitalyClient.call(@repository.storage, :commit_service, :get_commit_signatures, request, timeout: GitalyClient.fast_timeout) - signatures = Hash.new { |h, k| h[k] = [''.b, ''.b] } + signatures = Hash.new { |h, k| h[k] = [+''.b, +''.b] } current_commit_id = nil response.each do |message| @@ -383,7 +385,7 @@ module Gitlab request = Gitaly::GetCommitMessagesRequest.new(repository: @gitaly_repo, commit_ids: commit_ids) response = GitalyClient.call(@repository.storage, :commit_service, :get_commit_messages, request, timeout: GitalyClient.fast_timeout) - messages = Hash.new { |h, k| h[k] = ''.b } + messages = Hash.new { |h, k| h[k] = +''.b } current_commit_id = nil response.each do |rpc_message| diff --git a/lib/gitlab/gitaly_client/conflict_files_stitcher.rb b/lib/gitlab/gitaly_client/conflict_files_stitcher.rb index c275a065bce..0e00f6e8c44 100644 --- a/lib/gitlab/gitaly_client/conflict_files_stitcher.rb +++ b/lib/gitlab/gitaly_client/conflict_files_stitcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class ConflictFilesStitcher @@ -17,7 +19,7 @@ module Gitlab current_file = file_from_gitaly_header(gitaly_file.header) else - current_file.raw_content << gitaly_file.content + current_file.raw_content = "#{current_file.raw_content}#{gitaly_file.content}" end end end diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb index aa7e03301f5..6304f998563 100644 --- a/lib/gitlab/gitaly_client/conflicts_service.rb +++ b/lib/gitlab/gitaly_client/conflicts_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class ConflictsService diff --git a/lib/gitlab/gitaly_client/diff.rb b/lib/gitlab/gitaly_client/diff.rb index af9d674535b..dd192ccde1a 100644 --- a/lib/gitlab/gitaly_client/diff.rb +++ b/lib/gitlab/gitaly_client/diff.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class Diff diff --git a/lib/gitlab/gitaly_client/diff_stitcher.rb b/lib/gitlab/gitaly_client/diff_stitcher.rb index da243ee2d1a..98d327a7329 100644 --- a/lib/gitlab/gitaly_client/diff_stitcher.rb +++ b/lib/gitlab/gitaly_client/diff_stitcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class DiffStitcher @@ -20,7 +22,7 @@ module Gitlab current_diff = GitalyClient::Diff.new(diff_params) else - current_diff.patch += diff_msg.raw_patch_data + current_diff.patch = "#{current_diff.patch}#{diff_msg.raw_patch_data}" end if diff_msg.end_of_patch diff --git a/lib/gitlab/gitaly_client/health_check_service.rb b/lib/gitlab/gitaly_client/health_check_service.rb index 6c1213f5e20..0c495f60633 100644 --- a/lib/gitlab/gitaly_client/health_check_service.rb +++ b/lib/gitlab/gitaly_client/health_check_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class HealthCheckService diff --git a/lib/gitlab/gitaly_client/namespace_service.rb b/lib/gitlab/gitaly_client/namespace_service.rb index d4e982b649a..f0be3cbebd2 100644 --- a/lib/gitlab/gitaly_client/namespace_service.rb +++ b/lib/gitlab/gitaly_client/namespace_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class NamespaceService diff --git a/lib/gitlab/gitaly_client/notification_service.rb b/lib/gitlab/gitaly_client/notification_service.rb index 326e6f7dafc..873c3e4086d 100644 --- a/lib/gitlab/gitaly_client/notification_service.rb +++ b/lib/gitlab/gitaly_client/notification_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class NotificationService diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb index 4c78b790ce5..c32c2c0b2fb 100644 --- a/lib/gitlab/gitaly_client/operation_service.rb +++ b/lib/gitlab/gitaly_client/operation_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class OperationService diff --git a/lib/gitlab/gitaly_client/queue_enumerator.rb b/lib/gitlab/gitaly_client/queue_enumerator.rb index b8018029552..3a412102abe 100644 --- a/lib/gitlab/gitaly_client/queue_enumerator.rb +++ b/lib/gitlab/gitaly_client/queue_enumerator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class QueueEnumerator diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb index 8acc22e809e..d5633d167ac 100644 --- a/lib/gitlab/gitaly_client/ref_service.rb +++ b/lib/gitlab/gitaly_client/ref_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class RefService @@ -218,7 +220,7 @@ module Gitlab request = Gitaly::GetTagMessagesRequest.new(repository: @gitaly_repo, tag_ids: tag_ids) response = GitalyClient.call(@repository.storage, :ref_service, :get_tag_messages, request, timeout: GitalyClient.fast_timeout) - messages = Hash.new { |h, k| h[k] = ''.b } + messages = Hash.new { |h, k| h[k] = +''.b } current_tag_id = nil response.each do |rpc_message| diff --git a/lib/gitlab/gitaly_client/remote_service.rb b/lib/gitlab/gitaly_client/remote_service.rb index 4661448621b..24e8a5e16d3 100644 --- a/lib/gitlab/gitaly_client/remote_service.rb +++ b/lib/gitlab/gitaly_client/remote_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class RemoteService diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb index d7b36946b65..f968ebc2cbf 100644 --- a/lib/gitlab/gitaly_client/repository_service.rb +++ b/lib/gitlab/gitaly_client/repository_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class RepositoryService @@ -56,9 +58,9 @@ module Gitlab request = Gitaly::GetInfoAttributesRequest.new(repository: @gitaly_repo) response = GitalyClient.call(@storage, :repository_service, :get_info_attributes, request, timeout: GitalyClient.fast_timeout) - response.each_with_object("") do |message, attributes| + response.each_with_object([]) do |message, attributes| attributes << message.attributes - end + end.join end def fetch_remote(remote, ssh_auth:, forced:, no_tags:, timeout:, prune: true) diff --git a/lib/gitlab/gitaly_client/server_service.rb b/lib/gitlab/gitaly_client/server_service.rb index ad898278353..0ade6942db9 100644 --- a/lib/gitlab/gitaly_client/server_service.rb +++ b/lib/gitlab/gitaly_client/server_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient # Meant for extraction of server data, and later maybe to perform misc task diff --git a/lib/gitlab/gitaly_client/storage_service.rb b/lib/gitlab/gitaly_client/storage_service.rb index 3a26dd58ff4..4edcb0b8ba9 100644 --- a/lib/gitlab/gitaly_client/storage_service.rb +++ b/lib/gitlab/gitaly_client/storage_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class StorageService diff --git a/lib/gitlab/gitaly_client/storage_settings.rb b/lib/gitlab/gitaly_client/storage_settings.rb index 26d1f53f26c..754cccb6b3f 100644 --- a/lib/gitlab/gitaly_client/storage_settings.rb +++ b/lib/gitlab/gitaly_client/storage_settings.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient # This is a chokepoint that is meant to help us stop remove all places diff --git a/lib/gitlab/gitaly_client/util.rb b/lib/gitlab/gitaly_client/util.rb index 9c19c51d412..dce5d6a8ad0 100644 --- a/lib/gitlab/gitaly_client/util.rb +++ b/lib/gitlab/gitaly_client/util.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient module Util diff --git a/lib/gitlab/gitaly_client/wiki_file.rb b/lib/gitlab/gitaly_client/wiki_file.rb index 47c60c92484..ef2b23732d1 100644 --- a/lib/gitlab/gitaly_client/wiki_file.rb +++ b/lib/gitlab/gitaly_client/wiki_file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class WikiFile diff --git a/lib/gitlab/gitaly_client/wiki_page.rb b/lib/gitlab/gitaly_client/wiki_page.rb index a02d15db5dd..757a429fb8a 100644 --- a/lib/gitlab/gitaly_client/wiki_page.rb +++ b/lib/gitlab/gitaly_client/wiki_page.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitalyClient class WikiPage diff --git a/lib/gitlab/gitaly_client/wiki_service.rb b/lib/gitlab/gitaly_client/wiki_service.rb index 7c2c228ad01..2b3d622af4d 100644 --- a/lib/gitlab/gitaly_client/wiki_service.rb +++ b/lib/gitlab/gitaly_client/wiki_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'stringio' module Gitlab @@ -139,7 +141,7 @@ module Gitlab next unless message.name.present? || wiki_file if wiki_file - wiki_file.raw_data << message.raw_data + wiki_file.raw_data = "#{wiki_file.raw_data}#{message.raw_data}" else wiki_file = GitalyClient::WikiFile.new(message.to_h) # All gRPC strings in a response are frozen, so we get @@ -160,7 +162,7 @@ module Gitlab ) response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_get_formatted_data, request) - response.reduce("") { |memo, msg| memo << msg.data } + response.reduce([]) { |memo, msg| memo << msg.data }.join end private diff --git a/lib/gitlab/gitlab_import/client.rb b/lib/gitlab/gitlab_import/client.rb index 38ef12491df..86474159f8b 100644 --- a/lib/gitlab/gitlab_import/client.rb +++ b/lib/gitlab/gitlab_import/client.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitlabImport class Client diff --git a/lib/gitlab/gitlab_import/importer.rb b/lib/gitlab/gitlab_import/importer.rb index 047487f1d24..e84863deba8 100644 --- a/lib/gitlab/gitlab_import/importer.rb +++ b/lib/gitlab/gitlab_import/importer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitlabImport class Importer @@ -22,22 +24,22 @@ module Gitlab issues = client.issues(project_identifier) issues.each do |issue| - body = @formatter.author_line(issue["author"]["name"]) - body += issue["description"] + body = [@formatter.author_line(issue["author"]["name"])] + body << issue["description"] comments = client.issue_comments(project_identifier, issue["iid"]) if comments.any? - body += @formatter.comments_header + body << @formatter.comments_header end comments.each do |comment| - body += @formatter.comment(comment["author"]["name"], comment["created_at"], comment["body"]) + body << @formatter.comment(comment["author"]["name"], comment["created_at"], comment["body"]) end project.issues.create!( iid: issue["iid"], - description: body, + description: body.join, title: issue["title"], state: issue["state"], updated_at: issue["updated_at"], diff --git a/lib/gitlab/gitlab_import/project_creator.rb b/lib/gitlab/gitlab_import/project_creator.rb index 430b8c10058..35feea17351 100644 --- a/lib/gitlab/gitlab_import/project_creator.rb +++ b/lib/gitlab/gitlab_import/project_creator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GitlabImport class ProjectCreator diff --git a/lib/gitlab/google_code_import/client.rb b/lib/gitlab/google_code_import/client.rb index b1dbf554e41..52d714880b5 100644 --- a/lib/gitlab/google_code_import/client.rb +++ b/lib/gitlab/google_code_import/client.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GoogleCodeImport class Client diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb index 0c08c0fedaa..1e7203cb82a 100644 --- a/lib/gitlab/google_code_import/importer.rb +++ b/lib/gitlab/google_code_import/importer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GoogleCodeImport class Importer diff --git a/lib/gitlab/google_code_import/project_creator.rb b/lib/gitlab/google_code_import/project_creator.rb index 326cfcaa8af..eaef85acb98 100644 --- a/lib/gitlab/google_code_import/project_creator.rb +++ b/lib/gitlab/google_code_import/project_creator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GoogleCodeImport class ProjectCreator diff --git a/lib/gitlab/google_code_import/repository.rb b/lib/gitlab/google_code_import/repository.rb index ad33fc2cad2..19627c8cd35 100644 --- a/lib/gitlab/google_code_import/repository.rb +++ b/lib/gitlab/google_code_import/repository.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GoogleCodeImport class Repository diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 2bc081a6181..31bab20b044 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Gpg class Commit diff --git a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb index 6972bd685f7..d892d27a917 100644 --- a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb +++ b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Gpg class InvalidGpgSignatureUpdater diff --git a/lib/gitlab/grape_logging/formatters/lograge_with_timestamp.rb b/lib/gitlab/grape_logging/formatters/lograge_with_timestamp.rb index 41004408dec..9bb1e8fc7a2 100644 --- a/lib/gitlab/grape_logging/formatters/lograge_with_timestamp.rb +++ b/lib/gitlab/grape_logging/formatters/lograge_with_timestamp.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GrapeLogging module Formatters diff --git a/lib/gitlab/grape_logging/loggers/queue_duration_logger.rb b/lib/gitlab/grape_logging/loggers/queue_duration_logger.rb index 0adac79f25a..705e23adff2 100644 --- a/lib/gitlab/grape_logging/loggers/queue_duration_logger.rb +++ b/lib/gitlab/grape_logging/loggers/queue_duration_logger.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This grape_logging module (https://github.com/aserafin/grape_logging) makes it # possible to log how much time an API request was queued by Workhorse. module Gitlab diff --git a/lib/gitlab/grape_logging/loggers/user_logger.rb b/lib/gitlab/grape_logging/loggers/user_logger.rb index fa172861967..6caa6c715e7 100644 --- a/lib/gitlab/grape_logging/loggers/user_logger.rb +++ b/lib/gitlab/grape_logging/loggers/user_logger.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This grape_logging module (https://github.com/aserafin/grape_logging) makes it # possible to log the user who performed the Grape API action by retrieving # the user context from the request environment. diff --git a/lib/gitlab/graphql/authorize.rb b/lib/gitlab/graphql/authorize.rb index 93a903915b0..5e48bf9043d 100644 --- a/lib/gitlab/graphql/authorize.rb +++ b/lib/gitlab/graphql/authorize.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql # Allow fields to declare permissions their objects must have. The field diff --git a/lib/gitlab/graphql/authorize/authorize_resource.rb b/lib/gitlab/graphql/authorize/authorize_resource.rb index 40895686a8a..a56c4f6368d 100644 --- a/lib/gitlab/graphql/authorize/authorize_resource.rb +++ b/lib/gitlab/graphql/authorize/authorize_resource.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql module Authorize diff --git a/lib/gitlab/graphql/authorize/instrumentation.rb b/lib/gitlab/graphql/authorize/instrumentation.rb index 6cb8e617f62..d638d2b43ee 100644 --- a/lib/gitlab/graphql/authorize/instrumentation.rb +++ b/lib/gitlab/graphql/authorize/instrumentation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql module Authorize diff --git a/lib/gitlab/graphql/connections.rb b/lib/gitlab/graphql/connections.rb index 2582ffeb2a8..fbccdfa7b08 100644 --- a/lib/gitlab/graphql/connections.rb +++ b/lib/gitlab/graphql/connections.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql module Connections diff --git a/lib/gitlab/graphql/connections/keyset_connection.rb b/lib/gitlab/graphql/connections/keyset_connection.rb index 3c0d7e9784a..851054c0393 100644 --- a/lib/gitlab/graphql/connections/keyset_connection.rb +++ b/lib/gitlab/graphql/connections/keyset_connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql module Connections diff --git a/lib/gitlab/graphql/errors.rb b/lib/gitlab/graphql/errors.rb index f8c7ec24be1..fe74549e322 100644 --- a/lib/gitlab/graphql/errors.rb +++ b/lib/gitlab/graphql/errors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql module Errors diff --git a/lib/gitlab/graphql/expose_permissions.rb b/lib/gitlab/graphql/expose_permissions.rb index e3779995406..365b7cca24f 100644 --- a/lib/gitlab/graphql/expose_permissions.rb +++ b/lib/gitlab/graphql/expose_permissions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql module ExposePermissions diff --git a/lib/gitlab/graphql/present.rb b/lib/gitlab/graphql/present.rb index 2c7b64f1be9..7f69bf601d6 100644 --- a/lib/gitlab/graphql/present.rb +++ b/lib/gitlab/graphql/present.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql module Present diff --git a/lib/gitlab/graphql/present/instrumentation.rb b/lib/gitlab/graphql/present/instrumentation.rb index f87fd147b15..ab03c40c22d 100644 --- a/lib/gitlab/graphql/present/instrumentation.rb +++ b/lib/gitlab/graphql/present/instrumentation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql module Present diff --git a/lib/gitlab/graphql/variables.rb b/lib/gitlab/graphql/variables.rb index ffbaf65b512..b13ea37c21f 100644 --- a/lib/gitlab/graphql/variables.rb +++ b/lib/gitlab/graphql/variables.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphql class Variables diff --git a/lib/gitlab/graphs/commits.rb b/lib/gitlab/graphs/commits.rb index c4ffc19df09..66e1b2e78b4 100644 --- a/lib/gitlab/graphs/commits.rb +++ b/lib/gitlab/graphs/commits.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module Graphs class Commits diff --git a/lib/gitlab/hashed_storage/migrator.rb b/lib/gitlab/hashed_storage/migrator.rb index 4edc251facb..1f29cf10cad 100644 --- a/lib/gitlab/hashed_storage/migrator.rb +++ b/lib/gitlab/hashed_storage/migrator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HashedStorage # Hashed Storage Migrator diff --git a/lib/gitlab/hashed_storage/rake_helper.rb b/lib/gitlab/hashed_storage/rake_helper.rb index 22edd5f999d..38f552fab03 100644 --- a/lib/gitlab/hashed_storage/rake_helper.rb +++ b/lib/gitlab/hashed_storage/rake_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HashedStorage module RakeHelper diff --git a/lib/gitlab/health_checks/base_abstract_check.rb b/lib/gitlab/health_checks/base_abstract_check.rb index 8b365dab185..1d31f59999c 100644 --- a/lib/gitlab/health_checks/base_abstract_check.rb +++ b/lib/gitlab/health_checks/base_abstract_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks module BaseAbstractCheck diff --git a/lib/gitlab/health_checks/db_check.rb b/lib/gitlab/health_checks/db_check.rb index 08495c0a59e..2bcd25cd3cc 100644 --- a/lib/gitlab/health_checks/db_check.rb +++ b/lib/gitlab/health_checks/db_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks class DbCheck diff --git a/lib/gitlab/health_checks/gitaly_check.rb b/lib/gitlab/health_checks/gitaly_check.rb index 1f623e0b6ec..898733fea5d 100644 --- a/lib/gitlab/health_checks/gitaly_check.rb +++ b/lib/gitlab/health_checks/gitaly_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks class GitalyCheck diff --git a/lib/gitlab/health_checks/metric.rb b/lib/gitlab/health_checks/metric.rb index d62d9136886..62a5216d159 100644 --- a/lib/gitlab/health_checks/metric.rb +++ b/lib/gitlab/health_checks/metric.rb @@ -1,3 +1,6 @@ -module Gitlab::HealthChecks # rubocop:disable Naming/FileName +# rubocop:disable Naming/FileName +# frozen_string_literal: true + +module Gitlab::HealthChecks Metric = Struct.new(:name, :value, :labels) end diff --git a/lib/gitlab/health_checks/prometheus_text_format.rb b/lib/gitlab/health_checks/prometheus_text_format.rb index b3c759b4730..2a8f9d31cd5 100644 --- a/lib/gitlab/health_checks/prometheus_text_format.rb +++ b/lib/gitlab/health_checks/prometheus_text_format.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks class PrometheusTextFormat diff --git a/lib/gitlab/health_checks/redis/cache_check.rb b/lib/gitlab/health_checks/redis/cache_check.rb index 2f6c4db12bb..0c8fe83893b 100644 --- a/lib/gitlab/health_checks/redis/cache_check.rb +++ b/lib/gitlab/health_checks/redis/cache_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks module Redis diff --git a/lib/gitlab/health_checks/redis/queues_check.rb b/lib/gitlab/health_checks/redis/queues_check.rb index 63d2882c5b2..b1e33b9f459 100644 --- a/lib/gitlab/health_checks/redis/queues_check.rb +++ b/lib/gitlab/health_checks/redis/queues_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks module Redis diff --git a/lib/gitlab/health_checks/redis/redis_check.rb b/lib/gitlab/health_checks/redis/redis_check.rb index 8ceb0a0aa46..f7e46fce134 100644 --- a/lib/gitlab/health_checks/redis/redis_check.rb +++ b/lib/gitlab/health_checks/redis/redis_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks module Redis diff --git a/lib/gitlab/health_checks/redis/shared_state_check.rb b/lib/gitlab/health_checks/redis/shared_state_check.rb index f1ea1ffe1be..285ac271929 100644 --- a/lib/gitlab/health_checks/redis/shared_state_check.rb +++ b/lib/gitlab/health_checks/redis/shared_state_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks module Redis diff --git a/lib/gitlab/health_checks/result.rb b/lib/gitlab/health_checks/result.rb index e323e2c9723..d32a6980eb8 100644 --- a/lib/gitlab/health_checks/result.rb +++ b/lib/gitlab/health_checks/result.rb @@ -1,3 +1,6 @@ -module Gitlab::HealthChecks # rubocop:disable Naming/FileName +# rubocop:disable Naming/FileName +# frozen_string_literal: true + +module Gitlab::HealthChecks Result = Struct.new(:success, :message, :labels) end diff --git a/lib/gitlab/health_checks/simple_abstract_check.rb b/lib/gitlab/health_checks/simple_abstract_check.rb index 96945ce5b20..3588260d6eb 100644 --- a/lib/gitlab/health_checks/simple_abstract_check.rb +++ b/lib/gitlab/health_checks/simple_abstract_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module HealthChecks module SimpleAbstractCheck diff --git a/lib/gitlab/http_io.rb b/lib/gitlab/http_io.rb index 9d7763fc5ac..e768b8adb12 100644 --- a/lib/gitlab/http_io.rb +++ b/lib/gitlab/http_io.rb @@ -161,14 +161,14 @@ module Gitlab ## # Note: If provider does not return content_range, then we set it as we requested # Provider: minio - # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 - # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 + # - When the file size is larger than requested Content-range, the Content-range is included in responses with Net::HTTPPartialContent 206 + # - When the file size is smaller than requested Content-range, the Content-range is included in responses with Net::HTTPPartialContent 206 # Provider: AWS - # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 - # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 + # - When the file size is larger than requested Content-range, the Content-range is included in responses with Net::HTTPPartialContent 206 + # - When the file size is smaller than requested Content-range, the Content-range is included in responses with Net::HTTPPartialContent 206 # Provider: GCS - # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 - # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPOK 200 + # - When the file size is larger than requested Content-range, the Content-range is included in responses with Net::HTTPPartialContent 206 + # - When the file size is smaller than requested Content-range, the Content-range is included in responses with Net::HTTPOK 200 @chunk_range ||= (chunk_start...(chunk_start + @chunk.bytesize)) end diff --git a/lib/gitlab/kubernetes/helm.rb b/lib/gitlab/kubernetes/helm.rb index 1cd4f9e17b7..5a22b5e3364 100644 --- a/lib/gitlab/kubernetes/helm.rb +++ b/lib/gitlab/kubernetes/helm.rb @@ -1,7 +1,7 @@ module Gitlab module Kubernetes module Helm - HELM_VERSION = '2.7.2'.freeze + HELM_VERSION = '2.11.0'.freeze KUBECTL_VERSION = '1.11.0'.freeze NAMESPACE = 'gitlab-managed-apps'.freeze SERVICE_ACCOUNT = 'tiller'.freeze diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb index 06841ec7b76..7c026ac9e68 100644 --- a/lib/gitlab/kubernetes/helm/api.rb +++ b/lib/gitlab/kubernetes/helm/api.rb @@ -54,7 +54,11 @@ module Gitlab def create_config_map(command) command.config_map_resource.tap do |config_map_resource| - kubeclient.create_config_map(config_map_resource) + if config_map_exists?(config_map_resource) + kubeclient.update_config_map(config_map_resource) + else + kubeclient.create_config_map(config_map_resource) + end end end @@ -88,6 +92,12 @@ module Gitlab end end + def config_map_exists?(resource) + kubeclient.get_config_map(resource.metadata.name, resource.metadata.namespace) + rescue ::Kubeclient::ResourceNotFoundError + false + end + def service_account_exists?(resource) kubeclient.get_service_account(resource.metadata.name, resource.metadata.namespace) rescue ::Kubeclient::ResourceNotFoundError diff --git a/lib/gitlab/kubernetes/helm/client_command.rb b/lib/gitlab/kubernetes/helm/client_command.rb new file mode 100644 index 00000000000..72bafc07bf0 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/client_command.rb @@ -0,0 +1,26 @@ +module Gitlab + module Kubernetes + module Helm + module ClientCommand + def init_command + # Here we are always upgrading to the latest version of Tiller when + # installing an app. We ensure the helm version stored in the + # database is correct by also updating this after transition to + # :installed,:updated in Clusters::Concerns::ApplicationStatus + 'helm init --upgrade' + end + + def wait_for_tiller_command + # This is necessary to give Tiller time to restart after upgrade. + # Ideally we'd be able to use --wait but cannot because of + # https://github.com/helm/helm/issues/4855 + 'for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done' + end + + def repository_command + ['helm', 'repo', 'add', name, repository].shelljoin if repository + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb index 70e4ea08916..7aa258dd037 100644 --- a/lib/gitlab/kubernetes/helm/install_command.rb +++ b/lib/gitlab/kubernetes/helm/install_command.rb @@ -3,6 +3,7 @@ module Gitlab module Helm class InstallCommand include BaseCommand + include ClientCommand attr_reader :name, :files, :chart, :version, :repository, :preinstall, :postinstall @@ -20,6 +21,7 @@ module Gitlab def generate_script super + [ init_command, + wait_for_tiller_command, repository_command, repository_update_command, preinstall_command, @@ -34,14 +36,6 @@ module Gitlab private - def init_command - 'helm init --client-only' - end - - def repository_command - ['helm', 'repo', 'add', name, repository].shelljoin if repository - end - def repository_update_command 'helm repo update' if repository end diff --git a/lib/gitlab/kubernetes/helm/upgrade_command.rb b/lib/gitlab/kubernetes/helm/upgrade_command.rb index b36315f7a82..9daffc138b5 100644 --- a/lib/gitlab/kubernetes/helm/upgrade_command.rb +++ b/lib/gitlab/kubernetes/helm/upgrade_command.rb @@ -5,6 +5,7 @@ module Gitlab module Helm class UpgradeCommand include BaseCommand + include ClientCommand attr_reader :name, :chart, :version, :repository, :files @@ -20,6 +21,7 @@ module Gitlab def generate_script super + [ init_command, + wait_for_tiller_command, repository_command, script_command ].compact.join("\n") @@ -35,14 +37,6 @@ module Gitlab private - def init_command - 'helm init --client-only' - end - - def repository_command - "helm repo add #{name} #{repository}" if repository - end - def script_command upgrade_flags = "#{optional_version_flag}#{optional_tls_flags}" \ " --reset-values" \ diff --git a/lib/gitlab/kubernetes/kube_client.rb b/lib/gitlab/kubernetes/kube_client.rb index f266177bec1..b947f6b551e 100644 --- a/lib/gitlab/kubernetes/kube_client.rb +++ b/lib/gitlab/kubernetes/kube_client.rb @@ -16,7 +16,8 @@ module Gitlab SUPPORTED_API_GROUPS = { core: { group: 'api', version: 'v1' }, rbac: { group: 'apis/rbac.authorization.k8s.io', version: 'v1' }, - extensions: { group: 'apis/extensions', version: 'v1beta1' } + extensions: { group: 'apis/extensions', version: 'v1beta1' }, + knative: { group: 'apis/serving.knative.dev', version: 'v1alpha1' } }.freeze SUPPORTED_API_GROUPS.each do |name, params| diff --git a/lib/gitlab/private_commit_email.rb b/lib/gitlab/private_commit_email.rb index bade2248ccd..536fc9dae3a 100644 --- a/lib/gitlab/private_commit_email.rb +++ b/lib/gitlab/private_commit_email.rb @@ -18,6 +18,10 @@ module Gitlab match[:id].to_i end + def user_ids_for_emails(emails) + emails.map { |email| user_id_for_email(email) }.compact.uniq + end + def for_user(user) hostname = Gitlab::CurrentSettings.current_application_settings.commit_email_hostname diff --git a/lib/gitlab/sentry.rb b/lib/gitlab/sentry.rb index 24e3866128b..8079c5882c4 100644 --- a/lib/gitlab/sentry.rb +++ b/lib/gitlab/sentry.rb @@ -7,7 +7,7 @@ module Gitlab end def self.context(current_user = nil) - return unless self.enabled? + return unless enabled? Raven.tags_context(locale: I18n.locale) @@ -29,14 +29,22 @@ module Gitlab # # Provide an issue URL for follow up. def self.track_exception(exception, issue_url: nil, extra: {}) + track_acceptable_exception(exception, issue_url: issue_url, extra: extra) + + raise exception if should_raise? + end + + # This should be used when you do not want to raise an exception in + # development and test. If you need development and test to behave + # just the same as production you can use this instead of + # track_exception. + def self.track_acceptable_exception(exception, issue_url: nil, extra: {}) if enabled? extra[:issue_url] = issue_url if issue_url context # Make sure we've set everything we know in the context Raven.capture_exception(exception, extra: extra) end - - raise exception if should_raise? end def self.program_context diff --git a/lib/gitlab/view/presenter/base.rb b/lib/gitlab/view/presenter/base.rb index 36162faa1eb..c3fd6d317aa 100644 --- a/lib/gitlab/view/presenter/base.rb +++ b/lib/gitlab/view/presenter/base.rb @@ -11,8 +11,8 @@ module Gitlab attr_reader :subject - def can?(user, action, overriden_subject = nil) - super(user, action, overriden_subject || subject) + def can?(user, action, overridden_subject = nil) + super(user, action, overridden_subject || subject) end # delegate all #can? queries to the subject diff --git a/locale/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po index 903d72d9ea8..4a2b56f2806 100644 --- a/locale/ar_SA/gitlab.po +++ b/locale/ar_SA/gitlab.po @@ -681,7 +681,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2913,7 +2913,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po index e3a5e191023..6c6eeeb6580 100644 --- a/locale/bg/gitlab.po +++ b/locale/bg/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po index 91d5fb17000..a957023bb25 100644 --- a/locale/ca_ES/gitlab.po +++ b/locale/ca_ES/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po index 867b9b27ad2..9801999299f 100644 --- a/locale/cs_CZ/gitlab.po +++ b/locale/cs_CZ/gitlab.po @@ -621,7 +621,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2845,7 +2845,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po index f8412f28cbe..9c7b37f7f18 100644 --- a/locale/da_DK/gitlab.po +++ b/locale/da_DK/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po index 5f9fbc1cc39..07568765abb 100644 --- a/locale/de/gitlab.po +++ b/locale/de/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po index 15d537ff3b4..84ef902d5e1 100644 --- a/locale/eo/gitlab.po +++ b/locale/eo/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po index 0d8ee05b364..32e495695c6 100644 --- a/locale/es/gitlab.po +++ b/locale/es/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po index 1f699a8e06d..bc6b3b67d42 100644 --- a/locale/et_EE/gitlab.po +++ b/locale/et_EE/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po index c9b371f8df3..ecbf47aa928 100644 --- a/locale/fil_PH/gitlab.po +++ b/locale/fil_PH/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po index 1925235d48a..6e89ec73142 100644 --- a/locale/fr/gitlab.po +++ b/locale/fr/gitlab.po @@ -561,7 +561,7 @@ msgstr "Une erreur est survenue lors de la création de la nouvelle branche." msgid "An error occured whilst fetching the job trace." msgstr "Une erreur est survenue pendant le rapatriement de la trace de la tâche." -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "Une erreur est survenue lors du rapatriement de dernier pipeline." msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "Modifier l’identité de %{user_name}" msgid "Elasticsearch" msgstr "Elasticsearch" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "Intégration d’Elasticsearch. AWS Elasticsearch IAM." msgid "Email" diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d3e1a51370e..f18821adb5f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -501,7 +501,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po index 44c47901b56..5e2dbce1104 100644 --- a/locale/gl_ES/gitlab.po +++ b/locale/gl_ES/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po index 7cff1c5d712..9aadf885770 100644 --- a/locale/he_IL/gitlab.po +++ b/locale/he_IL/gitlab.po @@ -621,7 +621,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2845,7 +2845,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po index 2f3c35e4253..641886e65b0 100644 --- a/locale/id_ID/gitlab.po +++ b/locale/id_ID/gitlab.po @@ -531,7 +531,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2743,7 +2743,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po index 984a200c958..3b43d563dc5 100644 --- a/locale/it/gitlab.po +++ b/locale/it/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po index ac940230ac2..a254bfba027 100644 --- a/locale/ja/gitlab.po +++ b/locale/ja/gitlab.po @@ -531,7 +531,7 @@ msgstr "新しいブランチの作成中にエラーが発生しました。" msgid "An error occured whilst fetching the job trace." msgstr "ジョブトレースの取得中にエラーが発生しました。" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "最新のパイプラインの取得中にエラーが発生しました。" msgid "An error occured whilst loading all the files." @@ -2743,7 +2743,7 @@ msgstr "%{user_name} の ID を編集する" msgid "Elasticsearch" msgstr "Elasticsearch" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "Elasticsearch の統合。Elasticsearch AWS IAM。" msgid "Email" diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po index a50f5bfacef..daced0494cb 100644 --- a/locale/ko/gitlab.po +++ b/locale/ko/gitlab.po @@ -531,7 +531,7 @@ msgstr "새 브랜치를 만드는 동안 오류가 발생했습니다." msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2743,7 +2743,7 @@ msgstr "" msgid "Elasticsearch" msgstr "Elasticsearch" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/mn_MN/gitlab.po b/locale/mn_MN/gitlab.po index c256a2d2b1f..cf2c7224171 100644 --- a/locale/mn_MN/gitlab.po +++ b/locale/mn_MN/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/nb_NO/gitlab.po b/locale/nb_NO/gitlab.po index 9be8a4e8d0b..df490378e9c 100644 --- a/locale/nb_NO/gitlab.po +++ b/locale/nb_NO/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po index 2ad2eaafc33..8f9c3161a26 100644 --- a/locale/nl_NL/gitlab.po +++ b/locale/nl_NL/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po index a4bd1fe747b..ebe5ee77d71 100644 --- a/locale/pl_PL/gitlab.po +++ b/locale/pl_PL/gitlab.po @@ -621,7 +621,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2845,7 +2845,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po index 79e365319c9..39aa1256e4b 100644 --- a/locale/pt_BR/gitlab.po +++ b/locale/pt_BR/gitlab.po @@ -561,7 +561,7 @@ msgstr "Um erro ocorreu ao criar o novo branch." msgid "An error occured whilst fetching the job trace." msgstr "Ocorreu um erro ao carregar o rastro da tarefa." -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "Ocorreu um erro ao carregar o último pipeline." msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "Editar identidade para %{user_name}" msgid "Elasticsearch" msgstr "Elasticsearch" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "Integração com Elasticsearch. Elasticsearch AWS IAM." msgid "Email" diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po index 49613a3f462..a6b70d486fb 100644 --- a/locale/ro_RO/gitlab.po +++ b/locale/ro_RO/gitlab.po @@ -591,7 +591,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2811,7 +2811,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po index b8a4805498b..739f96cba9a 100644 --- a/locale/ru/gitlab.po +++ b/locale/ru/gitlab.po @@ -621,7 +621,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2845,7 +2845,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po index 633b2a6bda7..75df8a29e6b 100644 --- a/locale/sq_AL/gitlab.po +++ b/locale/sq_AL/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po index 723f4876053..1a8d2faf307 100644 --- a/locale/tr_TR/gitlab.po +++ b/locale/tr_TR/gitlab.po @@ -561,7 +561,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2777,7 +2777,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po index 99ba26152ee..30f1b5769d6 100644 --- a/locale/uk/gitlab.po +++ b/locale/uk/gitlab.po @@ -621,7 +621,7 @@ msgstr "Помилка при створенні нової гілки." msgid "An error occured whilst fetching the job trace." msgstr "Трапилася помилка при отриманні логу завдання." -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "Трапилася помилка при отриманні даних останнього конвеєра." msgid "An error occured whilst loading all the files." @@ -2845,7 +2845,7 @@ msgstr "Редагувати ідентифікацію для %{user_name}" msgid "Elasticsearch" msgstr "Elasticsearch" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "Інтеграція з Elasticsearch. Elasticsearch AWS IAM." msgid "Email" diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po index 2d3aeca7cc7..19fa17eaff1 100644 --- a/locale/zh_CN/gitlab.po +++ b/locale/zh_CN/gitlab.po @@ -531,7 +531,7 @@ msgstr "创建分支时发生错误。" msgid "An error occured whilst fetching the job trace." msgstr "获取作业日志时发生错误。" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "获取流水线时发生错误。" msgid "An error occured whilst loading all the files." @@ -2743,7 +2743,7 @@ msgstr "编辑 %{user_name} 的身份信息" msgid "Elasticsearch" msgstr "Elasticsearch" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "Elasticsearch集成及Elasticsearch AWS IAM。" msgid "Email" diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po index d8fe2d5b13e..6987f307dbb 100644 --- a/locale/zh_HK/gitlab.po +++ b/locale/zh_HK/gitlab.po @@ -531,7 +531,7 @@ msgstr "" msgid "An error occured whilst fetching the job trace." msgstr "" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "" msgid "An error occured whilst loading all the files." @@ -2743,7 +2743,7 @@ msgstr "" msgid "Elasticsearch" msgstr "" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "" msgid "Email" diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po index 1bccf6de738..4e0b07e717f 100644 --- a/locale/zh_TW/gitlab.po +++ b/locale/zh_TW/gitlab.po @@ -531,7 +531,7 @@ msgstr "創建新分支時發生錯誤。" msgid "An error occured whilst fetching the job trace." msgstr "取得工作追蹤資訊時發生錯誤" -msgid "An error occured whilst fetching the latest pipline." +msgid "An error occured whilst fetching the latest pipeline." msgstr "取得最新流水線時發生錯誤" msgid "An error occured whilst loading all the files." @@ -2743,7 +2743,7 @@ msgstr "編輯 %{user_name} 的身份" msgid "Elasticsearch" msgstr "Elasticsearch" -msgid "Elasticsearch intergration. Elasticsearch AWS IAM." +msgid "Elasticsearch integration. Elasticsearch AWS IAM." msgstr "Elasticsearch 整合。 Elasticsearch AWS IAM。" msgid "Email" diff --git a/package.json b/package.json index 2d6479fea3f..ac4b4672c86 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-syntax-import-meta": "^7.0.0", "@babel/preset-env": "^7.1.0", - "@gitlab-org/gitlab-ui": "^1.10.0", - "@gitlab/svgs": "^1.35.0", + "@gitlab/svgs": "^1.38.0", + "@gitlab/ui": "^1.11.0", "autosize": "^4.0.0", "axios": "^0.17.1", "babel-loader": "^8.0.4", diff --git a/qa/qa/page/profile/personal_access_tokens.rb b/qa/qa/page/profile/personal_access_tokens.rb index 2f0202951bb..9191dbe9cf3 100644 --- a/qa/qa/page/profile/personal_access_tokens.rb +++ b/qa/qa/page/profile/personal_access_tokens.rb @@ -8,7 +8,7 @@ module QA element :scopes_api_radios, "label :scopes" # rubocop:disable QA/ElementWithPattern end - view 'app/views/profiles/personal_access_tokens/index.html.haml' do + view 'app/views/shared/_personal_access_tokens_created_container.html.haml' do element :create_token_field, "text_field_tag 'created-personal-access-token'" # rubocop:disable QA/ElementWithPattern end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb index bc88e6450f5..135925c007f 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb @@ -10,7 +10,7 @@ module QA let(:key_title) { "key for ssh tests #{Time.now.to_f}" } let(:ssh_key) do - Factory::Resource::SSHKey.fabricate! do |resource| + Resource::SSHKey.fabricate! do |resource| resource.title = key_title end end @@ -38,7 +38,7 @@ module QA it 'user pushes to the repository' do # Create a project to push to - project = Factory::Resource::Project.fabricate! do |project| + project = Resource::Project.fabricate! do |project| project.name = 'git-protocol-project' end diff --git a/scripts/build_assets_image b/scripts/build_assets_image index 1d77524d503..4e5ef977161 100755 --- a/scripts/build_assets_image +++ b/scripts/build_assets_image @@ -1,5 +1,11 @@ #!/bin/bash +# Exit early if we don't want to build the image +if [[ "${BUILD_ASSETS_IMAGE}" != "true" ]] +then + exit 0 +fi + # Generate the image name based on the project this is being run in ASSETS_IMAGE_NAME=$(echo ${CI_PROJECT_NAME} | awk '{ diff --git a/scripts/rails4-gemfile-lock-check b/scripts/rails4-gemfile-lock-check new file mode 100755 index 00000000000..a74a49874e1 --- /dev/null +++ b/scripts/rails4-gemfile-lock-check @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +echo -e "=> Checking if Gemfile.rails4.lock is up-to-date...\\n" + +cp Gemfile.rails4.lock Gemfile.rails4.lock.orig +BUNDLE_GEMFILE=Gemfile.rails4 bundle install "$BUNDLE_INSTALL_FLAGS" +diff -u Gemfile.rails4.lock.orig Gemfile.rails4.lock >/dev/null 2>&1 + +if [ $? == 1 ] +then + diff -u Gemfile.rails4.lock.orig Gemfile.rails4.lock + + echo -e "\\n✖ ERROR: Gemfile.rails4.lock is not up-to-date! + Please run 'BUNDLE_GEMFILE=Gemfile.rails4 bundle install'\\n" >&2 + exit 1 +fi + +echo "✔ Gemfile.rails4.lock is up-to-date" +exit 0 diff --git a/scripts/rails5-gemfile-lock-check b/scripts/rails5-gemfile-lock-check deleted file mode 100755 index da6f1b7145e..00000000000 --- a/scripts/rails5-gemfile-lock-check +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -echo -e "=> Checking if Gemfile.rails5.lock is up-to-date...\\n" - -cp Gemfile.rails5.lock Gemfile.rails5.lock.orig -BUNDLE_GEMFILE=Gemfile.rails5 bundle install "$BUNDLE_INSTALL_FLAGS" -diff -u Gemfile.rails5.lock.orig Gemfile.rails5.lock >/dev/null 2>&1 - -if [ $? == 1 ] -then - diff -u Gemfile.rails5.lock.orig Gemfile.rails5.lock - - echo -e "\\n✖ ERROR: Gemfile.rails5.lock is not up-to-date! - Please run 'BUNDLE_GEMFILE=Gemfile.rails5 bundle install'\\n" >&2 - exit 1 -fi - -echo "✔ Gemfile.rails5.lock is up-to-date" -exit 0 diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 4e91068ab88..efc3ce74627 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -650,7 +650,7 @@ describe ApplicationController do describe '#access_denied' do controller(described_class) do def index - access_denied!(params[:message]) + access_denied!(params[:message], params[:status]) end end @@ -669,6 +669,12 @@ describe ApplicationController do expect(response).to have_gitlab_http_status(403) end + + it 'renders a status passed to access denied' do + get :index, status: 401 + + expect(response).to have_gitlab_http_status(401) + end end context 'when invalid UTF-8 parameters are received' do diff --git a/spec/controllers/concerns/issuable_collections_spec.rb b/spec/controllers/concerns/issuable_collections_spec.rb index d16a3464495..e93c923fd39 100644 --- a/spec/controllers/concerns/issuable_collections_spec.rb +++ b/spec/controllers/concerns/issuable_collections_spec.rb @@ -60,7 +60,7 @@ describe IssuableCollections do end end - describe '#filter_params' do + describe '#finder_options' do let(:params) do { assignee_id: '1', @@ -84,25 +84,20 @@ describe IssuableCollections do } end - it 'filters params' do + it 'only allows whitelisted params' do allow(controller).to receive(:cookies).and_return({}) - filtered_params = controller.send(:filter_params) + finder_options = controller.send(:finder_options) - expect(filtered_params).to eq({ + expect(finder_options).to eq({ 'assignee_id' => '1', 'assignee_username' => 'user1', 'author_id' => '2', 'author_username' => 'user2', - 'authorized_only' => 'true', - 'due_date' => '2017-01-01', - 'group_id' => '3', - 'iids' => '4', 'label_name' => 'foo', 'milestone_title' => 'bar', 'my_reaction_emoji' => 'thumbsup', - 'non_archived' => 'true', - 'project_id' => '5', + 'due_date' => '2017-01-01', 'scope' => 'all', 'search' => 'baz', 'sort' => 'priority', diff --git a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb index ed08a4c1bf2..f5860d4296b 100644 --- a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb +++ b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb @@ -39,8 +39,10 @@ describe Profiles::PersonalAccessTokensController do let!(:active_personal_access_token) { create(:personal_access_token, user: user) } let!(:inactive_personal_access_token) { create(:personal_access_token, :revoked, user: user) } let!(:impersonation_personal_access_token) { create(:personal_access_token, :impersonation, user: user) } + let(:token_value) { 's3cr3t' } before do + PersonalAccessToken.redis_store!(user.id, token_value) get :index end @@ -56,5 +58,9 @@ describe Profiles::PersonalAccessTokensController do expect(assigns(:active_personal_access_tokens)).not_to include(impersonation_personal_access_token) expect(assigns(:inactive_personal_access_tokens)).not_to include(impersonation_personal_access_token) end + + it "retrieves newly created personal access token value" do + expect(assigns(:new_personal_access_token)).to eql(token_value) + end end end diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 74771abde71..5fdf7f1229d 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -141,28 +141,6 @@ describe Projects::BlobController do expect(lines.first).to have_key('rich_text') end - context 'comment in any diff line feature flag' do - it 'renders context lines when feature disabled' do - stub_feature_flags(comment_in_any_diff_line: false) - - do_get(since: 1, to: 5, offset: 10, from_merge_request: true) - lines = JSON.parse(response.body) - all_context = lines.all? { |line| line['type'] == 'context' } - - expect(all_context).to be(true) - end - - it 'renders unchanged lines when feature enabled' do - stub_feature_flags(comment_in_any_diff_line: true) - - do_get(since: 1, to: 5, offset: 10, from_merge_request: true) - lines = JSON.parse(response.body) - all_unchanged = lines.all? { |line| line['type'].nil? } - - expect(all_unchanged).to be(true) - end - end - context 'when rendering match lines' do it 'adds top match line when "since" is less than 1' do do_get(since: 5, to: 10, offset: 10, from_merge_request: true) diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb index 73bf169085f..4567a51b88e 100644 --- a/spec/controllers/projects/deploy_keys_controller_spec.rb +++ b/spec/controllers/projects/deploy_keys_controller_spec.rb @@ -27,12 +27,8 @@ describe Projects::DeployKeysController do let(:project2) { create(:project, :internal)} let(:project_private) { create(:project, :private)} - let(:deploy_key_internal) do - create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCdMHEHyhRjbhEZVddFn6lTWdgEy5Q6Bz4nwGB76xWZI5YT/1WJOMEW+sL5zYd31kk7sd3FJ5L9ft8zWMWrr/iWXQikC2cqZK24H1xy+ZUmrRuJD4qGAaIVoyyzBL+avL+lF8J5lg6YSw8gwJY/lX64/vnJHUlWw2n5BF8IFOWhiw== dummy@gitlab.com') - end - let(:deploy_key_actual) do - create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNd/UJWhPrpb+b/G5oL109y57yKuCxE+WUGJGYaj7WQKsYRJmLYh1mgjrl+KVyfsWpq4ylOxIfFSnN9xBBFN8mlb0Fma5DC7YsSsibJr3MZ19ZNBprwNcdogET7aW9I0In7Wu5f2KqI6e5W/spJHCy4JVxzVMUvk6Myab0LnJ2iQ== dummy@gitlab.com') - end + let(:deploy_key_internal) { create(:deploy_key) } + let(:deploy_key_actual) { create(:deploy_key) } let!(:deploy_key_public) { create(:deploy_key, public: true) } let!(:deploy_keys_project_internal) do @@ -63,4 +59,145 @@ describe Projects::DeployKeysController do end end end + + describe '/enable/:id' do + let(:deploy_key) { create(:deploy_key) } + let(:project2) { create(:project) } + let!(:deploy_keys_project_internal) do + create(:deploy_keys_project, project: project2, deploy_key: deploy_key) + end + + context 'with anonymous user' do + before do + sign_out(:user) + end + + it 'redirects to login' do + expect do + put :enable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.not_to change { DeployKeysProject.count } + + expect(response).to have_http_status(302) + expect(response).to redirect_to(new_user_session_path) + end + end + + context 'with user with no permission' do + before do + sign_in(create(:user)) + end + + it 'returns 404' do + expect do + put :enable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.not_to change { DeployKeysProject.count } + + expect(response).to have_http_status(404) + end + end + + context 'with user with permission' do + before do + project2.add_maintainer(user) + end + + it 'returns 302' do + expect do + put :enable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.to change { DeployKeysProject.count }.by(1) + + expect(DeployKeysProject.where(project_id: project.id, deploy_key_id: deploy_key.id).count).to eq(1) + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_settings_repository_path(anchor: 'js-deploy-keys-settings')) + end + + it 'returns 404' do + put :enable, id: 0, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(404) + end + end + + context 'with admin' do + before do + sign_in(create(:admin)) + end + + it 'returns 302' do + expect do + put :enable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.to change { DeployKeysProject.count }.by(1) + + expect(DeployKeysProject.where(project_id: project.id, deploy_key_id: deploy_key.id).count).to eq(1) + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_settings_repository_path(anchor: 'js-deploy-keys-settings')) + end + end + end + + describe '/disable/:id' do + let(:deploy_key) { create(:deploy_key) } + let!(:deploy_key_project) { create(:deploy_keys_project, project: project, deploy_key: deploy_key) } + + context 'with anonymous user' do + before do + sign_out(:user) + end + + it 'redirects to login' do + put :disable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(302) + expect(response).to redirect_to(new_user_session_path) + expect(DeployKey.find(deploy_key.id)).to eq(deploy_key) + end + end + + context 'with user with no permission' do + before do + sign_in(create(:user)) + end + + it 'returns 404' do + put :disable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(404) + expect(DeployKey.find(deploy_key.id)).to eq(deploy_key) + end + end + + context 'with user with permission' do + it 'returns 302' do + put :disable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_settings_repository_path(anchor: 'js-deploy-keys-settings')) + + expect { DeployKey.find(deploy_key.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'returns 404' do + put :disable, id: 0, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(404) + end + end + + context 'with admin' do + before do + sign_in(create(:admin)) + end + + it 'returns 302' do + expect do + put :disable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.to change { DeployKey.count }.by(-1) + + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_settings_repository_path(anchor: 'js-deploy-keys-settings')) + + expect { DeployKey.find(deploy_key.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end end diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 898f3863008..d334a2ff566 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -49,7 +49,7 @@ describe RegistrationsController do end it 'displays an error when the reCAPTCHA is not solved' do - # Without this, `verify_recaptcha` arbitraily returns true in test env + # Without this, `verify_recaptcha` arbitrarily returns true in test env Recaptcha.configuration.skip_verify_env.delete('test') post(:create, user_params) diff --git a/spec/controllers/root_controller_spec.rb b/spec/controllers/root_controller_spec.rb index 7688538a468..995f803d757 100644 --- a/spec/controllers/root_controller_spec.rb +++ b/spec/controllers/root_controller_spec.rb @@ -98,7 +98,7 @@ describe RootController do it 'redirects to their assigned issues' do get :index - expect(response).to redirect_to issues_dashboard_path(assignee_id: user.id) + expect(response).to redirect_to issues_dashboard_path(assignee_username: user.username) end end @@ -110,7 +110,7 @@ describe RootController do it 'redirects to their assigned merge requests' do get :index - expect(response).to redirect_to merge_requests_dashboard_path(assignee_id: user.id) + expect(response).to redirect_to merge_requests_dashboard_path(assignee_username: user.username) end end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 8e25b61e2f1..c691b3f478b 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -89,7 +89,7 @@ describe SessionsController do end it 'displays an error when the reCAPTCHA is not solved' do - # Without this, `verify_recaptcha` arbitraily returns true in test env + # Without this, `verify_recaptcha` arbitrarily returns true in test env Recaptcha.configuration.skip_verify_env.delete('test') counter = double(:counter) diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb new file mode 100644 index 00000000000..e8584846b56 --- /dev/null +++ b/spec/db/schema_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Database schema' do + let(:connection) { ActiveRecord::Base.connection } + let(:tables) { connection.tables } + + # Use if you are certain that this column should not have a foreign key + IGNORED_FK_COLUMNS = { + abuse_reports: %w[reporter_id user_id], + application_settings: %w[performance_bar_allowed_group_id], + audit_events: %w[author_id entity_id], + award_emoji: %w[awardable_id user_id], + chat_names: %w[chat_id service_id team_id user_id], + chat_teams: %w[team_id], + ci_builds: %w[erased_by_id runner_id trigger_request_id user_id], + ci_pipelines: %w[user_id], + ci_runner_projects: %w[runner_id], + ci_trigger_requests: %w[commit_id], + cluster_providers_gcp: %w[gcp_project_id operation_id], + deploy_keys_projects: %w[deploy_key_id], + deployments: %w[deployable_id environment_id user_id], + emails: %w[user_id], + events: %w[target_id], + forked_project_links: %w[forked_from_project_id], + identities: %w[user_id], + issues: %w[last_edited_by_id], + keys: %w[user_id], + label_links: %w[target_id], + lfs_objects_projects: %w[lfs_object_id project_id], + members: %w[source_id created_by_id], + merge_requests: %w[last_edited_by_id], + namespaces: %w[owner_id parent_id], + notes: %w[author_id commit_id noteable_id updated_by_id resolved_by_id discussion_id], + notification_settings: %w[source_id], + oauth_access_grants: %w[resource_owner_id application_id], + oauth_access_tokens: %w[resource_owner_id application_id], + oauth_applications: %w[owner_id], + project_group_links: %w[group_id], + project_statistics: %w[namespace_id], + projects: %w[creator_id namespace_id ci_id], + redirect_routes: %w[source_id], + repository_languages: %w[programming_language_id], + routes: %w[source_id], + sent_notifications: %w[project_id noteable_id recipient_id commit_id in_reply_to_discussion_id], + snippets: %w[author_id], + spam_logs: %w[user_id], + subscriptions: %w[user_id subscribable_id], + taggings: %w[tag_id taggable_id tagger_id], + timelogs: %w[user_id], + todos: %w[target_id commit_id], + uploads: %w[model_id], + user_agent_details: %w[subject_id], + users: %w[color_scheme_id created_by_id theme_id], + users_star_projects: %w[user_id], + web_hooks: %w[service_id] + }.with_indifferent_access.freeze + + context 'for table' do + ActiveRecord::Base.connection.tables.sort.each do |table| + describe table do + let(:indexes) { connection.indexes(table) } + let(:columns) { connection.columns(table) } + let(:foreign_keys) { connection.foreign_keys(table) } + + context 'all foreign keys' do + # for index to be effective, the FK constraint has to be at first place + it 'are indexed' do + first_indexed_column = indexes.map(&:columns).map(&:first) + foreign_keys_columns = foreign_keys.map(&:column) + + expect(first_indexed_column.uniq).to include(*foreign_keys_columns) + end + end + + context 'columns ending with _id' do + let(:column_names) { columns.map(&:name) } + let(:column_names_with_id) { column_names.select { |column_name| column_name.ends_with?('_id') } } + let(:foreign_keys_columns) { foreign_keys.map(&:column) } + let(:ignored_columns) { ignored_fk_columns(table) } + + it 'do have the foreign keys' do + expect(column_names_with_id - ignored_columns).to contain_exactly(*foreign_keys_columns) + end + end + end + end + end + + private + + def ignored_fk_columns(column) + IGNORED_FK_COLUMNS.fetch(column, []) + end +end diff --git a/spec/factories/clusters/kubernetes_namespaces.rb b/spec/factories/clusters/kubernetes_namespaces.rb index 3a4f5193550..6ad93fb0f45 100644 --- a/spec/factories/clusters/kubernetes_namespaces.rb +++ b/spec/factories/clusters/kubernetes_namespaces.rb @@ -3,7 +3,6 @@ FactoryBot.define do factory :cluster_kubernetes_namespace, class: Clusters::KubernetesNamespace do association :cluster, :project, :provided_by_gcp - namespace { |n| "environment#{n}" } after(:build) do |kubernetes_namespace| cluster_project = kubernetes_namespace.cluster.cluster_project diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb index fe475e1f7a0..0b5ab16ad71 100644 --- a/spec/fast_spec_helper.rb +++ b/spec/fast_spec_helper.rb @@ -9,3 +9,4 @@ require 'active_support/all' ActiveSupport::Dependencies.autoload_paths << 'lib' ActiveSupport::Dependencies.autoload_paths << 'ee/lib' +ActiveSupport::XmlMini.backend = 'Nokogiri' diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index e16eae219a4..c7860bebb06 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -12,6 +12,10 @@ describe 'Admin > Users > Impersonation Tokens', :js do find(".settings-message") end + def created_impersonation_token + find("#created-personal-access-token").value + end + before do sign_in(admin) end @@ -39,6 +43,7 @@ describe 'Admin > Users > Impersonation Tokens', :js do expect(active_impersonation_tokens).to have_text('api') expect(active_impersonation_tokens).to have_text('read_user') expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1) + expect(created_impersonation_token).not_to be_empty end end diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index d32f33ca1e2..f7c7a257075 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -130,7 +130,7 @@ describe "Admin::Users" do context 'with regex to match internal user email address set', :js do before do stub_application_setting(user_default_external: true) - stub_application_setting(user_default_internal_regex: '.internal@') + stub_application_setting(user_default_internal_regex: '\.internal@') visit new_admin_user_path end @@ -169,6 +169,22 @@ describe "Admin::Users" do expects_warning_to_be_hidden end + + it 'creates an internal user' do + user_name = 'tester1' + fill_in 'user_email', with: 'test.internal@domain.ch' + fill_in 'user_name', with: 'tester1 name' + fill_in 'user_username', with: user_name + + expects_external_to_be_unchecked + expects_warning_to_be_shown + + click_button 'Create user' + + new_user = User.find_by(username: user_name) + + expect(new_user.external).to be_falsy + end end end end diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb index bd4c00d97b1..5fa1a26f1a6 100644 --- a/spec/features/atom/dashboard_issues_spec.rb +++ b/spec/features/atom/dashboard_issues_spec.rb @@ -25,35 +25,35 @@ describe "Dashboard Issues Feed" do it "renders atom feed via personal access token" do personal_access_token = create(:personal_access_token, user: user) - visit issues_dashboard_path(:atom, private_token: personal_access_token.token, assignee_id: user.id) + visit issues_dashboard_path(:atom, private_token: personal_access_token.token, assignee_username: user.username) expect(response_headers['Content-Type']).to have_content('application/atom+xml') expect(body).to have_selector('title', text: "#{user.name} issues") end it "renders atom feed via feed token" do - visit issues_dashboard_path(:atom, feed_token: user.feed_token, assignee_id: user.id) + visit issues_dashboard_path(:atom, feed_token: user.feed_token, assignee_username: user.username) expect(response_headers['Content-Type']).to have_content('application/atom+xml') expect(body).to have_selector('title', text: "#{user.name} issues") end it "renders atom feed with url parameters" do - visit issues_dashboard_path(:atom, feed_token: user.feed_token, state: 'opened', assignee_id: user.id) + visit issues_dashboard_path(:atom, feed_token: user.feed_token, state: 'opened', assignee_username: user.username) link = find('link[type="application/atom+xml"]') params = CGI.parse(URI.parse(link[:href]).query) expect(params).to include('feed_token' => [user.feed_token]) expect(params).to include('state' => ['opened']) - expect(params).to include('assignee_id' => [user.id.to_s]) + expect(params).to include('assignee_username' => [user.username.to_s]) end context "issue with basic fields" do let!(:issue2) { create(:issue, author: user, assignees: [assignee], project: project2, description: 'test desc') } it "renders issue fields" do - visit issues_dashboard_path(:atom, feed_token: user.feed_token, assignee_id: assignee.id) + visit issues_dashboard_path(:atom, feed_token: user.feed_token, assignee_username: assignee.username) entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue2.title}')]") @@ -76,7 +76,7 @@ describe "Dashboard Issues Feed" do end it "renders issue label and milestone info" do - visit issues_dashboard_path(:atom, feed_token: user.feed_token, assignee_id: assignee.id) + visit issues_dashboard_path(:atom, feed_token: user.feed_token, assignee_username: assignee.username) entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue1.title}')]") diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb index b431f72fcc9..fbc2e5cc3d3 100644 --- a/spec/features/dashboard/issuables_counter_spec.rb +++ b/spec/features/dashboard/issuables_counter_spec.rb @@ -45,11 +45,11 @@ describe 'Navigation bar counter', :use_clean_rails_memory_store_caching do end def issues_path - issues_dashboard_path(assignee_id: user.id) + issues_dashboard_path(assignee_username: user.username) end def merge_requests_path - merge_requests_dashboard_path(assignee_id: user.id) + merge_requests_dashboard_path(assignee_username: user.username) end def expect_counters(issuable_type, count) diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb index 95e2610dd4a..c0434f767bb 100644 --- a/spec/features/dashboard/issues_filter_spec.rb +++ b/spec/features/dashboard/issues_filter_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe 'Dashboard Issues filtering', :js do include Spec::Support::Helpers::Features::SortingHelpers + include FilteredSearchHelpers let(:user) { create(:user) } let(:project) { create(:project) } @@ -25,27 +26,21 @@ describe 'Dashboard Issues filtering', :js do context 'filtering by milestone' do it 'shows all issues with no milestone' do - show_milestone_dropdown - - click_link 'No Milestone' + input_filtered_search("milestone:none") expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1) expect(page).to have_selector('.issue', count: 1) end it 'shows all issues with the selected milestone' do - show_milestone_dropdown - - page.within '.dropdown-content' do - click_link milestone.title - end + input_filtered_search("milestone:%\"#{milestone.title}\"") expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1) expect(page).to have_selector('.issue', count: 1) end it 'updates atom feed link' do - visit_issues(milestone_title: '', assignee_id: user.id) + visit_issues(milestone_title: '', assignee_username: user.username) link = find('.nav-controls a[title="Subscribe to RSS feed"]') params = CGI.parse(URI.parse(link[:href]).query) @@ -54,10 +49,10 @@ describe 'Dashboard Issues filtering', :js do expect(params).to include('feed_token' => [user.feed_token]) expect(params).to include('milestone_title' => ['']) - expect(params).to include('assignee_id' => [user.id.to_s]) + expect(params).to include('assignee_username' => [user.username.to_s]) expect(auto_discovery_params).to include('feed_token' => [user.feed_token]) expect(auto_discovery_params).to include('milestone_title' => ['']) - expect(auto_discovery_params).to include('assignee_id' => [user.id.to_s]) + expect(auto_discovery_params).to include('assignee_username' => [user.username.to_s]) end end @@ -66,10 +61,7 @@ describe 'Dashboard Issues filtering', :js do let!(:label_link) { create(:label_link, label: label, target: issue) } it 'shows all issues with the selected label' do - page.within '.labels-filter' do - find('.dropdown').click - click_link label.title - end + input_filtered_search("label:~#{label.title}") page.within 'ul.content-list' do expect(page).to have_content issue.title @@ -80,12 +72,12 @@ describe 'Dashboard Issues filtering', :js do context 'sorting' do before do - visit_issues(assignee_id: user.id) + visit_issues(assignee_username: user.username) end it 'remembers last sorting value' do sort_by('Created date') - visit_issues(assignee_id: user.id) + visit_issues(assignee_username: user.username) expect(find('.issues-filters')).to have_content('Created date') end @@ -98,11 +90,6 @@ describe 'Dashboard Issues filtering', :js do end end - def show_milestone_dropdown - click_button 'Milestone' - expect(page).to have_selector('.dropdown-content', visible: true) - end - def visit_issues(*args) visit issues_dashboard_path(*args) end diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 4ae062f242a..9957bec0f0b 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' RSpec.describe 'Dashboard Issues' do + include FilteredSearchHelpers + let(:current_user) { create :user } let(:user) { current_user } # Shared examples depend on this being available let!(:public_project) { create(:project, :public) } @@ -14,7 +16,7 @@ RSpec.describe 'Dashboard Issues' do before do [project, project_with_issues_disabled].each { |project| project.add_maintainer(current_user) } sign_in(current_user) - visit issues_dashboard_path(assignee_id: current_user.id) + visit issues_dashboard_path(assignee_username: current_user.username) end describe 'issues' do @@ -24,26 +26,9 @@ RSpec.describe 'Dashboard Issues' do expect(page).not_to have_content(other_issue.title) end - it 'shows checkmark when unassigned is selected for assignee', :js do - find('.js-assignee-search').click - find('li', text: 'Unassigned').click - find('.js-assignee-search').click - - expect(find('li[data-user-id="0"] a.is-active')).to be_visible - end - it 'shows issues when current user is author', :js do - execute_script("document.querySelector('#assignee_id').value=''") - find('.js-author-search', match: :first).click - - expect(find('li[data-user-id="null"] a.is-active')).to be_visible - - find('.dropdown-menu-author li a', match: :first, text: current_user.to_reference).click - find('.js-author-search', match: :first).click - - page.within '.dropdown-menu-user' do - expect(find('.dropdown-menu-author li a.is-active', match: :first, text: current_user.to_reference)).to be_visible - end + reset_filters + input_filtered_search("author:#{current_user.to_reference}") expect(page).to have_content(authored_issue.title) expect(page).to have_content(authored_issue_on_public_project.title) @@ -53,7 +38,7 @@ RSpec.describe 'Dashboard Issues' do it 'state filter tabs work' do find('#state-closed').click - expect(page).to have_current_path(issues_dashboard_url(assignee_id: current_user.id, state: 'closed'), url: true) + expect(page).to have_current_path(issues_dashboard_url(assignee_username: current_user.username, state: 'closed'), url: true) end it_behaves_like "it has an RSS button with current_user's feed token" diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb index 6802974c2ee..2d4659d380f 100644 --- a/spec/features/dashboard/label_filter_spec.rb +++ b/spec/features/dashboard/label_filter_spec.rb @@ -1,6 +1,11 @@ require 'spec_helper' describe 'Dashboard > label filter', :js do + include FilteredSearchHelpers + + let(:filtered_search) { find('.filtered-search') } + let(:filter_dropdown) { find("#js-dropdown-label .filter-dropdown") } + let(:user) { create(:user) } let(:project) { create(:project, name: 'test', namespace: user.namespace) } let(:project2) { create(:project, name: 'test2', path: 'test2', namespace: user.namespace) } @@ -13,17 +18,15 @@ describe 'Dashboard > label filter', :js do sign_in(user) visit issues_dashboard_path + + init_label_search end context 'duplicate labels' do it 'removes duplicate labels' do - page.within('.labels-filter') do - click_button 'Label' - end + filtered_search.send_keys('bu') - page.within('.dropdown-menu-labels') do - expect(page).to have_selector('.dropdown-content a', text: 'bug', count: 1) - end + expect(filter_dropdown).to have_selector('.filter-dropdown-item', text: 'bug', count: 1) end end end diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb index f51142f5790..282bf542e77 100644 --- a/spec/features/dashboard/merge_requests_spec.rb +++ b/spec/features/dashboard/merge_requests_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Dashboard Merge Requests' do include Spec::Support::Helpers::Features::SortingHelpers - include FilterItemSelectHelper + include FilteredSearchHelpers include ProjectForksHelper let(:current_user) { create :user } @@ -36,7 +36,7 @@ describe 'Dashboard Merge Requests' do context 'no merge requests exist' do it 'shows an empty state' do - visit merge_requests_dashboard_path(assignee_id: current_user.id) + visit merge_requests_dashboard_path(assignee_username: current_user.username) expect(page).to have_selector('.empty-state') end @@ -79,7 +79,7 @@ describe 'Dashboard Merge Requests' do end before do - visit merge_requests_dashboard_path(assignee_id: current_user.id) + visit merge_requests_dashboard_path(assignee_username: current_user.username) end it 'shows assigned merge requests' do @@ -92,8 +92,8 @@ describe 'Dashboard Merge Requests' do end it 'shows authored merge requests', :js do - filter_item_select('Any Assignee', '.js-assignee-search') - filter_item_select(current_user.to_reference, '.js-author-search') + reset_filters + input_filtered_search("author:#{current_user.to_reference}") expect(page).to have_content(authored_merge_request.title) expect(page).to have_content(authored_merge_request_from_fork.title) @@ -104,8 +104,7 @@ describe 'Dashboard Merge Requests' do end it 'shows error message without filter', :js do - filter_item_select('Any Assignee', '.js-assignee-search') - filter_item_select('Any Author', '.js-author-search') + reset_filters expect(page).to have_content('Please select at least one filter to see results') end @@ -113,7 +112,7 @@ describe 'Dashboard Merge Requests' do it 'shows sorted merge requests' do sort_by('Created date') - visit merge_requests_dashboard_path(assignee_id: current_user.id) + visit merge_requests_dashboard_path(assignee_username: current_user.username) expect(find('.issues-filters')).to have_content('Created date') end diff --git a/spec/features/dashboard/milestone_filter_spec.rb b/spec/features/dashboard/milestone_filter_spec.rb deleted file mode 100644 index 00373050aeb..00000000000 --- a/spec/features/dashboard/milestone_filter_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -require 'spec_helper' - -describe 'Dashboard > milestone filter', :js do - include FilterItemSelectHelper - - let(:user) { create(:user) } - let(:project) { create(:project, name: 'test', namespace: user.namespace) } - let(:milestone) { create(:milestone, title: 'v1.0', project: project) } - let(:milestone2) { create(:milestone, title: 'v2.0', project: project) } - let!(:issue) { create :issue, author: user, project: project, milestone: milestone } - let!(:issue2) { create :issue, author: user, project: project, milestone: milestone2 } - - dropdown_toggle_button = '.js-milestone-select' - - before do - sign_in(user) - end - - context 'default state' do - it 'shows issues with Any Milestone' do - visit issues_dashboard_path(author_id: user.id) - - page.all('.issue-info').each do |issue_info| - expect(issue_info.text).to match(/v\d.0/) - end - end - end - - context 'filtering by milestone' do - before do - visit issues_dashboard_path(author_id: user.id) - filter_item_select('v1.0', dropdown_toggle_button) - find(dropdown_toggle_button).click - wait_for_requests - end - - it 'shows issues with Milestone v1.0' do - expect(find('.issues-list')).to have_selector('.issue', count: 1) - expect(find('.milestone-filter .dropdown-content')).to have_selector('a.is-active', count: 1) - end - - it 'should not change active Milestone unless clicked' do - page.within '.milestone-filter' do - expect(find('.dropdown-content')).to have_selector('a.is-active', count: 1) - - find('.dropdown-menu-close').click - - expect(page).not_to have_selector('.dropdown.open') - - find(dropdown_toggle_button).click - - expect(find('.dropdown-content')).to have_selector('a.is-active', count: 1) - expect(find('.dropdown-content a.is-active')).to have_content('v1.0') - end - end - end - - context 'with milestone filter in URL' do - before do - visit issues_dashboard_path(author_id: user.id, milestone_title: milestone.title) - find(dropdown_toggle_button).click - wait_for_requests - end - - it 'has milestone selected' do - expect(find('.milestone-filter .dropdown-content')).to have_css('.is-active', text: milestone.title) - end - - it 'removes milestone filter from URL after clicking "Any Milestone"' do - expect(current_url).to include("milestone_title=#{milestone.title}") - - find('.milestone-filter .dropdown-content li', text: 'Any Milestone').click - - expect(current_url).not_to include('milestone_title') - end - end -end diff --git a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb index c42fcd92a36..97dd0afd002 100644 --- a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb @@ -20,7 +20,7 @@ describe 'Dropdown emoji', :js do end def dropdown_emoji_size - page.all('#js-dropdown-my-reaction .filter-dropdown .filter-dropdown-item').size + all('gl-emoji[data-name]').size end def click_emoji(text) diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 1456a2f0375..f2e4c5779df 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -27,7 +27,7 @@ describe 'New/edit issue', :js do before do # Using `allow_any_instance_of`/`and_wrap_original`, `original` would # somehow refer to the very block we defined to _wrap_ that method, instead of - # the original method, resulting in infinite recurison when called. + # the original method, resulting in infinite recursion when called. # This is likely a bug with helper modules included into dynamically generated view classes. # To work around this, we have to hold on to and call to the original implementation manually. original_issue_dropdown_options = FormHelper.instance_method(:issue_assignees_dropdown_options) diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb index 3dfcbc2fcb8..297cd808460 100644 --- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb +++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb @@ -55,11 +55,11 @@ describe 'User creates branch and merge request on issue page', :js do test_branch_name_checking(input_branch_name) test_source_checking(input_source) - # The button inside dropdown should be disabled if any errors occured. + # The button inside dropdown should be disabled if any errors occurred. expect(page).to have_button('Create branch', disabled: true) end - # The top level button should be disabled if any errors occured. + # The top level button should be disabled if any errors occurred. expect(page).to have_button('Create branch', disabled: true) end diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb index 7d261ec7dae..4771d2c6d28 100644 --- a/spec/features/issues/user_sorts_issues_spec.rb +++ b/spec/features/issues/user_sorts_issues_spec.rb @@ -26,7 +26,7 @@ describe "User sorts issues" do click_link('Milestone') end - visit(issues_dashboard_path(assignee_id: user.id)) + visit(issues_dashboard_path(assignee_username: user.username)) expect(find('.issues-filters a.is-active')).to have_content('Milestone') diff --git a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb index 82cfe600d52..e163868e8e7 100644 --- a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb @@ -25,7 +25,7 @@ describe 'User sorts merge requests' do click_link('Milestone') end - visit(merge_requests_dashboard_path(assignee_id: user.id)) + visit(merge_requests_dashboard_path(assignee_username: user.username)) expect(find('.issues-filters a.is-active')).to have_content('Milestone') @@ -41,7 +41,7 @@ describe 'User sorts merge requests' do it 'fallbacks to issuable_sort cookie key when remembering the sorting option' do set_cookie('issuable_sort', 'milestone') - visit(merge_requests_dashboard_path(assignee_id: user.id)) + visit(merge_requests_dashboard_path(assignee_username: user.username)) expect(find('.issues-filters a.is-active')).to have_content('Milestone') end diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 8461cd0027c..dee213a11d4 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -43,10 +43,12 @@ describe 'Profile > Personal Access Tokens', :js do check "read_user" click_on "Create personal access token" + expect(active_personal_access_tokens).to have_text(name) expect(active_personal_access_tokens).to have_text('In') expect(active_personal_access_tokens).to have_text('api') expect(active_personal_access_tokens).to have_text('read_user') + expect(created_personal_access_token).not_to be_empty end context "when creation fails" do @@ -57,6 +59,7 @@ describe 'Profile > Personal Access Tokens', :js do expect { click_on "Create personal access token" }.not_to change { PersonalAccessToken.count } expect(page).to have_content("Name cannot be nil") + expect(page).not_to have_selector("#created-personal-access-token") end end end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index a1323699969..99a7fbb63bd 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -719,7 +719,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do context 'on mobile', :js do let(:job) { create(:ci_build, pipeline: pipeline) } - it 'renders collpased sidebar' do + it 'renders collapsed sidebar' do page.current_window.resize_to(600, 800) visit project_job_path(project, job) @@ -738,7 +738,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do wait_for_requests expect(page).to have_css('.js-job-sidebar.right-sidebar-expanded') - expect(page).not_to have_css('.js-job-sidebar.right-sidebar-collpased') + expect(page).not_to have_css('.js-job-sidebar.right-sidebar-collapsed') end end diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb index af38f77c0c6..444de26733f 100644 --- a/spec/features/search/user_uses_header_search_field_spec.rb +++ b/spec/features/search/user_uses_header_search_field_spec.rb @@ -21,13 +21,17 @@ describe 'User uses header search field' do it 'shows assigned issues' do find('.search-input-container .dropdown-menu').click_link('Issues assigned to me') - expect(find('.js-assignee-search')).to have_content(user.name) + expect(page).to have_selector('.filtered-search') + expect_tokens([assignee_token(user.name)]) + expect_filtered_search_input_empty end it 'shows created issues' do find('.search-input-container .dropdown-menu').click_link("Issues I've created") - expect(find('.js-author-search')).to have_content(user.name) + expect(page).to have_selector('.filtered-search') + expect_tokens([author_token(user.name)]) + expect_filtered_search_input_empty end end @@ -37,13 +41,17 @@ describe 'User uses header search field' do it 'shows assigned merge requests' do find('.search-input-container .dropdown-menu').click_link('Merge requests assigned to me') - expect(find('.js-assignee-search')).to have_content(user.name) + expect(page).to have_selector('.filtered-search') + expect_tokens([assignee_token(user.name)]) + expect_filtered_search_input_empty end it 'shows created merge requests' do find('.search-input-container .dropdown-menu').click_link("Merge requests I've created") - expect(find('.js-author-search')).to have_content(user.name) + expect(page).to have_selector('.filtered-search') + expect_tokens([author_token(user.name)]) + expect_filtered_search_input_empty end end end diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index 44758f862a8..ad856bd062e 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe 'Login' do include TermsHelper + include UserLoginHelper before do stub_authentication_activity_metrics(debug: true) @@ -546,29 +547,6 @@ describe 'Login' do ensure_tab_pane_correctness(false) end end - - def ensure_tab_pane_correctness(visit_path = true) - if visit_path - visit new_user_session_path - end - - ensure_tab_pane_counts - ensure_one_active_tab - ensure_one_active_pane - end - - def ensure_tab_pane_counts - tabs_count = page.all('[role="tab"]').size - expect(page).to have_selector('[role="tabpanel"]', count: tabs_count) - end - - def ensure_one_active_tab - expect(page).to have_selector('ul.new-session-tabs > li > a.active', count: 1) - end - - def ensure_one_active_pane - expect(page).to have_selector('.tab-pane.active', count: 1) - end end context 'when terms are enforced' do diff --git a/spec/finders/pipelines_finder_spec.rb b/spec/finders/pipelines_finder_spec.rb index c6e832ad69b..c2c304589c9 100644 --- a/spec/finders/pipelines_finder_spec.rb +++ b/spec/finders/pipelines_finder_spec.rb @@ -225,7 +225,7 @@ describe PipelinesFinder do end end - context 'when the project has limited access to piplines' do + context 'when the project has limited access to pipelines' do let(:project) { create(:project, :private, :repository) } let(:current_user) { create(:user) } let!(:pipelines) { create_list(:ci_pipeline, 2, project: project) } diff --git a/spec/fixtures/trace/sample_trace b/spec/fixtures/trace/sample_trace index 7bfe3f83b7b..3d8beb0dec2 100644 --- a/spec/fixtures/trace/sample_trace +++ b/spec/fixtures/trace/sample_trace @@ -2334,12 +2334,12 @@ Boards::Lists::MoveService keeps position of lists when list type is closed when list type is set to label keeps position of lists when new position is nil - keeps position of lists when new positon is equal to old position - keeps position of lists when new positon is negative - keeps position of lists when new positon is equal to number of labels lists - keeps position of lists when new positon is greater than number of labels lists - increments position of intermediate lists when new positon is equal to first position - decrements position of intermediate lists when new positon is equal to last position + keeps position of lists when new position is equal to old position + keeps position of lists when new position is negative + keeps position of lists when new position is equal to number of labels lists + keeps position of lists when new position is greater than number of labels lists + increments position of intermediate lists when new position is equal to first position + decrements position of intermediate lists when new position is equal to last position decrements position of intermediate lists when new position is greater than old position increments position of intermediate lists when new position is lower than old position when board parent is a group @@ -2347,12 +2347,12 @@ Boards::Lists::MoveService keeps position of lists when list type is closed when list type is set to label keeps position of lists when new position is nil - keeps position of lists when new positon is equal to old position - keeps position of lists when new positon is negative - keeps position of lists when new positon is equal to number of labels lists - keeps position of lists when new positon is greater than number of labels lists - increments position of intermediate lists when new positon is equal to first position - decrements position of intermediate lists when new positon is equal to last position + keeps position of lists when new position is equal to old position + keeps position of lists when new position is negative + keeps position of lists when new position is equal to number of labels lists + keeps position of lists when new position is greater than number of labels lists + increments position of intermediate lists when new position is equal to first position + decrements position of intermediate lists when new position is equal to last position decrements position of intermediate lists when new position is greater than old position increments position of intermediate lists when new position is lower than old position diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb index 120b23e66ac..f0c2e4768ec 100644 --- a/spec/helpers/auth_helper_spec.rb +++ b/spec/helpers/auth_helper_spec.rb @@ -42,6 +42,16 @@ describe AuthHelper do end end + describe 'form_based_auth_provider_has_active_class?' do + it 'selects main LDAP server' do + allow(helper).to receive(:auth_providers) { [:twitter, :ldapprimary, :ldapsecondary, :kerberos] } + expect(helper.form_based_auth_provider_has_active_class?(:twitter)).to be(false) + expect(helper.form_based_auth_provider_has_active_class?(:ldapprimary)).to be(true) + expect(helper.form_based_auth_provider_has_active_class?(:ldapsecondary)).to be(false) + expect(helper.form_based_auth_provider_has_active_class?(:kerberos)).to be(false) + end + end + describe 'enabled_button_based_providers' do before do allow(helper).to receive(:auth_providers) { [:twitter, :github] } diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb index 9a2372de69f..8e336469c27 100644 --- a/spec/helpers/profiles_helper_spec.rb +++ b/spec/helpers/profiles_helper_spec.rb @@ -4,12 +4,17 @@ describe ProfilesHelper do describe '#commit_email_select_options' do it 'returns an array with private commit email along with all the verified emails' do user = create(:user) + create(:email, user: user) + confirmed_email1 = create(:email, :confirmed, user: user) + confirmed_email2 = create(:email, :confirmed, user: user) + private_email = user.private_commit_email - verified_emails = user.verified_emails - [private_email] emails = [ ["Use a private email - #{private_email}", Gitlab::PrivateCommitEmail::TOKEN], - verified_emails + user.email, + confirmed_email1.email, + confirmed_email2.email ] expect(helper.commit_email_select_options(user)).to match_array(emails) diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 8bfd520528f..4945749f524 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -135,5 +135,40 @@ describe SearchHelper do expect(search_filter_input_options('')[:data]['base-endpoint']).to eq("/groups#{group_path(@group)}") end end + + context 'dashboard' do + it 'does not include group-id and project-id' do + expect(search_filter_input_options('')[:data]['project-id']).to eq(nil) + expect(search_filter_input_options('')[:data]['group-id']).to eq(nil) + end + + it 'includes dashboard base-endpoint' do + expect(search_filter_input_options('')[:data]['base-endpoint']).to eq("/dashboard") + end + end + end + + describe 'search_history_storage_prefix' do + context 'project' do + it 'returns project full_path' do + @project = create(:project, :repository) + + expect(search_history_storage_prefix).to eq(@project.full_path) + end + end + + context 'group' do + it 'returns group full_path' do + @group = create(:group, :nested, name: 'group-name') + + expect(search_history_storage_prefix).to eq(@group.full_path) + end + end + + context 'dashboard' do + it 'returns dashboard' do + expect(search_history_storage_prefix).to eq("dashboard") + end + end end end diff --git a/spec/javascripts/diffs/components/commit_item_spec.js b/spec/javascripts/diffs/components/commit_item_spec.js index 7606847ada9..8b2ca6506c4 100644 --- a/spec/javascripts/diffs/components/commit_item_spec.js +++ b/spec/javascripts/diffs/components/commit_item_spec.js @@ -21,7 +21,7 @@ const getAvatarElement = vm => vm.$el.querySelector('.user-avatar-link'); const getCommitterElement = vm => vm.$el.querySelector('.commiter'); const getCommitActionsElement = vm => vm.$el.querySelector('.commit-actions'); -describe('diffs/components/commit_widget', () => { +describe('diffs/components/commit_item', () => { const Component = Vue.extend(CommitItem); const timeago = getTimeago(); const { commit } = getDiffWithCommit(); @@ -37,15 +37,15 @@ describe('diffs/components/commit_widget', () => { it('renders commit title', () => { const titleElement = getTitleElement(vm); - expect(titleElement).toHaveAttr('href', commit.commitUrl); - expect(titleElement).toHaveText(commit.titleHtml); + expect(titleElement).toHaveAttr('href', commit.commit_url); + expect(titleElement).toHaveText(commit.title_html); }); it('renders commit description', () => { const descElement = getDescElement(vm); const descExpandElement = getDescExpandElement(vm); - const expected = commit.descriptionHtml.replace(/
/g, ''); + const expected = commit.description_html.replace(/
/g, ''); expect(trimText(descElement.innerHTML)).toEqual(trimText(expected)); expect(descExpandElement).not.toBeNull(); @@ -56,7 +56,7 @@ describe('diffs/components/commit_widget', () => { const labelElement = shaElement.querySelector('.label'); const buttonElement = shaElement.querySelector('button'); - expect(labelElement.textContent).toEqual(commit.shortId); + expect(labelElement.textContent).toEqual(commit.short_id); expect(buttonElement).toHaveData('clipboard-text', commit.id); }); @@ -64,27 +64,27 @@ describe('diffs/components/commit_widget', () => { const avatarElement = getAvatarElement(vm); const imgElement = avatarElement.querySelector('img'); - expect(avatarElement).toHaveAttr('href', commit.author.webUrl); + expect(avatarElement).toHaveAttr('href', commit.author.web_url); expect(imgElement).toHaveClass('s36'); expect(imgElement).toHaveAttr('alt', commit.author.name); - expect(imgElement).toHaveAttr('src', commit.author.avatarUrl); + expect(imgElement).toHaveAttr('src', commit.author.avatar_url); }); it('renders committer text', () => { const committerElement = getCommitterElement(vm); const nameElement = committerElement.querySelector('a'); - const expectTimeText = timeago.format(commit.authoredDate); + const expectTimeText = timeago.format(commit.authored_date); const expectedText = `${commit.author.name} authored ${expectTimeText}`; expect(trimText(committerElement.textContent)).toEqual(expectedText); - expect(nameElement).toHaveAttr('href', commit.author.webUrl); + expect(nameElement).toHaveAttr('href', commit.author.web_url); expect(nameElement).toHaveText(commit.author.name); }); describe('without commit description', () => { beforeEach(done => { - vm.commit.descriptionHtml = ''; + vm.commit.description_html = ''; vm.$nextTick() .then(done) @@ -103,9 +103,9 @@ describe('diffs/components/commit_widget', () => { describe('with no matching user', () => { beforeEach(done => { vm.commit.author = null; - vm.commit.authorEmail = TEST_AUTHOR_EMAIL; - vm.commit.authorName = TEST_AUTHOR_NAME; - vm.commit.authorGravatarUrl = TEST_AUTHOR_GRAVATAR; + vm.commit.author_email = TEST_AUTHOR_EMAIL; + vm.commit.author_name = TEST_AUTHOR_NAME; + vm.commit.author_gravatar_url = TEST_AUTHOR_GRAVATAR; vm.$nextTick() .then(done) @@ -132,7 +132,7 @@ describe('diffs/components/commit_widget', () => { describe('with signature', () => { beforeEach(done => { - vm.commit.signatureHtml = TEST_SIGNATURE_HTML; + vm.commit.signature_html = TEST_SIGNATURE_HTML; vm.$nextTick() .then(done) @@ -148,7 +148,7 @@ describe('diffs/components/commit_widget', () => { describe('with pipeline status', () => { beforeEach(done => { - vm.commit.pipelineStatusPath = TEST_PIPELINE_STATUS_PATH; + vm.commit.pipeline_status_path = TEST_PIPELINE_STATUS_PATH; vm.$nextTick() .then(done) diff --git a/spec/javascripts/diffs/components/commit_widget_spec.js b/spec/javascripts/diffs/components/commit_widget_spec.js index 951eb57255d..2b60bd232ed 100644 --- a/spec/javascripts/diffs/components/commit_widget_spec.js +++ b/spec/javascripts/diffs/components/commit_widget_spec.js @@ -19,6 +19,6 @@ describe('diffs/components/commit_widget', () => { const commitElement = vm.$el.querySelector('li.commit'); expect(commitElement).not.toBeNull(); - expect(commitElement).toContainText(commit.shortId); + expect(commitElement).toContainText(commit.short_id); }); }); diff --git a/spec/javascripts/diffs/components/diff_content_spec.js b/spec/javascripts/diffs/components/diff_content_spec.js index 36bd042f3c4..c25f6167163 100644 --- a/spec/javascripts/diffs/components/diff_content_spec.js +++ b/spec/javascripts/diffs/components/diff_content_spec.js @@ -56,14 +56,14 @@ describe('DiffContent', () => { describe('image diff', () => { beforeEach(done => { - vm.diffFile.newPath = GREEN_BOX_IMAGE_URL; - vm.diffFile.newSha = 'DEF'; - vm.diffFile.oldPath = RED_BOX_IMAGE_URL; - vm.diffFile.oldSha = 'ABC'; - vm.diffFile.viewPath = ''; + vm.diffFile.new_path = GREEN_BOX_IMAGE_URL; + vm.diffFile.new_sha = 'DEF'; + vm.diffFile.old_path = RED_BOX_IMAGE_URL; + vm.diffFile.old_sha = 'ABC'; + vm.diffFile.view_path = ''; vm.diffFile.discussions = [{ ...discussionsMockData }]; vm.$store.state.diffs.commentForms.push({ - fileHash: vm.diffFile.fileHash, + fileHash: vm.diffFile.file_hash, x: 10, y: 20, width: 100, @@ -113,10 +113,10 @@ describe('DiffContent', () => { describe('file diff', () => { it('should have download buttons in place', done => { const el = vm.$el; - vm.diffFile.newPath = 'test.abc'; - vm.diffFile.newSha = 'DEF'; - vm.diffFile.oldPath = 'test.abc'; - vm.diffFile.oldSha = 'ABC'; + vm.diffFile.new_path = 'test.abc'; + vm.diffFile.new_sha = 'DEF'; + vm.diffFile.old_path = 'test.abc'; + vm.diffFile.old_sha = 'ABC'; vm.$nextTick(() => { expect(el.querySelectorAll('.js-diff-inline-view').length).toEqual(0); diff --git a/spec/javascripts/diffs/components/diff_file_header_spec.js b/spec/javascripts/diffs/components/diff_file_header_spec.js index 0192d583c6c..9530b50c729 100644 --- a/spec/javascripts/diffs/components/diff_file_header_spec.js +++ b/spec/javascripts/diffs/components/diff_file_header_spec.js @@ -3,7 +3,6 @@ import Vuex from 'vuex'; import diffsModule from '~/diffs/store/modules'; import notesModule from '~/notes/stores/modules'; import DiffFileHeader from '~/diffs/components/diff_file_header.vue'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; Vue.use(Vuex); @@ -24,9 +23,9 @@ describe('diff_file_header', () => { }); beforeEach(() => { - const diffFile = convertObjectPropsToCamelCase(diffDiscussionMock.diff_file, { deep: true }); + const diffFile = diffDiscussionMock.diff_file; props = { - diffFile, + diffFile: { ...diffFile }, canCurrentUserFork: false, }; }); @@ -62,8 +61,8 @@ describe('diff_file_header', () => { beforeEach(() => { props.discussionPath = 'link://to/discussion'; Object.assign(props.diffFile, { - submoduleLink: 'link://to/submodule', - submoduleTreeUrl: 'some://tree/url', + submodule_link: 'link://to/submodule', + submodule_tree_url: 'some://tree/url', }); }); @@ -80,18 +79,18 @@ describe('diff_file_header', () => { vm = mountComponentWithStore(Component, { props, store }); - expect(vm.titleLink).toBe(props.diffFile.submoduleTreeUrl); + expect(vm.titleLink).toBe(props.diffFile.submodule_tree_url); }); it('returns the submoduleLink for submodules without submoduleTreeUrl', () => { Object.assign(props.diffFile, { submodule: true, - submoduleTreeUrl: null, + submodule_tree_url: null, }); vm = mountComponentWithStore(Component, { props, store }); - expect(vm.titleLink).toBe(props.diffFile.submoduleLink); + expect(vm.titleLink).toBe(props.diffFile.submodule_link); }); it('sets the correct path to the discussion', () => { @@ -107,7 +106,7 @@ describe('diff_file_header', () => { beforeEach(() => { Object.assign(props.diffFile, { blob: { id: 'b10b1db10b1d' }, - filePath: 'path/to/file', + file_path: 'path/to/file', }); }); @@ -116,7 +115,7 @@ describe('diff_file_header', () => { vm = mountComponentWithStore(Component, { props, store }); - expect(vm.filePath).toBe(props.diffFile.filePath); + expect(vm.filePath).toBe(props.diffFile.file_path); }); it('appends the truncated blob id for submodules', () => { @@ -125,14 +124,14 @@ describe('diff_file_header', () => { vm = mountComponentWithStore(Component, { props, store }); expect(vm.filePath).toBe( - `${props.diffFile.filePath} @ ${props.diffFile.blob.id.substr(0, 8)}`, + `${props.diffFile.file_path} @ ${props.diffFile.blob.id.substr(0, 8)}`, ); }); }); describe('titleTag', () => { it('returns a link tag if fileHash is set', () => { - props.diffFile.fileHash = 'some hash'; + props.diffFile.file_hash = 'some hash'; vm = mountComponentWithStore(Component, { props, store }); @@ -140,7 +139,7 @@ describe('diff_file_header', () => { }); it('returns a span tag if fileHash is not set', () => { - props.diffFile.fileHash = null; + props.diffFile.file_hash = null; vm = mountComponentWithStore(Component, { props, store }); @@ -151,8 +150,8 @@ describe('diff_file_header', () => { describe('isUsingLfs', () => { beforeEach(() => { Object.assign(props.diffFile, { - storedExternally: true, - externalStorage: 'lfs', + stored_externally: true, + external_storage: 'lfs', }); }); @@ -163,7 +162,7 @@ describe('diff_file_header', () => { }); it('returns false if file is not stored externally', () => { - props.diffFile.storedExternally = false; + props.diffFile.stored_externally = false; vm = mountComponentWithStore(Component, { props, store }); @@ -171,7 +170,7 @@ describe('diff_file_header', () => { }); it('returns false if file is not stored in LFS', () => { - props.diffFile.externalStorage = 'not lfs'; + props.diffFile.external_storage = 'not lfs'; vm = mountComponentWithStore(Component, { props, store }); @@ -200,7 +199,7 @@ describe('diff_file_header', () => { describe('viewFileButtonText', () => { it('contains the truncated content SHA', () => { const dummySha = 'deebd00f is no SHA'; - props.diffFile.contentSha = dummySha; + props.diffFile.content_sha = dummySha; vm = mountComponentWithStore(Component, { props, store }); @@ -212,7 +211,7 @@ describe('diff_file_header', () => { describe('viewReplacedFileButtonText', () => { it('contains the truncated base SHA', () => { const dummySha = 'deadabba sings no more'; - props.diffFile.diffRefs.baseSha = dummySha; + props.diffFile.diff_refs.base_sha = dummySha; vm = mountComponentWithStore(Component, { props, store }); @@ -281,32 +280,32 @@ describe('diff_file_header', () => { const filePaths = () => vm.$el.querySelectorAll('.file-title-name'); it('displays the path of a added file', () => { - props.diffFile.renamedFile = false; + props.diffFile.renamed_file = false; vm = mountComponentWithStore(Component, { props, store }); expect(filePaths()).toHaveLength(1); - expect(filePaths()[0]).toHaveText(props.diffFile.filePath); + expect(filePaths()[0]).toHaveText(props.diffFile.file_path); }); it('displays path for deleted file', () => { - props.diffFile.renamedFile = false; - props.diffFile.deletedFile = true; + props.diffFile.renamed_file = false; + props.diffFile.deleted_file = true; vm = mountComponentWithStore(Component, { props, store }); expect(filePaths()).toHaveLength(1); - expect(filePaths()[0]).toHaveText(`${props.diffFile.filePath} deleted`); + expect(filePaths()[0]).toHaveText(`${props.diffFile.file_path} deleted`); }); it('displays old and new path if the file was renamed', () => { - props.diffFile.renamedFile = true; + props.diffFile.renamed_file = true; vm = mountComponentWithStore(Component, { props, store }); expect(filePaths()).toHaveLength(2); - expect(filePaths()[0]).toHaveText(props.diffFile.oldPath); - expect(filePaths()[1]).toHaveText(props.diffFile.newPath); + expect(filePaths()[0]).toHaveText(props.diffFile.old_path); + expect(filePaths()[1]).toHaveText(props.diffFile.new_path); }); }); @@ -323,19 +322,19 @@ describe('diff_file_header', () => { describe('file mode', () => { it('it displays old and new file mode if it changed', () => { - props.diffFile.modeChanged = true; + props.diffFile.mode_changed = true; vm = mountComponentWithStore(Component, { props, store }); const { fileMode } = vm.$refs; expect(fileMode).not.toBe(undefined); - expect(fileMode).toContainText(props.diffFile.aMode); - expect(fileMode).toContainText(props.diffFile.bMode); + expect(fileMode).toContainText(props.diffFile.a_mode); + expect(fileMode).toContainText(props.diffFile.b_mode); }); it('does not display the file mode if it has not changed', () => { - props.diffFile.modeChanged = false; + props.diffFile.mode_changed = false; vm = mountComponentWithStore(Component, { props, store }); @@ -350,8 +349,8 @@ describe('diff_file_header', () => { it('displays the LFS label for files stored in LFS', () => { Object.assign(props.diffFile, { - storedExternally: true, - externalStorage: 'lfs', + stored_externally: true, + external_storage: 'lfs', }); vm = mountComponentWithStore(Component, { props, store }); @@ -361,7 +360,7 @@ describe('diff_file_header', () => { }); it('does not display the LFS label for files stored in repository', () => { - props.diffFile.storedExternally = false; + props.diffFile.stored_externally = false; vm = mountComponentWithStore(Component, { props, store }); @@ -378,7 +377,7 @@ describe('diff_file_header', () => { it('should show edit button when file is editable', () => { props.addMergeRequestButtons = true; - props.diffFile.editPath = '/'; + props.diffFile.edit_path = '/'; vm = mountComponentWithStore(Component, { props, store }); expect(vm.$el.querySelector('.js-edit-blob')).toContainText('Edit'); @@ -386,8 +385,8 @@ describe('diff_file_header', () => { it('should not show edit button when file is deleted', () => { props.addMergeRequestButtons = true; - props.diffFile.deletedFile = true; - props.diffFile.editPath = '/'; + props.diffFile.deleted_file = true; + props.diffFile.edit_path = '/'; vm = mountComponentWithStore(Component, { props, store }); expect(vm.$el.querySelector('.js-edit-blob')).toEqual(null); @@ -397,7 +396,7 @@ describe('diff_file_header', () => { describe('addMergeRequestButtons', () => { beforeEach(() => { props.addMergeRequestButtons = true; - props.diffFile.editPath = ''; + props.diffFile.edit_path = ''; }); describe('view on environment button', () => { @@ -405,8 +404,8 @@ describe('diff_file_header', () => { const title = 'url.title'; it('displays link to external url', () => { - props.diffFile.externalUrl = url; - props.diffFile.formattedExternalUrl = title; + props.diffFile.external_url = url; + props.diffFile.formatted_external_url = title; vm = mountComponentWithStore(Component, { props, store }); @@ -415,8 +414,8 @@ describe('diff_file_header', () => { }); it('hides link if no external url', () => { - props.diffFile.externalUrl = ''; - props.diffFile.formattedExternalUrl = title; + props.diffFile.external_url = ''; + props.diffFile.formattedExternal_url = title; vm = mountComponentWithStore(Component, { props, store }); @@ -434,11 +433,11 @@ describe('diff_file_header', () => { path: 'lib/base.js', name: 'base.js', mode: '100644', - readableText: true, + readable_text: true, icon: 'file-text-o', }; propsCopy.addMergeRequestButtons = true; - propsCopy.diffFile.deletedFile = true; + propsCopy.diffFile.deleted_file = true; vm = mountComponentWithStore(Component, { props: propsCopy, @@ -459,11 +458,11 @@ describe('diff_file_header', () => { path: 'lib/base.js', name: 'base.js', mode: '100644', - readableText: true, + readable_text: true, icon: 'file-text-o', }; propsCopy.addMergeRequestButtons = true; - propsCopy.diffFile.deletedFile = true; + propsCopy.diffFile.deleted_file = true; const discussionGetter = () => [diffDiscussionMock]; const notesModuleMock = notesModule(); diff --git a/spec/javascripts/diffs/components/diff_file_spec.js b/spec/javascripts/diffs/components/diff_file_spec.js index 882ad3685a2..51bb4807960 100644 --- a/spec/javascripts/diffs/components/diff_file_spec.js +++ b/spec/javascripts/diffs/components/diff_file_spec.js @@ -17,14 +17,14 @@ describe('DiffFile', () => { describe('template', () => { it('should render component with file header, file content components', () => { const el = vm.$el; - const { fileHash, filePath } = vm.file; + const { file_hash, file_path } = vm.file; - expect(el.id).toEqual(fileHash); + expect(el.id).toEqual(file_hash); expect(el.classList.contains('diff-file')).toEqual(true); expect(el.querySelectorAll('.diff-content.hidden').length).toEqual(0); expect(el.querySelector('.js-file-title')).toBeDefined(); - expect(el.querySelector('.file-title-name').innerText.indexOf(filePath)).toBeGreaterThan(-1); + expect(el.querySelector('.file-title-name').innerText.indexOf(file_path)).toBeGreaterThan(-1); expect(el.querySelector('.js-syntax-highlight')).toBeDefined(); expect(vm.file.renderIt).toEqual(false); @@ -52,7 +52,7 @@ describe('DiffFile', () => { it('should have collapsed text and link', done => { vm.file.renderIt = true; vm.file.collapsed = false; - vm.file.highlightedDiffLines = null; + vm.file.highlighted_diff_lines = null; vm.$nextTick(() => { expect(vm.$el.innerText).toContain('This diff is collapsed'); @@ -90,8 +90,8 @@ describe('DiffFile', () => { describe('too large diff', () => { it('should have too large warning and blob link', done => { const BLOB_LINK = '/file/view/path'; - vm.file.tooLarge = true; - vm.file.viewPath = BLOB_LINK; + vm.file.too_large = true; + vm.file.view_path = BLOB_LINK; vm.$nextTick(() => { expect(vm.$el.innerText).toContain( @@ -107,4 +107,26 @@ describe('DiffFile', () => { }); }); }); + + describe('watch collapsed', () => { + it('calls handleLoadCollapsedDiff if collapsed changed & file has no lines', done => { + spyOn(vm, 'handleLoadCollapsedDiff'); + + vm.file.highlighted_diff_lines = undefined; + vm.file.parallel_diff_lines = []; + vm.file.collapsed = true; + + vm.$nextTick() + .then(() => { + vm.file.collapsed = false; + + return vm.$nextTick(); + }) + .then(() => { + expect(vm.handleLoadCollapsedDiff).toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + }); }); diff --git a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js index 6972e0ee913..038db8eaa7c 100644 --- a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js +++ b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js @@ -11,16 +11,16 @@ describe('DiffLineGutterContent', () => { const cmp = Vue.extend(DiffLineGutterContent); const props = Object.assign({}, options); props.line = { - lineCode: 'LC_42', + line_code: 'LC_42', type: 'new', - oldLine: null, - newLine: 1, - discussions: [], + old_line: null, + new_line: 1, + discussions: [{ ...discussionsMockData }], text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', - richText: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', - metaData: null, + rich_text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + meta_data: null, }; - props.fileHash = getDiffFileMock().fileHash; + props.fileHash = getDiffFileMock().file_hash; props.contextLinesPath = '/context/lines/path'; return createComponentWithStore(cmp, store, props).$mount(); @@ -37,7 +37,7 @@ describe('DiffLineGutterContent', () => { it('should return # if there is no lineCode', () => { const component = createComponent(); - component.line.lineCode = ''; + component.line.line_code = ''; expect(component.lineHref).toEqual('#'); }); @@ -46,6 +46,7 @@ describe('DiffLineGutterContent', () => { describe('discussions, hasDiscussions, shouldShowAvatarsOnGutter', () => { it('should return empty array when there is no discussion', () => { const component = createComponent(); + component.line.discussions = []; expect(component.hasDiscussions).toEqual(false); expect(component.shouldShowAvatarsOnGutter).toEqual(false); @@ -54,8 +55,8 @@ describe('DiffLineGutterContent', () => { it('should return discussions for the given lineCode', () => { const cmp = Vue.extend(DiffLineGutterContent); const props = { - line: getDiffFileMock().highlightedDiffLines[1], - fileHash: getDiffFileMock().fileHash, + line: getDiffFileMock().highlighted_diff_lines[1], + fileHash: getDiffFileMock().file_hash, showCommentButton: true, contextLinesPath: '/context/lines/path', }; @@ -104,10 +105,10 @@ describe('DiffLineGutterContent', () => { it('should render user avatars', () => { const component = createComponent({ showCommentButton: true, - lineCode: getDiffFileMock().highlightedDiffLines[1].lineCode, + lineCode: getDiffFileMock().highlighted_diff_lines[1].line_code, }); - expect(component.$el.querySelector('.diff-comment-avatar-holders')).toBeDefined(); + expect(component.$el.querySelector('.diff-comment-avatar-holders')).not.toBe(null); }); }); }); diff --git a/spec/javascripts/diffs/components/diff_line_note_form_spec.js b/spec/javascripts/diffs/components/diff_line_note_form_spec.js index c39b54d9cc9..81b66cf7c9b 100644 --- a/spec/javascripts/diffs/components/diff_line_note_form_spec.js +++ b/spec/javascripts/diffs/components/diff_line_note_form_spec.js @@ -13,10 +13,10 @@ describe('DiffLineNoteForm', () => { beforeEach(() => { diffFile = getDiffFileMock(); - diffLines = diffFile.highlightedDiffLines; + diffLines = diffFile.highlighted_diff_lines; component = createComponentWithStore(Vue.extend(DiffLineNoteForm), store, { - diffFileHash: diffFile.fileHash, + diffFileHash: diffFile.file_hash, diffLines, line: diffLines[0], noteTargetLine: diffLines[0], @@ -61,7 +61,7 @@ describe('DiffLineNoteForm', () => { expect(window.confirm).not.toHaveBeenCalled(); component.$nextTick(() => { expect(component.cancelCommentForm).toHaveBeenCalledWith({ - lineCode: diffLines[0].lineCode, + lineCode: diffLines[0].line_code, }); expect(component.resetAutoSave).toHaveBeenCalled(); diff --git a/spec/javascripts/diffs/components/inline_diff_view_spec.js b/spec/javascripts/diffs/components/inline_diff_view_spec.js index 705558e860b..2316ee29106 100644 --- a/spec/javascripts/diffs/components/inline_diff_view_spec.js +++ b/spec/javascripts/diffs/components/inline_diff_view_spec.js @@ -1,4 +1,5 @@ import Vue from 'vue'; +import '~/behaviors/markdown/render_gfm'; import InlineDiffView from '~/diffs/components/inline_diff_view.vue'; import store from '~/mr_notes/stores'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; @@ -10,14 +11,16 @@ describe('InlineDiffView', () => { const getDiffFileMock = () => Object.assign({}, diffFileMockData); const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)]; - beforeEach(() => { + beforeEach(done => { const diffFile = getDiffFileMock(); store.dispatch('diffs/setInlineDiffViewType'); component = createComponentWithStore(Vue.extend(InlineDiffView), store, { diffFile, - diffLines: diffFile.highlightedDiffLines, + diffLines: diffFile.highlighted_diff_lines, }).$mount(); + + Vue.nextTick(done); }); describe('template', () => { @@ -32,7 +35,7 @@ describe('InlineDiffView', () => { it('should render discussions', done => { const el = component.$el; - component.$store.dispatch('setInitialNotes', getDiscussionsMockData()); + component.diffLines[1].discussions = getDiscussionsMockData(); Vue.nextTick(() => { expect(el.querySelectorAll('.notes_holder').length).toEqual(1); diff --git a/spec/javascripts/diffs/components/parallel_diff_view_spec.js b/spec/javascripts/diffs/components/parallel_diff_view_spec.js index 091e01868d3..6f6b1c41915 100644 --- a/spec/javascripts/diffs/components/parallel_diff_view_spec.js +++ b/spec/javascripts/diffs/components/parallel_diff_view_spec.js @@ -14,7 +14,7 @@ describe('ParallelDiffView', () => { component = createComponentWithStore(Vue.extend(ParallelDiffView), store, { diffFile, - diffLines: diffFile.parallelDiffLines, + diffLines: diffFile.parallel_diff_lines, }).$mount(); }); diff --git a/spec/javascripts/diffs/mock_data/diff_file.js b/spec/javascripts/diffs/mock_data/diff_file.js index be194ab414f..031c9842f2f 100644 --- a/spec/javascripts/diffs/mock_data/diff_file.js +++ b/spec/javascripts/diffs/mock_data/diff_file.js @@ -1,130 +1,130 @@ export default { submodule: false, - submoduleLink: null, + submodule_link: null, blob: { id: '9e10516ca50788acf18c518a231914a21e5f16f7', path: 'CHANGELOG', name: 'CHANGELOG', mode: '100644', - readableText: true, + readable_text: true, icon: 'file-text-o', }, - blobPath: 'CHANGELOG', - blobName: 'CHANGELOG', - blobIcon: '<i aria-hidden="true" data-hidden="true" class="fa fa-file-text-o fa-fw"></i>', - fileHash: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a', - filePath: 'CHANGELOG', - newFile: false, - deletedFile: false, - renamedFile: false, - oldPath: 'CHANGELOG', - newPath: 'CHANGELOG', - modeChanged: false, - aMode: '100644', - bMode: '100644', + blob_path: 'CHANGELOG', + blob_name: 'CHANGELOG', + blob_icon: '<i aria-hidden="true" data-hidden="true" class="fa fa-file-text-o fa-fw"></i>', + file_hash: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a', + file_path: 'CHANGELOG', + new_file: false, + deleted_file: false, + renamed_file: false, + old_path: 'CHANGELOG', + new_path: 'CHANGELOG', + mode_changed: false, + a_mode: '100644', + b_mode: '100644', text: true, viewer: { name: 'text', }, - addedLines: 2, - removedLines: 0, - diffRefs: { - baseSha: 'e63f41fe459e62e1228fcef60d7189127aeba95a', - startSha: 'd9eaefe5a676b820c57ff18cf5b68316025f7962', - headSha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13', + added_lines: 2, + removed_lines: 0, + diff_refs: { + base_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a', + start_sha: 'd9eaefe5a676b820c57ff18cf5b68316025f7962', + head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13', }, - contentSha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13', - storedExternally: null, - externalStorage: null, - oldPathHtml: 'CHANGELOG', - newPathHtml: 'CHANGELOG', - editPath: '/gitlab-org/gitlab-test/edit/spooky-stuff/CHANGELOG', - viewPath: '/gitlab-org/gitlab-test/blob/spooky-stuff/CHANGELOG', - replacedViewPath: null, + content_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13', + stored_externally: null, + external_storage: null, + old_path_html: 'CHANGELOG', + new_path_html: 'CHANGELOG', + edit_path: '/gitlab-org/gitlab-test/edit/spooky-stuff/CHANGELOG', + view_path: '/gitlab-org/gitlab-test/blob/spooky-stuff/CHANGELOG', + replaced_view_path: null, collapsed: false, renderIt: false, - tooLarge: false, - contextLinesPath: + too_large: false, + context_lines_path: '/gitlab-org/gitlab-test/blob/c48ee0d1bf3b30453f5b32250ce03134beaa6d13/CHANGELOG/diff', - highlightedDiffLines: [ + highlighted_diff_lines: [ { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1', type: 'new', - oldLine: null, - newLine: 1, + old_line: null, + new_line: 1, discussions: [], text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', - richText: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', - metaData: null, + rich_text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + meta_data: null, }, { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2', type: 'new', - oldLine: null, - newLine: 2, + old_line: null, + new_line: 2, discussions: [], text: '+<span id="LC2" class="line" lang="plaintext"></span>\n', - richText: '+<span id="LC2" class="line" lang="plaintext"></span>\n', - metaData: null, + rich_text: '+<span id="LC2" class="line" lang="plaintext"></span>\n', + meta_data: null, }, { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', type: null, - oldLine: 1, - newLine: 3, + old_line: 1, + new_line: 3, discussions: [], text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', - richText: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', - metaData: null, + rich_text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + meta_data: null, }, { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', type: null, - oldLine: 2, - newLine: 4, + old_line: 2, + new_line: 4, discussions: [], text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', - richText: ' <span id="LC4" class="line" lang="plaintext"></span>\n', - metaData: null, + rich_text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', + meta_data: null, }, { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', type: null, - oldLine: 3, - newLine: 5, + old_line: 3, + new_line: 5, discussions: [], text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', - richText: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', - metaData: null, + rich_text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + meta_data: null, }, { - lineCode: null, + line_code: null, type: 'match', - oldLine: null, - newLine: null, + old_line: null, + new_line: null, discussions: [], text: '', - richText: '', - metaData: { - oldPos: 3, - newPos: 5, + rich_text: '', + meta_data: { + old_pos: 3, + new_pos: 5, }, }, ], - parallelDiffLines: [ + parallel_diff_lines: [ { left: { type: 'empty-cell', }, right: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1', type: 'new', - oldLine: null, - newLine: 1, + old_line: null, + new_line: 1, discussions: [], text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', - richText: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', - metaData: null, + rich_text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + meta_data: null, }, }, { @@ -132,107 +132,107 @@ export default { type: 'empty-cell', }, right: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2', type: 'new', - oldLine: null, - newLine: 2, + old_line: null, + new_line: 2, discussions: [], text: '+<span id="LC2" class="line" lang="plaintext"></span>\n', - richText: '<span id="LC2" class="line" lang="plaintext"></span>\n', - metaData: null, + rich_text: '<span id="LC2" class="line" lang="plaintext"></span>\n', + meta_data: null, }, }, { left: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', + line_Code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', type: null, - oldLine: 1, - newLine: 3, + old_line: 1, + new_line: 3, discussions: [], text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', - richText: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', - metaData: null, + rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + meta_data: null, }, right: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', type: null, - oldLine: 1, - newLine: 3, + old_line: 1, + new_line: 3, discussions: [], text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', - richText: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', - metaData: null, + rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + meta_data: null, }, }, { left: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', type: null, - oldLine: 2, - newLine: 4, + old_line: 2, + new_line: 4, discussions: [], text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', - richText: '<span id="LC4" class="line" lang="plaintext"></span>\n', - metaData: null, + rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n', + meta_data: null, }, right: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', type: null, - oldLine: 2, - newLine: 4, + old_line: 2, + new_line: 4, discussions: [], text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', - richText: '<span id="LC4" class="line" lang="plaintext"></span>\n', - metaData: null, + rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n', + meta_data: null, }, }, { left: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', type: null, - oldLine: 3, - newLine: 5, + old_line: 3, + new_line: 5, discussions: [], text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', - richText: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', - metaData: null, + rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + meta_data: null, }, right: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', type: null, - oldLine: 3, - newLine: 5, + old_line: 3, + new_line: 5, discussions: [], text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', - richText: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', - metaData: null, + rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + meta_data: null, }, }, { left: { - lineCode: null, + line_code: null, type: 'match', - oldLine: null, - newLine: null, + old_line: null, + new_line: null, discussions: [], text: '', - richText: '', - metaData: { - oldPos: 3, - newPos: 5, + rich_text: '', + meta_data: { + old_pos: 3, + new_pos: 5, }, }, right: { - lineCode: null, + line_code: null, type: 'match', - oldLine: null, - newLine: null, + old_line: null, + new_line: null, discussions: [], text: '', - richText: '', - metaData: { - oldPos: 3, - newPos: 5, + rich_text: '', + meta_data: { + old_pos: 3, + new_pos: 5, }, }, }, diff --git a/spec/javascripts/diffs/mock_data/diff_with_commit.js b/spec/javascripts/diffs/mock_data/diff_with_commit.js index bee04fa4932..d646294ee84 100644 --- a/spec/javascripts/diffs/mock_data/diff_with_commit.js +++ b/spec/javascripts/diffs/mock_data/diff_with_commit.js @@ -1,9 +1,7 @@ -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; - const FIXTURE = 'merge_request_diffs/with_commit.json'; preloadFixtures(FIXTURE); export default function getDiffWithCommit() { - return convertObjectPropsToCamelCase(getJSONFixture(FIXTURE), { deep: true }); + return getJSONFixture(FIXTURE); } diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js index 17d0f31bdd3..acd95a3dd8b 100644 --- a/spec/javascripts/diffs/store/actions_spec.js +++ b/spec/javascripts/diffs/store/actions_spec.js @@ -97,46 +97,46 @@ describe('DiffsStoreActions', () => { const state = { diffFiles: [ { - fileHash: 'ABC', - parallelDiffLines: [ + file_hash: 'ABC', + parallel_diff_lines: [ { left: { - lineCode: 'ABC_1_1', + line_code: 'ABC_1_1', discussions: [], }, right: { - lineCode: 'ABC_1_1', + line_code: 'ABC_1_1', discussions: [], }, }, ], - highlightedDiffLines: [ + highlighted_diff_lines: [ { - lineCode: 'ABC_1_1', + line_code: 'ABC_1_1', discussions: [], - oldLine: 5, - newLine: null, + old_line: 5, + new_line: null, }, ], - diffRefs: { - baseSha: 'abc', - headSha: 'def', - startSha: 'ghi', + diff_refs: { + base_sha: 'abc', + head_sha: 'def', + start_sha: 'ghi', }, - newPath: 'file1', - oldPath: 'file2', + new_path: 'file1', + old_path: 'file2', }, ], }; const diffPosition = { - baseSha: 'abc', - headSha: 'def', - startSha: 'ghi', - newLine: null, - newPath: 'file1', - oldLine: 5, - oldPath: 'file2', + base_sha: 'abc', + head_sha: 'def', + start_sha: 'ghi', + new_line: null, + new_path: 'file1', + old_line: 5, + old_path: 'file2', }; const singleDiscussion = { @@ -145,7 +145,7 @@ describe('DiffsStoreActions', () => { diff_file: { file_hash: 'ABC', }, - fileHash: 'ABC', + file_hash: 'ABC', resolvable: true, position: diffPosition, original_position: diffPosition, @@ -164,24 +164,22 @@ describe('DiffsStoreActions', () => { discussion: singleDiscussion, diffPositionByLineCode: { ABC_1_1: { - baseSha: 'abc', - headSha: 'def', - startSha: 'ghi', - newLine: null, - newPath: 'file1', - oldLine: 5, - oldPath: 'file2', - lineCode: 'ABC_1_1', - positionType: 'text', + base_sha: 'abc', + head_sha: 'def', + start_sha: 'ghi', + new_line: null, + new_path: 'file1', + old_line: 5, + old_path: 'file2', + line_code: 'ABC_1_1', + position_type: 'text', }, }, }, }, ], [], - () => { - done(); - }, + done, ); }); }); @@ -191,11 +189,11 @@ describe('DiffsStoreActions', () => { const state = { diffFiles: [ { - fileHash: 'ABC', - parallelDiffLines: [ + file_hash: 'ABC', + parallel_diff_lines: [ { left: { - lineCode: 'ABC_1_1', + line_code: 'ABC_1_1', discussions: [ { id: 1, @@ -203,14 +201,14 @@ describe('DiffsStoreActions', () => { ], }, right: { - lineCode: 'ABC_1_1', + line_code: 'ABC_1_1', discussions: [], }, }, ], - highlightedDiffLines: [ + highlighted_diff_lines: [ { - lineCode: 'ABC_1_1', + line_code: 'ABC_1_1', discussions: [], }, ], @@ -219,7 +217,7 @@ describe('DiffsStoreActions', () => { }; const singleDiscussion = { id: '1', - fileHash: 'ABC', + file_hash: 'ABC', line_code: 'ABC_1_1', }; @@ -238,9 +236,7 @@ describe('DiffsStoreActions', () => { }, ], [], - () => { - done(); - }, + done, ); }); }); @@ -420,7 +416,7 @@ describe('DiffsStoreActions', () => { const getters = { getDiffFileDiscussions: jasmine.createSpy().and.returnValue([{ id: 1 }]), diffHasAllExpandedDiscussions: jasmine.createSpy().and.returnValue(true), - diffHasAllCollpasedDiscussions: jasmine.createSpy().and.returnValue(false), + diffHasAllCollapsedDiscussions: jasmine.createSpy().and.returnValue(false), }; const dispatch = jasmine.createSpy('dispatch'); @@ -438,7 +434,7 @@ describe('DiffsStoreActions', () => { const getters = { getDiffFileDiscussions: jasmine.createSpy().and.returnValue([{ id: 1 }]), diffHasAllExpandedDiscussions: jasmine.createSpy().and.returnValue(false), - diffHasAllCollpasedDiscussions: jasmine.createSpy().and.returnValue(true), + diffHasAllCollapsedDiscussions: jasmine.createSpy().and.returnValue(true), }; const dispatch = jasmine.createSpy(); @@ -456,7 +452,7 @@ describe('DiffsStoreActions', () => { const getters = { getDiffFileDiscussions: jasmine.createSpy().and.returnValue([{ expanded: false, id: 1 }]), diffHasAllExpandedDiscussions: jasmine.createSpy().and.returnValue(false), - diffHasAllCollpasedDiscussions: jasmine.createSpy().and.returnValue(false), + diffHasAllCollapsedDiscussions: jasmine.createSpy().and.returnValue(false), }; const dispatch = jasmine.createSpy(); diff --git a/spec/javascripts/diffs/store/getters_spec.js b/spec/javascripts/diffs/store/getters_spec.js index 9c3a38fd526..eef95c823fb 100644 --- a/spec/javascripts/diffs/store/getters_spec.js +++ b/spec/javascripts/diffs/store/getters_spec.js @@ -106,13 +106,13 @@ describe('Diffs Module Getters', () => { }); }); - describe('diffHasAllCollpasedDiscussions', () => { + describe('diffHasAllCollapsedDiscussions', () => { it('returns true when all discussions are collapsed', () => { discussionMock.diff_file.file_hash = diffFileMock.fileHash; discussionMock.expanded = false; expect( - getters.diffHasAllCollpasedDiscussions(localState, { + getters.diffHasAllCollapsedDiscussions(localState, { getDiffFileDiscussions: () => [discussionMock], })(diffFileMock), ).toEqual(true); @@ -120,7 +120,7 @@ describe('Diffs Module Getters', () => { it('returns false when there are no discussions', () => { expect( - getters.diffHasAllCollpasedDiscussions(localState, { + getters.diffHasAllCollapsedDiscussions(localState, { getDiffFileDiscussions: () => [], })(diffFileMock), ).toEqual(false); @@ -130,7 +130,7 @@ describe('Diffs Module Getters', () => { discussionMock1.expanded = false; expect( - getters.diffHasAllCollpasedDiscussions(localState, { + getters.diffHasAllCollapsedDiscussions(localState, { getDiffFileDiscussions: () => [discussionMock, discussionMock1], })(diffFileMock), ).toEqual(false); @@ -195,12 +195,12 @@ describe('Diffs Module Getters', () => { discussionMock.expanded = true; line.left = { - lineCode: 'ABC', + line_code: 'ABC', discussions: [discussionMock], }; line.right = { - lineCode: 'DEF', + line_code: 'DEF', discussions: [discussionMock1], }; }); @@ -259,7 +259,7 @@ describe('Diffs Module Getters', () => { describe('getDiffFileDiscussions', () => { it('returns an array with discussions when fileHash matches and the discussion belongs to a diff', () => { - discussionMock.diff_file.file_hash = diffFileMock.fileHash; + discussionMock.diff_file.file_hash = diffFileMock.file_hash; expect( getters.getDiffFileDiscussions(localState, {}, {}, { discussions: [discussionMock] })( @@ -279,10 +279,10 @@ describe('Diffs Module Getters', () => { describe('getDiffFileByHash', () => { it('returns file by hash', () => { const fileA = { - fileHash: '123', + file_hash: '123', }; const fileB = { - fileHash: '456', + file_hash: '456', }; localState.diffFiles = [fileA, fileB]; diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js index 8821cde76f4..598d723c940 100644 --- a/spec/javascripts/diffs/store/mutations_spec.js +++ b/spec/javascripts/diffs/store/mutations_spec.js @@ -37,7 +37,7 @@ describe('DiffsStoreMutations', () => { mutations[types.SET_DIFF_DATA](state, diffMock); - const firstLine = state.diffFiles[0].parallelDiffLines[0]; + const firstLine = state.diffFiles[0].parallel_diff_lines[0]; expect(firstLine.right.text).toBeUndefined(); expect(state.diffFiles[0].renderIt).toEqual(true); @@ -98,19 +98,19 @@ describe('DiffsStoreMutations', () => { it('should call utils.addContextLines with proper params', () => { const options = { lineNumbers: { oldLineNumber: 1, newLineNumber: 2 }, - contextLines: [{ oldLine: 1, newLine: 1, lineCode: 'ff9200_1_1', discussions: [] }], + contextLines: [{ old_line: 1, new_line: 1, line_code: 'ff9200_1_1', discussions: [] }], fileHash: 'ff9200', params: { bottom: true, }, }; const diffFile = { - fileHash: options.fileHash, - highlightedDiffLines: [], - parallelDiffLines: [], + file_hash: options.fileHash, + highlighted_diff_lines: [], + parallel_diff_lines: [], }; const state = { diffFiles: [diffFile] }; - const lines = [{ oldLine: 1, newLine: 1 }]; + const lines = [{ old_line: 1, new_line: 1 }]; const findDiffFileSpy = spyOnDependency(mutations, 'findDiffFile').and.returnValue(diffFile); const removeMatchLineSpy = spyOnDependency(mutations, 'removeMatchLine'); @@ -133,8 +133,8 @@ describe('DiffsStoreMutations', () => { ); expect(addContextLinesSpy).toHaveBeenCalledWith({ - inlineLines: diffFile.highlightedDiffLines, - parallelLines: diffFile.parallelDiffLines, + inlineLines: diffFile.highlighted_diff_lines, + parallelLines: diffFile.parallel_diff_lines, contextLines: options.contextLines, bottom: options.params.bottom, lineNumbers: options.lineNumbers, @@ -144,54 +144,50 @@ describe('DiffsStoreMutations', () => { describe('ADD_COLLAPSED_DIFFS', () => { it('should update the state with the given data for the given file hash', () => { - const spy = spyOnDependency(mutations, 'convertObjectPropsToCamelCase').and.callThrough(); - const fileHash = 123; - const state = { diffFiles: [{}, { fileHash, existingField: 0 }] }; - const data = { diff_files: [{ file_hash: fileHash, extra_field: 1, existingField: 1 }] }; + const state = { diffFiles: [{}, { file_hash: fileHash, existing_field: 0 }] }; + const data = { diff_files: [{ file_hash: fileHash, extra_field: 1, existing_field: 1 }] }; mutations[types.ADD_COLLAPSED_DIFFS](state, { file: state.diffFiles[1], data }); - expect(spy).toHaveBeenCalledWith(data, { deep: true }); - - expect(state.diffFiles[1].fileHash).toEqual(fileHash); - expect(state.diffFiles[1].existingField).toEqual(1); - expect(state.diffFiles[1].extraField).toEqual(1); + expect(state.diffFiles[1].file_hash).toEqual(fileHash); + expect(state.diffFiles[1].existing_field).toEqual(1); + expect(state.diffFiles[1].extra_field).toEqual(1); }); }); describe('SET_LINE_DISCUSSIONS_FOR_FILE', () => { it('should add discussions to the given line', () => { const diffPosition = { - baseSha: 'ed13df29948c41ba367caa757ab3ec4892509910', - headSha: 'b921914f9a834ac47e6fd9420f78db0f83559130', - newLine: null, - newPath: '500-lines-4.txt', - oldLine: 5, - oldPath: '500-lines-4.txt', - startSha: 'ed13df29948c41ba367caa757ab3ec4892509910', + base_sha: 'ed13df29948c41ba367caa757ab3ec4892509910', + head_sha: 'b921914f9a834ac47e6fd9420f78db0f83559130', + new_line: null, + new_path: '500-lines-4.txt', + old_line: 5, + old_path: '500-lines-4.txt', + start_sha: 'ed13df29948c41ba367caa757ab3ec4892509910', }; const state = { latestDiff: true, diffFiles: [ { - fileHash: 'ABC', - parallelDiffLines: [ + file_hash: 'ABC', + parallel_diff_lines: [ { left: { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [], }, right: { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [], }, }, ], - highlightedDiffLines: [ + highlighted_diff_lines: [ { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [], }, ], @@ -206,7 +202,7 @@ describe('DiffsStoreMutations', () => { original_position: diffPosition, position: diffPosition, diff_file: { - file_hash: state.diffFiles[0].fileHash, + file_hash: state.diffFiles[0].file_hash, }, }; @@ -219,46 +215,46 @@ describe('DiffsStoreMutations', () => { diffPositionByLineCode, }); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(1); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[0].id).toEqual(1); - expect(state.diffFiles[0].parallelDiffLines[0].right.discussions).toEqual([]); + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions.length).toEqual(1); + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions[0].id).toEqual(1); + expect(state.diffFiles[0].parallel_diff_lines[0].right.discussions).toEqual([]); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(1); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions[0].id).toEqual(1); + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions.length).toEqual(1); + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions[0].id).toEqual(1); }); it('should add legacy discussions to the given line', () => { const diffPosition = { - baseSha: 'ed13df29948c41ba367caa757ab3ec4892509910', - headSha: 'b921914f9a834ac47e6fd9420f78db0f83559130', - newLine: null, - newPath: '500-lines-4.txt', - oldLine: 5, - oldPath: '500-lines-4.txt', - startSha: 'ed13df29948c41ba367caa757ab3ec4892509910', - lineCode: 'ABC_1', + base_sha: 'ed13df29948c41ba367caa757ab3ec4892509910', + head_sha: 'b921914f9a834ac47e6fd9420f78db0f83559130', + new_line: null, + new_path: '500-lines-4.txt', + old_line: 5, + old_path: '500-lines-4.txt', + start_sha: 'ed13df29948c41ba367caa757ab3ec4892509910', + line_code: 'ABC_1', }; const state = { latestDiff: true, diffFiles: [ { - fileHash: 'ABC', - parallelDiffLines: [ + file_hash: 'ABC', + parallel_diff_lines: [ { left: { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [], }, right: { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [], }, }, ], - highlightedDiffLines: [ + highlighted_diff_lines: [ { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [], }, ], @@ -271,7 +267,7 @@ describe('DiffsStoreMutations', () => { diff_discussion: true, active: true, diff_file: { - file_hash: state.diffFiles[0].fileHash, + file_hash: state.diffFiles[0].file_hash, }, }; @@ -284,11 +280,11 @@ describe('DiffsStoreMutations', () => { diffPositionByLineCode, }); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(1); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[0].id).toEqual(1); + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions.length).toEqual(1); + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions[0].id).toEqual(1); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(1); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions[0].id).toEqual(1); + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions.length).toEqual(1); + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions[0].id).toEqual(1); }); }); @@ -297,11 +293,11 @@ describe('DiffsStoreMutations', () => { const state = { diffFiles: [ { - fileHash: 'ABC', - parallelDiffLines: [ + file_hash: 'ABC', + parallel_diff_lines: [ { left: { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [ { id: 1, @@ -314,14 +310,14 @@ describe('DiffsStoreMutations', () => { ], }, right: { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [], }, }, ], - highlightedDiffLines: [ + highlighted_diff_lines: [ { - lineCode: 'ABC_1', + line_code: 'ABC_1', discussions: [ { id: 1, @@ -343,8 +339,8 @@ describe('DiffsStoreMutations', () => { lineCode: 'ABC_1', }); - expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(0); - expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(0); + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions.length).toEqual(0); + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions.length).toEqual(0); }); }); diff --git a/spec/javascripts/diffs/store/utils_spec.js b/spec/javascripts/diffs/store/utils_spec.js index f49dee3696d..d4ef17c5ef8 100644 --- a/spec/javascripts/diffs/store/utils_spec.js +++ b/spec/javascripts/diffs/store/utils_spec.js @@ -18,7 +18,7 @@ const getDiffFileMock = () => Object.assign({}, diffFileMockData); describe('DiffsStoreUtils', () => { describe('findDiffFile', () => { - const files = [{ fileHash: 1, name: 'one' }]; + const files = [{ file_hash: 1, name: 'one' }]; it('should return correct file', () => { expect(utils.findDiffFile(files, 1).name).toEqual('one'); @@ -41,13 +41,13 @@ describe('DiffsStoreUtils', () => { describe('findIndexInInlineLines', () => { it('should return correct index for given line numbers', () => { - expectSet(utils.findIndexInInlineLines, getDiffFileMock().highlightedDiffLines); + expectSet(utils.findIndexInInlineLines, getDiffFileMock().highlighted_diff_lines); }); }); describe('findIndexInParallelLines', () => { it('should return correct index for given line numbers', () => { - expectSet(utils.findIndexInParallelLines, getDiffFileMock().parallelDiffLines, {}); + expectSet(utils.findIndexInParallelLines, getDiffFileMock().parallel_diff_lines, {}); }); }); }); @@ -56,33 +56,39 @@ describe('DiffsStoreUtils', () => { it('should remove match line properly by regarding the bottom parameter', () => { const diffFile = getDiffFileMock(); const lineNumbers = { oldLineNumber: 3, newLineNumber: 5 }; - const inlineIndex = utils.findIndexInInlineLines(diffFile.highlightedDiffLines, lineNumbers); - const parallelIndex = utils.findIndexInParallelLines(diffFile.parallelDiffLines, lineNumbers); - const atInlineIndex = diffFile.highlightedDiffLines[inlineIndex]; - const atParallelIndex = diffFile.parallelDiffLines[parallelIndex]; + const inlineIndex = utils.findIndexInInlineLines( + diffFile.highlighted_diff_lines, + lineNumbers, + ); + const parallelIndex = utils.findIndexInParallelLines( + diffFile.parallel_diff_lines, + lineNumbers, + ); + const atInlineIndex = diffFile.highlighted_diff_lines[inlineIndex]; + const atParallelIndex = diffFile.parallel_diff_lines[parallelIndex]; utils.removeMatchLine(diffFile, lineNumbers, false); - expect(diffFile.highlightedDiffLines[inlineIndex]).not.toEqual(atInlineIndex); - expect(diffFile.parallelDiffLines[parallelIndex]).not.toEqual(atParallelIndex); + expect(diffFile.highlighted_diff_lines[inlineIndex]).not.toEqual(atInlineIndex); + expect(diffFile.parallel_diff_lines[parallelIndex]).not.toEqual(atParallelIndex); utils.removeMatchLine(diffFile, lineNumbers, true); - expect(diffFile.highlightedDiffLines[inlineIndex + 1]).not.toEqual(atInlineIndex); - expect(diffFile.parallelDiffLines[parallelIndex + 1]).not.toEqual(atParallelIndex); + expect(diffFile.highlighted_diff_lines[inlineIndex + 1]).not.toEqual(atInlineIndex); + expect(diffFile.parallel_diff_lines[parallelIndex + 1]).not.toEqual(atParallelIndex); }); }); describe('addContextLines', () => { it('should add context lines properly with bottom parameter', () => { const diffFile = getDiffFileMock(); - const inlineLines = diffFile.highlightedDiffLines; - const parallelLines = diffFile.parallelDiffLines; + const inlineLines = diffFile.highlighted_diff_lines; + const parallelLines = diffFile.parallel_diff_lines; const lineNumbers = { oldLineNumber: 3, newLineNumber: 5 }; const contextLines = [{ lineNumber: 42 }]; const options = { inlineLines, parallelLines, contextLines, lineNumbers, bottom: true }; - const inlineIndex = utils.findIndexInInlineLines(diffFile.highlightedDiffLines, lineNumbers); - const parallelIndex = utils.findIndexInParallelLines(diffFile.parallelDiffLines, lineNumbers); + const inlineIndex = utils.findIndexInInlineLines(inlineLines, lineNumbers); + const parallelIndex = utils.findIndexInParallelLines(parallelLines, lineNumbers); const normalizedParallelLine = { left: options.contextLines[0], right: options.contextLines[0], @@ -112,30 +118,30 @@ describe('DiffsStoreUtils', () => { noteableType: MERGE_REQUEST_NOTEABLE_TYPE, diffFile, noteTargetLine: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', - metaData: null, - newLine: 3, - oldLine: 1, + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', + meta_data: null, + new_line: 3, + old_line: 1, }, diffViewType: PARALLEL_DIFF_VIEW_TYPE, linePosition: LINE_POSITION_LEFT, }; const position = JSON.stringify({ - base_sha: diffFile.diffRefs.baseSha, - start_sha: diffFile.diffRefs.startSha, - head_sha: diffFile.diffRefs.headSha, - old_path: diffFile.oldPath, - new_path: diffFile.newPath, + base_sha: diffFile.diff_refs.base_sha, + start_sha: diffFile.diff_refs.start_sha, + head_sha: diffFile.diff_refs.head_sha, + old_path: diffFile.old_path, + new_path: diffFile.new_path, position_type: TEXT_DIFF_POSITION_TYPE, - old_line: options.noteTargetLine.oldLine, - new_line: options.noteTargetLine.newLine, + old_line: options.noteTargetLine.old_line, + new_line: options.noteTargetLine.new_line, }); const postData = { view: options.diffViewType, line_type: options.linePosition === LINE_POSITION_RIGHT ? NEW_LINE_TYPE : OLD_LINE_TYPE, - merge_request_diff_head_sha: diffFile.diffRefs.headSha, + merge_request_diff_head_sha: diffFile.diff_refs.head_sha, in_reply_to_discussion_id: '', note_project_id: '', target_type: options.noteableType, @@ -146,7 +152,7 @@ describe('DiffsStoreUtils', () => { noteable_id: options.noteableData.id, commit_id: '', type: DIFF_NOTE_TYPE, - line_code: options.noteTargetLine.lineCode, + line_code: options.noteTargetLine.line_code, note: options.note, position, }, @@ -160,8 +166,8 @@ describe('DiffsStoreUtils', () => { it('should create legacy note form data', () => { const diffFile = getDiffFileMock(); - delete diffFile.diffRefs.startSha; - delete diffFile.diffRefs.headSha; + delete diffFile.diff_refs.start_sha; + delete diffFile.diff_refs.head_sha; noteableDataMock.targetType = MERGE_REQUEST_NOTEABLE_TYPE; @@ -171,24 +177,24 @@ describe('DiffsStoreUtils', () => { noteableType: MERGE_REQUEST_NOTEABLE_TYPE, diffFile, noteTargetLine: { - lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', - metaData: null, - newLine: 3, - oldLine: 1, + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', + meta_data: null, + new_line: 3, + old_line: 1, }, diffViewType: PARALLEL_DIFF_VIEW_TYPE, linePosition: LINE_POSITION_LEFT, }; const position = JSON.stringify({ - base_sha: diffFile.diffRefs.baseSha, + base_sha: diffFile.diff_refs.base_sha, start_sha: undefined, head_sha: undefined, - old_path: diffFile.oldPath, - new_path: diffFile.newPath, + old_path: diffFile.old_path, + new_path: diffFile.new_path, position_type: TEXT_DIFF_POSITION_TYPE, - old_line: options.noteTargetLine.oldLine, - new_line: options.noteTargetLine.newLine, + old_line: options.noteTargetLine.old_line, + new_line: options.noteTargetLine.new_line, }); const postData = { @@ -205,7 +211,7 @@ describe('DiffsStoreUtils', () => { noteable_id: options.noteableData.id, commit_id: '', type: LEGACY_DIFF_NOTE_TYPE, - line_code: options.noteTargetLine.lineCode, + line_code: options.noteTargetLine.line_code, note: options.note, position, }, @@ -225,61 +231,61 @@ describe('DiffsStoreUtils', () => { const lines = [{ type: null }, { type: MATCH_LINE_TYPE }]; const linesWithReferences = utils.addLineReferences(lines, lineNumbers, true); - expect(linesWithReferences[0].oldLine).toEqual(lineNumbers.oldLineNumber + 1); - expect(linesWithReferences[0].newLine).toEqual(lineNumbers.newLineNumber + 1); - expect(linesWithReferences[1].metaData.oldPos).toEqual(4); - expect(linesWithReferences[1].metaData.newPos).toEqual(5); + expect(linesWithReferences[0].old_line).toEqual(lineNumbers.oldLineNumber + 1); + expect(linesWithReferences[0].new_line).toEqual(lineNumbers.newLineNumber + 1); + expect(linesWithReferences[1].meta_data.old_pos).toEqual(4); + expect(linesWithReferences[1].meta_data.new_pos).toEqual(5); }); it('should add correct line references when bottom falsy', () => { const lines = [{ type: null }, { type: MATCH_LINE_TYPE }, { type: null }]; const linesWithReferences = utils.addLineReferences(lines, lineNumbers); - expect(linesWithReferences[0].oldLine).toEqual(0); - expect(linesWithReferences[0].newLine).toEqual(1); - expect(linesWithReferences[1].metaData.oldPos).toEqual(2); - expect(linesWithReferences[1].metaData.newPos).toEqual(3); + expect(linesWithReferences[0].old_line).toEqual(0); + expect(linesWithReferences[0].new_line).toEqual(1); + expect(linesWithReferences[1].meta_data.old_pos).toEqual(2); + expect(linesWithReferences[1].meta_data.new_pos).toEqual(3); }); }); describe('trimFirstCharOfLineContent', () => { it('trims the line when it starts with a space', () => { - expect(utils.trimFirstCharOfLineContent({ richText: ' diff' })).toEqual({ + expect(utils.trimFirstCharOfLineContent({ rich_text: ' diff' })).toEqual({ discussions: [], - richText: 'diff', + rich_text: 'diff', }); }); it('trims the line when it starts with a +', () => { - expect(utils.trimFirstCharOfLineContent({ richText: '+diff' })).toEqual({ + expect(utils.trimFirstCharOfLineContent({ rich_text: '+diff' })).toEqual({ discussions: [], - richText: 'diff', + rich_text: 'diff', }); }); it('trims the line when it starts with a -', () => { - expect(utils.trimFirstCharOfLineContent({ richText: '-diff' })).toEqual({ + expect(utils.trimFirstCharOfLineContent({ rich_text: '-diff' })).toEqual({ discussions: [], - richText: 'diff', + rich_text: 'diff', }); }); it('does not trims the line when it starts with a letter', () => { - expect(utils.trimFirstCharOfLineContent({ richText: 'diff' })).toEqual({ + expect(utils.trimFirstCharOfLineContent({ rich_text: 'diff' })).toEqual({ discussions: [], - richText: 'diff', + rich_text: 'diff', }); }); it('does not modify the provided object', () => { const lineObj = { discussions: [], - richText: ' diff', + rich_text: ' diff', }; utils.trimFirstCharOfLineContent(lineObj); - expect(lineObj).toEqual({ discussions: [], richText: ' diff' }); + expect(lineObj).toEqual({ discussions: [], rich_text: ' diff' }); }); it('handles a undefined or null parameter', () => { @@ -289,33 +295,33 @@ describe('DiffsStoreUtils', () => { describe('prepareDiffData', () => { it('sets the renderIt and collapsed attribute on files', () => { - const preparedDiff = { diffFiles: [getDiffFileMock()] }; + const preparedDiff = { diff_files: [getDiffFileMock()] }; utils.prepareDiffData(preparedDiff); - const firstParallelDiffLine = preparedDiff.diffFiles[0].parallelDiffLines[2]; + const firstParallelDiffLine = preparedDiff.diff_files[0].parallel_diff_lines[2]; expect(firstParallelDiffLine.left.discussions.length).toBe(0); expect(firstParallelDiffLine.left).not.toHaveAttr('text'); expect(firstParallelDiffLine.right.discussions.length).toBe(0); expect(firstParallelDiffLine.right).not.toHaveAttr('text'); - const firstParallelChar = firstParallelDiffLine.right.richText.charAt(0); + const firstParallelChar = firstParallelDiffLine.right.rich_text.charAt(0); expect(firstParallelChar).not.toBe(' '); expect(firstParallelChar).not.toBe('+'); expect(firstParallelChar).not.toBe('-'); - const checkLine = preparedDiff.diffFiles[0].highlightedDiffLines[0]; + const checkLine = preparedDiff.diff_files[0].highlighted_diff_lines[0]; expect(checkLine.discussions.length).toBe(0); expect(checkLine).not.toHaveAttr('text'); - const firstChar = checkLine.richText.charAt(0); + const firstChar = checkLine.rich_text.charAt(0); expect(firstChar).not.toBe(' '); expect(firstChar).not.toBe('+'); expect(firstChar).not.toBe('-'); - expect(preparedDiff.diffFiles[0].renderIt).toBeTruthy(); - expect(preparedDiff.diffFiles[0].collapsed).toBeFalsy(); + expect(preparedDiff.diff_files[0].renderIt).toBeTruthy(); + expect(preparedDiff.diff_files[0].collapsed).toBeFalsy(); }); }); @@ -398,7 +404,7 @@ describe('DiffsStoreUtils', () => { discussion, diffPosition: { ...diffPosition, - lineCode: 'ABC_1', + line_code: 'ABC_1', }, latestDiff: true, }), @@ -429,36 +435,36 @@ describe('DiffsStoreUtils', () => { beforeAll(() => { files = [ { - newPath: 'app/index.js', - deletedFile: false, - newFile: false, - removedLines: 10, - addedLines: 0, - fileHash: 'test', + new_path: 'app/index.js', + deleted_file: false, + new_file: false, + removed_lines: 10, + added_lines: 0, + file_hash: 'test', }, { - newPath: 'app/test/index.js', - deletedFile: false, - newFile: true, - removedLines: 0, - addedLines: 0, - fileHash: 'test', + new_path: 'app/test/index.js', + deleted_file: false, + new_file: true, + removed_lines: 0, + added_lines: 0, + file_hash: 'test', }, { - newPath: 'app/test/filepathneedstruncating.js', - deletedFile: false, - newFile: true, - removedLines: 0, - addedLines: 0, - fileHash: 'test', + new_path: 'app/test/filepathneedstruncating.js', + deleted_file: false, + new_file: true, + removed_lines: 0, + added_lines: 0, + file_hash: 'test', }, { - newPath: 'package.json', - deletedFile: true, - newFile: false, - removedLines: 0, - addedLines: 0, - fileHash: 'test', + new_path: 'package.json', + deleted_file: true, + new_file: false, + removed_lines: 0, + added_lines: 0, + file_hash: 'test', }, ]; }); diff --git a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js index 0c1d5f5b0b4..4f561df7943 100644 --- a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js @@ -754,6 +754,50 @@ describe('Filtered Search Visual Tokens', () => { expect(updateLabelTokenColorSpy.calls.count()).toBe(0); expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); }); + + it('does not update user token appearance for `none` filter', () => { + const { tokenNameElement } = findElements(authorToken); + + const tokenName = tokenNameElement.innerText; + const tokenValue = 'none'; + + subject.renderVisualTokenValue(authorToken, tokenName, tokenValue); + + expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); + }); + + it('does not update user token appearance for `any` filter', () => { + const { tokenNameElement } = findElements(authorToken); + + const tokenName = tokenNameElement.innerText; + const tokenValue = 'any'; + + subject.renderVisualTokenValue(authorToken, tokenName, tokenValue); + + expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); + }); + + it('does not update label token color for `none` filter', () => { + const { tokenNameElement } = findElements(bugLabelToken); + + const tokenName = tokenNameElement.innerText; + const tokenValue = 'none'; + + subject.renderVisualTokenValue(bugLabelToken, tokenName, tokenValue); + + expect(updateLabelTokenColorSpy.calls.count()).toBe(0); + }); + + it('does not update label token color for `any` filter', () => { + const { tokenNameElement } = findElements(bugLabelToken); + + const tokenName = tokenNameElement.innerText; + const tokenValue = 'any'; + + subject.renderVisualTokenValue(bugLabelToken, tokenName, tokenValue); + + expect(updateLabelTokenColorSpy.calls.count()).toBe(0); + }); }); describe('updateUserTokenAppearance', () => { @@ -763,19 +807,6 @@ describe('Filtered Search Visual Tokens', () => { spyOn(UsersCache, 'retrieve').and.callFake(username => usersCacheSpy(username)); }); - it('ignores special value "none"', done => { - usersCacheSpy = username => { - expect(username).toBe('none'); - done.fail('Should not resolve "none"!'); - }; - const { tokenValueContainer, tokenValueElement } = findElements(authorToken); - - subject - .updateUserTokenAppearance(tokenValueContainer, tokenValueElement, 'none') - .then(done) - .catch(done.fail); - }); - it('ignores error if UsersCache throws', done => { spyOn(window, 'Flash'); const dummyError = new Error('Earth rotated backwards'); diff --git a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js index d85354c3681..c9c09ee9afe 100644 --- a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js @@ -77,7 +77,7 @@ describe('IDE pipelines actions', () => { { type: 'setErrorMessage', payload: { - text: 'An error occured whilst fetching the latest pipline.', + text: 'An error occured whilst fetching the latest pipeline.', action: jasmine.any(Function), actionText: 'Please try again', actionPayload: null, diff --git a/spec/javascripts/jobs/components/empty_state_spec.js b/spec/javascripts/jobs/components/empty_state_spec.js index 0a39709221c..a2df79bdda0 100644 --- a/spec/javascripts/jobs/components/empty_state_spec.js +++ b/spec/javascripts/jobs/components/empty_state_spec.js @@ -84,6 +84,7 @@ describe('Empty State', () => { vm = mountComponent(Component, { ...props, content, + action: null, }); expect(vm.$el.querySelector('.js-job-empty-state-action')).toBeNull(); diff --git a/spec/javascripts/notes/components/diff_with_note_spec.js b/spec/javascripts/notes/components/diff_with_note_spec.js index 0c16103714a..95461396f10 100644 --- a/spec/javascripts/notes/components/diff_with_note_spec.js +++ b/spec/javascripts/notes/components/diff_with_note_spec.js @@ -1,6 +1,5 @@ import Vue from 'vue'; import DiffWithNote from '~/notes/components/diff_with_note.vue'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { createStore } from '~/mr_notes/stores'; import { mountComponentWithStore } from 'spec/helpers'; @@ -11,7 +10,7 @@ describe('diff_with_note', () => { let store; let vm; const diffDiscussionMock = getJSONFixture(discussionFixture)[0]; - const diffDiscussion = convertObjectPropsToCamelCase(diffDiscussionMock); + const diffDiscussion = diffDiscussionMock; const Component = Vue.extend(DiffWithNote); const props = { discussion: diffDiscussion, @@ -65,7 +64,7 @@ describe('diff_with_note', () => { describe('image diff', () => { beforeEach(() => { const imageDiffDiscussionMock = getJSONFixture(imageDiscussionFixture)[0]; - props.discussion = convertObjectPropsToCamelCase(imageDiffDiscussionMock); + props.discussion = imageDiffDiscussionMock; }); it('shows image diff', () => { diff --git a/spec/javascripts/pipelines/graph/job_item_spec.js b/spec/javascripts/pipelines/graph/job_item_spec.js index 41b614cc95e..88e1789184d 100644 --- a/spec/javascripts/pipelines/graph/job_item_spec.js +++ b/spec/javascripts/pipelines/graph/job_item_spec.js @@ -140,14 +140,12 @@ describe('pipeline graph job item', () => { }); describe('tooltip placement', () => { - const tooltipBoundary = 'a[data-boundary="viewport"]'; - it('does not set tooltip boundary by default', () => { component = mountComponent(JobComponent, { job: mockJob, }); - expect(component.$el.querySelector(tooltipBoundary)).toBeNull(); + expect(component.tooltipBoundary).toBeNull(); }); it('sets tooltip boundary to viewport for small dropdowns', () => { @@ -156,7 +154,7 @@ describe('pipeline graph job item', () => { dropdownLength: 1, }); - expect(component.$el.querySelector(tooltipBoundary)).not.toBeNull(); + expect(component.tooltipBoundary).toEqual('viewport'); }); it('does not set tooltip boundary for large lists', () => { @@ -165,7 +163,7 @@ describe('pipeline graph job item', () => { dropdownLength: 7, }); - expect(component.$el.querySelector(tooltipBoundary)).toBeNull(); + expect(component.tooltipBoundary).toBeNull(); }); }); diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 7530fd2a43b..7a4ca587313 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -1,4 +1,4 @@ -/* eslint-disable no-var, one-var, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, object-shorthand, prefer-template, vars-on-top */ +/* eslint-disable no-var, one-var, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, object-shorthand, vars-on-top */ import $ from 'jquery'; import '~/gl_dropdown'; @@ -109,16 +109,16 @@ describe('Search autocomplete dropdown', () => { assertLinks = function(list, issuesPath, mrsPath) { if (issuesPath) { - const issuesAssignedToMeLink = `a[href="${issuesPath}/?assignee_id=${userId}"]`; - const issuesIHaveCreatedLink = `a[href="${issuesPath}/?author_id=${userId}"]`; + const issuesAssignedToMeLink = `a[href="${issuesPath}/?assignee_username=${userName}"]`; + const issuesIHaveCreatedLink = `a[href="${issuesPath}/?author_username=${userName}"]`; expect(list.find(issuesAssignedToMeLink).length).toBe(1); expect(list.find(issuesAssignedToMeLink).text()).toBe('Issues assigned to me'); expect(list.find(issuesIHaveCreatedLink).length).toBe(1); expect(list.find(issuesIHaveCreatedLink).text()).toBe("Issues I've created"); } - const mrsAssignedToMeLink = `a[href="${mrsPath}/?assignee_id=${userId}"]`; - const mrsIHaveCreatedLink = `a[href="${mrsPath}/?author_id=${userId}"]`; + const mrsAssignedToMeLink = `a[href="${mrsPath}/?assignee_username=${userName}"]`; + const mrsIHaveCreatedLink = `a[href="${mrsPath}/?author_username=${userName}"]`; expect(list.find(mrsAssignedToMeLink).length).toBe(1); expect(list.find(mrsAssignedToMeLink).text()).toBe('Merge requests assigned to me'); @@ -186,7 +186,7 @@ describe('Search autocomplete dropdown', () => { widget.searchInput.val('help'); widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); - link = "a[href='" + projectIssuesPath + '/?assignee_id=' + userId + "']"; + link = `a[href='${projectIssuesPath}/?assignee_username=${userName}']`; expect(list.find(link).length).toBe(0); }); diff --git a/spec/javascripts/vue_mr_widget/components/deployment_spec.js b/spec/javascripts/vue_mr_widget/components/deployment_spec.js index ebbcaeb6f30..056b4df8fdc 100644 --- a/spec/javascripts/vue_mr_widget/components/deployment_spec.js +++ b/spec/javascripts/vue_mr_widget/components/deployment_spec.js @@ -41,7 +41,7 @@ describe('Deployment component', () => { describe('', () => { beforeEach(() => { - vm = mountComponent(Component, { deployment: { ...deploymentMockData } }); + vm = mountComponent(Component, { deployment: { ...deploymentMockData }, showMetrics: true }); }); describe('deployTimeago', () => { @@ -174,11 +174,31 @@ describe('Deployment component', () => { }); }); + describe('with showMetrics enabled', () => { + beforeEach(() => { + vm = mountComponent(Component, { deployment: { ...deploymentMockData }, showMetrics: true }); + }); + + it('shows metrics', () => { + expect(vm.$el).toContainElement('.js-mr-memory-usage'); + }); + }); + + describe('with showMetrics disabled', () => { + beforeEach(() => { + vm = mountComponent(Component, { deployment: { ...deploymentMockData }, showMetrics: false }); + }); + + it('hides metrics', () => { + expect(vm.$el).not.toContainElement('.js-mr-memory-usage'); + }); + }); + describe('without changes', () => { beforeEach(() => { delete deploymentMockData.changes; - vm = mountComponent(Component, { deployment: { ...deploymentMockData } }); + vm = mountComponent(Component, { deployment: { ...deploymentMockData }, showMetrics: true }); }); it('renders the link to the review app without dropdown', () => { @@ -192,6 +212,7 @@ describe('Deployment component', () => { beforeEach(() => { vm = mountComponent(Component, { deployment: Object.assign({}, deploymentMockData, { status: 'running' }), + showMetrics: true, }); }); @@ -208,6 +229,7 @@ describe('Deployment component', () => { beforeEach(() => { vm = mountComponent(Component, { deployment: Object.assign({}, deploymentMockData, { status: 'success' }), + showMetrics: true, }); }); @@ -220,6 +242,7 @@ describe('Deployment component', () => { beforeEach(() => { vm = mountComponent(Component, { deployment: Object.assign({}, deploymentMockData, { status: 'failed' }), + showMetrics: true, }); }); diff --git a/spec/lib/gitlab/ci/build/policy/changes_spec.rb b/spec/lib/gitlab/ci/build/policy/changes_spec.rb index ab401108c84..523d00c1272 100644 --- a/spec/lib/gitlab/ci/build/policy/changes_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/changes_spec.rb @@ -49,6 +49,12 @@ describe Gitlab::Ci::Build::Policy::Changes do expect(policy).to be_satisfied_by(pipeline, seed) end + it 'is satisfied by matching a pattern with a glob' do + policy = described_class.new(%w[some/**/*.{rb,txt}]) + + expect(policy).to be_satisfied_by(pipeline, seed) + end + it 'is not satisfied when pattern does not match path' do policy = described_class.new(%w[some/*.rb]) @@ -61,6 +67,12 @@ describe Gitlab::Ci::Build::Policy::Changes do expect(policy).not_to be_satisfied_by(pipeline, seed) end + it 'is not satified when pattern with glob does not match' do + policy = described_class.new(%w[invalid/*.{md,rake}]) + + expect(policy).not_to be_satisfied_by(pipeline, seed) + end + context 'when pipelines does not run for a branch update' do before do pipeline.before_sha = Gitlab::Git::BLANK_SHA diff --git a/spec/lib/gitlab/ci/build/policy/refs_spec.rb b/spec/lib/gitlab/ci/build/policy/refs_spec.rb index 7211187e511..553fc0fb9bf 100644 --- a/spec/lib/gitlab/ci/build/policy/refs_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/refs_spec.rb @@ -16,7 +16,7 @@ describe Gitlab::Ci::Build::Policy::Refs do end end - context 'when maching tags' do + context 'when matching tags' do context 'when pipeline runs for a tag' do let(:pipeline) do build_stubbed(:ci_pipeline, ref: 'feature', tag: true) @@ -56,10 +56,10 @@ describe Gitlab::Ci::Build::Policy::Refs do end end - context 'when maching a source' do + context 'when matching a source' do let(:pipeline) { build_stubbed(:ci_pipeline, source: :push) } - it 'is satisifed when provided source keyword matches' do + it 'is satisfied when provided source keyword matches' do expect(described_class.new(%w[pushes])) .to be_satisfied_by(pipeline) end diff --git a/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb b/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb index d48aac15f28..bd1f2c92844 100644 --- a/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::Ci::Config::Entry::Artifacts do let(:config) { { paths: %w[public/] } } describe '#value' do - it 'returns artifacs configuration' do + it 'returns artifacts configuration' do expect(entry.value).to eq config end end diff --git a/spec/lib/gitlab/ci/config/entry/policy_spec.rb b/spec/lib/gitlab/ci/config/entry/policy_spec.rb index bef93fe7af7..83001b7fdd8 100644 --- a/spec/lib/gitlab/ci/config/entry/policy_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/policy_spec.rb @@ -58,7 +58,7 @@ describe Gitlab::Ci::Config::Entry::Policy do end context 'when using complex policy' do - context 'when specifiying refs policy' do + context 'when specifying refs policy' do let(:config) { { refs: ['master'] } } it 'is a correct configuraton' do diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb index 1140bfdf6c3..38943138cbf 100644 --- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb @@ -19,7 +19,7 @@ describe Gitlab::Ci::Config::Entry::Reports do shared_examples 'a valid entry' do |keyword, file| describe '#value' do - it 'returns artifacs configuration' do + it 'returns artifacts configuration' do expect(entry.value).to eq({ "#{keyword}": [file] } ) end end diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb index 46874662edd..e1e0582cd11 100644 --- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb +++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb @@ -36,7 +36,7 @@ describe Gitlab::Ci::Variables::Collection::Item do shared_examples 'raises error for invalid type' do it do expect { described_class.new(key: variable_key, value: variable_value) } - .to raise_error ArgumentError, /`value` must be of type String, while it was:/ + .to raise_error ArgumentError, /`#{variable_key}` must be of type String, while it was:/ end end @@ -46,7 +46,7 @@ describe Gitlab::Ci::Variables::Collection::Item do let(:variable_value) { nil } let(:expected_value) { nil } - it_behaves_like 'creates variable' + it_behaves_like 'raises error for invalid type' end context "when it's an empty string" do diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 4e83b27e4a5..23f27939dd2 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1338,7 +1338,12 @@ describe Gitlab::Database::MigrationHelpers do end describe '#index_exists_by_name?' do - it 'returns true if an index exists' do + # TODO: remove rails5-only after removing rails4 tests + # rails 4 can not handle multiple indexes on the same column set if + # index was added by 't.index' - t.index is used by default in schema.rb in + # rails 5. Let's run this test only in rails 5 env: + # see https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21492#note_113602758 + it 'returns true if an index exists', :rails5 do expect(model.index_exists_by_name?(:projects, 'index_projects_on_path')) .to be_truthy end diff --git a/spec/lib/gitlab/file_detector_spec.rb b/spec/lib/gitlab/file_detector_spec.rb index edab53247e9..4ba9094b24e 100644 --- a/spec/lib/gitlab/file_detector_spec.rb +++ b/spec/lib/gitlab/file_detector_spec.rb @@ -15,14 +15,22 @@ describe Gitlab::FileDetector do describe '.type_of' do it 'returns the type of a README file' do - %w[README readme INDEX index].each do |filename| + filenames = Gitlab::MarkupHelper::PLAIN_FILENAMES + Gitlab::MarkupHelper::PLAIN_FILENAMES.map(&:upcase) + extensions = Gitlab::MarkupHelper::EXTENSIONS + Gitlab::MarkupHelper::EXTENSIONS.map(&:upcase) + + filenames.each do |filename| expect(described_class.type_of(filename)).to eq(:readme) - %w[.md .adoc .rst].each do |extname| - expect(described_class.type_of(filename + extname)).to eq(:readme) + + extensions.each do |extname| + expect(described_class.type_of("#{filename}.#{extname}")).to eq(:readme) end end end + it 'returns nil for a README.rb file' do + expect(described_class.type_of('README.rb')).to be_nil + end + it 'returns nil for a README file in a directory' do expect(described_class.type_of('foo/README.md')).to be_nil end diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 9ef27081f98..6be35eee0fd 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -94,7 +94,7 @@ describe Gitlab::Git::Commit, :seed_helper do context 'body_size less than threshold' do let(:body_size) { 123 } - it 'fetches commit message seperately' do + it 'fetches commit message separately' do expect(described_class).to receive(:get_message).with(repository, id) commit.safe_message diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 54291e847d8..1fe73c12fc0 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1095,12 +1095,26 @@ describe Gitlab::Git::Repository, :seed_helper do end it 'returns no Gitaly::DiffStats when there is a nil SHA' do + expect_any_instance_of(Gitlab::GitalyClient::CommitService) + .not_to receive(:diff_stats) + collection = repository.diff_stats(nil, 'master') expect(collection).to be_a(Gitlab::Git::DiffStatsCollection) expect(collection).to be_a(Enumerable) expect(collection.to_a).to be_empty end + + it 'returns no Gitaly::DiffStats when there is a BLANK_SHA' do + expect_any_instance_of(Gitlab::GitalyClient::CommitService) + .not_to receive(:diff_stats) + + collection = repository.diff_stats(Gitlab::Git::BLANK_SHA, 'master') + + expect(collection).to be_a(Gitlab::Git::DiffStatsCollection) + expect(collection).to be_a(Enumerable) + expect(collection.to_a).to be_empty + end end describe "#ls_files" do diff --git a/spec/lib/gitlab/git/tag_spec.rb b/spec/lib/gitlab/git/tag_spec.rb index 2d9db576a6c..c5bad062c2a 100644 --- a/spec/lib/gitlab/git/tag_spec.rb +++ b/spec/lib/gitlab/git/tag_spec.rb @@ -68,7 +68,7 @@ describe Gitlab::Git::Tag, :seed_helper do context 'message_size less than threshold' do let(:message_size) { 123 } - it 'fetches tag message seperately' do + it 'fetches tag message separately' do expect(described_class).to receive(:get_message).with(repository, gitaly_tag.id) tag.message diff --git a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb index 25684ea9e2c..efca8564894 100644 --- a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb @@ -240,7 +240,12 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi .and_return(user.id) end - it 'returns the existing merge request' do + # TODO: remove rails5-only after removing rails4 tests + # rails 4 can not handle multiple indexes on the same column set if + # index was added by 't.index' - t.index is used by default in schema.rb in + # rails 5. Let's run this test only in rails 5 env: + # see https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21492#note_113602758 + it 'returns the existing merge request', :rails5 do mr1, exists1 = importer.create_merge_request mr2, exists2 = importer.create_merge_request diff --git a/spec/lib/gitlab/kubernetes/helm/api_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb index a8124ced28c..8bce7a4cdf5 100644 --- a/spec/lib/gitlab/kubernetes/helm/api_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb @@ -36,6 +36,7 @@ describe Gitlab::Kubernetes::Helm::Api do describe '#install' do before do allow(client).to receive(:create_pod).and_return(nil) + allow(client).to receive(:get_config_map).and_return(nil) allow(client).to receive(:create_config_map).and_return(nil) allow(client).to receive(:create_service_account).and_return(nil) allow(client).to receive(:create_cluster_role_binding).and_return(nil) @@ -57,6 +58,18 @@ describe Gitlab::Kubernetes::Helm::Api do subject.install(command) end + + context 'config map already exists' do + before do + expect(client).to receive(:get_config_map).with("values-content-configuration-#{application_name}", gitlab_namespace).and_return(resource) + end + + it 'updates the config map' do + expect(client).to receive(:update_config_map).with(resource).once + + subject.install(command) + end + end end context 'without a service account' do @@ -88,8 +101,8 @@ describe Gitlab::Kubernetes::Helm::Api do context 'service account and cluster role binding does not exist' do before do - expect(client).to receive('get_service_account').with('tiller', 'gitlab-managed-apps').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil)) - expect(client).to receive('get_cluster_role_binding').with('tiller-admin').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil)) + expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil)) + expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil)) end it 'creates a service account, followed the cluster role binding on kubeclient' do @@ -102,8 +115,8 @@ describe Gitlab::Kubernetes::Helm::Api do context 'service account already exists' do before do - expect(client).to receive('get_service_account').with('tiller', 'gitlab-managed-apps').and_return(service_account_resource) - expect(client).to receive('get_cluster_role_binding').with('tiller-admin').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil)) + expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_return(service_account_resource) + expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil)) end it 'updates the service account, followed by creating the cluster role binding' do @@ -116,8 +129,8 @@ describe Gitlab::Kubernetes::Helm::Api do context 'service account and cluster role binding already exists' do before do - expect(client).to receive('get_service_account').with('tiller', 'gitlab-managed-apps').and_return(service_account_resource) - expect(client).to receive('get_cluster_role_binding').with('tiller-admin').and_return(cluster_role_binding_resource) + expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_return(service_account_resource) + expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_return(cluster_role_binding_resource) end it 'updates the service account, followed by creating the cluster role binding' do @@ -130,7 +143,7 @@ describe Gitlab::Kubernetes::Helm::Api do context 'a non-404 error is thrown' do before do - expect(client).to receive('get_service_account').with('tiller', 'gitlab-managed-apps').and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil)) + expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil)) end it 'raises an error' do diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb index 2b7e3ea6def..39852b7fe29 100644 --- a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb @@ -26,7 +26,8 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm repo add app-name https://repository.example.com helm repo update #{helm_install_comand} @@ -54,7 +55,8 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm repo add app-name https://repository.example.com helm repo update #{helm_install_command} @@ -84,7 +86,8 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done #{helm_install_command} EOS end @@ -111,7 +114,8 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm repo add app-name https://repository.example.com helm repo update #{helm_install_command} @@ -134,7 +138,8 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm repo add app-name https://repository.example.com helm repo update #{helm_install_command} @@ -157,7 +162,8 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm repo add app-name https://repository.example.com helm repo update #{helm_install_command} @@ -182,7 +188,8 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm repo add app-name https://repository.example.com helm repo update #{helm_install_command} diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb index c92bc92c42d..2dd3a570a1d 100644 --- a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb @@ -30,7 +30,7 @@ describe Gitlab::Kubernetes::Helm::Pod do it 'should generate the appropriate specifications for the container' do container = subject.generate.spec.containers.first expect(container.name).to eq('helm') - expect(container.image).to eq('registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/2.7.2-kube-1.11.0') + expect(container.image).to eq('registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/2.11.0-kube-1.11.0') expect(container.env.count).to eq(3) expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT]) expect(container.command).to match_array(["/bin/sh"]) diff --git a/spec/lib/gitlab/kubernetes/helm/upgrade_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/upgrade_command_spec.rb index 9c9fc91ef3c..9b201dae417 100644 --- a/spec/lib/gitlab/kubernetes/helm/upgrade_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/upgrade_command_spec.rb @@ -21,7 +21,8 @@ describe Gitlab::Kubernetes::Helm::UpgradeCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm upgrade #{application.name} #{application.chart} --tls --tls-ca-cert /data/helm/#{application.name}/config/ca.pem --tls-cert /data/helm/#{application.name}/config/cert.pem --tls-key /data/helm/#{application.name}/config/key.pem --reset-values --install --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml EOS end @@ -33,7 +34,8 @@ describe Gitlab::Kubernetes::Helm::UpgradeCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm upgrade #{application.name} #{application.chart} --tls --tls-ca-cert /data/helm/#{application.name}/config/ca.pem --tls-cert /data/helm/#{application.name}/config/cert.pem --tls-key /data/helm/#{application.name}/config/key.pem --reset-values --install --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml EOS end @@ -56,7 +58,8 @@ describe Gitlab::Kubernetes::Helm::UpgradeCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm repo add #{application.name} #{application.repository} helm upgrade #{application.name} #{application.chart} --tls --tls-ca-cert /data/helm/#{application.name}/config/ca.pem --tls-cert /data/helm/#{application.name}/config/cert.pem --tls-key /data/helm/#{application.name}/config/key.pem --reset-values --install --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml EOS @@ -70,7 +73,8 @@ describe Gitlab::Kubernetes::Helm::UpgradeCommand do it_behaves_like 'helm commands' do let(:commands) do <<~EOS - helm init --client-only + helm init --upgrade + for i in $(seq 1 30); do helm version && break; sleep 1s; echo "Retrying ($i)..."; done helm upgrade #{application.name} #{application.chart} --reset-values --install --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml EOS end diff --git a/spec/lib/gitlab/kubernetes/kube_client_spec.rb b/spec/lib/gitlab/kubernetes/kube_client_spec.rb index eed4135d8a2..3979a43216c 100644 --- a/spec/lib/gitlab/kubernetes/kube_client_spec.rb +++ b/spec/lib/gitlab/kubernetes/kube_client_spec.rb @@ -66,6 +66,20 @@ describe Gitlab::Kubernetes::KubeClient do end end + describe '#knative_client' do + subject { client.knative_client } + + it_behaves_like 'a Kubeclient' + + it 'has the extensions API group endpoint' do + expect(subject.api_endpoint.to_s).to match(%r{\/apis\/serving.knative.dev\Z}) + end + + it 'has the api_version' do + expect(subject.instance_variable_get(:@api_version)).to eq('v1alpha1') + end + end + describe 'core API' do let(:core_client) { client.core_client } diff --git a/spec/lib/gitlab/private_commit_email_spec.rb b/spec/lib/gitlab/private_commit_email_spec.rb index bc86cd3842a..10bf624bbdd 100644 --- a/spec/lib/gitlab/private_commit_email_spec.rb +++ b/spec/lib/gitlab/private_commit_email_spec.rb @@ -4,6 +4,9 @@ require 'spec_helper' describe Gitlab::PrivateCommitEmail do let(:hostname) { Gitlab::CurrentSettings.current_application_settings.commit_email_hostname } + let(:id) { 1 } + let(:valid_email) { "#{id}-foo@#{hostname}" } + let(:invalid_email) { "#{id}-foo@users.noreply.bar.com" } context '.regex' do subject { described_class.regex } @@ -16,18 +19,25 @@ describe Gitlab::PrivateCommitEmail do end context '.user_id_for_email' do - let(:id) { 1 } - it 'parses user id from email' do - email = "#{id}-foo@#{hostname}" - - expect(described_class.user_id_for_email(email)).to eq(id) + expect(described_class.user_id_for_email(valid_email)).to eq(id) end it 'returns nil on invalid commit email' do - email = "#{id}-foo@users.noreply.bar.com" + expect(described_class.user_id_for_email(invalid_email)).to be_nil + end + end + + context '.user_ids_for_email' do + it 'returns deduplicated user IDs for each valid email' do + result = described_class.user_ids_for_emails([valid_email, valid_email, invalid_email]) + + expect(result).to eq([id]) + end - expect(described_class.user_id_for_email(email)).to be_nil + it 'returns an empty array with no valid emails' do + result = described_class.user_ids_for_emails([invalid_email]) + expect(result).to eq([]) end end diff --git a/spec/lib/gitlab/sentry_spec.rb b/spec/lib/gitlab/sentry_spec.rb index 499757da061..d3b41b27b80 100644 --- a/spec/lib/gitlab/sentry_spec.rb +++ b/spec/lib/gitlab/sentry_spec.rb @@ -52,4 +52,28 @@ describe Gitlab::Sentry do end end end + + context '.track_acceptable_exception' do + let(:exception) { RuntimeError.new('boom') } + + before do + allow(described_class).to receive(:enabled?).and_return(true) + end + + it 'calls Raven.capture_exception' do + expected_extras = { + some_other_info: 'info', + issue_url: 'http://gitlab.com/gitlab-org/gitlab-ce/issues/1' + } + + expect(Raven).to receive(:capture_exception) + .with(exception, extra: a_hash_including(expected_extras)) + + described_class.track_acceptable_exception( + exception, + issue_url: 'http://gitlab.com/gitlab-org/gitlab-ce/issues/1', + extra: { some_other_info: 'info' } + ) + end + end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 6849bc6db7a..d02c3a5765f 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1928,12 +1928,26 @@ describe Ci::Build do describe '#repo_url' do subject { build.repo_url } - it { is_expected.to be_a(String) } - it { is_expected.to end_with(".git") } - it { is_expected.to start_with(project.web_url[0..6]) } - it { is_expected.to include(build.token) } - it { is_expected.to include('gitlab-ci-token') } - it { is_expected.to include(project.web_url[7..-1]) } + context 'when token is set' do + before do + build.ensure_token + end + + it { is_expected.to be_a(String) } + it { is_expected.to end_with(".git") } + it { is_expected.to start_with(project.web_url[0..6]) } + it { is_expected.to include(build.token) } + it { is_expected.to include('gitlab-ci-token') } + it { is_expected.to include(project.web_url[7..-1]) } + end + + context 'when token is empty' do + before do + build.token = nil + end + + it { is_expected.to be_nil} + end end describe '#stuck?' do @@ -2043,7 +2057,8 @@ describe Ci::Build do end context 'use from gitlab-ci.yml' do - let(:pipeline) { create(:ci_pipeline) } + let(:project) { create(:project, :repository) } + let(:pipeline) { create(:ci_pipeline, project: project) } before do stub_ci_pipeline_yaml_file(config) @@ -2085,56 +2100,6 @@ describe Ci::Build do describe '#variables' do let(:container_registry_enabled) { false } - let(:gitlab_version_info) { Gitlab::VersionInfo.parse(Gitlab::VERSION) } - let(:predefined_variables) do - [ - { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true }, - { key: 'CI_PIPELINE_URL', value: project.web_url + "/pipelines/#{pipeline.id}", public: true }, - { key: 'CI_JOB_ID', value: build.id.to_s, public: true }, - { key: 'CI_JOB_URL', value: project.web_url + "/-/jobs/#{build.id}", public: true }, - { key: 'CI_JOB_TOKEN', value: build.token, public: false }, - { key: 'CI_BUILD_ID', value: build.id.to_s, public: true }, - { key: 'CI_BUILD_TOKEN', value: build.token, public: false }, - { key: 'CI_REGISTRY_USER', value: 'gitlab-ci-token', public: true }, - { key: 'CI_REGISTRY_PASSWORD', value: build.token, public: false }, - { key: 'CI_REPOSITORY_URL', value: build.repo_url, public: false }, - { key: 'CI', value: 'true', public: true }, - { key: 'GITLAB_CI', value: 'true', public: true }, - { key: 'GITLAB_FEATURES', value: project.licensed_features.join(','), public: true }, - { key: 'CI_SERVER_NAME', value: 'GitLab', public: true }, - { key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true }, - { key: 'CI_SERVER_VERSION_MAJOR', value: gitlab_version_info.major.to_s, public: true }, - { key: 'CI_SERVER_VERSION_MINOR', value: gitlab_version_info.minor.to_s, public: true }, - { key: 'CI_SERVER_VERSION_PATCH', value: gitlab_version_info.patch.to_s, public: true }, - { key: 'CI_SERVER_REVISION', value: Gitlab.revision, public: true }, - { key: 'CI_JOB_NAME', value: 'test', public: true }, - { key: 'CI_JOB_STAGE', value: 'test', public: true }, - { key: 'CI_COMMIT_SHA', value: build.sha, public: true }, - { key: 'CI_COMMIT_BEFORE_SHA', value: build.before_sha, public: true }, - { key: 'CI_COMMIT_REF_NAME', value: build.ref, public: true }, - { key: 'CI_COMMIT_REF_SLUG', value: build.ref_slug, public: true }, - { key: 'CI_NODE_TOTAL', value: '1', public: true }, - { key: 'CI_BUILD_REF', value: build.sha, public: true }, - { key: 'CI_BUILD_BEFORE_SHA', value: build.before_sha, public: true }, - { key: 'CI_BUILD_REF_NAME', value: build.ref, public: true }, - { key: 'CI_BUILD_REF_SLUG', value: build.ref_slug, public: true }, - { key: 'CI_BUILD_NAME', value: 'test', public: true }, - { key: 'CI_BUILD_STAGE', value: 'test', public: true }, - { key: 'CI_PROJECT_ID', value: project.id.to_s, public: true }, - { key: 'CI_PROJECT_NAME', value: project.path, public: true }, - { key: 'CI_PROJECT_PATH', value: project.full_path, public: true }, - { key: 'CI_PROJECT_PATH_SLUG', value: project.full_path_slug, public: true }, - { key: 'CI_PROJECT_NAMESPACE', value: project.namespace.full_path, public: true }, - { key: 'CI_PROJECT_URL', value: project.web_url, public: true }, - { key: 'CI_PROJECT_VISIBILITY', value: 'private', public: true }, - { key: 'CI_PIPELINE_IID', value: pipeline.iid.to_s, public: true }, - { key: 'CI_CONFIG_PATH', value: pipeline.ci_yaml_file_path, public: true }, - { key: 'CI_PIPELINE_SOURCE', value: pipeline.source, public: true }, - { key: 'CI_COMMIT_MESSAGE', value: pipeline.git_commit_message, public: true }, - { key: 'CI_COMMIT_TITLE', value: pipeline.git_commit_title, public: true }, - { key: 'CI_COMMIT_DESCRIPTION', value: pipeline.git_commit_description, public: true } - ] - end before do stub_container_registry_config(enabled: container_registry_enabled, host_port: 'registry.example.com') @@ -2143,11 +2108,174 @@ describe Ci::Build do subject { build.variables } context 'returns variables' do + let(:predefined_variables) do + [ + { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true }, + { key: 'CI_PIPELINE_URL', value: project.web_url + "/pipelines/#{pipeline.id}", public: true }, + { key: 'CI_JOB_ID', value: build.id.to_s, public: true }, + { key: 'CI_JOB_URL', value: project.web_url + "/-/jobs/#{build.id}", public: true }, + { key: 'CI_JOB_TOKEN', value: 'my-token', public: false }, + { key: 'CI_BUILD_ID', value: build.id.to_s, public: true }, + { key: 'CI_BUILD_TOKEN', value: 'my-token', public: false }, + { key: 'CI_REGISTRY_USER', value: 'gitlab-ci-token', public: true }, + { key: 'CI_REGISTRY_PASSWORD', value: 'my-token', public: false }, + { key: 'CI_REPOSITORY_URL', value: build.repo_url, public: false }, + { key: 'CI', value: 'true', public: true }, + { key: 'GITLAB_CI', value: 'true', public: true }, + { key: 'GITLAB_FEATURES', value: project.licensed_features.join(','), public: true }, + { key: 'CI_SERVER_NAME', value: 'GitLab', public: true }, + { key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true }, + { key: 'CI_SERVER_VERSION_MAJOR', value: Gitlab.version_info.major.to_s, public: true }, + { key: 'CI_SERVER_VERSION_MINOR', value: Gitlab.version_info.minor.to_s, public: true }, + { key: 'CI_SERVER_VERSION_PATCH', value: Gitlab.version_info.patch.to_s, public: true }, + { key: 'CI_SERVER_REVISION', value: Gitlab.revision, public: true }, + { key: 'CI_JOB_NAME', value: 'test', public: true }, + { key: 'CI_JOB_STAGE', value: 'test', public: true }, + { key: 'CI_COMMIT_SHA', value: build.sha, public: true }, + { key: 'CI_COMMIT_BEFORE_SHA', value: build.before_sha, public: true }, + { key: 'CI_COMMIT_REF_NAME', value: build.ref, public: true }, + { key: 'CI_COMMIT_REF_SLUG', value: build.ref_slug, public: true }, + { key: 'CI_NODE_TOTAL', value: '1', public: true }, + { key: 'CI_BUILD_REF', value: build.sha, public: true }, + { key: 'CI_BUILD_BEFORE_SHA', value: build.before_sha, public: true }, + { key: 'CI_BUILD_REF_NAME', value: build.ref, public: true }, + { key: 'CI_BUILD_REF_SLUG', value: build.ref_slug, public: true }, + { key: 'CI_BUILD_NAME', value: 'test', public: true }, + { key: 'CI_BUILD_STAGE', value: 'test', public: true }, + { key: 'CI_PROJECT_ID', value: project.id.to_s, public: true }, + { key: 'CI_PROJECT_NAME', value: project.path, public: true }, + { key: 'CI_PROJECT_PATH', value: project.full_path, public: true }, + { key: 'CI_PROJECT_PATH_SLUG', value: project.full_path_slug, public: true }, + { key: 'CI_PROJECT_NAMESPACE', value: project.namespace.full_path, public: true }, + { key: 'CI_PROJECT_URL', value: project.web_url, public: true }, + { key: 'CI_PROJECT_VISIBILITY', value: 'private', public: true }, + { key: 'CI_PIPELINE_IID', value: pipeline.iid.to_s, public: true }, + { key: 'CI_CONFIG_PATH', value: pipeline.ci_yaml_file_path, public: true }, + { key: 'CI_PIPELINE_SOURCE', value: pipeline.source, public: true }, + { key: 'CI_COMMIT_MESSAGE', value: pipeline.git_commit_message, public: true }, + { key: 'CI_COMMIT_TITLE', value: pipeline.git_commit_title, public: true }, + { key: 'CI_COMMIT_DESCRIPTION', value: pipeline.git_commit_description, public: true } + ] + end + before do + build.token = 'my-token' build.yaml_variables = [] end it { is_expected.to include(*predefined_variables) } + + context 'when yaml variables are undefined' do + let(:pipeline) do + create(:ci_pipeline, project: project, + sha: project.commit.id, + ref: project.default_branch) + end + + before do + build.yaml_variables = nil + end + + context 'use from gitlab-ci.yml' do + before do + stub_ci_pipeline_yaml_file(config) + end + + context 'when config is not found' do + let(:config) { nil } + + it { is_expected.to include(*predefined_variables) } + end + + context 'when config does not have a questioned job' do + let(:config) do + YAML.dump({ + test_other: { + script: 'Hello World' + } + }) + end + + it { is_expected.to include(*predefined_variables) } + end + + context 'when config has variables' do + let(:config) do + YAML.dump({ + test: { + script: 'Hello World', + variables: { + KEY: 'value' + } + } + }) + end + + let(:variables) do + [{ key: 'KEY', value: 'value', public: true }] + end + + it { is_expected.to include(*predefined_variables) } + it { is_expected.to include(*variables) } + end + end + end + + describe 'variables ordering' do + context 'when variables hierarchy is stubbed' do + let(:build_pre_var) { { key: 'build', value: 'value', public: true } } + let(:project_pre_var) { { key: 'project', value: 'value', public: true } } + let(:pipeline_pre_var) { { key: 'pipeline', value: 'value', public: true } } + let(:build_yaml_var) { { key: 'yaml', value: 'value', public: true } } + + before do + allow(build).to receive(:predefined_variables) { [build_pre_var] } + allow(build).to receive(:yaml_variables) { [build_yaml_var] } + allow(build).to receive(:persisted_variables) { [] } + + allow_any_instance_of(Project) + .to receive(:predefined_variables) { [project_pre_var] } + + project.variables.create!(key: 'secret', value: 'value') + + allow_any_instance_of(Ci::Pipeline) + .to receive(:predefined_variables) { [pipeline_pre_var] } + end + + it 'returns variables in order depending on resource hierarchy' do + is_expected.to eq( + [build_pre_var, + project_pre_var, + pipeline_pre_var, + build_yaml_var, + { key: 'secret', value: 'value', public: false }]) + end + end + + context 'when build has environment and user-provided variables' do + let(:expected_variables) do + predefined_variables.map { |variable| variable.fetch(:key) } + + %w[YAML_VARIABLE CI_ENVIRONMENT_NAME CI_ENVIRONMENT_SLUG + CI_ENVIRONMENT_URL] + end + + before do + create(:environment, project: build.project, + name: 'staging') + + build.yaml_variables = [{ key: 'YAML_VARIABLE', + value: 'var', + public: true }] + build.environment = 'staging' + end + + it 'matches explicit variables ordering' do + received_variables = subject.map { |variable| variable.fetch(:key) } + + expect(received_variables).to eq expected_variables + end + end + end end context 'when build has user' do @@ -2409,75 +2537,20 @@ describe Ci::Build do end before do - pipeline_schedule.pipelines << pipeline + pipeline_schedule.pipelines << pipeline.reload pipeline_schedule.reload end it { is_expected.to include(pipeline_schedule_variable.to_runner_variable) } end - context 'when yaml_variables are undefined' do - let(:pipeline) do - create(:ci_pipeline, project: project, - sha: project.commit.id, - ref: project.default_branch) - end - - before do - build.yaml_variables = nil - end - - context 'use from gitlab-ci.yml' do - before do - stub_ci_pipeline_yaml_file(config) - end - - context 'when config is not found' do - let(:config) { nil } - - it { is_expected.to include(*predefined_variables) } - end - - context 'when config does not have a questioned job' do - let(:config) do - YAML.dump({ - test_other: { - script: 'Hello World' - } - }) - end - - it { is_expected.to include(*predefined_variables) } - end - - context 'when config has variables' do - let(:config) do - YAML.dump({ - test: { - script: 'Hello World', - variables: { - KEY: 'value' - } - } - }) - end - let(:variables) do - [{ key: 'KEY', value: 'value', public: true }] - end - - it { is_expected.to include(*predefined_variables) } - it { is_expected.to include(*variables) } - end - end - end - context 'when container registry is enabled' do let(:container_registry_enabled) { true } let(:ci_registry) do - { key: 'CI_REGISTRY', value: 'registry.example.com', public: true } + { key: 'CI_REGISTRY', value: 'registry.example.com', public: true } end let(:ci_registry_image) do - { key: 'CI_REGISTRY_IMAGE', value: project.container_registry_url, public: true } + { key: 'CI_REGISTRY_IMAGE', value: project.container_registry_url, public: true } end context 'and is disabled for project' do @@ -2598,66 +2671,6 @@ describe Ci::Build do end end - describe 'variables ordering' do - context 'when variables hierarchy is stubbed' do - let(:build_pre_var) { { key: 'build', value: 'value', public: true } } - let(:project_pre_var) { { key: 'project', value: 'value', public: true } } - let(:pipeline_pre_var) { { key: 'pipeline', value: 'value', public: true } } - let(:build_yaml_var) { { key: 'yaml', value: 'value', public: true } } - - before do - allow(build).to receive(:predefined_variables) { [build_pre_var] } - allow(build).to receive(:yaml_variables) { [build_yaml_var] } - allow(build).to receive(:persisted_variables) { [] } - - allow_any_instance_of(Project) - .to receive(:predefined_variables) { [project_pre_var] } - - allow_any_instance_of(Project) - .to receive(:ci_variables_for) - .with(ref: 'master', environment: nil) do - [create(:ci_variable, key: 'secret', value: 'value')] - end - - allow_any_instance_of(Ci::Pipeline) - .to receive(:predefined_variables) { [pipeline_pre_var] } - end - - it 'returns variables in order depending on resource hierarchy' do - is_expected.to eq( - [build_pre_var, - project_pre_var, - pipeline_pre_var, - build_yaml_var, - { key: 'secret', value: 'value', public: false }]) - end - end - - context 'when build has environment and user-provided variables' do - let(:expected_variables) do - predefined_variables.map { |variable| variable.fetch(:key) } + - %w[YAML_VARIABLE CI_ENVIRONMENT_NAME CI_ENVIRONMENT_SLUG - CI_ENVIRONMENT_URL] - end - - before do - create(:environment, project: build.project, - name: 'staging') - - build.yaml_variables = [{ key: 'YAML_VARIABLE', - value: 'var', - public: true }] - build.environment = 'staging' - end - - it 'matches explicit variables ordering' do - received_variables = subject.map { |variable| variable.fetch(:key) } - - expect(received_variables).to eq expected_variables - end - end - end - context 'when build has not been persisted yet' do let(:build) do described_class.new( diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index 86de9dc60f2..b5aa1dcece5 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -35,7 +35,7 @@ describe Clusters::Applications::Prometheus do describe 'transition to installed' do let(:project) { create(:project) } - let(:cluster) { create(:cluster, projects: [project]) } + let(:cluster) { create(:cluster, :with_installed_helm, projects: [project]) } let(:prometheus_service) { double('prometheus_service') } subject { create(:clusters_applications_prometheus, :installing, cluster: cluster) } diff --git a/spec/models/clusters/kubernetes_namespace_spec.rb b/spec/models/clusters/kubernetes_namespace_spec.rb index c068c4d7739..56c98d016c9 100644 --- a/spec/models/clusters/kubernetes_namespace_spec.rb +++ b/spec/models/clusters/kubernetes_namespace_spec.rb @@ -45,14 +45,14 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do end end - describe '#configure_predefined_variables' do + describe '#set_defaults' do let(:kubernetes_namespace) { build(:cluster_kubernetes_namespace) } let(:cluster) { kubernetes_namespace.cluster } let(:platform) { kubernetes_namespace.platform_kubernetes } - subject { kubernetes_namespace.configure_predefined_credentials } + subject { kubernetes_namespace.set_defaults } - describe 'namespace' do + describe '#namespace' do before do platform.update_column(:namespace, namespace) end @@ -80,7 +80,7 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do end end - describe 'service_account_name' do + describe '#service_account_name' do let(:service_account_name) { "#{kubernetes_namespace.namespace}-service-account" } it 'should set a service account name based on namespace' do diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index ed41ff7a0fa..2a0039a0635 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -72,6 +72,7 @@ describe Commit do context 'using eager loading' do let!(:alice) { create(:user, email: 'alice@example.com') } let!(:bob) { create(:user, email: 'hunter2@example.com') } + let!(:jeff) { create(:user) } let(:alice_commit) do described_class.new(RepoHelpers.sample_commit, project).tap do |c| @@ -93,7 +94,14 @@ describe Commit do end end - let!(:commits) { [alice_commit, bob_commit, eve_commit] } + let(:jeff_commit) do + # The commit for Jeff uses his private commit email + described_class.new(RepoHelpers.sample_commit, project).tap do |c| + c.author_email = jeff.private_commit_email + end + end + + let!(:commits) { [alice_commit, bob_commit, eve_commit, jeff_commit] } before do create(:email, user: bob, email: 'bob@example.com') @@ -125,6 +133,20 @@ describe Commit do expect(bob_commit.author).to eq(bob) end + it "preloads the authors for Commits using a User's private commit Email" do + commits.each(&:lazy_author) + + expect(jeff_commit.author).to eq(jeff) + end + + it "preloads the authors for Commits using a User's outdated private commit Email" do + jeff.update!(username: 'new-username') + + commits.each(&:lazy_author) + + expect(jeff_commit.author).to eq(jeff) + end + it 'sets the author to Nil if an author could not be found for a Commit' do commits.each(&:lazy_author) diff --git a/spec/models/concerns/awardable_spec.rb b/spec/models/concerns/awardable_spec.rb index debc02fa51f..5713106418d 100644 --- a/spec/models/concerns/awardable_spec.rb +++ b/spec/models/concerns/awardable_spec.rb @@ -37,8 +37,8 @@ describe Awardable do create(:award_emoji, awardable: issue3, name: "star", user: award_emoji.user) create(:award_emoji, awardable: issue3, name: "star", user: award_emoji2.user) - expect(Issue.awarded(award_emoji.user)).to eq [issue, issue3] - expect(Issue.awarded(award_emoji2.user)).to eq [issue2, issue3] + expect(Issue.awarded(award_emoji.user)).to contain_exactly(issue, issue3) + expect(Issue.awarded(award_emoji2.user)).to contain_exactly(issue2, issue3) end end diff --git a/spec/models/concerns/deployable_spec.rb b/spec/models/concerns/deployable_spec.rb index ac79c75a55e..6951be903fe 100644 --- a/spec/models/concerns/deployable_spec.rb +++ b/spec/models/concerns/deployable_spec.rb @@ -49,5 +49,26 @@ describe Deployable do expect(environment).to be_nil end end + + context 'when environment scope contains invalid character' do + let(:job) do + create( + :ci_build, + name: 'job:deploy-to-test-site', + environment: '$CI_JOB_NAME', + options: { + environment: { + name: '$CI_JOB_NAME', + url: 'http://staging.example.com/$CI_JOB_NAME', + on_stop: 'stop_review_app' + } + }) + end + + it 'does not create a deployment and environment record' do + expect(deployment).to be_nil + expect(environment).to be_nil + end + end end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 131db6a5ff9..a58dc8e25e8 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1782,7 +1782,7 @@ describe MergeRequest do allow(subject).to receive(:head_pipeline) { nil } end - it { expect(subject.mergeable_ci_state?).to be_truthy } + it { expect(subject.mergeable_ci_state?).to be_falsey } end end diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb index 19c2862264f..973d6bdb2a0 100644 --- a/spec/models/project_services/chat_message/push_message_spec.rb +++ b/spec/models/project_services/chat_message/push_message_spec.rb @@ -48,12 +48,12 @@ describe ChatMessage::PushMessage do 'test.user pushed to branch [master](http://url.com/commits/master) of [project_name](http://url.com) ([Compare changes](http://url.com/compare/before...after))') expect(subject.attachments).to eq( "[abcdefgh](http://url1.com): message1 - author1\n\n[12345678](http://url2.com): message2 - author2") - expect(subject.activity).to eq({ - title: 'test.user pushed to branch', + expect(subject.activity).to eq( + title: 'test.user pushed to branch [master](http://url.com/commits/master)', subtitle: 'in [project_name](http://url.com)', text: '[Compare changes](http://url.com/compare/before...after)', image: 'http://someavatar.com' - }) + ) end end end @@ -89,12 +89,53 @@ describe ChatMessage::PushMessage do expect(subject.pretext).to eq( 'test.user pushed new tag [new_tag](http://url.com/commits/new_tag) to [project_name](http://url.com)') expect(subject.attachments).to be_empty - expect(subject.activity).to eq({ - title: 'test.user created tag', + expect(subject.activity).to eq( + title: 'test.user pushed new tag [new_tag](http://url.com/commits/new_tag)', subtitle: 'in [project_name](http://url.com)', text: '[Compare changes](http://url.com/compare/0000000000000000000000000000000000000000...after)', image: 'http://someavatar.com' - }) + ) + end + end + end + + context 'removed tag' do + let(:args) do + { + after: Gitlab::Git::BLANK_SHA, + before: 'before', + project_name: 'project_name', + ref: 'refs/tags/new_tag', + user_name: 'test.user', + user_avatar: 'http://someavatar.com', + project_url: 'http://url.com' + } + end + + context 'without markdown' do + it 'returns a message regarding removal of tags' do + expect(subject.pretext).to eq('test.user removed tag ' \ + 'new_tag from ' \ + '<http://url.com|project_name>') + expect(subject.attachments).to be_empty + end + end + + context 'with markdown' do + before do + args[:markdown] = true + end + + it 'returns a message regarding removal of tags' do + expect(subject.pretext).to eq( + 'test.user removed tag new_tag from [project_name](http://url.com)') + expect(subject.attachments).to be_empty + expect(subject.activity).to eq( + title: 'test.user removed tag new_tag', + subtitle: 'in [project_name](http://url.com)', + text: '[Compare changes](http://url.com/compare/before...0000000000000000000000000000000000000000)', + image: 'http://someavatar.com' + ) end end end @@ -122,12 +163,12 @@ describe ChatMessage::PushMessage do expect(subject.pretext).to eq( 'test.user pushed new branch [master](http://url.com/commits/master) to [project_name](http://url.com)') expect(subject.attachments).to be_empty - expect(subject.activity).to eq({ - title: 'test.user created branch', + expect(subject.activity).to eq( + title: 'test.user pushed new branch [master](http://url.com/commits/master)', subtitle: 'in [project_name](http://url.com)', text: '[Compare changes](http://url.com/compare/0000000000000000000000000000000000000000...after)', image: 'http://someavatar.com' - }) + ) end end end @@ -154,12 +195,12 @@ describe ChatMessage::PushMessage do expect(subject.pretext).to eq( 'test.user removed branch master from [project_name](http://url.com)') expect(subject.attachments).to be_empty - expect(subject.activity).to eq({ - title: 'test.user removed branch', + expect(subject.activity).to eq( + title: 'test.user removed branch master', subtitle: 'in [project_name](http://url.com)', text: '[Compare changes](http://url.com/compare/before...0000000000000000000000000000000000000000)', image: 'http://someavatar.com' - }) + ) end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index bdff68cee8b..51278836604 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3087,6 +3087,14 @@ describe Project do it 'does not flag as read-only' do expect { project.migrate_to_hashed_storage! }.not_to change { project.repository_read_only } end + + context 'when partially migrated' do + it 'returns true' do + project = create(:project, storage_version: 1, skip_disk_validation: true) + + expect(project.migrate_to_hashed_storage!).to be_truthy + end + end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 0ac5bd666ae..733c1c49f08 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1174,6 +1174,22 @@ describe User do expect(described_class.by_any_email(user.email, confirmed: true)).to eq([user]) end + + it 'finds user through a private commit email' do + user = create(:user) + private_email = user.private_commit_email + + expect(described_class.by_any_email(private_email)).to eq([user]) + expect(described_class.by_any_email(private_email, confirmed: true)).to eq([user]) + end + + it 'finds user through a private commit email in an array' do + user = create(:user) + private_email = user.private_commit_email + + expect(described_class.by_any_email([private_email])).to eq([user]) + expect(described_class.by_any_email([private_email], confirmed: true)).to eq([user]) + end end describe '.search' do @@ -1501,7 +1517,12 @@ describe User do email_unconfirmed = create :email, user: user user.reload - expect(user.all_emails).to match_array([user.email, email_unconfirmed.email, email_confirmed.email]) + expect(user.all_emails).to contain_exactly( + user.email, + user.private_commit_email, + email_unconfirmed.email, + email_confirmed.email + ) end end @@ -1512,7 +1533,11 @@ describe User do email_confirmed = create :email, user: user, confirmed_at: Time.now create :email, user: user - expect(user.verified_emails).to match_array([user.email, user.private_commit_email, email_confirmed.email]) + expect(user.verified_emails).to contain_exactly( + user.email, + user.private_commit_email, + email_confirmed.email + ) end end @@ -1532,6 +1557,14 @@ describe User do expect(user.verified_email?(user.private_commit_email)).to be_truthy end + it 'returns true for an outdated private commit email' do + old_email = user.private_commit_email + + user.update!(username: 'changed-username') + + expect(user.verified_email?(old_email)).to be_truthy + end + it 'returns false when the email is not verified/confirmed' do email_unconfirmed = create :email, user: user user.reload diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb index bd32faf06ef..8022f61e67d 100644 --- a/spec/policies/ci/pipeline_policy_spec.rb +++ b/spec/policies/ci/pipeline_policy_spec.rb @@ -74,5 +74,23 @@ describe Ci::PipelinePolicy, :models do expect(policy).to be_allowed :update_pipeline end end + + describe 'destroy_pipeline' do + let(:project) { create(:project, :public) } + + context 'when user has owner access' do + let(:user) { project.owner } + + it 'is enabled' do + expect(policy).to be_allowed :destroy_pipeline + end + end + + context 'when user is not owner' do + it 'is disabled' do + expect(policy).not_to be_allowed :destroy_pipeline + end + end + end end end diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index f0e1992bccd..638cc9767d4 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -438,6 +438,67 @@ describe API::Pipelines do end end + describe 'DELETE /projects/:id/pipelines/:pipeline_id' do + context 'authorized user' do + let(:owner) { project.owner } + + it 'destroys the pipeline' do + delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner) + + expect(response).to have_gitlab_http_status(204) + expect { pipeline.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'returns 404 when it does not exist' do + delete api("/projects/#{project.id}/pipelines/123456", owner) + + expect(response).to have_gitlab_http_status(404) + expect(json_response['message']).to eq '404 Not found' + end + + it 'logs an audit event' do + expect { delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner) }.to change { SecurityEvent.count }.by(1) + end + + context 'when the pipeline has jobs' do + let!(:build) { create(:ci_build, project: project, pipeline: pipeline) } + + it 'destroys associated jobs' do + delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner) + + expect(response).to have_gitlab_http_status(204) + expect { build.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + + context 'unauthorized user' do + context 'when user is not member' do + it 'should return a 404' do + delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", non_member) + + expect(response).to have_gitlab_http_status(404) + expect(json_response['message']).to eq '404 Project Not Found' + end + end + + context 'when user is developer' do + let(:developer) { create(:user) } + + before do + project.add_developer(developer) + end + + it 'should return a 403' do + delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", developer) + + expect(response).to have_gitlab_http_status(403) + expect(json_response['message']).to eq '403 Forbidden' + end + end + end + end + describe 'POST /projects/:id/pipelines/:pipeline_id/retry' do context 'authorized user' do let!(:pipeline) do diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index e6d01c9689f..bb913ae0e79 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -2018,11 +2018,11 @@ describe API::Users do expect(json_response['message']).to eq('403 Forbidden') end - it 'returns a personal access token' do + it 'returns an impersonation token' do get api("/users/#{user.id}/impersonation_tokens/#{impersonation_token.id}", admin) expect(response).to have_gitlab_http_status(200) - expect(json_response['token']).to be_present + expect(json_response['token']).not_to be_present expect(json_response['impersonation']).to be_truthy end end diff --git a/spec/serializers/environment_status_entity_spec.rb b/spec/serializers/environment_status_entity_spec.rb index 58e2e627410..8a6a38fe5f8 100644 --- a/spec/serializers/environment_status_entity_spec.rb +++ b/spec/serializers/environment_status_entity_spec.rb @@ -40,4 +40,40 @@ describe EnvironmentStatusEntity do it { is_expected.to include(:stop_url) } end + + context 'when deployment has metrics' do + let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) } + + let(:simple_metrics) do + { + success: true, + metrics: {}, + last_update: 42 + } + end + + before do + project.add_maintainer(user) + allow(deployment).to receive(:prometheus_adapter).and_return(prometheus_adapter) + allow(prometheus_adapter).to receive(:query).with(:deployment, deployment).and_return(simple_metrics) + allow(entity).to receive(:deployment).and_return(deployment) + end + + context 'when deployment succeeded' do + let(:deployment) { create(:deployment, :succeed, :review_app) } + + it 'returns metrics url' do + expect(subject[:metrics_url]) + .to eq("/#{project.namespace.name}/#{project.name}/environments/#{environment.id}/deployments/#{deployment.iid}/metrics") + end + end + + context 'when deployment is running' do + let(:deployment) { create(:deployment, :running, :review_app) } + + it 'does not return metrics url' do + expect(subject[:metrics_url]).to be_nil + end + end + end end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 193148d403a..4d9c5aabbda 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -608,5 +608,53 @@ describe Ci::CreatePipelineService do .to eq variables_attributes.map(&:with_indifferent_access) end end + + context 'when pipeline has a job with environment' do + let(:pipeline) { execute_service } + + before do + stub_ci_pipeline_yaml_file(YAML.dump(config)) + end + + context 'when environment name is valid' do + let(:config) do + { + review_app: { + script: 'deploy', + environment: { + name: 'review/${CI_COMMIT_REF_NAME}', + url: 'http://${CI_COMMIT_REF_SLUG}-staging.example.com' + } + } + } + end + + it 'has a job with environment' do + expect(pipeline.builds.count).to eq(1) + expect(pipeline.builds.first.persisted_environment.name).to eq('review/master') + expect(pipeline.builds.first.deployment).to be_created + end + end + + context 'when environment name is invalid' do + let(:config) do + { + 'job:deploy-to-test-site': { + script: 'deploy', + environment: { + name: '${CI_JOB_NAME}', + url: 'https://$APP_URL' + } + } + } + end + + it 'has a job without environment' do + expect(pipeline.builds.count).to eq(1) + expect(pipeline.builds.first.persisted_environment).to be_nil + expect(pipeline.builds.first.deployment).to be_nil + end + end + end end end diff --git a/spec/services/ci/destroy_pipeline_service_spec.rb b/spec/services/ci/destroy_pipeline_service_spec.rb new file mode 100644 index 00000000000..097daf67feb --- /dev/null +++ b/spec/services/ci/destroy_pipeline_service_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ::Ci::DestroyPipelineService do + let(:project) { create(:project) } + let!(:pipeline) { create(:ci_pipeline, project: project) } + + subject { described_class.new(project, user).execute(pipeline) } + + context 'user is owner' do + let(:user) { project.owner } + + it 'destroys the pipeline' do + subject + + expect { pipeline.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'logs an audit event' do + expect { subject }.to change { SecurityEvent.count }.by(1) + end + + context 'when the pipeline has jobs' do + let!(:build) { create(:ci_build, project: project, pipeline: pipeline) } + + it 'destroys associated jobs' do + subject + + expect { build.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'destroys associated stages' do + stages = pipeline.stages + + subject + + expect(stages).to all(raise_error(ActiveRecord::RecordNotFound)) + end + + context 'when job has artifacts' do + let!(:artifact) { create(:ci_job_artifact, :archive, job: build) } + + it 'destroys associated artifacts' do + subject + + expect { artifact.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + end + + context 'user is not owner' do + let(:user) { create(:user) } + + it 'raises an exception' do + expect { subject }.to raise_error(Gitlab::Access::AccessDeniedError) + end + end +end diff --git a/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb b/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb index fc922218ad0..661364ac765 100644 --- a/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb +++ b/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb @@ -44,7 +44,7 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d let(:namespace) { "#{project.path}-#{project.id}" } let(:kubernetes_namespace) do - build(:cluster_kubernetes_namespace, + create(:cluster_kubernetes_namespace, cluster: cluster, project: cluster_project.project, cluster_project: cluster_project) diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index e0335880e8e..81b2c17fdb5 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -32,7 +32,7 @@ describe SystemHooksService do end it do - project.old_path_with_namespace = 'transfered_from_path' + project.old_path_with_namespace = 'transferred_from_path' expect(event_data(project, :transfer)).to include( :event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility, diff --git a/spec/services/users/build_service_spec.rb b/spec/services/users/build_service_spec.rb index 051e8c87f39..b7b9817efdb 100644 --- a/spec/services/users/build_service_spec.rb +++ b/spec/services/users/build_service_spec.rb @@ -8,7 +8,7 @@ describe Users::BuildService do context 'with an admin user' do let(:admin_user) { create(:admin) } - let(:service) { described_class.new(admin_user, params) } + let(:service) { described_class.new(admin_user, ActionController::Parameters.new(params).permit!) } it 'returns a valid user' do expect(service.execute).to be_valid @@ -159,9 +159,9 @@ describe Users::BuildService do true | true | 'fl@example.com' | '' | true true | false | 'fl@example.com' | '' | true - true | nil | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | true - true | true | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | true - true | false | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | true + true | nil | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false + true | true | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false + true | false | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false true | nil | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true true | true | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cd69160be10..3fedb9ed48c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -235,6 +235,10 @@ RSpec.configure do |config| example.run if Gitlab::Database.mysql? end + config.around(:each, :rails5) do |example| + example.run if Gitlab.rails5? + end + # This makes sure the `ApplicationController#can?` method is stubbed with the # original implementation for all view specs. config.before(:each, type: :view) do diff --git a/spec/support/helpers/filter_item_select_helper.rb b/spec/support/helpers/filter_item_select_helper.rb deleted file mode 100644 index 519e84d359e..00000000000 --- a/spec/support/helpers/filter_item_select_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -# Helper allows you to select value from filter-items -# -# Params -# value - value for select -# selector - css selector of item -# -# Usage: -# -# filter_item_select('Any Author', '.js-author-search') -# -module FilterItemSelectHelper - def filter_item_select(value, selector) - find(selector).click - wait_for_requests - page.within('.dropdown-content') do - click_link value - end - end -end diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb index 35ae04b16c6..ccaf86aa3a6 100644 --- a/spec/support/helpers/kubernetes_helpers.rb +++ b/spec/support/helpers/kubernetes_helpers.rb @@ -17,6 +17,7 @@ module KubernetesHelpers WebMock.stub_request(:get, api_url + '/api/v1').to_return(kube_response(kube_v1_discovery_body)) WebMock.stub_request(:get, api_url + '/apis/extensions/v1beta1').to_return(kube_response(kube_v1beta1_discovery_body)) WebMock.stub_request(:get, api_url + '/apis/rbac.authorization.k8s.io/v1').to_return(kube_response(kube_v1_rbac_authorization_discovery_body)) + WebMock.stub_request(:get, api_url + '/apis/serving.knative.dev/v1alpha1').to_return(kube_response(kube_v1alpha1_serving_knative_discovery_body)) end def stub_kubeclient_pods(response = nil) @@ -134,6 +135,18 @@ module KubernetesHelpers } end + def kube_v1alpha1_serving_knative_discovery_body + { + "kind" => "APIResourceList", + "resources" => [ + { "name" => "revisions", "namespaced" => true, "kind" => "Revision" }, + { "name" => "services", "namespaced" => true, "kind" => "Service" }, + { "name" => "configurations", "namespaced" => true, "kind" => "Configuration" }, + { "name" => "routes", "namespaced" => true, "kind" => "Route" } + ] + } + end + def kube_pods_body { "kind" => "PodList", diff --git a/spec/support/helpers/user_login_helper.rb b/spec/support/helpers/user_login_helper.rb new file mode 100644 index 00000000000..36c002f53af --- /dev/null +++ b/spec/support/helpers/user_login_helper.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module UserLoginHelper + def ensure_tab_pane_correctness(visit_path = true) + if visit_path + visit new_user_session_path + end + + ensure_tab_pane_counts + ensure_one_active_tab + ensure_one_active_pane + end + + def ensure_tab_pane_counts + tabs_count = page.all('[role="tab"]').size + expect(page).to have_selector('[role="tabpanel"]', count: tabs_count) + end + + def ensure_one_active_tab + expect(page).to have_selector('ul.new-session-tabs > li > a.active', count: 1) + end + + def ensure_one_active_pane + expect(page).to have_selector('.tab-pane.active', count: 1) + end +end diff --git a/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb index 82f0dd5d00f..c391cc48f4e 100644 --- a/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb +++ b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb @@ -44,10 +44,40 @@ shared_examples 'cluster application status specs' do |application_name| subject { create(application_name, :installing) } it 'is installed' do - subject.make_installed + subject.make_installed! expect(subject).to be_installed end + + it 'updates helm version' do + subject.cluster.application_helm.update!(version: '1.2.3') + + subject.make_installed! + + subject.cluster.application_helm.reload + + expect(subject.cluster.application_helm.version).to eq(Gitlab::Kubernetes::Helm::HELM_VERSION) + end + end + + describe '#make_updated' do + subject { create(application_name, :updating) } + + it 'is updated' do + subject.make_updated! + + expect(subject).to be_updated + end + + it 'updates helm version' do + subject.cluster.application_helm.update!(version: '1.2.3') + + subject.make_updated! + + subject.cluster.application_helm.reload + + expect(subject.cluster.application_helm.version).to eq(Gitlab::Kubernetes::Helm::HELM_VERSION) + end end describe '#make_errored' do diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb index f17c5ac6aac..05b4fb49ea3 100644 --- a/spec/workers/emails_on_push_worker_spec.rb +++ b/spec/workers/emails_on_push_worker_spec.rb @@ -101,7 +101,7 @@ describe EmailsOnPushWorker, :mailer do context "when there are multiple recipients" do before do - # This is a hack because we modify the mail object before sending, for efficency, + # This is a hack because we modify the mail object before sending, for efficiency, # but the TestMailer adapter just appends the objects to an array. To clone a mail # object, create a new one! # https://github.com/mikel/mail/issues/314#issuecomment-12750108 diff --git a/vendor/licenses.csv b/vendor/licenses.csv index ea3d3fd02f9..f6fd1efaa83 100644 --- a/vendor/licenses.csv +++ b/vendor/licenses.csv @@ -67,9 +67,8 @@ @babel/template,7.1.2,MIT @babel/traverse,7.1.0,MIT @babel/types,7.1.2,MIT -@gitlab-org/gitlab-svgs,1.32.0,MIT -@gitlab-org/gitlab-ui,1.10.0,MIT @gitlab/svgs,1.35.0,MIT +@gitlab/ui,1.11.0,MIT @sindresorhus/is,0.7.0,MIT @types/jquery,2.0.48,MIT @vue/component-compiler-utils,2.2.0,MIT diff --git a/yarn.lock b/yarn.lock index 38e0f9d6201..3ee1b2525be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -616,20 +616,6 @@ lodash "^4.17.10" to-fast-properties "^2.0.0" -"@gitlab-org/gitlab-svgs@^1.23.0": - version "1.32.0" - resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.32.0.tgz#a65ab7724fa7d55be8e5cc9b2dbe3f0757432fd3" - integrity sha512-L3o8dFUd2nSkVZBwh2hCJWzNzADJ3dTBZxamND8NLosZK9/ohNhccmsQOZGyMCUHaOzm4vifaaXkAXh04UtMKA== - -"@gitlab-org/gitlab-ui@^1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-ui/-/gitlab-ui-1.10.0.tgz#3ac54ecaa25ea558324f0b382c97fcf9e3c4f0a5" - integrity sha512-kfoCKA+AmWZ3hf1wOS8W9mPJs/7lF+a01PK//+sw2MOLv6PlduJJmdN8drFuJ65o6cTJ1f9FMVB80R6D71XVKQ== - dependencies: - "@gitlab-org/gitlab-svgs" "^1.23.0" - bootstrap-vue "^2.0.0-rc.11" - vue "^2.5.16" - "@gitlab/eslint-config@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@gitlab/eslint-config/-/eslint-config-1.1.0.tgz#9757764b3a78b6bacfbcd9533331cb6345ffdd59" @@ -643,10 +629,25 @@ eslint-plugin-promise "^4.0.1" eslint-plugin-vue "^5.0.0-beta.3" -"@gitlab/svgs@^1.35.0": - version "1.35.0" - resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.35.0.tgz#01b6a0948bb3897fbbac9f50ce23c559c514ea0e" - integrity sha512-XKrTniSYKG5U8+8ZqDJqoW8ORahuPBfHrfsC1dHBPvo1xA/QGJxlpUdeqSFw2O19h481ut4yW1dF+OFpIa/mrw== +"@gitlab/svgs@^1.38.0": + version "1.38.0" + resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.38.0.tgz#e2f6e73379d60c7c63af4df8242a94c4671a1dfe" + integrity sha512-Mzv6PxVbWEPvvMgXHaGxk8UE1Gard2gifca6loLgfLH7BtjXfESiZyJdQkkTSeBYp5MoqQa88Kw+vJYobwjsSw== + +"@gitlab/ui@^1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-1.11.0.tgz#b771c2c3d627cf9efbe98c71ee5739624f2ff51f" + integrity sha512-hGMHM45kcv9725R6G+n/HxvF3KfVb9oBGRNf1+4n3xAGmtXJ2NlPdIXIsDaye3EeVF9PTOtjLuaqrcp6AGNqZg== + dependencies: + babel-standalone "^6.26.0" + bootstrap-vue "^2.0.0-rc.11" + copy-to-clipboard "^3.0.8" + highlight.js "^9.13.1" + js-beautify "^1.8.8" + lodash "^4.17.11" + url-search-params-polyfill "^5.0.0" + vue "^2.5.16" + vue-loader "^15.4.2" "@sindresorhus/is@^0.7.0": version "0.7.0" @@ -682,11 +683,21 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.2.tgz#f19f05314d5421fe37e74153254201a7bf00a707" integrity sha512-m9zXmifkZsMHZBOyxZWilMwmTlpC8x5Ty360JKTiXvlXZfBWYpsg9ZZvP/Ye+iZUh+Q+MxDLjItVTWIsfwz+8Q== +"@types/node@^10.11.7": + version "10.12.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.9.tgz#a07bfa74331471e1dc22a47eb72026843f7b95c8" + integrity sha512-eajkMXG812/w3w4a1OcBlaTwsFPO5F7fJ/amy+tieQxEMWBlbV1JGSjkFM+zkHNf81Cad+dfIRA+IBkvmvdAeA== + "@types/parse5@^5": version "5.0.0" resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.0.tgz#9ae2106efc443d7c1e26570aa8247828c9c80f11" integrity sha512-J5D3z703XTDIGQFYXsnU9uRCW9e9mMEFO0Kpe6kykyiboqziru/RlZ0hM2P+PKTG4NHG1SjLrqae/NrV2iJApQ== +"@types/semver@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45" + integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ== + "@vue/component-compiler-utils@^2.0.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-2.2.0.tgz#bbbb7ed38a9a8a7c93abe7ef2e54a90a04b631b4" @@ -1214,6 +1225,11 @@ babel-runtime@^6.22.0, babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" +babel-standalone@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-standalone/-/babel-standalone-6.26.0.tgz#15fb3d35f2c456695815ebf1ed96fe7f015b6886" + integrity sha1-Ffs9NfLEVmlYFevx7Zb+fwFbaIY= + babel-template@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" @@ -1874,6 +1890,11 @@ commander@2, commander@^2.18.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ== +commander@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== + commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -1956,6 +1977,14 @@ concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" +config-chain@~1.1.5: + version "1.1.12" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + configstore@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.1.tgz#094ee662ab83fad9917678de114faaea8fcdca90" @@ -2056,6 +2085,13 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +copy-to-clipboard@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9" + integrity sha512-c3GdeY8qxCHGezVb1EFQfHYK/8NZRemgcTIzPq7PuxjHAf/raKibn2QdhHPb/y6q74PMgH6yizaDZlRmw6QyKw== + dependencies: + toggle-selection "^1.0.3" + core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -2862,6 +2898,18 @@ editions@^1.3.3: resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== +editorconfig@^0.15.0: + version "0.15.2" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.2.tgz#047be983abb9ab3c2eefe5199cb2b7c5689f0702" + integrity sha512-GWjSI19PVJAM9IZRGOS+YKI8LN+/sjkSjNyvxL5ucqP9/IqtYNXBaQ/6c/hkPNYQHyOHra2KoXZI/JVpuqwmcQ== + dependencies: + "@types/node" "^10.11.7" + "@types/semver" "^5.5.0" + commander "^2.19.0" + lru-cache "^4.1.3" + semver "^5.6.0" + sigmund "^1.0.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -4083,6 +4131,11 @@ he@^1.1.0, he@^1.1.1: resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= +highlight.js@^9.13.1: + version "9.13.1" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e" + integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A== + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -4814,6 +4867,16 @@ jquery.waitforimages@^2.2.0: resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg== +js-beautify@^1.8.8: + version "1.8.8" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.8.8.tgz#1eb175b73a3571a5f1ed8d98e7cf2b05bfa98471" + integrity sha512-qVNq7ZZ7ZbLdzorvSlRDadS0Rh5oyItaE95v6I4wbbuSiijxn7SnnsV6dvKlcXuO2jX7lK8tn9fBulx34K/Ejg== + dependencies: + config-chain "~1.1.5" + editorconfig "^0.15.0" + mkdirp "~0.5.0" + nopt "~4.0.1" + js-cookie@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.1.3.tgz#48071625217ac9ecfab8c343a13d42ec09ff0526" @@ -5171,7 +5234,7 @@ lodash.upperfirst@4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984= -lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0: +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -5702,7 +5765,7 @@ nopt@3.x: dependencies: abbrev "1" -nopt@^4.0.1: +nopt@^4.0.1, nopt@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= @@ -6394,6 +6457,11 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + proxy-addr@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" @@ -6987,6 +7055,11 @@ semver-diff@^2.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== +semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" @@ -7114,6 +7187,11 @@ shebang-regex@^1.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= +sigmund@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -7724,6 +7802,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toggle-selection@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= + touch@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" @@ -7976,6 +8059,11 @@ url-parse@^1.1.8: querystringify "~1.0.0" requires-port "1.0.x" +url-search-params-polyfill@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/url-search-params-polyfill/-/url-search-params-polyfill-5.0.0.tgz#09b98337c89dcf6c6a6a0bfeb096f6ba83b7526b" + integrity sha512-+SCD22QJp4UnqPOI5UTTR0Ljuh8cHbjEf1lIiZrZ8nHTlTixqwVsVQTSfk5vrmDz7N09/Y+ka5jQr0ff35FnQQ== + url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" |