diff --git a/.eslintrc.yml b/.eslintrc.yml index 2b881d5f20..2612fd3371 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -5,6 +5,7 @@ globals: gl: false gon: false localStorage: false + IS_EE: false plugins: - import - html diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 059b181bb1..5b39304444 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,6 @@ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.21-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.29" variables: - MYSQL_ALLOW_EMPTY_PASSWORD: "1" RAILS_ENV: "test" NODE_ENV: "test" SIMPLECOV: "true" @@ -37,6 +36,7 @@ include: - local: .gitlab/ci/cng.gitlab-ci.yml - local: .gitlab/ci/docs.gitlab-ci.yml - local: .gitlab/ci/frontend.gitlab-ci.yml + - local: .gitlab/ci/memory.gitlab-ci.yml - local: .gitlab/ci/pages.gitlab-ci.yml - local: .gitlab/ci/qa.gitlab-ci.yml - local: .gitlab/ci/reports.gitlab-ci.yml diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index 0ca6d7a350..b865b212ac 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -6,8 +6,8 @@ /doc/ @axil @marcia @eread @mikelewis # Frontend maintainers should see everything in `app/assets/` -app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya -*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya +app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter +*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter # Someone from the database team should review changes in `db/` db/ @abrandl @NikolayS @@ -19,3 +19,5 @@ db/ @abrandl @NikolayS /lib/gitlab/ci/templates/ @nolith @zj /lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah /lib/gitlab/ci/templates/Security/ @plafoucriere @gonzoyumo @twoodham +/ee/app/models/project_alias.rb @patrickbajao +/ee/lib/api/project_aliases.rb @patrickbajao diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml index 5aa1a85640..5bc109f2b7 100644 --- a/.gitlab/ci/docs.gitlab-ci.yml +++ b/.gitlab/ci/docs.gitlab-ci.yml @@ -12,7 +12,9 @@ # Trigger a manual docs build in gitlab-docs only on non docs-only branches. # Useful to preview the docs changes live. review-docs-deploy-manual: - <<: *review-docs + extends: + - .review-docs + - .no-docs-and-no-qa stage: build script: - gem install gitlab --no-document @@ -21,9 +23,6 @@ review-docs-deploy-manual: only: - branches@gitlab-org/gitlab-ce - branches@gitlab-org/gitlab-ee - except: - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ # Always trigger a docs build in gitlab-docs only on docs-only branches. # Useful to preview the docs changes live. @@ -66,6 +65,8 @@ docs lint: - scripts/lint-changelog-yaml - mv doc/ /tmp/gitlab-docs/content/$DOCS_GITLAB_REPO_SUFFIX - cd /tmp/gitlab-docs + # Lint Markdown + - bundle exec mdl content/$DOCS_GITLAB_REPO_SUFFIX -c $CI_PROJECT_DIR/.mdlrc # Build HTML from Markdown - bundle exec nanoc # Check the internal links diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index 6afa668af2..b3e7c85385 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -1,26 +1,25 @@ .assets-compile-cache: &assets-compile-cache cache: - key: "assets-compile:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v5" + key: "assets-compile:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v6" paths: - vendor/ruby/ - .yarn-cache/ - tmp/cache/assets/sprockets - policy: pull-push .use-pg: &use-pg services: - - name: postgres:9.6 + - name: postgres:9.6.11 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] - name: redis:alpine -gitlab:assets:compile: +.gitlab:assets:compile-metadata: <<: *assets-compile-cache extends: .dedicated-no-docs-pull-cache-job image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-git-2.21-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.29-docker-18.06.1 dependencies: - setup-test-env services: - - docker:stable-dind + - docker:19.03.0-dind variables: NODE_ENV: "production" RAILS_ENV: "production" @@ -33,7 +32,7 @@ gitlab:assets:compile: DOCKER_HOST: tcp://docker:2375 script: - node --version - - retry yarn install --frozen-lockfile --production --cache-folder .yarn-cache + - retry yarn install --frozen-lockfile --production --cache-folder .yarn-cache --prefer-offline - free -m - retry bundle exec rake gitlab:assets:compile - time scripts/build_assets_image @@ -58,14 +57,32 @@ gitlab:assets:compile: - docker - gitlab-org -compile-assets: +gitlab:assets:compile: + extends: .gitlab:assets:compile-metadata + cache: + policy: pull-push + only: + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + +gitlab:assets:compile pull-cache: + extends: .gitlab:assets:compile-metadata + cache: + policy: pull + except: + refs: + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + - /(^docs[\/-].*|.*-docs$)/ + +.compile-assets-metadata: extends: .dedicated-runner <<: *use-pg <<: *assets-compile-cache stage: prepare script: - node --version - - retry yarn install --frozen-lockfile --cache-folder .yarn-cache + - retry yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline - free -m - retry bundle exec rake gitlab:assets:compile - scripts/clean-old-cached-assets @@ -77,8 +94,23 @@ compile-assets: paths: - node_modules - public/assets + +compile-assets: + extends: .compile-assets-metadata + cache: + policy: pull-push + only: + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + +compile-assets pull-cache: + extends: .compile-assets-metadata + cache: + policy: pull except: refs: + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee - /(^docs[\/-].*|.*-docs$)/ gitlab:ui:visual: @@ -87,6 +119,7 @@ gitlab:ui:visual: allow_failure: true dependencies: - compile-assets + - compile-assets pull-cache script: # Remove node modules from GitLab that may conflict with gitlab-ui - rm -r node_modules @@ -116,6 +149,7 @@ karma: <<: *use-pg dependencies: - compile-assets + - compile-assets pull-cache - setup-test-env variables: # we override the max_old_space_size to prevent OOM errors @@ -134,14 +168,15 @@ karma: paths: - chrome_debug.log - coverage-javascript/ - reports: - junit: junit_karma.xml +# reports: +# junit: junit_karma.xml jest: extends: .dedicated-no-docs-and-no-qa-pull-cache-job <<: *use-pg dependencies: - compile-assets + - compile-assets pull-cache - setup-test-env script: - scripts/gitaly-test-spawn @@ -156,8 +191,8 @@ jest: paths: - coverage-frontend/ - junit_jest.xml - reports: - junit: junit_jest.xml +# reports: +# junit: junit_jest.xml cache: key: jest paths: @@ -196,7 +231,7 @@ qa:selectors: before_script: [] script: - date - - yarn install --frozen-lockfile --cache-folder .yarn-cache + - yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline - date - yarn run webpack-prod @@ -232,6 +267,7 @@ jsdoc: stage: post-test dependencies: - compile-assets + - compile-assets pull-cache before_script: [] script: - date diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index b7ef4b3174..4da7f40476 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -28,16 +28,26 @@ policy: pull stage: test -.dedicated-no-docs-pull-cache-job: - extends: .dedicated-pull-cache-job +.no-docs: except: - - /(^docs[\/-].*|.*-docs$)/ + refs: + - /(^docs[\/-].*|.*-docs$)/ + +.no-docs-and-no-qa: + except: + refs: + - /(^docs[\/-].*|.*-docs$)/ + - /(^qa[\/-].*|.*-qa$)/ + +.dedicated-no-docs-pull-cache-job: + extends: + - .dedicated-pull-cache-job + - .no-docs .dedicated-no-docs-and-no-qa-pull-cache-job: - extends: .dedicated-pull-cache-job - except: - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ + extends: + - .dedicated-pull-cache-job + - .no-docs-and-no-qa # Jobs that do not need a DB .dedicated-no-docs-no-db-pull-cache-job: @@ -45,6 +55,12 @@ variables: SETUP_DB: "false" +# Jobs that need a dedicated runner, with no cache +.dedicated-no-docs: + extends: + - .dedicated-runner + - .no-docs + .single-script-job-dedicated-runner: extends: .dedicated-runner image: ruby:2.6-alpine diff --git a/.gitlab/ci/memory.gitlab-ci.yml b/.gitlab/ci/memory.gitlab-ci.yml new file mode 100644 index 0000000000..ffe5dbdc31 --- /dev/null +++ b/.gitlab/ci/memory.gitlab-ci.yml @@ -0,0 +1,42 @@ +memory-static: + extends: .dedicated-no-docs-no-db-pull-cache-job + script: + # Uses two different reports from the 'derailed_benchmars' gem. + + # Loads each of gems in the Gemfile and checks how much memory they consume when they are required. + # 'derailed_benchmarks' internally uses 'get_process_mem' + - bundle exec derailed bundle:mem > tmp/memory_bundle_mem.txt + - scripts/generate-gems-size-metrics-static tmp/memory_bundle_mem.txt >> 'tmp/memory_metrics.txt' + + # Outputs detailed information about objects created while gems are loaded. + # 'derailed_benchmarks' internally uses 'memory_profiler' + - bundle exec derailed bundle:objects > tmp/memory_bundle_objects.txt + - scripts/generate-gems-memory-metrics-static tmp/memory_bundle_objects.txt >> 'tmp/memory_metrics.txt' + artifacts: + paths: + - tmp/memory_*.txt + reports: + metrics: tmp/memory_metrics.txt + +# Show memory usage caused by invoking require per gem. +# Unlike `memory-static`, it hits the app with one request to ensure that any last minute require-s have been called. +# The application is booted in `production` environment. +# All tests are run without a webserver (directly using Rack::Mock by default). +memory-on-boot: + extends: .rspec-metadata-pg-10 + variables: + NODE_ENV: "production" + RAILS_ENV: "production" + SETUP_DB: "true" + SKIP_STORAGE_VALIDATION: "true" + # we override the max_old_space_size to prevent OOM errors + NODE_OPTIONS: --max_old_space_size=3584 + script: + # Both bootsnap and derailed monkey-patch Kernel#require, which leads to circular dependency + - DISABLE_BOOTSNAP=true PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> 'tmp/memory_on_boot.txt' + - scripts/generate-memory-metrics-on-boot tmp/memory_on_boot.txt >> 'tmp/memory_on_boot_metrics.txt' + artifacts: + paths: + - tmp/memory_*.txt + reports: + metrics: tmp/memory_on_boot_metrics.txt diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index 68280506da..c7a51beeee 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -1,6 +1,6 @@ .use-pg: &use-pg services: - - name: postgres:9.6 + - name: postgres:9.6.11 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] - name: redis:alpine @@ -10,11 +10,6 @@ command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] - name: redis:alpine -.use-mysql: &use-mysql - services: - - mysql:5.7 - - redis:alpine - .only-schedules-master: &only-schedules-master only: - schedules@gitlab-org/gitlab-ce @@ -25,8 +20,9 @@ - master@gitlab/gitlab-ee .gitlab-setup: &gitlab-setup - extends: .dedicated-no-docs-and-no-qa-pull-cache-job - <<: *use-pg + extends: + - .dedicated-no-docs-and-no-qa-pull-cache-job + - .use-pg variables: SETUP_DB: "false" script: @@ -48,7 +44,9 @@ - bundle exec rake $CI_JOB_NAME .rspec-metadata: &rspec-metadata - extends: .dedicated-pull-cache-job + extends: + - .dedicated-pull-cache-job + - .no-docs-and-no-qa stage: test script: - JOB_NAME=( $CI_JOB_NAME ) @@ -68,6 +66,8 @@ - scripts/gitaly-test-spawn - date - 'export KNAPSACK_TEST_FILE_PATTERN=$(ruby -r./lib/quality/test_level.rb -e "puts Quality::TestLevel.new.pattern(:${TEST_LEVEL})")' + - mkdir -p tmp/memory_test + - export MEMORY_TEST_PATH="tmp/memory_test/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_memory.csv" - knapsack rspec "--color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag level:${TEST_LEVEL} --tag ~geo" - date artifacts: @@ -79,11 +79,9 @@ - rspec_flaky/ - rspec_profiling/ - tmp/capybara/ - reports: - junit: junit_rspec.xml - except: - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ + - tmp/memory_test/ +# reports: +# junit: junit_rspec.xml .rspec-metadata-pg: &rspec-metadata-pg <<: *rspec-metadata @@ -94,10 +92,6 @@ <<: *use-pg-10 image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.21-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.29" -.rspec-metadata-mysql: &rspec-metadata-mysql - <<: *rspec-metadata - <<: *use-mysql - # DB migration, rollback, and seed jobs .db-migrate-reset: &db-migrate-reset extends: .dedicated-no-docs-and-no-qa-pull-cache-job @@ -131,8 +125,10 @@ - setup-test-env setup-test-env: - extends: .dedicated-runner-default-cache - <<: *use-pg + extends: + - .dedicated-runner-default-cache + - .no-docs + - .use-pg stage: prepare script: - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' @@ -143,8 +139,6 @@ setup-test-env: - tmp/tests - config/secrets.yml - vendor/gitaly-ruby - except: - - /(^docs[\/-].*|.*-docs$)/ rspec unit pg: <<: *rspec-metadata-pg @@ -173,42 +167,6 @@ rspec system pg-10: <<: *only-schedules-master parallel: 24 -rspec unit mysql: - <<: *rspec-metadata-mysql - <<: *only-schedules-master - parallel: 20 - -rspec integration mysql: - <<: *rspec-metadata-mysql - <<: *only-schedules-master - parallel: 6 - -rspec system mysql: - <<: *rspec-metadata-mysql - <<: *only-schedules-master - parallel: 24 - -.rspec-mysql-on-demand: &rspec-mysql-on-demand - only: - variables: - - $CI_COMMIT_MESSAGE =~ /\[run mysql\]/i - - $CI_COMMIT_REF_NAME =~ /mysql/ - -rspec unit mysql on-demand: - <<: *rspec-metadata-mysql - <<: *rspec-mysql-on-demand - parallel: 20 - -rspec integration mysql on-demand: - <<: *rspec-metadata-mysql - <<: *rspec-mysql-on-demand - parallel: 6 - -rspec system mysql on-demand: - <<: *rspec-metadata-mysql - <<: *rspec-mysql-on-demand - parallel: 24 - rspec-fast-spec-helper: <<: *rspec-metadata-pg script: @@ -226,16 +184,11 @@ rspec quarantine pg: <<: *rspec-quarantine allow_failure: true -rspec quarantine mysql: - <<: *rspec-metadata-mysql - <<: *rspec-quarantine - <<: *only-schedules-master - allow_failure: true - static-analysis: extends: .dedicated-no-docs-no-db-pull-cache-job dependencies: - compile-assets + - compile-assets pull-cache - setup-test-env script: - scripts/static-analysis @@ -250,11 +203,12 @@ static-analysis: downtime_check: <<: *rake-exec except: - - master - - tags - - /^[\d-]+-stable(-ee)?$/ - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ + refs: + - master + - tags + - /^[\d-]+-stable(-ee)?$/ + - /(^docs[\/-].*|.*-docs$)/ + - /(^qa[\/-].*|.*-qa$)/ dependencies: - setup-test-env @@ -262,12 +216,13 @@ ee_compat_check: <<: *rake-exec dependencies: [] except: - - master - - tags - - /[\d-]+-stable(-ee)?/ - - /^security-/ - - branches@gitlab-org/gitlab-ee - - branches@gitlab/gitlab-ee + refs: + - master + - tags + - /[\d-]+-stable(-ee)?/ + - /^security-/ + - branches@gitlab-org/gitlab-ee + - branches@gitlab/gitlab-ee retry: 0 artifacts: name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}" @@ -280,10 +235,6 @@ db:migrate:reset-pg: <<: *db-migrate-reset <<: *use-pg -db:migrate:reset-mysql: - <<: *db-migrate-reset - <<: *use-mysql - db:check-schema-pg: <<: *db-migrate-reset <<: *use-pg @@ -294,15 +245,11 @@ migration:path-pg: <<: *migration-paths <<: *use-pg -migration:path-mysql: - <<: *migration-paths - <<: *use-mysql - .db-rollback: &db-rollback extends: .dedicated-no-docs-and-no-qa-pull-cache-job script: - - bundle exec rake db:migrate VERSION=20170523121229 - - bundle exec rake db:migrate + - bundle exec rake db:migrate VERSION=20180101160629 + - bundle exec rake db:migrate SKIP_SCHEMA_VERSION_CHECK=true dependencies: - setup-test-env @@ -310,26 +257,18 @@ db:rollback-pg: <<: *db-rollback <<: *use-pg -db:rollback-mysql: - <<: *db-rollback - <<: *use-mysql - gitlab:setup-pg: <<: *gitlab-setup <<: *use-pg dependencies: - setup-test-env -gitlab:setup-mysql: - <<: *gitlab-setup - <<: *use-mysql - dependencies: - - setup-test-env - coverage: # Don't include dedicated-no-docs-no-db-pull-cache-job here since we need to # download artifacts from all the rspec jobs instead of from setup-test-env only - extends: .dedicated-runner-default-cache + extends: + - .dedicated-runner-default-cache + - .no-docs-and-no-qa cache: policy: pull variables: @@ -337,6 +276,7 @@ coverage: stage: post-test script: - bundle exec scripts/merge-simplecov + - bundle exec scripts/gather-test-memory-data coverage: '/LOC \((\d+\.\d+%)\) covered.$/' artifacts: name: coverage @@ -344,6 +284,4 @@ coverage: paths: - coverage/index.html - coverage/assets/ - except: - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ + - tmp/memory_test/ diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml index d0e09dbf2f..ca55bbd32a 100644 --- a/.gitlab/ci/reports.gitlab-ci.yml +++ b/.gitlab/ci/reports.gitlab-ci.yml @@ -1,98 +1,26 @@ include: - template: Code-Quality.gitlab-ci.yml + - template: Security/SAST.gitlab-ci.yml + - template: Security/Dependency-Scanning.gitlab-ci.yml code_quality: - extends: .dedicated-no-docs-no-db-pull-cache-job + extends: .dedicated-no-docs # gitlab-org runners set `privileged: false` but we need to have it set to true # since we're using Docker in Docker tags: [] before_script: [] cache: {} - dependencies: [] - variables: - SETUP_DB: "false" sast: - extends: .dedicated-no-docs-no-db-pull-cache-job - image: docker:stable - variables: - SAST_CONFIDENCE_LEVEL: 2 - DOCKER_DRIVER: overlay2 - allow_failure: true + extends: .dedicated-no-docs tags: [] before_script: [] cache: {} - dependencies: [] - services: - - docker:stable-dind - script: - - | # this is required to avoid undesirable reset of Docker image ENV variables being set on build stage - function propagate_env_vars() { - CURRENT_ENV=$(printenv) - - for VAR_NAME; do - echo $CURRENT_ENV | grep "${VAR_NAME}=" > /dev/null && echo "--env $VAR_NAME " - done - } - - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') - - | - docker run \ - $(propagate_env_vars \ - SAST_ANALYZER_IMAGES \ - SAST_ANALYZER_IMAGE_PREFIX \ - SAST_ANALYZER_IMAGE_TAG \ - SAST_DEFAULT_ANALYZERS \ - SAST_BRAKEMAN_LEVEL \ - SAST_GOSEC_LEVEL \ - SAST_FLAWFINDER_LEVEL \ - SAST_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \ - SAST_PULL_ANALYZER_IMAGE_TIMEOUT \ - SAST_RUN_ANALYZER_TIMEOUT \ - ) \ - --volume "$PWD:/code" \ - --volume /var/run/docker.sock:/var/run/docker.sock \ - "registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code - artifacts: - reports: - sast: gl-sast-report.json + variables: + SAST_BRAKEMAN_LEVEL: 2 dependency_scanning: - extends: .dedicated-no-docs-no-db-pull-cache-job - image: docker:stable - variables: - DOCKER_DRIVER: overlay2 - allow_failure: true + extends: .dedicated-no-docs tags: [] before_script: [] cache: {} - dependencies: [] - services: - - docker:stable-dind - script: - - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') - - | # this is required to avoid undesirable reset of Docker image ENV variables being set on build stage - function propagate_env_vars() { - CURRENT_ENV=$(printenv) - - for VAR_NAME; do - echo $CURRENT_ENV | grep "${VAR_NAME}=" > /dev/null && echo "--env $VAR_NAME " - done - } - - | - docker run \ - $(propagate_env_vars \ - DS_ANALYZER_IMAGES \ - DS_ANALYZER_IMAGE_PREFIX \ - DS_ANALYZER_IMAGE_TAG \ - DS_DEFAULT_ANALYZERS \ - DEP_SCAN_DISABLE_REMOTE_CHECKS \ - DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \ - DS_PULL_ANALYZER_IMAGE_TIMEOUT \ - DS_RUN_ANALYZER_TIMEOUT \ - ) \ - --volume "$PWD:/code" \ - --volume /var/run/docker.sock:/var/run/docker.sock \ - "registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code - artifacts: - reports: - dependency_scanning: gl-dependency-scanning-report.json diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml index 9b764028be..e3a77574d7 100644 --- a/.gitlab/ci/review.gitlab-ci.yml +++ b/.gitlab/ci/review.gitlab-ci.yml @@ -35,7 +35,7 @@ <<: *review-base image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine services: - - docker:stable-dind + - docker:19.03.0-dind tags: - gitlab-org - docker @@ -77,6 +77,7 @@ schedule:review-build-cng: .review-deploy-base: &review-deploy-base <<: *review-base allow_failure: true + retry: 1 stage: review variables: HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}" @@ -95,10 +96,16 @@ schedule:review-build-cng: - install_api_client_dependencies_with_apk - source scripts/review_apps/review-apps.sh script: - - perform_review_app_deployment + - check_kube_domain + - ensure_namespace + - install_tiller + - install_external_dns + - download_chart + - deploy || display_deployment_debug + - wait_for_review_app_to_be_accessible + - add_license artifacts: - paths: - - review_app_url.txt + paths: [review_app_url.txt] expire_in: 2 days when: always @@ -108,8 +115,6 @@ review-deploy: schedule:review-deploy: <<: *review-deploy-base <<: *review-schedules-only - script: - - perform_review_app_deployment review-stop: <<: *review-base @@ -124,11 +129,11 @@ review-stop: script: - source scripts/review_apps/review-apps.sh - delete - - cleanup .review-qa-base: &review-qa-base <<: *review-docker allow_failure: true + retry: 2 stage: qa variables: <<: *review-docker-variables @@ -169,7 +174,38 @@ review-qa-all: script: - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/review-qa-all_master_report.json - export KNAPSACK_TEST_FILE_PATTERN=qa/specs/features/**/*_spec.rb - - gitlab-qa Test::Instance::Any "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" + - gitlab-qa Test::Instance::Any "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" -- --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml --format html --out tmp/rspec.htm --color --format documentation + +parallel-spec-reports: + extends: .dedicated-runner + dependencies: + - review-qa-all + image: ruby:2.6-alpine + services: [] + before_script: [] + variables: + SETUP_DB: "false" + NEW_PARALLEL_SPECS_REPORT: qa/report-new.html + BASE_ARTIFACT_URL: "${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/file/qa/" + stage: post-test + allow_failure: true + when: manual + retry: 0 + artifacts: + when: always + paths: + - qa/report-new.html + - qa/gitlab-qa-run-* + reports: + junit: qa/gitlab-qa-run-*/**/rspec-*.xml + script: + - apk add --update build-base libxml2-dev libxslt-dev && rm -rf /var/cache/apk/* + - gem install nokogiri + - cd qa/gitlab-qa-run-*/gitlab-* + - ARTIFACT_DIRS=$(pwd |rev| awk -F / '{print $1,$2}' | rev | sed s_\ _/_) + - cd ../../.. + - '[[ -f $NEW_PARALLEL_SPECS_REPORT ]] || echo "{}" > ${NEW_PARALLEL_SPECS_REPORT}' + - scripts/merge-html-reports ${NEW_PARALLEL_SPECS_REPORT} ${BASE_ARTIFACT_URL}${ARTIFACT_DIRS} qa/gitlab-qa-run-*/**/rspec.htm .review-performance-base: &review-performance-base <<: *review-qa-base @@ -225,11 +261,12 @@ danger-review: except: refs: - master + - /^[\d-]+-stable(-ee)?$/ variables: - $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/ - $CI_COMMIT_REF_NAME =~ /.*-stable(-ee)?-prepare-.*/ script: - git version - node --version - - yarn install --frozen-lockfile --cache-folder .yarn-cache + - yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline - danger --fail-on-errors=true diff --git a/.gitlab/ci/setup.gitlab-ci.yml b/.gitlab/ci/setup.gitlab-ci.yml index debc90a1cb..c1fc3a893c 100644 --- a/.gitlab/ci/setup.gitlab-ci.yml +++ b/.gitlab/ci/setup.gitlab-ci.yml @@ -15,7 +15,9 @@ cache gems: - setup-test-env gitlab_git_test: - extends: .dedicated-runner + extends: + - .dedicated-runner + - .no-docs-and-no-qa variables: SETUP_DB: "false" before_script: [] @@ -23,12 +25,11 @@ gitlab_git_test: cache: {} script: - spec/support/prepare-gitlab-git-test-for-commit --check-for-changes - except: - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ no_ee_check: - extends: .dedicated-runner + extends: + - .dedicated-runner + - .no-docs-and-no-qa variables: SETUP_DB: "false" before_script: [] @@ -38,6 +39,3 @@ no_ee_check: - scripts/no-ee-check only: - /.+/@gitlab-org/gitlab-ce - except: - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ diff --git a/.gitlab/ci/test-metadata.gitlab-ci.yml b/.gitlab/ci/test-metadata.gitlab-ci.yml index c51f825f83..2454ea8565 100644 --- a/.gitlab/ci/test-metadata.gitlab-ci.yml +++ b/.gitlab/ci/test-metadata.gitlab-ci.yml @@ -12,7 +12,9 @@ - rspec_profiling/ retrieve-tests-metadata: - <<: *tests-metadata-state + extends: + - .tests-metadata-state + - .no-docs-and-no-qa stage: prepare cache: key: tests_metadata @@ -25,9 +27,6 @@ retrieve-tests-metadata: - mkdir -p rspec_profiling/ - wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH - '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}' - except: - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ update-tests-metadata: <<: *tests-metadata-state @@ -69,9 +68,10 @@ flaky-examples-check: only: - branches except: - - master - - /(^docs[\/-].*|.*-docs$)/ - - /(^qa[\/-].*|.*-qa$)/ + refs: + - master + - /(^docs[\/-].*|.*-docs$)/ + - /(^qa[\/-].*|.*-qa$)/ artifacts: expire_in: 30d paths: diff --git a/.gitlab/issue_templates/Database Reviewer.md b/.gitlab/issue_templates/Database Reviewer.md deleted file mode 100644 index acbaf5c196..0000000000 --- a/.gitlab/issue_templates/Database Reviewer.md +++ /dev/null @@ -1,34 +0,0 @@ -#### Database Reviewer Checklist - -Thank you for becoming a ~database reviewer! Please work on the list -below to complete your setup. For any question, reach out to #database -an mention `@abrandl`. - -- [ ] Change issue title to include your name: `Database Reviewer Checklist: Your Name` -- [ ] Review general [code review guide](https://docs.gitlab.com/ee/development/code_review.html) -- [ ] Review [database review documentation](https://about.gitlab.com/handbook/engineering/workflow/code-review/database.html) -- [ ] Familiarize with [migration helpers](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/database/migration_helpers.rb) and review usage in existing migrations -- [ ] Read [database migration style guide](https://docs.gitlab.com/ee/development/migration_style_guide.html) -- [ ] Familiarize with best practices in [database guides](https://docs.gitlab.com/ee/development/#database-guides) -- [ ] Watch [Optimising Rails Database Queries: Episode 1](https://www.youtube.com/watch?v=79GurlaxhsI) -- [ ] Read [Understanding EXPLAIN plans](https://docs.gitlab.com/ee/development/understanding_explain_plans.html) -- [ ] Review [database best practices](https://docs.gitlab.com/ee/development/#best-practices) -- [ ] Review how we use [database instances restored from a backup](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd) for testing and make sure you're set up to execute pipelines (check [README.md](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd/blob/master/README.md) and reach out to @abrandl since this is currently subject to being changed) -- [ ] Get yourself added to [`@gl-database`](https://gitlab.com/groups/gl-database/-/group_members) group and respond to @-mentions to the group (reach out to any maintainer on the group to get added). You will get TODOs on gitlab.com for group mentions. -- [ ] Make sure you have proper access to at least a read-only replica in staging and production -- [ ] Indicate in `data/team.yml` your role as a database reviewer ([example MR](https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/19600/diffs)). Assign MR to your manager for merge. -- [ ] Send one MR to improve the [review documentation](https://about.gitlab.com/handbook/engineering/workflow/code-review/database.html) or the [issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Database%20Reviewer.md) - -Note that *approving and accepting* merge requests is *restricted* to -Database Maintainers only. As a reviewer, pass the MR to a maintainer -for approval. - -You're all set! Watch out for TODOs on GitLab.com. - -###### Where to go for questions? - -Reach out to `#database` on Slack and mention `@abrandl` for any questions. - -cc @abrandl - -/label ~meta ~database diff --git a/.gitlab/issue_templates/Documentation.md b/.gitlab/issue_templates/Documentation.md index 67602b7b2d..f4070a4475 100644 --- a/.gitlab/issue_templates/Documentation.md +++ b/.gitlab/issue_templates/Documentation.md @@ -4,7 +4,7 @@ Note: Doc work as part of feature development is covered in the Feature Request template. * For issues related to features of the docs.gitlab.com site, see - https://gitlab.com/gitlab-com/gitlab-docs/issues/ + https://gitlab.com/gitlab-org/gitlab-docs/issues/ * For information about documentation content and process, see https://docs.gitlab.com/ee/development/documentation/ --> diff --git a/.gitlab/merge_request_templates/Change documentation location.md b/.gitlab/merge_request_templates/Change documentation location.md index c80af95d5e..7dc80a641c 100644 --- a/.gitlab/merge_request_templates/Change documentation location.md +++ b/.gitlab/merge_request_templates/Change documentation location.md @@ -22,7 +22,7 @@ https://docs.gitlab.com/ce/development/documentation/index.html#changing-documen - [ ] Make sure internal links pointing to the document in question are not broken. - [ ] Search and replace any links referring to old docs in GitLab Rails app, specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories. -- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ce/development/writing_documentation.html#redirections-for-pages-with-disqus-comments) +- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ce/development/documentation/index.html#redirections-for-pages-with-disqus-comments) to the new document if there are any Disqus comments on the old document thread. - [ ] Update the link in `features.yml` (if applicable) - [ ] If working on CE and the `ee-compat-check` jobs fails, submit an MR to EE diff --git a/.mdlrc b/.mdlrc new file mode 100644 index 0000000000..151c54f7d4 --- /dev/null +++ b/.mdlrc @@ -0,0 +1,7 @@ +# This is the options file for mdl, configured in .gitlab/ci/docs.gitlab-ci.yml, +# and related to the style file ./mdlrc.style + +# See https://github.com/markdownlint/markdownlint/blob/master/docs/configuration.md + +ignore_front_matter true +style File.expand_path('.mdlrc.style', __dir__) diff --git a/.mdlrc.style b/.mdlrc.style new file mode 100644 index 0000000000..0ca3611df0 --- /dev/null +++ b/.mdlrc.style @@ -0,0 +1,21 @@ +# This is the style file for mdl, configured in .gitlab/ci/docs.gitlab-ci.yml, +# and related to the options file ./mdlrc + +# See https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md +# for more detailed information on the rules and styles. + +rule "MD001" +rule "MD003", :style => :atx +rule "MD011" +rule "MD023" +rule "MD032" +rule "MD034" +rule "MD037" + +# Should not be used currently: + +# rule "MD004", :style => :dash # unordered list style - dash +# False positives, see https://github.com/markdownlint/markdownlint/issues/261 + +# rule "MD039" # Spaces inside link text +# Crashes when link text has certain punctuation diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 698570efb0..41714eefa9 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -466,12 +466,10 @@ Rails/LinkToBlank: Rails/Presence: Exclude: - 'app/models/ci/pipeline.rb' - - 'app/models/clusters/platforms/kubernetes.rb' - 'app/models/concerns/mentionable.rb' - 'app/models/project_services/hipchat_service.rb' - 'app/models/project_services/irker_service.rb' - 'app/models/project_services/jira_service.rb' - - 'app/models/project_services/kubernetes_service.rb' - 'app/models/project_services/packagist_service.rb' - 'app/models/wiki_page.rb' - 'lib/gitlab/github_import/importer/releases_importer.rb' @@ -514,7 +512,6 @@ Security/YAMLLoad: - 'spec/config/mail_room_spec.rb' - 'spec/initializers/secret_token_spec.rb' - 'spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb' - - 'spec/models/project_services/kubernetes_service_spec.rb' # Offense count: 34 # Configuration parameters: EnforcedStyle. diff --git a/CHANGELOG.md b/CHANGELOG.md index 2180f24f7e..9e24988705 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,20 +2,27 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. -## 12.0.9 +## 12.1.11 + +- No changes. + +## 12.1.10 + +- No changes. + +## 12.1.9 ### Security (1 change) -- Upgrade pages to 1.6.3. +- Upgrade pages to 1.7.2. -## 12.0.8 +## 12.1.8 -### Security (22 changes) +### Security (21 changes) - Ensure only authorised users can create notes on Merge Requests and Issues. - Add :login_recaptcha_protection_enabled setting to prevent bots from brute-force attacks. -- Queries for Upload should be scoped by model. - Speed up regexp in namespace format by failing fast after reaching maximum namespace depth. - Limit the size of issuable description and comments. - Send TODOs for comments on commits correctly. @@ -37,36 +44,349 @@ entry. - Fix SSRF via DNS rebinding in Kubernetes Integration. -## 12.0.7 +## 12.1.7 - Unreleased due to QA failure. -## 12.0.6 +## 12.1.6 ### Security (2 changes) -- Upgrade Gitaly to 1.47.2 to prevent revision flag injection exploits. -- Upgrade pages to 1.6.2 to prevent gitlab api token recovery from cookie. +- Upgrade Gitaly to 1.53.2 to prevent revision flag injection exploits. +- Upgrade pages to 1.7.1 to prevent gitlab api token recovery from cookie. -## 12.0.5 +## 12.1.5 - No changes. -## 12.0.4 +## 12.1.4 + +### Fixed (3 changes, 1 of them is from the community) + +- Properly translate term in projects list. !30958 +- Add exclusive lease to mergeability check process. !31082 +- Fix Docker in Docker (DIND) listen port behavior change by adding DOCKER_TLS_CERTDIR in CI job templates. !31201 (Cameron Boulton) + +### Performance (1 change) + +- Improve job log rendering performance. !31262 + + +## 12.1.3 + +### Fixed (11 changes) + +- Prevent multiple confirmation modals from opening when deleting a repository. !30532 +- Fix the project auto devops API. !30946 +- Fix "Certificate misses intermediates" UI error when enabling Let's Encrypt integration for pages domain. !30995 +- Fix xterm css not loading for environment terminal. !31023 +- Set DOCKER_TLS_CERTDIR in Auto Dev-Ops CI template to fix jobs using Docker-in-Docker. !31078 +- Set DOCKER_TLS_CERTDIR in CI job templates to fix Docker-in-Docker service. !31080 +- Support Docker OCI images. !31127 +- Fix error rendering submodules in MR diffs when there is no .gitmodules. !31162 +- Fix pdf.js rendering pages in the wrong order. !31222 +- Fix exception handling in Gitaly autodetection. !31285 +- Fix bug that caused diffs not to show on MRs with changes to submodules. + +### Performance (1 change) + +- Optimise import performance. !31045 + + +## 12.1.2 + +### Security (1 change) + +- Use source project as permissions reference for MergeRequestsController#pipelines. ### Security (9 changes) - Restrict slash commands to users who can log in. - Patch XSS issue in wiki links. +- Queries for Upload should be scoped by model. - Filter merge request params on the new merge request page. - Fix Server Side Request Forgery mitigation bypass. - Show badges if pipelines are public otherwise default to project permissions. - Do not allow localhost url redirection in GitHub Integration. - Do not show moved issue id for users that cannot read issue. -- Use source project as permissions reference for MergeRequestsController#pipelines. - Drop feature to take ownership of trigger token. +## 12.1.1 + +- No changes. + +## 12.1.0 + +### Security (11 changes, 2 of them are from the community) + +- Update tar to 2.2.2. !29949 (Takuya Noguchi) +- Update lodash to 4.7.14 and lodash.mergewith to 4.6.2. !30602 (Takuya Noguchi) +- Correctly check permissions when creating snippet notes. +- Gate MR head_pipeline behind read_pipeline ability. +- Prevent Billion Laughs attack. +- Add missing authorizations in GraphQL. +- Fix Denial of Service for comments when rendering issues/MR comments. +- Expose merge requests count based on user access. +- Fix DoS vulnerability in color validation regex. +- Prevent the detection of merge request templates by unauthorized users. +- Persist tmp snippet uploads at users. + +### Removed (7 changes) + +- Disable Kubernetes credential passthrough for managed project-level clusters. !29262 +- Remove deprecated group routes. !29351 +- Remove support for creating non-RBAC kubernetes clusters. !29614 +- Remove Kubernetes service integration and Kubernetes service template from available deployment platforms. !29786 +- Remove MySQL support. !29790 +- Remove depreated /u/:username routing. !30044 +- Remove support for legacy pipeline triggers. !30133 + +### Fixed (84 changes, 14 of them are from the community) + +- Update a user's routes after updating their name. !23272 +- Show poper panel when validation error occurs in admin settings panels. !25434 +- Expect bytes from Gitaly RPC GetRawChanges. !28164 +- Sanitize LDAP output in Rake tasks. !28427 +- Left align mr widget icons and text. !28561 +- Keep the empty folders in the tree. !29196 +- Fix incorrect emoji placement in commit diff discussion. !29445 +- Fix favicon path with uploads of object store. !29482 (Roger Meier) +- Remove duplicate trailing +/- char in merge request discussions. !29518 +- Fix the signup form's username validation messages not displaying. !29678 (Jiaan Louw) +- Fix broken environment selector and always display it on monitoring dashboard. !29705 +- Fix Container Scanning job timeout when using the kubernetes executor. !29706 +- Look for new branches more carefully. !29761 +- Fix nested lists unnecessary margin. !29775 (Kuba Kopeć) +- Fix reports jobs timing out because of cache. !29780 +- Fix Double Border in Profile Page. !29784 (Yoginth <@yo>) +- Remove minimum character limits for fuzzy searches when using a CTE. !29810 +- Set default sort method for dashboard projects list. !29830 (David Palubin) +- Protect TeamCity builds from triggering when a branch has been deleted. And a MR-option. !29836 (Nikolay Novikov, Raphael Tweitmann) +- Fix pipeline schedule does not run correctly when it's scheduled at the same time with the cron worker. !29848 +- Always shows author of created issue/started discussion/comment in HTML body and text of email. !29886 (Frank van Rest) +- Build correct basenames for title search results. !29898 +- Resolve "500 error when forking via the web IDE button". !29909 +- Turn commit sha in monitor charts popover to link. !29914 +- Fix broken URLs for uploads with a plus in the filename. !29915 +- Retry fetching Kubernetes Secret#token (#63507). !29922 +- Enforce presence of pipeline when "Pipeline must succeed" project setting is enabled. !29926 +- Fix unresponsive reply button in discussions. !29936 +- Allow asynchronous rebase operations to be monitored. !29940 +- Resolve Avatar in Please sign in pattern too large. !29944 +- Persist the cluster a deployment was deployed to. !29960 +- Fix runner tags search dropdown being empty when there are tags. !29985 +- Display the correct amount of projects being migrated/rolled-back to Hashed Storage when specifying ranges. !29996 +- Resolve Environment details header border misaligned. !30011 +- Correct link to docs for External Dashboard. !30019 +- Fix Jupyter-Git integration. !30020 (Amit Rathi) +- Update Mermaid to 8.1.0. !30036 +- Fix background migrations failing with unused replication slot. !30042 +- Disable Rails SQL query cache when applying service templates. !30060 +- Set higher TTL for write lock of trace to prevent concurrent archiving. !30064 +- Fix charts on Cluster health page. !30073 +- Display boards filter bar on mobile. !30120 +- Fix IDE editor not showing when switching back from preview. !30135 +- Support note position tracing on an image. !30158 +- Replace slugifyWithHyphens with improved slugify function. !30172 (Luke Ward) +- 'Open' and 'Closed' issue board lists no longer display a redundant tooltip. !30187 +- Fix pipelines table to update without refreshing after action. !30190 +- Change ruby_process_start_time_seconds metric to unix timestamp instead of seconds from boot. !30195 +- Fix attachments using the wrong URLs in e-mails. !30197 +- Make sure UnicornSampler is started only in master process. !30215 +- Don't show image diff note on text file. !30221 +- Fix median counting for cycle analytics. !30229 +- In WebIDE allow adding new entries of the same name as deleted entry. !30239 +- Don't let logged out user do manual order. !30264 +- Skip spam check for task list updates. !30279 +- Make Housekeeping button do a full garbage collection. !30289 +- Removing an image should not output binary data. !30314 +- Fix spacing issues for toasts. !30345 +- Fix race in forbid_sidekiq_in_transactions.rb. !30359 +- Fixed back navigation for projects filter. !30373 +- Fix environments broken terminal. !30401 +- Fix invalid SSL certificate errors on Drone CI service. !30422 +- Fix subgroup url in search drop down. !30457 +- Make unicorn_workers to return meaningful results. !30506 +- Fix wrong URL when creating milestones from instance milestones dashboard. !30512 +- Fixed incorrect line wrap for assignee label in issues. !30523 (Marc Schwede) +- Improves section header whitespace on the CI/CD Charts page. !30531 +- Prevent multiple confirmation modals from opening when deleting a repository. !30532 +- Aligns CI icon in Merge Request dashboard. !30558 +- Add text-secondary to controls in project list. !30567 +- Review Tools: Add large z-index to toolbar. !30583 +- Hide restricted and disallowed visibility radios. !30590 +- Resolve Label picker: Line break on long label titles. !30610 +- Fix a bug that prevented projects containing merge request diff comments from being imported. !30630 +- I fixed z index bug in diff page. !30657 (Faruk Can) +- Allow client authentication method to be configured for OpenID Connect. !30683 (Vincent Fazio) +- Fix commenting before discussions are loaded. !30724 +- Fix linebreak rendering in Mermaid flowcharts. !30730 +- Make httpclient respect system SSL configuration. !30749 +- Bump fog-aws to v3.5.2. !30803 +- API: Allow changing only ci_default_git_depth. !30888 (Mathieu Parent) +- Search issuables by iids. (Riccardo Padovani) +- Fix broken warnings while Editing Issues and Edit File on MR. +- Make sure we are receiving the proper information on the MR Popover by updating the IID in the graphql query. + +### Changed (39 changes, 8 of them are from the community) + +- Improve group list UI. !26542 +- Backport and Docs for Paginate license management and add license search. !27602 +- Update merge requests section description text on project settings page. !27838 +- Knative version bump 0.5 -> 0.6. !28798 (Chris Baumbauer) +- Add salesforce logo for salesforce SSO. !28857 +- Enforced requirements for UltraAuth users. !28941 (Kartikey Tanna) +- Return 400 when deleting tags more often than once per hour. !29448 +- Add identity information to external authorization requests. !29461 +- Enable just-in-time Kubernetes resource creation for project-level clusters. !29515 +- renamed discussion to thread in merge-request and issue timeline. !29553 (Michel Engelen) +- Changed HTTP Status Code for disabled repository on /branches and /commits to 404. !29585 (Sam Battalio) +- Enable Git object pools. !29595 (jramsay) +- Updated container registry to display error message when special characters in path. Documentation has also been updated. !29616 +- Allow developers to delete tags. !29668 +- Will not update issue timestamps when changing positions in a list. !29677 +- Include a link back to the MR for Visual Review feedback form. !29719 +- Improve discussion reply buttons layout and how jump to next discussion button appears. !29779 +- Renders a pre-release tag for releases. !29797 +- Migrate NULL values for users.private_profile column and update users API to reject null value for private_profile. !29888 +- Re-name files in Web IDE in a more natural way. !29948 +- Include events from subgroups in group's activity. !29953 (Fabian Schneider @fabsrc) +- Upgrade to Gitaly v1.49.0. !29990 +- Remove group and instance clusters feature flag. !30124 +- Add support for creating random passwords in user creation API. !30138 +- Support CIDR notation in IP rate limiter. !30146 +- Add Redis call details in Peek performance bar. !30191 +- Create Knative role and binding with service account. !30235 +- Add cleanup migration for MR's multiple assignees. !30261 +- Updates PHP template to php:latest to ensure always targeting latest stable. !30319 (Paul Giberson) +- Format `from` and `to` fields in JSON audit log. !30333 +- Upgrade to Gitaly v1.51.0. !30353 +- Modify cycle analytics on project level. !30356 +- Extract clair version as CLAIR_EXECUTABLE_VERSION variable and update clair executable from v8 to v11. !30396 +- Upgrade Rouge to 3.5.1. !30431 +- Move multiple issue boards to core. !30503 +- Upgrade to Gitaly v1.52.0. !30568 +- Upgrade to Gitaly v1.53.0. !30614 +- Open WebIDE in fork when user doesn't have access. !30642 +- Propagate python version variable. (Can Eldem) + +### Performance (25 changes, 1 of them is from the community) + +- Remove tooltip directive on project avatar image component. !29631 (George Tsiolis) +- Use Rugged if we detect storage is NFS and we can access the disk. !29725 +- Add endpoint for fetching diverging commit counts. !29802 +- Cache feature flag names in Redis for a minute. !29816 +- Avoid storing backtraces from Bitbucket Cloud imports in the database. !29862 +- Remove import columns from projects table. !29863 +- Enable Gitaly ref name caching for discussions.json. !29951 +- Allow caching of negative FindCommit matches. !29952 +- Eliminate N+1 queries in Dashboard::TodosController. !29954 +- Memoize non-existent custom appearances. !29957 +- Add a separate endpoint for fetching MRs serialized as widgets. !29979 +- Use CTE to fetch clusters hierarchy in single query. !30063 +- Enable Gitaly ref caching for SearchController. !30105 +- Avoid loading pipeline status in search results. !30111 +- Improve performance of MergeRequestsController#ci_environment_status endpoint. !30224 +- Add a memory cache local to the thread to reduce Redis load. !30233 +- Cache Flipper persisted names directly to local memory storage. !30265 +- Limit amount of JUnit tests returned. !30274 +- Cache Flipper feature flags in L1 and L2 caches. !30276 +- Prevent amplification of ReactiveCachingWorker jobs upon failures. !30432 +- Allow ReactiveCaching to support nil value. !30456 +- Improve performance of fetching environments statuses. !30560 +- Do Redis lookup in batches in ActiveSession.sessions_from_ids. !30561 +- Remove catfile cache feature flag. !30750 +- Fix Gitaly auto-detection caching. !30954 + +### Added (46 changes, 12 of them are from the community) + +- Document the negative commit message push rule for the API. !14004 (Maikel Vlasman) +- Expose saml_provider_id in the users API. !14045 +- Improve Project API. !28327 (Mathieu Parent) +- Remove Sentry from application settings. !28447 (Roger Meier) +- Implement borderless discussion design with new reply field. !28580 +- Enable terminals for instance and group clusters. !28613 +- Resolve Multiple discussions per line in merge request diffs. !28748 +- Adds link to Grafana in Admin > Monitoring settings when grafana is enabled in config. !28937 (Romain Maneschi) +- Bring Manual Ordering on Issue List. !29410 +- Added commit type to tree GraphQL response. !29412 +- New API for User Counts, updates on success of an MR the count on top and in other tabs. !29441 +- Add option to limit time tracking units to hours. !29469 (Jon Kolb) +- Add confirmation for registry image deletion. !29505 +- Sync merge ref upon mergeability check. !29569 +- Show an Upcoming Status for Releases. !29577 +- Add order_by and sort params to list runner jobs api. !29629 (Sujay Patel) +- Allow custom username for deploy tokens. !29639 +- Add a verified pill next to email addresses under the admin users section. !29669 +- Add rake task to clean orphan artifact files. !29681 +- Render GFM in GraphQL. !29700 +- Upgrade asciidoctor version to 2.0.10. !29741 (Rajendra Kadam) +- Allow auto-completing scoped labels. !29749 +- Enable syntax highlighting for AsciiDoc. !29835 (Guillaume Grossetie) +- Expose placeholder element for metrics charts in GFM. !29861 +- Added a min schema version check to db:migrate. !29882 +- Extract zoom link from issue and pass to frontend. !29910 (raju249) +- GraphQL mutations for add, remove and toggle emoji. !29919 +- Labeled issue boards can now collapse. !29955 +- Allow Ingress to be uninstalled from the UI. !29977 +- Add permission check to metrics dashboards endpoint. !30017 +- Allow JupyterHub to be uninstalled from the UI. !30097 +- Allow GitLab Runner to be uninstalled from the UI. !30176 +- GraphQL mutations for managing Notes. !30210 +- Add API for CRUD group clusters. !30213 +- Add endpoint to move multiple issues in boards. !30216 +- Enable terminals button for group clusters. !30255 +- Prevent excessive sanitization of AsciiDoc ouptut. !30290 (Guillaume Grossetie) +- Extend `MergeToRefService` to create merge ref from an arbitrary ref. !30361 +- Add CI variable to provide GitLab HOST. !30417 +- Add migration for adding rule_type to approval_project_rules. !30575 +- Enable section anchors in Asciidoctor. !30666 (Guillaume Grossetie) +- Preserve footnote link ids in Asciidoctor. !30790 (Guillaume Grossetie) +- Add support for generating SSL certificates for custon pages domains through Let's Encrypt. +- Introduce default: for gitlab-ci.yml. +- Move Multiple Issue Boards for Projects to Core. +- Add Gitaly data to the usage ping. + +### Other (35 changes, 15 of them are from the community) + +- Remove unresolved class and fixed height in discussion header. !28440 (David Palubin) +- Moved EE/CE code differences for file `app/views/search/_category.html.haml` into CE. !28755 (Michel Engelen) +- Changes "Todo" to "To Do" in the UI for clarity. !28844 +- Migrate GitLab managed project-level clusters to unmanaged if a Kubernetes namespace was unable to be created. !29251 +- Migrate GitLab managed project-level clusters to unmanaged if they are missing a Kubernetes service account token. !29648 +- Add strategies column to operations_feature_flag_scopes table. !29808 +- Disallow `NULL` values for `geo_nodes.primary` column. !29818 (Arun Kumar Mohan) +- Replace 'JIRA' with 'Jira'. !29849 (Takuya Noguchi) +- Support jsonb default in add_column_with_default migration helper. !29871 +- Update pagination prev and next texts. !29911 +- Adds metrics to measure cost of expensive operations. !29928 +- Always allow access to health endpoints from localhost in dev. !29930 +- Update GitLab Runner Helm Chart to 0.6.0. !29982 +- Use darker gray color for system note metadata and edited text. !30054 +- Fix typo in docs about Elasticsearch. !30162 (Takuya Noguchi) +- Fix typo in code comments about Elasticsearch. !30163 (Takuya Noguchi) +- Update mixin-deep to 1.3.2. !30223 (Takuya Noguchi) +- Migrate markdown header_spec.js to Jest. !30228 (Martin Hobert) +- Remove istanbul JavaScript package. !30232 (Takuya Noguchi) +- Centralize markdownlint configuration. !30263 +- Use PostgreSQL 9.6.11 in CI tests. !30270 (Takuya Noguchi) +- Fix typo in updateResolvableDiscussionsCounts action. !30278 (Frank van Rest) +- Change color for namespace in commit search. !30312 +- Remove applySuggestion from notes service. !30399 (Frank van Rest) +- Improved readability of storage statistics in group / project admin area. !30406 +- Alignign empty container registry message with design guidelines. !30502 +- Remove toggleAward from notes service. !30536 (Frank van Rest) +- Remove deleteNote from notes service. !30537 (Frank van Rest) +- change the use of boardService in favor of boardsStore on footer for the board component. !30616 (eduarmreyes) +- Update example Prometheus scrape config. !30739 +- Update GitLab Pages to v1.7.0. +- Add token_encrypted column to operations_feature_flags_clients table. +- Removes EE diff for app/views/profiles/preferences/show.html.haml. +- Removes EE differences for app/views/layouts/fullscreen.html.haml. +- Removes EE differences for app/views/admin/users/show.html.haml. + + ## 12.0.3 (2019-06-27) - No changes. @@ -415,6 +735,15 @@ entry. - Moves snowplow to CE repo. +## 11.11.4 (2019-06-26) + +### Fixed (3 changes) + +- Fix Fogbugz Importer not working. !29383 +- Fix scrolling to top on assignee change. !29500 +- Fix IDE commit using latest ref in branch and overriding contents. !29769 + + ## 11.11.3 (2019-06-10) ### Fixed (5 changes) @@ -628,6 +957,27 @@ entry. - Add some frozen string to spec/**/*.rb. (gfyoung) +## 11.10.8 (2019-06-27) + +- No changes. +### Security (10 changes) + +- Fix Denial of Service for comments when rendering issues/MR comments. +- Gate MR head_pipeline behind read_pipeline ability. +- Fix DoS vulnerability in color validation regex. +- Expose merge requests count based on user access. +- Persist tmp snippet uploads at users. +- Add missing authorizations in GraphQL. +- Disable Rails SQL query cache when applying service templates. +- Prevent Billion Laughs attack. +- Correctly check permissions when creating snippet notes. +- Prevent the detection of merge request templates by unauthorized users. + +### Performance (1 change) + +- Add improvements to global search of issues and merge requests. !27817 + + ## 11.10.6 (2019-06-04) ### Fixed (7 changes, 1 of them is from the community) diff --git a/Dangerfile b/Dangerfile index d0a605f8d8..094d55e865 100644 --- a/Dangerfile +++ b/Dangerfile @@ -19,4 +19,5 @@ unless helper.release_automation? danger.import_dangerfile(path: 'danger/single_codebase') danger.import_dangerfile(path: 'danger/gitlab_ui_wg') danger.import_dangerfile(path: 'danger/ce_ee_vue_templates') + danger.import_dangerfile(path: 'danger/only_documentation') end diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 6bd281069f..ede3db7b44 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -1.47.3 +1.53.3 diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION index 266146b87c..f8a696c8dc 100644 --- a/GITLAB_PAGES_VERSION +++ b/GITLAB_PAGES_VERSION @@ -1 +1 @@ -1.6.3 +1.7.2 diff --git a/Gemfile b/Gemfile index c9a95fb7a3..8bffc2a973 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rails', '5.1.7' +gem 'rails', '5.2.3' # Improves copy-on-write performance for MRI gem 'nakayoshi_fork', '~> 0.0.4' @@ -11,7 +11,7 @@ gem 'responders', '~> 2.0' gem 'sprockets', '~> 3.7.0' # Default values for AR models -gem 'gitlab-default_value_for', '~> 3.1.1', require: 'default_value_for' +gem 'default_value_for', '~> 3.2.0' # Supported DBs gem 'mysql2', '~> 0.4.10', group: :mysql @@ -84,6 +84,7 @@ gem 'rack-cors', '~> 1.0.0', require: 'rack/cors' gem 'graphql', '~> 1.8.0' gem 'graphiql-rails', '~> 1.4.10' gem 'apollo_upload_server', '~> 2.0.0.beta3' +gem 'graphql-docs', '~> 1.6.0', group: [:development, :test] # Disable strong_params so that Mash does not respond to :permitted? gem 'hashie-forbidden_attributes' @@ -99,7 +100,7 @@ gem 'carrierwave', '~> 1.3' gem 'mini_magick' # for backups -gem 'fog-aws', '~> 3.3' +gem 'fog-aws', '~> 3.5' # Locked until fog-google resolves https://github.com/fog/fog-google/issues/421. # Also see config/initializers/fog_core_patch.rb. gem 'fog-core', '= 2.1.0' @@ -129,10 +130,10 @@ gem 'rdoc', '~> 6.0' gem 'org-ruby', '~> 0.9.12' gem 'creole', '~> 0.5.0' gem 'wikicloth', '0.8.1' -gem 'asciidoctor', '~> 1.5.8' +gem 'asciidoctor', '~> 2.0.10' gem 'asciidoctor-include-ext', '~> 0.3.1', require: false -gem 'asciidoctor-plantuml', '0.0.8' -gem 'rouge', '~> 3.1' +gem 'asciidoctor-plantuml', '0.0.9' +gem 'rouge', '~> 3.5' gem 'truncato', '~> 0.7.11' gem 'bootstrap_form', '~> 4.2.0' gem 'nokogiri', '~> 1.10.3' @@ -211,7 +212,7 @@ gem 'discordrb-webhooks-blackst0ne', '~> 3.3', require: false # HipChat integration gem 'hipchat', '~> 1.5.0' -# JIRA integration +# Jira integration gem 'jira-ruby', '~> 1.4' # Flowdock integration @@ -300,13 +301,16 @@ gem 'peek-pg', '~> 1.3.0', group: :postgres gem 'peek-rblineprof', '~> 0.2.0' gem 'peek-redis', '~> 1.2.0' +# Memory benchmarks +gem 'derailed_benchmarks', require: false + # Metrics group :metrics do gem 'method_source', '~> 0.8', require: false gem 'influxdb', '~> 0.2', require: false # Prometheus - gem 'prometheus-client-mmap', '~> 0.9.4' + gem 'prometheus-client-mmap', '~> 0.9.8' gem 'raindrops', '~> 0.18' end @@ -336,7 +340,7 @@ group :development, :test do gem 'database_cleaner', '~> 1.7.0' gem 'factory_bot_rails', '~> 4.8.2' - gem 'rspec-rails', '~> 3.7.0' + gem 'rspec-rails', '~> 3.8.0' gem 'rspec-retry', '~> 0.6.1' gem 'rspec_profiling', '~> 0.0.5' gem 'rspec-set', '~> 0.1.3' @@ -365,6 +369,7 @@ group :development, :test do gem 'haml_lint', '~> 0.31.0', require: false gem 'simplecov', '~> 0.16.1', require: false gem 'bundler-audit', '~> 0.5.0', require: false + gem 'mdl', '~> 0.5.0', require: false gem 'benchmark-ips', '~> 2.3.0', require: false @@ -374,7 +379,6 @@ group :development, :test do gem 'activerecord_sane_schema_dumper', '1.0' gem 'stackprof', '~> 0.2.10', require: false - gem 'derailed_benchmarks', require: false gem 'simple_po_parser', '~> 1.1.2', require: false @@ -417,7 +421,7 @@ gem 'vmstat', '~> 2.3.0' gem 'sys-filesystem', '~> 1.1.6' # SSH host key support -gem 'net-ssh', '~> 5.0' +gem 'net-ssh', '~> 5.2' gem 'sshkey', '~> 2.0' # Required for ED25519 SSH host key support @@ -427,7 +431,7 @@ group :ed25519 do end # Gitaly GRPC client -gem 'gitaly-proto', '~> 1.32.0', require: 'gitaly' +gem 'gitaly-proto', '~> 1.37.0', require: 'gitaly' gem 'grpc', '~> 1.19.0' diff --git a/Gemfile.lock b/Gemfile.lock index 4cebf73f17..60939ae918 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,44 +6,48 @@ GEM ace-rails-ap (4.1.2) acme-client (2.0.2) faraday (~> 0.9, >= 0.9.1) - actioncable (5.1.7) - actionpack (= 5.1.7) + actioncable (5.2.3) + actionpack (= 5.2.3) nio4r (~> 2.0) - websocket-driver (~> 0.6.1) - actionmailer (5.1.7) - actionpack (= 5.1.7) - actionview (= 5.1.7) - activejob (= 5.1.7) + websocket-driver (>= 0.6.1) + actionmailer (5.2.3) + actionpack (= 5.2.3) + actionview (= 5.2.3) + activejob (= 5.2.3) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.1.7) - actionview (= 5.1.7) - activesupport (= 5.1.7) + actionpack (5.2.3) + actionview (= 5.2.3) + activesupport (= 5.2.3) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.1.7) - activesupport (= 5.1.7) + actionview (5.2.3) + activesupport (= 5.2.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.1.7) - activesupport (= 5.1.7) + activejob (5.2.3) + activesupport (= 5.2.3) globalid (>= 0.3.6) - activemodel (5.1.7) - activesupport (= 5.1.7) - activerecord (5.1.7) - activemodel (= 5.1.7) - activesupport (= 5.1.7) - arel (~> 8.0) + activemodel (5.2.3) + activesupport (= 5.2.3) + activerecord (5.2.3) + activemodel (= 5.2.3) + activesupport (= 5.2.3) + arel (>= 9.0) activerecord-explain-analyze (0.1.0) activerecord (>= 4) pg activerecord_sane_schema_dumper (1.0) rails (>= 5, < 6) - activesupport (5.1.7) + activestorage (5.2.3) + actionpack (= 5.2.3) + activerecord (= 5.2.3) + marcel (~> 0.3.1) + activesupport (5.2.3) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -60,17 +64,17 @@ GEM apollo_upload_server (2.0.0.beta.3) graphql (>= 1.8) rails (>= 4.2) - arel (8.0.0) + arel (9.0.0) asana (0.8.1) faraday (~> 0.9) faraday_middleware (~> 0.9) faraday_middleware-multi_json (~> 0.0) oauth2 (~> 1.0) - asciidoctor (1.5.8) + asciidoctor (2.0.10) asciidoctor-include-ext (0.3.1) asciidoctor (>= 1.5.6, < 3.0.0) - asciidoctor-plantuml (0.0.8) - asciidoctor (~> 1.5) + asciidoctor-plantuml (0.0.9) + asciidoctor (>= 1.5.6, < 3.0.0) ast (2.4.0) atomic (1.1.99) attr_encrypted (3.1.0) @@ -163,6 +167,8 @@ GEM html-pipeline declarative (0.0.10) declarative-option (0.1.0) + default_value_for (3.2.0) + activerecord (>= 3.2.0, < 6.0) derailed_benchmarks (1.3.5) benchmark-ips (~> 2) get_process_mem (~> 0) @@ -214,6 +220,8 @@ GEM excon (0.62.0) execjs (2.6.0) expression_parser (0.9.0) + extended-markdown-filter (0.6.0) + html-pipeline (~> 2.0) factory_bot (4.8.2) activesupport (>= 3.0.0) factory_bot_rails (4.8.2) @@ -245,7 +253,7 @@ GEM fog-json ipaddress (~> 0.8) xml-simple (~> 1.1) - fog-aws (3.3.0) + fog-aws (3.5.2) fog-core (~> 2.1) fog-json (~> 1.1) fog-xml (~> 0.1) @@ -288,6 +296,7 @@ GEM fuubar (2.2.0) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) + gemoji (3.0.1) gemojione (3.3.0) json get_process_mem (0.2.3) @@ -301,11 +310,9 @@ GEM gettext_i18n_rails (>= 0.7.1) po_to_json (>= 1.0.0) rails (>= 3.2.0) - gitaly-proto (1.32.0) + gitaly-proto (1.37.0) grpc (~> 1.0) github-markup (1.7.0) - gitlab-default_value_for (3.1.1) - activerecord (>= 3.2.0, < 6.0) gitlab-labkit (0.3.0) actionpack (~> 5) activesupport (~> 5) @@ -370,6 +377,14 @@ GEM railties sprockets-rails graphql (1.8.1) + graphql-docs (1.6.0) + commonmarker (~> 0.16) + escape_utils (~> 1.2) + extended-markdown-filter (~> 0.4) + gemoji (~> 3.0) + graphql (~> 1.6) + html-pipeline (~> 2.8) + sass (~> 3.4) grpc (1.19.0) google-protobuf (~> 3.1) googleapis-common-protos-types (~> 1.0.0) @@ -459,6 +474,7 @@ GEM kgio (2.11.2) knapsack (1.17.0) rake + kramdown (1.17.0) kubeclient (4.2.2) http (~> 3.0) recursive-open-struct (~> 1.0, >= 1.0.4) @@ -492,6 +508,12 @@ GEM mail (2.7.1) mini_mime (>= 0.1.1) mail_room (0.9.1) + marcel (0.3.3) + mimemagic (~> 0.3.2) + mdl (0.5.0) + kramdown (~> 1.12, >= 1.12.0) + mixlib-cli (~> 1.7, >= 1.7.0) + mixlib-config (~> 2.2, >= 2.2.1) memoist (0.16.0) memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) @@ -505,6 +527,9 @@ GEM mini_mime (1.0.1) mini_portile2 (2.4.0) minitest (5.11.3) + mixlib-cli (1.7.0) + mixlib-config (2.2.18) + tomlrb msgpack (1.2.10) multi_json (1.13.1) multi_xml (0.6.0) @@ -515,7 +540,7 @@ GEM mysql2 (0.4.10) nakayoshi_fork (0.0.4) net-ldap (0.16.0) - net-ssh (5.0.1) + net-ssh (5.2.0) netrc (0.11.0) nio4r (2.3.1) nokogiri (1.10.3) @@ -652,7 +677,7 @@ GEM parser unparser procto (0.0.3) - prometheus-client-mmap (0.9.4) + prometheus-client-mmap (0.9.8) pry (0.11.3) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -687,17 +712,18 @@ GEM rack-test (1.1.0) rack (>= 1.0, < 3) rack-timeout (0.5.1) - rails (5.1.7) - actioncable (= 5.1.7) - actionmailer (= 5.1.7) - actionpack (= 5.1.7) - actionview (= 5.1.7) - activejob (= 5.1.7) - activemodel (= 5.1.7) - activerecord (= 5.1.7) - activesupport (= 5.1.7) + rails (5.2.3) + actioncable (= 5.2.3) + actionmailer (= 5.2.3) + actionpack (= 5.2.3) + actionview (= 5.2.3) + activejob (= 5.2.3) + activemodel (= 5.2.3) + activerecord (= 5.2.3) + activestorage (= 5.2.3) + activesupport (= 5.2.3) bundler (>= 1.3.0) - railties (= 5.1.7) + railties (= 5.2.3) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.2) actionpack (~> 5.x, >= 5.0.1) @@ -711,12 +737,12 @@ GEM rails-i18n (5.1.1) i18n (>= 0.7, < 2) railties (>= 5.0, < 6) - railties (5.1.7) - actionpack (= 5.1.7) - activesupport (= 5.1.7) + railties (5.2.3) + actionpack (= 5.2.3) + activesupport (= 5.2.3) method_source rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) + thor (>= 0.19.0, < 2.0) rainbow (3.0.0) raindrops (0.19.0) rake (12.3.2) @@ -770,41 +796,41 @@ GEM retriable (3.1.2) rinku (2.0.0) rotp (2.1.2) - rouge (3.3.0) + rouge (3.5.1) rqrcode (0.7.0) chunky_png rqrcode-rails3 (0.1.7) rqrcode (>= 0.4.2) - rspec (3.7.0) - rspec-core (~> 3.7.0) - rspec-expectations (~> 3.7.0) - rspec-mocks (~> 3.7.0) - rspec-core (3.7.1) - rspec-support (~> 3.7.0) - rspec-expectations (3.7.0) + rspec (3.8.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-core (3.8.2) + rspec-support (~> 3.8.0) + rspec-expectations (3.8.4) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.7.0) - rspec-mocks (3.7.0) + rspec-support (~> 3.8.0) + rspec-mocks (3.8.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.7.0) + rspec-support (~> 3.8.0) rspec-parameterized (0.4.2) binding_ninja (>= 0.2.3) parser proc_to_ast rspec (>= 2.13, < 4) unparser - rspec-rails (3.7.2) + rspec-rails (3.8.2) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 3.7.0) - rspec-expectations (~> 3.7.0) - rspec-mocks (~> 3.7.0) - rspec-support (~> 3.7.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-support (~> 3.8.0) rspec-retry (0.6.1) rspec-core (> 3.3) rspec-set (0.1.3) - rspec-support (3.7.1) + rspec-support (3.8.2) rspec_junit_formatter (0.4.1) rspec-core (>= 2, < 4, != 2.12.0) rspec_profiling (0.0.5) @@ -943,6 +969,7 @@ GEM parslet (~> 1.8.0) toml-rb (1.0.0) citrus (~> 3.0, > 3.0) + tomlrb (1.2.8) truncato (0.7.11) htmlentities (~> 4.3.1) nokogiri (>= 1.7.0, <= 2.0) @@ -999,7 +1026,7 @@ GEM hashdiff webpack-rails (0.9.11) railties (>= 3.2.0) - websocket-driver (0.6.5) + websocket-driver (0.7.0) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.3) wikicloth (0.8.1) @@ -1025,9 +1052,9 @@ DEPENDENCIES akismet (~> 2.0) apollo_upload_server (~> 2.0.0.beta3) asana (~> 0.8.1) - asciidoctor (~> 1.5.8) + asciidoctor (~> 2.0.10) asciidoctor-include-ext (~> 0.3.1) - asciidoctor-plantuml (= 0.0.8) + asciidoctor-plantuml (= 0.0.9) attr_encrypted (~> 3.1.0) awesome_print babosa (~> 1.0.2) @@ -1056,6 +1083,7 @@ DEPENDENCIES creole (~> 0.5.0) database_cleaner (~> 1.7.0) deckar01-task_list (= 2.2.0) + default_value_for (~> 3.2.0) derailed_benchmarks device_detector devise (~> 4.6) @@ -1077,7 +1105,7 @@ DEPENDENCIES flipper-active_support_cache_store (~> 0.13.0) flowdock (~> 0.7) fog-aliyun (~> 0.3) - fog-aws (~> 3.3) + fog-aws (~> 3.5) fog-core (= 2.1.0) fog-google (~> 1.8) fog-local (~> 0.6) @@ -1091,9 +1119,8 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly-proto (~> 1.32.0) + gitaly-proto (~> 1.37.0) github-markup (~> 1.7.0) - gitlab-default_value_for (~> 3.1.1) gitlab-labkit (~> 0.3.0) gitlab-markup (~> 1.7.0) gitlab-sidekiq-fetcher (~> 0.4.0) @@ -1109,6 +1136,7 @@ DEPENDENCIES grape_logging (~> 1.7) graphiql-rails (~> 1.4.10) graphql (~> 1.8.0) + graphql-docs (~> 1.6.0) grpc (~> 1.19.0) haml_lint (~> 0.31.0) hamlit (~> 2.8.8) @@ -1134,6 +1162,7 @@ DEPENDENCIES lograge (~> 0.5) loofah (~> 2.2) mail_room (~> 0.9.1) + mdl (~> 0.5.0) memory_profiler (~> 0.9) method_source (~> 0.8) mimemagic (~> 0.3.2) @@ -1142,7 +1171,7 @@ DEPENDENCIES mysql2 (~> 0.4.10) nakayoshi_fork (~> 0.0.4) net-ldap - net-ssh (~> 5.0) + net-ssh (~> 5.2) nokogiri (~> 1.10.3) oauth2 (~> 1.4) octokit (~> 4.9) @@ -1173,7 +1202,7 @@ DEPENDENCIES peek-redis (~> 1.2.0) pg (~> 1.1) premailer-rails (~> 1.9.7) - prometheus-client-mmap (~> 0.9.4) + prometheus-client-mmap (~> 0.9.8) pry-byebug (~> 3.5.1) pry-rails (~> 0.3.4) puma (~> 3.12) @@ -1184,7 +1213,7 @@ DEPENDENCIES rack-oauth2 (~> 1.9.3) rack-proxy (~> 0.6.0) rack-timeout - rails (= 5.1.7) + rails (= 5.2.3) rails-controller-testing rails-i18n (~> 5.1) rainbow (~> 3.0) @@ -1199,10 +1228,10 @@ DEPENDENCIES redis-rails (~> 5.0.2) request_store (~> 1.3) responders (~> 2.0) - rouge (~> 3.1) + rouge (~> 3.5) rqrcode-rails3 (~> 0.1.7) rspec-parameterized - rspec-rails (~> 3.7.0) + rspec-rails (~> 3.8.0) rspec-retry (~> 0.6.1) rspec-set (~> 0.1.3) rspec_junit_formatter diff --git a/PROCESS.md b/PROCESS.md index 07b150ea46..22b68b0aac 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -84,44 +84,29 @@ star, smile, etc.). Some good tips about code reviews can be found in our [Code Review Guidelines]: https://docs.gitlab.com/ce/development/code_review.html +## Feature flags + +Overview and details of feature flag processes in development of GitLab itself is described in [feature flags process documentation](https://docs.gitlab.com/ee/development/feature_flags/process.html). + +Guides on how to include feature flags in your backend/frontend code while developing GitLab are described in [developing with feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/developing.html). + +Getting access and how to expose the feature to users is detailed in [controlling feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/controls.html). + +## Feature proposals from the 22nd to the 1st + +To allow the Product and Engineering teams time to discuss issues that will be placed into an upcoming milestone, +Product Managers must have their proposal for that milestone ready by the 22nd of each month. + +This proposal will be shared with Engineering for discussion, feedback, and planning. +The plan for the upcoming milestone must be finalized by the 1st of the month, one week before kickoff on the 8th. + ## Feature freeze on the 7th for the release on the 22nd -The feature freeze on the 7th has been discontinued. The [transition period overview](https://gitlab.com/gitlab-org/release/docs/blob/21cbd409dd5f157fe252f254f3e897f01908abe2/general/deploy/auto-deploy-transition.md#transition) +The feature freeze on the 7th has been discontinued. [Transition period overview](https://gitlab.com/gitlab-org/release/docs/blob/21cbd409dd5f157fe252f254f3e897f01908abe2/general/deploy/auto-deploy-transition.md#transition) describes the change to this process. During the transition period, the only guarantee that a change will be included in the release on the 22nd is if the change has been deployed to GitLab.com prior to this date. -### Feature flags - -Merge requests that make changes hidden behind a feature flag, or remove an -existing feature flag because a feature is deemed stable, may be merged (and -picked into the stable branches) up to the 19th of the month. Such merge -requests should have the ~"feature flag" label assigned, and don't require a -corresponding exception request to be created. - -A level of common sense should be applied when deciding whether to have a feature -behind a feature flag off or on by default. - -The following guidelines can be applied to help make this decision: - -* If the feature is not fully ready or functioning, the feature flag should be disabled by default. -* If the feature is ready but there are concerns about performance or impact, the feature flag should be enabled by default, but -disabled via chatops before deployment on GitLab.com environments. If the performance concern is confirmed, the final release should have the feature flag disabled by default. -* In most other cases, the feature flag can be enabled by default. - -For more information on rolling out changes using feature flags, read [through the documentation](https://docs.gitlab.com/ee/development/rolling_out_changes_using_feature_flags.html). - -In order to build the final package and present the feature for self-hosted -customers, the feature flag should be removed. This should happen before the -22nd, ideally _at least_ 2 days before. That means MRs with feature -flags being picked at the 19th would have quite a tight schedule, so picking -these _earlier_ is preferable. - -While rare, release managers may decide to reject picking a change into a stable -branch, even when feature flags are used. This might be necessary if the changes -are deemed problematic, too invasive, or there simply isn't enough time to -properly test how the changes behave on GitLab.com. - ### Between the 1st and the 7th These types of merge requests for the upcoming release need special consideration: diff --git a/README.md b/README.md index e64f04cea5..51dc87ac65 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ To see how GitLab looks please see the [features page on our website](https://ab - Manage Git repositories with fine grained access controls that keep your code secure - Perform code reviews and enhance collaboration with merge requests -- Complete continuous integration (CI) and CD pipelines to builds, test, and deploy your applications +- Complete continuous integration (CI) and continuous deployment/delivery (CD) pipelines to build, test, and deploy your applications - Each project can also have an issue tracker, issue board, and a wiki - Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises - Completely free and open source (MIT Expat license) diff --git a/VERSION b/VERSION index 18eb8a00cf..d6cf4b5bb6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -12.0.9 +12.1.11 diff --git a/app/assets/images/auth_buttons/salesforce_64.png b/app/assets/images/auth_buttons/salesforce_64.png new file mode 100644 index 0000000000..c8a86a0c51 Binary files /dev/null and b/app/assets/images/auth_buttons/salesforce_64.png differ diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 7cebb88f3a..a649c52140 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -12,6 +12,7 @@ const Api = { groupProjectsPath: '/api/:version/groups/:id/projects.json', projectsPath: '/api/:version/projects.json', projectPath: '/api/:version/projects/:id', + forkedProjectsPath: '/api/:version/projects/:id/forks', projectLabelsPath: '/:namespace_path/:project_path/-/labels', projectMergeRequestsPath: '/api/:version/projects/:id/merge_requests', projectMergeRequestPath: '/api/:version/projects/:id/merge_requests/:mrid', @@ -23,6 +24,7 @@ const Api = { issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key', projectTemplatePath: '/api/:version/projects/:id/templates/:type/:key', projectTemplatesPath: '/api/:version/projects/:id/templates/:type', + userCountsPath: '/api/:version/user_counts', usersPath: '/api/:version/users.json', userPath: '/api/:version/users/:id', userStatusPath: '/api/:version/users/:id/status', @@ -113,6 +115,21 @@ const Api = { return axios.get(url); }, + /** + * Get all projects for a forked relationship to a specified project + * @param {string} projectPath - Path or ID of a project + * @param {Object} params - Get request parameters + * @returns {Promise} - Request promise + */ + projectForks(projectPath, params) { + const url = Api.buildUrl(Api.forkedProjectsPath).replace( + ':id', + encodeURIComponent(projectPath), + ); + + return axios.get(url, { params }); + }, + /** * Get all Merge Requests for a project, eventually filtering based on * supplied parameters @@ -296,6 +313,11 @@ const Api = { }); }, + userCounts() { + const url = Api.buildUrl(this.userCountsPath); + return axios.get(url); + }, + userStatus(id, options) { const url = Api.buildUrl(this.userStatusPath).replace(':id', encodeURIComponent(id)); return axios.get(url, { diff --git a/app/assets/javascripts/behaviors/markdown/render_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_mermaid.js index d0b7f3ff7a..dbc28beffb 100644 --- a/app/assets/javascripts/behaviors/markdown/render_mermaid.js +++ b/app/assets/javascripts/behaviors/markdown/render_mermaid.js @@ -36,7 +36,8 @@ export default function renderMermaid($els) { }); $els.each((i, el) => { - const source = el.textContent; + // Mermaid doesn't like `
` tags, so collapse all like tags into `
`, which is parsed correctly. + const source = el.textContent.replace(//g, '
'); /** * Restrict the rendering to a certain amount of character to @@ -59,6 +60,14 @@ export default function renderMermaid($els) { mermaid.init(undefined, el, id => { const svg = document.getElementById(id); + // As of https://github.com/knsv/mermaid/commit/57b780a0d, + // Mermaid will make two init callbacks:one to initialize the + // flow charts, and another to initialize the Gannt charts. + // Guard against an error caused by double initialization. + if (svg.classList.contains('mermaid')) { + return; + } + svg.classList.add('mermaid'); // pre > code > svg diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js index 45b9e57f9a..c6122fbc68 100644 --- a/app/assets/javascripts/boards/components/board.js +++ b/app/assets/javascripts/boards/components/board.js @@ -1,6 +1,7 @@ +import $ from 'jquery'; import Sortable from 'sortablejs'; import Vue from 'vue'; -import { n__ } from '~/locale'; +import { n__, s__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; import Tooltip from '~/vue_shared/directives/tooltip'; import AccessorUtilities from '../../lib/utils/accessor'; @@ -53,12 +54,19 @@ export default Vue.extend({ const { issuesSize } = this.list; return `${n__('%d issue', '%d issues', issuesSize)}`; }, + caretTooltip() { + return this.list.isExpanded ? s__('Boards|Collapse') : s__('Boards|Expand'); + }, isNewIssueShown() { return ( this.list.type === 'backlog' || (!this.disabled && this.list.type !== 'closed' && this.list.type !== 'blank') ); }, + uniqueKey() { + // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings + return `boards.${this.boardId}.${this.list.type}.${this.list.id}`; + }, }, watch: { filter: { @@ -72,31 +80,34 @@ export default Vue.extend({ }, }, mounted() { - this.sortableOptions = getBoardSortableDefaultOptions({ + const instance = this; + + const sortableOptions = getBoardSortableDefaultOptions({ disabled: this.disabled, group: 'boards', draggable: '.is-draggable', handle: '.js-board-handle', - onEnd: e => { + onEnd(e) { sortableEnd(); + const sortable = this; + if (e.newIndex !== undefined && e.oldIndex !== e.newIndex) { - const order = this.sortable.toArray(); + const order = sortable.toArray(); const list = boardsStore.findList('id', parseInt(e.item.dataset.id, 10)); - this.$nextTick(() => { + instance.$nextTick(() => { boardsStore.moveList(list, order); }); } }, }); - this.sortable = Sortable.create(this.$el.parentNode, this.sortableOptions); + Sortable.create(this.$el.parentNode, sortableOptions); }, created() { if (this.list.isExpandable && AccessorUtilities.isLocalStorageAccessSafe()) { - const isCollapsed = - localStorage.getItem(`boards.${this.boardId}.${this.list.type}.expanded`) === 'false'; + const isCollapsed = localStorage.getItem(`${this.uniqueKey}.expanded`) === 'false'; this.list.isExpanded = !isCollapsed; } @@ -105,16 +116,17 @@ export default Vue.extend({ showNewIssueForm() { this.$refs['board-list'].showIssueForm = !this.$refs['board-list'].showIssueForm; }, - toggleExpanded(e) { - if (this.list.isExpandable && !e.target.classList.contains('js-no-trigger-collapse')) { + toggleExpanded() { + if (this.list.isExpandable) { this.list.isExpanded = !this.list.isExpanded; if (AccessorUtilities.isLocalStorageAccessSafe()) { - localStorage.setItem( - `boards.${this.boardId}.${this.list.type}.expanded`, - this.list.isExpanded, - ); + localStorage.setItem(`${this.uniqueKey}.expanded`, this.list.isExpanded); } + + // When expanding/collapsing, the tooltip on the caret button sometimes stays open. + // Close all tooltips manually to prevent dangling tooltips. + $('.tooltip').tooltip('hide'); } }, }, diff --git a/app/assets/javascripts/boards/components/board_blank_state.vue b/app/assets/javascripts/boards/components/board_blank_state.vue index 1cbd31729c..d8b0b60c18 100644 --- a/app/assets/javascripts/boards/components/board_blank_state.vue +++ b/app/assets/javascripts/boards/components/board_blank_state.vue @@ -1,4 +1,5 @@ + + diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index b1a8b13f3a..787ff110bf 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -227,7 +227,7 @@ export default { :class="{ 'd-none': !list.isExpanded, 'd-flex flex-column': list.isExpanded }" class="board-list-component position-relative h-100" > -
+
  • - Showing all issues + {{ __('Showing all issues') }} Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
  • diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue index cc6af8e88c..4180023b7d 100644 --- a/app/assets/javascripts/boards/components/board_new_issue.vue +++ b/app/assets/javascripts/boards/components/board_new_issue.vue @@ -102,9 +102,9 @@ export default {
    -
    An error occurred. Please try again.
    +
    {{ __('An error occurred. Please try again.') }}
    - + {{ __('Submit issue') }} - Submit issue - - - Cancel - + {{ + __('Cancel') + }}
    diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index c587b276fa..2ace0060c4 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -38,6 +38,7 @@ export default Vue.extend({ issue: {}, list: {}, loadingAssignees: false, + timeTrackingLimitToHours: boardsStore.timeTracking.limitToHours, }; }, computed: { diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue new file mode 100644 index 0000000000..b05de4538f --- /dev/null +++ b/app/assets/javascripts/boards/components/boards_selector.vue @@ -0,0 +1,334 @@ + + + diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue index a8516f178f..7f554c9966 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.vue +++ b/app/assets/javascripts/boards/components/issue_card_inner.vue @@ -124,7 +124,7 @@ export default { return `${this.rootPath}${assignee.username}`; }, avatarUrlTitle(assignee) { - return `Avatar for ${assignee.name}`; + return sprintf(__(`Avatar for %{assigneeName}`), { assigneeName: assignee.name }); }, showLabel(label) { if (!label.id) return false; @@ -160,9 +160,10 @@ export default { :title="__('Confidential')" class="confidential-icon append-right-4" :aria-label="__('Confidential')" - />{{ - issue.title - }} + /> + + {{ issue.title }} +
    @@ -204,13 +205,13 @@ export default { placement="bottom" class="board-issue-path block-truncated bold" >{{ issueReferencePath }}#{{ issue.iid }} + > + #{{ issue.iid }} - + + - Assignee {{ assignee.name }} + {{ __('Assignee') }} + {{ assignee.name }} @{{ assignee.username }} @@ -240,9 +242,8 @@ export default { :title="assigneeCounterTooltip" class="avatar-counter" data-placement="bottom" + >{{ assigneeCounterLabel }} - {{ assigneeCounterLabel }} -
    diff --git a/app/assets/javascripts/boards/components/issue_time_estimate.vue b/app/assets/javascripts/boards/components/issue_time_estimate.vue index 98c1d29db1..3385aad5b1 100644 --- a/app/assets/javascripts/boards/components/issue_time_estimate.vue +++ b/app/assets/javascripts/boards/components/issue_time_estimate.vue @@ -2,6 +2,7 @@ import { GlTooltip } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility'; +import boardsStore from '../stores/boards_store'; export default { components: { @@ -14,12 +15,17 @@ export default { required: true, }, }, + data() { + return { + limitToHours: boardsStore.timeTracking.limitToHours, + }; + }, computed: { title() { - return stringifyTime(parseSeconds(this.estimate), true); + return stringifyTime(parseSeconds(this.estimate, { limitToHours: this.limitToHours }), true); }, timeEstimate() { - return stringifyTime(parseSeconds(this.estimate)); + return stringifyTime(parseSeconds(this.estimate, { limitToHours: this.limitToHours })); }, }, }; diff --git a/app/assets/javascripts/boards/components/modal/empty_state.vue b/app/assets/javascripts/boards/components/modal/empty_state.vue index 091700de93..66f5900971 100644 --- a/app/assets/javascripts/boards/components/modal/empty_state.vue +++ b/app/assets/javascripts/boards/components/modal/empty_state.vue @@ -1,4 +1,5 @@ + + diff --git a/app/assets/javascripts/branches/components/graph_bar.vue b/app/assets/javascripts/branches/components/graph_bar.vue new file mode 100644 index 0000000000..83da41ca09 --- /dev/null +++ b/app/assets/javascripts/branches/components/graph_bar.vue @@ -0,0 +1,69 @@ + + + diff --git a/app/assets/javascripts/branches/constants.js b/app/assets/javascripts/branches/constants.js new file mode 100644 index 0000000000..16949e662d --- /dev/null +++ b/app/assets/javascripts/branches/constants.js @@ -0,0 +1,6 @@ +export const SIDES = { + full: 'full', + left: 'left', + right: 'right', +}; +export const MAX_COMMIT_COUNT = 1000; diff --git a/app/assets/javascripts/branches/divergence_graph.js b/app/assets/javascripts/branches/divergence_graph.js new file mode 100644 index 0000000000..7dbaf984ac --- /dev/null +++ b/app/assets/javascripts/branches/divergence_graph.js @@ -0,0 +1,51 @@ +import Vue from 'vue'; +import { __ } from '../locale'; +import createFlash from '../flash'; +import axios from '../lib/utils/axios_utils'; +import DivergenceGraph from './components/divergence_graph.vue'; + +export function createGraphVueApp(el, data, maxCommits) { + return new Vue({ + el, + render(h) { + return h(DivergenceGraph, { + props: { + defaultBranch: 'master', + distance: data.distance ? parseInt(data.distance, 10) : null, + aheadCount: parseInt(data.ahead, 10), + behindCount: parseInt(data.behind, 10), + maxCommits, + }, + }); + }, + }); +} + +export default endpoint => { + const names = [...document.querySelectorAll('.js-branch-item')].map( + ({ dataset }) => dataset.name, + ); + return axios + .get(endpoint, { + params: { names }, + }) + .then(({ data }) => { + const maxCommits = Object.entries(data).reduce((acc, [, val]) => { + const max = Math.max(...Object.values(val)); + return max > acc ? max : acc; + }, 100); + + Object.entries(data).forEach(([branchName, val]) => { + const el = document.querySelector( + `[data-name="${branchName}"] .js-branch-divergence-graph`, + ); + + if (!el) return; + + createGraphVueApp(el, val, maxCommits); + }); + }) + .catch(() => + createFlash(__('Error fetching diverging counts for branches. Please try again.')), + ); +}; diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue index 4771090aa7..cd2121db3b 100644 --- a/app/assets/javascripts/clusters/components/application_row.vue +++ b/app/assets/javascripts/clusters/components/application_row.vue @@ -207,7 +207,7 @@ export default { return __('Updating'); } - return __('Updated'); + return this.updateSuccessful ? __('Updated to') : __('Updated'); }, updateFailureDescription() { return s__('ClusterIntegration|Update failed. Please check the logs and try again.'); @@ -331,8 +331,6 @@ export default { class="form-text text-muted label p-0 js-cluster-application-update-details" > {{ versionLabel }} - to - - {{ __('More information') }} - + {{ + __('More information') + }}

    import LoadingButton from '~/vue_shared/components/loading_button.vue'; import { APPLICATION_STATUS } from '~/clusters/constants'; +import { __ } from '~/locale'; const { UPDATING, UNINSTALLING } = APPLICATION_STATUS; @@ -22,7 +23,7 @@ export default { return this.status === UNINSTALLING; }, label() { - return this.loading ? this.__('Uninstalling') : this.__('Uninstall'); + return this.loading ? __('Uninstalling') : __('Uninstall'); }, }, }; diff --git a/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue b/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue index 65827f1cb6..920439ebb2 100644 --- a/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue +++ b/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue @@ -14,7 +14,9 @@ const CUSTOM_APP_WARNING_TEXT = { [PROMETHEUS]: s__('ClusterIntegration|All data will be deleted and cannot be restored.'), [RUNNER]: s__('ClusterIntegration|Any running pipelines will be canceled.'), [KNATIVE]: s__('ClusterIntegration|The associated IP will be deleted and cannot be restored.'), - [JUPYTER]: '', + [JUPYTER]: s__( + 'ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored.', + ), }; export default { diff --git a/app/assets/javascripts/clusters/services/application_state_machine.js b/app/assets/javascripts/clusters/services/application_state_machine.js index 17ea4d7779..6e632519d8 100644 --- a/app/assets/javascripts/clusters/services/application_state_machine.js +++ b/app/assets/javascripts/clusters/services/application_state_machine.js @@ -80,6 +80,9 @@ const applicationStateMachine = { installFailed: false, }, }, + [NOT_INSTALLABLE]: { + target: NOT_INSTALLABLE, + }, // This is possible in artificial environments for E2E testing [INSTALLED]: { target: INSTALLED, @@ -108,6 +111,9 @@ const applicationStateMachine = { updateSuccessful: false, }, }, + [NOT_INSTALLABLE]: { + target: NOT_INSTALLABLE, + }, [UNINSTALL_EVENT]: { target: UNINSTALLING, effects: { diff --git a/app/assets/javascripts/commons/index.js b/app/assets/javascripts/commons/index.js index 0d2fe2925d..ad0f6cc149 100644 --- a/app/assets/javascripts/commons/index.js +++ b/app/assets/javascripts/commons/index.js @@ -4,3 +4,6 @@ import './jquery'; import './bootstrap'; import './vue'; import '../lib/utils/axios_utils'; +import { openUserCountsBroadcast } from './nav/user_merge_requests'; + +openUserCountsBroadcast(); diff --git a/app/assets/javascripts/commons/nav/user_merge_requests.js b/app/assets/javascripts/commons/nav/user_merge_requests.js new file mode 100644 index 0000000000..8e694cca6a --- /dev/null +++ b/app/assets/javascripts/commons/nav/user_merge_requests.js @@ -0,0 +1,67 @@ +import Api from '~/api'; + +let channel; + +function broadcastCount(newCount) { + if (!channel) { + return; + } + + channel.postMessage(newCount); +} + +function updateUserMergeRequestCounts(newCount) { + const mergeRequestsCountEl = document.querySelector('.merge-requests-count'); + mergeRequestsCountEl.textContent = newCount.toLocaleString(); + mergeRequestsCountEl.classList.toggle('hidden', Number(newCount) === 0); +} + +/** + * Refresh user counts (and broadcast if open) + */ +export function refreshUserMergeRequestCounts() { + return Api.userCounts() + .then(({ data }) => { + const count = data.merge_requests; + + updateUserMergeRequestCounts(count); + broadcastCount(count); + }) + .catch(ex => { + console.error(ex); // eslint-disable-line no-console + }); +} + +/** + * Close the broadcast channel for user counts + */ +export function closeUserCountsBroadcast() { + if (!channel) { + return; + } + + channel.close(); + channel = null; +} + +/** + * Open the broadcast channel for user counts, adds user id so we only update + * + * **Please note:** + * Not supported in all browsers, but not polyfilling for now + * to keep bundle size small and + * no special functionality lost except cross tab notifications + */ +export function openUserCountsBroadcast() { + closeUserCountsBroadcast(); + + if (window.BroadcastChannel) { + const currentUserId = typeof gon !== 'undefined' && gon && gon.current_user_id; + if (currentUserId) { + channel = new BroadcastChannel(`mr_count_channel_${currentUserId}`); + channel.onmessage = ev => { + updateUserMergeRequestCounts(ev.data); + }; + } + } +} diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js index d0cc4897ae..a4394ab7e9 100644 --- a/app/assets/javascripts/commons/polyfills.js +++ b/app/assets/javascripts/commons/polyfills.js @@ -12,6 +12,7 @@ import 'core-js/es/promise/finally'; import 'core-js/es/string/code-point-at'; import 'core-js/es/string/from-code-point'; import 'core-js/es/string/includes'; +import 'core-js/es/string/starts-with'; import 'core-js/es/symbol'; import 'core-js/es/map'; import 'core-js/es/weak-map'; diff --git a/app/assets/javascripts/confidential_merge_request/components/dropdown.vue b/app/assets/javascripts/confidential_merge_request/components/dropdown.vue new file mode 100644 index 0000000000..444640980a --- /dev/null +++ b/app/assets/javascripts/confidential_merge_request/components/dropdown.vue @@ -0,0 +1,58 @@ + + + diff --git a/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue b/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue new file mode 100644 index 0000000000..197a070606 --- /dev/null +++ b/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue @@ -0,0 +1,140 @@ + + + diff --git a/app/assets/javascripts/confidential_merge_request/index.js b/app/assets/javascripts/confidential_merge_request/index.js new file mode 100644 index 0000000000..9672821d30 --- /dev/null +++ b/app/assets/javascripts/confidential_merge_request/index.js @@ -0,0 +1,30 @@ +import Vue from 'vue'; +import { parseBoolean } from '../lib/utils/common_utils'; +import ProjectFormGroup from './components/project_form_group.vue'; +import state from './state'; + +export function isConfidentialIssue() { + return parseBoolean(document.querySelector('.js-create-mr').dataset.isConfidential); +} + +export function canCreateConfidentialMergeRequest() { + return isConfidentialIssue() && Object.keys(state.selectedProject).length > 0; +} + +export function init() { + const el = document.getElementById('js-forked-project'); + + return new Vue({ + el, + render(h) { + return h(ProjectFormGroup, { + props: { + namespacePath: el.dataset.namespacePath, + projectPath: el.dataset.projectPath, + newForkPath: el.dataset.newForkPath, + helpPagePath: el.dataset.helpPagePath, + }, + }); + }, + }); +} diff --git a/app/assets/javascripts/confidential_merge_request/state.js b/app/assets/javascripts/confidential_merge_request/state.js new file mode 100644 index 0000000000..95b0580f4b --- /dev/null +++ b/app/assets/javascripts/confidential_merge_request/state.js @@ -0,0 +1,5 @@ +import Vue from 'vue'; + +export default Vue.observable({ + selectedProject: {}, +}); diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js index 8f5cece078..dce9c1a541 100644 --- a/app/assets/javascripts/create_merge_request_dropdown.js +++ b/app/assets/javascripts/create_merge_request_dropdown.js @@ -5,6 +5,12 @@ import Flash from './flash'; import DropLab from './droplab/drop_lab'; import ISetter from './droplab/plugins/input_setter'; import { __, sprintf } from './locale'; +import { + init as initConfidentialMergeRequest, + isConfidentialIssue, + canCreateConfidentialMergeRequest, +} from './confidential_merge_request'; +import confidentialMergeRequestState from './confidential_merge_request/state'; // Todo: Remove this when fixing issue in input_setter plugin const InputSetter = Object.assign({}, ISetter); @@ -12,6 +18,17 @@ const InputSetter = Object.assign({}, ISetter); const CREATE_MERGE_REQUEST = 'create-mr'; const CREATE_BRANCH = 'create-branch'; +function createEndpoint(projectPath, endpoint) { + if (canCreateConfidentialMergeRequest()) { + return endpoint.replace( + projectPath, + confidentialMergeRequestState.selectedProject.pathWithNamespace, + ); + } + + return endpoint; +} + export default class CreateMergeRequestDropdown { constructor(wrapperEl) { this.wrapperEl = wrapperEl; @@ -42,6 +59,8 @@ export default class CreateMergeRequestDropdown { this.refIsValid = true; this.refsPath = this.wrapperEl.dataset.refsPath; this.suggestedRef = this.refInput.value; + this.projectPath = this.wrapperEl.dataset.projectPath; + this.projectId = this.wrapperEl.dataset.projectId; // These regexps are used to replace // a backend generated new branch name and its source (ref) @@ -58,6 +77,14 @@ export default class CreateMergeRequestDropdown { }; this.init(); + + if (isConfidentialIssue()) { + this.createMergeRequestButton.setAttribute( + 'data-dropdown-trigger', + '#create-merge-request-dropdown', + ); + initConfidentialMergeRequest(); + } } available() { @@ -113,7 +140,9 @@ export default class CreateMergeRequestDropdown { this.isCreatingBranch = true; return axios - .post(this.createBranchPath) + .post(createEndpoint(this.projectPath, this.createBranchPath), { + confidential_issue_project_id: canCreateConfidentialMergeRequest() ? this.projectId : null, + }) .then(({ data }) => { this.branchCreated = true; window.location.href = data.url; @@ -125,7 +154,11 @@ export default class CreateMergeRequestDropdown { this.isCreatingMergeRequest = true; return axios - .post(this.createMrPath) + .post(this.createMrPath, { + target_project_id: canCreateConfidentialMergeRequest() + ? confidentialMergeRequestState.selectedProject.id + : null, + }) .then(({ data }) => { this.mergeRequestCreated = true; window.location.href = data.url; @@ -149,6 +182,8 @@ export default class CreateMergeRequestDropdown { } enable() { + if (isConfidentialIssue() && !canCreateConfidentialMergeRequest()) return; + this.createMergeRequestButton.classList.remove('disabled'); this.createMergeRequestButton.removeAttribute('disabled'); @@ -205,7 +240,7 @@ export default class CreateMergeRequestDropdown { if (!ref) return false; return axios - .get(`${this.refsPath}${encodeURIComponent(ref)}`) + .get(`${createEndpoint(this.projectPath, this.refsPath)}${encodeURIComponent(ref)}`) .then(({ data }) => { const branches = data[Object.keys(data)[0]]; const tags = data[Object.keys(data)[1]]; @@ -325,6 +360,12 @@ export default class CreateMergeRequestDropdown { let xhr = null; event.preventDefault(); + if (isConfidentialIssue() && !event.target.classList.contains('js-create-target')) { + this.droplab.hooks.forEach(hook => hook.list.toggle()); + + return; + } + if (this.isBusy()) { return; } diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js index b56e08175c..d4b994d492 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js @@ -17,6 +17,7 @@ Vue.use(Translate); export default () => { const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed'; + const cycleAnalyticsEl = document.querySelector('#cycle-analytics'); // eslint-disable-next-line no-new new Vue({ @@ -33,7 +34,6 @@ export default () => { 'stage-production-component': stageComponent, }, data() { - const cycleAnalyticsEl = document.querySelector('#cycle-analytics'); const cycleAnalyticsService = new CycleAnalyticsService({ requestPath: cycleAnalyticsEl.dataset.requestPath, }); @@ -56,7 +56,13 @@ export default () => { }, }, created() { - this.fetchCycleAnalyticsData(); + // Conditional check placed here to prevent this method from being called on the + // new Cycle Analytics page (i.e. the new page will be initialized blank and only + // after a group is selected the cycle analyitcs data will be fetched). Once the + // old (current) page has been removed this entire created method as well as the + // variable itself can be completely removed. + // Follow up issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/64490 + if (cycleAnalyticsEl.dataset.requestPath) this.fetchCycleAnalyticsData(); }, methods: { handleError() { diff --git a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js index f66e07ba31..7817b41514 100644 --- a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js +++ b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js @@ -32,15 +32,15 @@ const CommentAndResolveBtn = Vue.extend({ buttonText: function() { if (this.isDiscussionResolved) { if (this.textareaIsEmpty) { - return __('Unresolve discussion'); + return __('Unresolve thread'); } else { - return __('Comment & unresolve discussion'); + return __('Comment & unresolve thread'); } } else { if (this.textareaIsEmpty) { - return __('Resolve discussion'); + return __('Resolve thread'); } else { - return __('Comment & resolve discussion'); + return __('Comment & resolve thread'); } } }, diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue index aaa9f8b759..58d5b658b1 100644 --- a/app/assets/javascripts/diffs/components/commit_item.vue +++ b/app/assets/javascripts/diffs/components/commit_item.vue @@ -49,6 +49,8 @@ export default { return this.author.id ? this.author.id : ''; }, authorUrl() { + // TODO: when the vue i18n rules are merged need to disable @gitlab/i18n/no-non-i18n-strings + // name: 'mailto:' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives return this.author.web_url || `mailto:${this.commit.author_email}`; }, authorAvatar() { @@ -80,7 +82,7 @@ export default { v-html="commit.title_html" > - · {{ commit.short_id }} + · {{ commit.short_id }} diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index eb9f146594..4b226e3069 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -151,7 +151,11 @@ export default { stickyMonitor(this.$refs.header, contentTop() - fileHeaderHeight - 1, false); }, methods: { - ...mapActions('diffs', ['toggleFileDiscussions', 'toggleFullDiff']), + ...mapActions('diffs', [ + 'toggleFileDiscussions', + 'toggleFileDiscussionWrappers', + 'toggleFullDiff', + ]), handleToggleFile(e, checkTarget) { if ( !checkTarget || @@ -165,7 +169,7 @@ export default { this.$emit('showForkMessage'); }, handleToggleDiscussions() { - this.toggleFileDiscussions(this.diffFile); + this.toggleFileDiscussionWrappers(this.diffFile); }, handleFileNameClick(e) { const isLinkToOtherPage = diff --git a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue index 7cf3d90d46..af5550aec3 100644 --- a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue +++ b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue @@ -1,5 +1,4 @@ @@ -74,9 +63,9 @@ export default { @@ -87,7 +76,7 @@ export default { :img-src="note.author.avatar_url" :tooltip-text="getTooltipText(note)" class="diff-comment-avatar js-diff-comment-avatar" - @click.native="toggleDiscussions" + @click.native="$emit('toggleLineDiscussions')" /> +{{ moreCount }} 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 1281f9b17e..351110f0a8 100644 --- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue +++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue @@ -105,7 +105,13 @@ export default { }, }, methods: { - ...mapActions('diffs', ['loadMoreLines', 'showCommentForm', 'setHighlightedRow']), + ...mapActions('diffs', [ + 'loadMoreLines', + 'showCommentForm', + 'setHighlightedRow', + 'toggleLineDiscussions', + 'toggleLineDiscussionWrappers', + ]), handleCommentButton() { this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.fileHash }); }, @@ -184,7 +190,14 @@ export default { @click="setHighlightedRow(lineCode)" > - + 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 1faa0493e7..a06dbd70ac 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue @@ -1,11 +1,14 @@ @@ -49,13 +59,23 @@ export default { :discussions="line.discussions" :help-page-path="helpPagePath" /> - + + + diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue index 8c76a555b6..b2bc3d9914 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_view.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue @@ -57,6 +57,7 @@ export default { :diff-file-hash="diffFile.file_hash" :line="line" :help-page-path="helpPagePath" + :has-draft="shouldRenderDraftRow(diffFile.file_hash, line) || false" /> -import diffDiscussions from './diff_discussions.vue'; -import diffLineNoteForm from './diff_line_note_form.vue'; +import { mapActions } from 'vuex'; +import DiffDiscussions from './diff_discussions.vue'; +import DiffLineNoteForm from './diff_line_note_form.vue'; +import DiffDiscussionReply from './diff_discussion_reply.vue'; export default { components: { - diffDiscussions, - diffLineNoteForm, + DiffDiscussions, + DiffLineNoteForm, + DiffDiscussionReply, }, props: { line: { @@ -25,28 +28,44 @@ export default { required: false, default: '', }, + hasDraftLeft: { + type: Boolean, + required: false, + default: false, + }, + hasDraftRight: { + type: Boolean, + required: false, + default: false, + }, }, computed: { hasExpandedDiscussionOnLeft() { return this.line.left && this.line.left.discussions.length - ? this.line.left.discussions.every(discussion => discussion.expanded) + ? this.line.left.discussionsExpanded : false; }, hasExpandedDiscussionOnRight() { return this.line.right && this.line.right.discussions.length - ? this.line.right.discussions.every(discussion => discussion.expanded) + ? this.line.right.discussionsExpanded : false; }, hasAnyExpandedDiscussion() { return this.hasExpandedDiscussionOnLeft || this.hasExpandedDiscussionOnRight; }, shouldRenderDiscussionsOnLeft() { - return this.line.left && this.line.left.discussions && this.hasExpandedDiscussionOnLeft; + return ( + this.line.left && + this.line.left.discussions && + this.line.left.discussions.length && + this.hasExpandedDiscussionOnLeft + ); }, shouldRenderDiscussionsOnRight() { return ( this.line.right && this.line.right.discussions && + this.line.right.discussions.length && this.hasExpandedDiscussionOnRight && this.line.right.type ); @@ -81,6 +100,22 @@ export default { return hasCommentFormOnLeft || hasCommentFormOnRight; }, + shouldRenderReplyPlaceholderOnLeft() { + return Boolean( + this.line.left && this.line.left.discussions && this.line.left.discussions.length, + ); + }, + shouldRenderReplyPlaceholderOnRight() { + return Boolean( + this.line.right && this.line.right.discussions && this.line.right.discussions.length, + ); + }, + }, + methods: { + ...mapActions('diffs', ['showCommentForm']), + showNewDiscussionForm() { + this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.diffFileHash }); + }, }, }; @@ -90,37 +125,51 @@ export default {

    - + + +
    - + + + diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue index 41a80d9985..c477e68c33 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue @@ -58,6 +58,8 @@ export default { :diff-file-hash="diffFile.file_hash" :line-index="index" :help-page-path="helpPagePath" + :has-draft-left="hasParallelDraftLeft(diffFile.file_hash, line) || false" + :has-draft-right="hasParallelDraftRight(diffFile.file_hash, line) || false" /> () => false, + hasParallelDraftRight: () => () => false, }, }; diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 88d7b4bba6..32e0d8f42e 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -12,6 +12,7 @@ import { getNoteFormData, convertExpandLines, idleCallback, + allDiscussionWrappersExpanded, } from './utils'; import * as types from './mutation_types'; import { @@ -79,6 +80,7 @@ export const assignDiscussionsToDiff = ( discussions = rootState.notes.discussions, ) => { const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles); + const hash = getLocationHash(); discussions .filter(discussion => discussion.diff_discussion) @@ -86,6 +88,7 @@ export const assignDiscussionsToDiff = ( commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, { discussion, diffPositionByLineCode, + hash, }); }); @@ -99,6 +102,10 @@ export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => { commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash: file_hash, lineCode: line_code, id }); }; +export const toggleLineDiscussions = ({ commit }, options) => { + commit(types.TOGGLE_LINE_DISCUSSIONS, options); +}; + export const renderFileForDiscussionId = ({ commit, rootState, state }, discussionId) => { const discussion = rootState.notes.discussions.find(d => d.id === discussionId); @@ -257,6 +264,31 @@ export const toggleFileDiscussions = ({ getters, dispatch }, diff) => { }); }; +export const toggleFileDiscussionWrappers = ({ commit }, diff) => { + const discussionWrappersExpanded = allDiscussionWrappersExpanded(diff); + let linesWithDiscussions; + if (diff.highlighted_diff_lines) { + linesWithDiscussions = diff.highlighted_diff_lines.filter(line => line.discussions.length); + } + if (diff.parallel_diff_lines) { + linesWithDiscussions = diff.parallel_diff_lines.filter( + line => + (line.left && line.left.discussions.length) || + (line.right && line.right.discussions.length), + ); + } + + if (linesWithDiscussions.length) { + linesWithDiscussions.forEach(line => { + commit(types.TOGGLE_LINE_DISCUSSIONS, { + fileHash: diff.file_hash, + lineCode: line.line_code, + expanded: !discussionWrappersExpanded, + }); + }); + } +}; + export const saveDiffDiscussion = ({ state, dispatch }, { note, formData }) => { const postData = getNoteFormData({ commit: state.commit, @@ -267,7 +299,7 @@ export const saveDiffDiscussion = ({ state, dispatch }, { note, formData }) => { return dispatch('saveNote', postData, { root: true }) .then(result => dispatch('updateDiscussion', result.discussion, { root: true })) .then(discussion => dispatch('assignDiscussionsToDiff', [discussion])) - .then(() => dispatch('updateResolvableDiscussonsCounts', null, { root: true })) + .then(() => dispatch('updateResolvableDiscussionsCounts', null, { root: true })) .then(() => dispatch('closeDiffFileCommentForm', formData.diffFile.file_hash)) .catch(() => createFlash(s__('MergeRequests|Saving the comment failed'))); }; diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index 8d6111da50..9db56331fa 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -35,3 +35,5 @@ export const ADD_CURRENT_VIEW_DIFF_FILE_LINES = 'ADD_CURRENT_VIEW_DIFF_FILE_LINE export const TOGGLE_DIFF_FILE_RENDERING_MORE = 'TOGGLE_DIFF_FILE_RENDERING_MORE'; export const SET_SHOW_SUGGEST_POPOVER = 'SET_SHOW_SUGGEST_POPOVER'; + +export const TOGGLE_LINE_DISCUSSIONS = 'TOGGLE_LINE_DISCUSSIONS'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 00181a63c4..a66f205bbb 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -6,6 +6,7 @@ import { addContextLines, prepareDiffData, isDiscussionApplicableToLine, + updateLineInFile, } from './utils'; import * as types from './mutation_types'; @@ -109,7 +110,7 @@ export default { })); }, - [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { discussion, diffPositionByLineCode }) { + [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { discussion, diffPositionByLineCode, hash }) { const { latestDiff } = state; const discussionLineCode = discussion.line_code; @@ -130,13 +131,27 @@ export default { : [], }); + const setDiscussionsExpanded = line => { + const isLineNoteTargeted = line.discussions.some( + disc => disc.notes && disc.notes.find(note => hash === `note_${note.id}`), + ); + + return { + ...line, + discussionsExpanded: + line.discussions && line.discussions.length + ? line.discussions.some(disc => !disc.resolved) || isLineNoteTargeted + : false, + }; + }; + state.diffFiles = state.diffFiles.map(diffFile => { if (diffFile.file_hash === fileHash) { const file = { ...diffFile }; if (file.highlighted_diff_lines) { file.highlighted_diff_lines = file.highlighted_diff_lines.map(line => - lineCheck(line) ? mapDiscussions(line) : line, + setDiscussionsExpanded(lineCheck(line) ? mapDiscussions(line) : line), ); } @@ -148,8 +163,10 @@ export default { if (left || right) { return { ...line, - left: line.left ? mapDiscussions(line.left) : null, - right: line.right ? mapDiscussions(line.right, () => !left) : null, + left: line.left ? setDiscussionsExpanded(mapDiscussions(line.left)) : null, + right: line.right + ? setDiscussionsExpanded(mapDiscussions(line.right, () => !left)) + : null, }; } @@ -173,32 +190,11 @@ export default { [types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) { const selectedFile = state.diffFiles.find(f => f.file_hash === fileHash); if (selectedFile) { - if (selectedFile.parallel_diff_lines) { - const targetLine = selectedFile.parallel_diff_lines.find( - line => - (line.left && line.left.line_code === lineCode) || - (line.right && line.right.line_code === lineCode), - ); - if (targetLine) { - const side = targetLine.left && targetLine.left.line_code === lineCode ? 'left' : 'right'; - - Object.assign(targetLine[side], { - discussions: targetLine[side].discussions.filter(discussion => discussion.notes.length), - }); - } - } - - if (selectedFile.highlighted_diff_lines) { - const targetInlineLine = selectedFile.highlighted_diff_lines.find( - line => line.line_code === lineCode, - ); - - if (targetInlineLine) { - Object.assign(targetInlineLine, { - discussions: targetInlineLine.discussions.filter(discussion => discussion.notes.length), - }); - } - } + updateLineInFile(selectedFile, lineCode, line => + Object.assign(line, { + discussions: line.discussions.filter(discussion => discussion.notes.length), + }), + ); if (selectedFile.discussions && selectedFile.discussions.length) { selectedFile.discussions = selectedFile.discussions.filter( @@ -207,6 +203,15 @@ export default { } } }, + + [types.TOGGLE_LINE_DISCUSSIONS](state, { fileHash, lineCode, expanded }) { + const selectedFile = state.diffFiles.find(f => f.file_hash === fileHash); + + updateLineInFile(selectedFile, lineCode, line => + Object.assign(line, { discussionsExpanded: expanded }), + ); + }, + [types.TOGGLE_FOLDER_OPEN](state, path) { state.treeEntries[path].opened = !state.treeEntries[path].opened; }, diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index 71956255ee..1c3ed84001 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -454,3 +454,48 @@ export const convertExpandLines = ({ }; export const idleCallback = cb => requestIdleCallback(cb); + +export const updateLineInFile = (selectedFile, lineCode, updateFn) => { + if (selectedFile.parallel_diff_lines) { + const targetLine = selectedFile.parallel_diff_lines.find( + line => + (line.left && line.left.line_code === lineCode) || + (line.right && line.right.line_code === lineCode), + ); + if (targetLine) { + const side = targetLine.left && targetLine.left.line_code === lineCode ? 'left' : 'right'; + + updateFn(targetLine[side]); + } + } + if (selectedFile.highlighted_diff_lines) { + const targetInlineLine = selectedFile.highlighted_diff_lines.find( + line => line.line_code === lineCode, + ); + + if (targetInlineLine) { + updateFn(targetInlineLine); + } + } +}; + +export const allDiscussionWrappersExpanded = diff => { + const discussionsExpandedArray = []; + if (diff.parallel_diff_lines) { + diff.parallel_diff_lines.forEach(line => { + if (line.left && line.left.discussions.length) { + discussionsExpandedArray.push(line.left.discussionsExpanded); + } + if (line.right && line.right.discussions.length) { + discussionsExpandedArray.push(line.right.discussionsExpanded); + } + }); + } else if (diff.highlighted_diff_lines) { + diff.parallel_diff_lines.forEach(line => { + if (line.discussions.length) { + discussionsExpandedArray.push(line.discussionsExpanded); + } + }); + } + return discussionsExpandedArray.every(el => el); +}; diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue index f8a637138a..426bb63d4f 100644 --- a/app/assets/javascripts/environments/components/container.vue +++ b/app/assets/javascripts/environments/components/container.vue @@ -57,6 +57,7 @@ export default { :user-callouts-path="userCalloutsPath" :lock-promotion-svg-path="lockPromotionSvgPath" :help-canary-deployments-path="helpCanaryDeploymentsPath" + :deploy-boards-help-path="deployBoardsHelpPath" /> -import { s__, sprintf } from '~/locale'; +import { __, s__, sprintf } from '~/locale'; import { formatTime } from '~/lib/utils/datetime_utility'; import Icon from '~/vue_shared/components/icon.vue'; import eventHub from '../event_hub'; @@ -28,7 +28,7 @@ export default { }, computed: { title() { - return 'Deploy to...'; + return __('Deploy to...'); }, }, methods: { @@ -80,7 +80,8 @@ export default { data-toggle="dropdown" > - + + @@ -94,9 +95,10 @@ export default { class="js-manual-action-link no-btn btn d-flex align-items-center" @click="onClickAction(action)" > - {{ action.name }} + {{ action.name }} - {{ remainingTime(action) }} + + {{ remainingTime(action) }} diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index f0e80cba75..813045cb5e 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -1,4 +1,5 @@ diff --git a/app/assets/javascripts/groups/components/item_caret.vue b/app/assets/javascripts/groups/components/item_caret.vue index 43b9607ea8..18ea481987 100644 --- a/app/assets/javascripts/groups/components/item_caret.vue +++ b/app/assets/javascripts/groups/components/item_caret.vue @@ -21,5 +21,5 @@ export default { diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue index bc6851ea2b..734a9a89c7 100644 --- a/app/assets/javascripts/groups/components/item_stats.vue +++ b/app/assets/javascripts/groups/components/item_stats.vue @@ -48,7 +48,7 @@ export default { :title="__('Subgroups')" :value="item.subgroupCount" css-class="number-subgroups" - icon-name="folder" + icon-name="folder-o" /> -
    diff --git a/app/assets/javascripts/groups/components/item_type_icon.vue b/app/assets/javascripts/groups/components/item_type_icon.vue index e1ebd03cb5..ae69fbd7bd 100644 --- a/app/assets/javascripts/groups/components/item_type_icon.vue +++ b/app/assets/javascripts/groups/components/item_type_icon.vue @@ -20,7 +20,7 @@ export default { computed: { iconClass() { if (this.itemType === ITEM_TYPE.GROUP) { - return this.isGroupOpen ? 'folder-open' : 'folder'; + return this.isGroupOpen ? 'folder-open' : 'folder-o'; } return 'bookmark'; }, diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js index a1263d1cda..f1cc675658 100644 --- a/app/assets/javascripts/groups_select.js +++ b/app/assets/javascripts/groups_select.js @@ -77,9 +77,7 @@ export default function groupsSelect() { } }, formatResult(object) { - return `
    ${ - object.full_name - }
    ${object.full_path}
    `; + return `
    ${object.full_name}
    ${object.full_path}
    `; }, formatSelection(object) { return object.full_name; diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue index 4be4b02ac1..c8fbc3cb9f 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue @@ -107,7 +107,8 @@ export default { @click="openFileInEditor" > - {{ file.name }} + + {{ file.name }}
    diff --git a/app/assets/javascripts/ide/components/external_link.vue b/app/assets/javascripts/ide/components/external_link.vue index 954f84cea1..d1857f0176 100644 --- a/app/assets/javascripts/ide/components/external_link.vue +++ b/app/assets/javascripts/ide/components/external_link.vue @@ -27,7 +27,7 @@ export default { target="_blank" rel="noopener noreferrer" > - Open in file view + {{ __('Open in file view') }}
    diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue index 95782b2c88..1af86a9448 100644 --- a/app/assets/javascripts/ide/components/ide_tree_list.vue +++ b/app/assets/javascripts/ide/components/ide_tree_list.vue @@ -30,6 +30,9 @@ export default { showLoading() { return !this.currentTree || this.currentTree.loading; }, + actualTreeList() { + return this.currentTree.tree.filter(entry => !entry.moved); + }, }, mounted() { this.updateViewer(this.viewerType); @@ -54,9 +57,9 @@ export default {
    -