diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000000..2bae7ca9fb --- /dev/null +++ b/.babelrc @@ -0,0 +1,20 @@ +{ + "presets": [ + ["latest", { "es2015": { "modules": false } }], + "stage-2" + ], + "env": { + "coverage": { + "plugins": [ + ["istanbul", { + "exclude": [ + "spec/javascripts/**/*" + ] + }], + ["transform-define", { + "process.env.BABEL_ENV": "coverage" + }] + ] + } + } +} diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..1605e483e9 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,10 @@ +/builds/ +/coverage/ +/coverage-javascript/ +/node_modules/ +/public/ +/tmp/ +/vendor/ +karma.config.js +webpack.config.js +/app/assets/javascripts/locale/**/*.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000..aba8112c5a --- /dev/null +++ b/.eslintrc @@ -0,0 +1,33 @@ +{ + "env": { + "jquery": true, + "browser": true, + "es6": true + }, + "extends": "airbnb-base", + "globals": { + "_": false, + "gl": false, + "gon": false, + "localStorage": false + }, + "plugins": [ + "filenames", + "import", + "html", + "promise" + ], + "settings": { + "html/html-extensions": [".html", ".html.raw", ".vue"], + "import/resolver": { + "webpack": { + "config": "./config/webpack.config.js" + } + } + }, + "rules": { + "filenames/match-regex": [2, "^[a-z0-9_]+$"], + "no-multiple-empty-lines": ["error", { "max": 1 }], + "promise/catch-or-return": "error" + } +} diff --git a/.flayignore b/.flayignore index 44df2ba237..4759702511 100644 --- a/.flayignore +++ b/.flayignore @@ -1,3 +1,5 @@ *.erb lib/gitlab/sanitizers/svg/whitelist.rb lib/gitlab/diff/position_tracer.rb +app/policies/project_policy.rb +app/models/concerns/relative_positioning.rb diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index ab791a4cd6..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -CHANGELOG.md merge=union -*.js.es6 gitlab-language=javascript diff --git a/.gitignore b/.gitignore index bb7b8ef856..0fb97ffb98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ *.log *.swp +*.mo +*.edit.po .DS_Store .bundle .chef .directory /.envrc +eslint-report.html /.gitlab_shell_secret .idea /.rbenv-version @@ -29,6 +32,7 @@ /config/unicorn.rb /config/secrets.yml /config/sidekiq.yml +/config/registry.key /coverage/* /coverage-javascript/ /db/*.sqlite3 @@ -37,16 +41,19 @@ /doc/code/* /dump.rdb /log/*.log* +/node_modules/ /nohup.out /public/assets/ /public/uploads.* /public/uploads/ /shared/artifacts/ +/spec/javascripts/fixtures/blob/pdf/ /rails_best_practices_output.html /tags /tmp/* /vendor/bundle/* -/builds/* +/builds* /shared/* /.gitlab_workhorse_secret -.pc/ +/webpack-report/ +/locale/**/LC_MESSAGES diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 76117a4873..86c459a9f6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,232 +1,381 @@ -image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3-git-2.7-phantomjs-2.1" +image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-golang-1.8-git-2.7-phantomjs-2.1-node-7.1-postgresql-9.6" cache: - key: "ruby-231" + key: "ruby-233" paths: - vendor/ruby variables: MYSQL_ALLOW_EMPTY_PASSWORD: "1" - # retry tests only in CI environment - RSPEC_RETRY_RETRY_COUNT: "3" RAILS_ENV: "test" + NODE_ENV: "test" SIMPLECOV: "true" - SETUP_DB: "true" - USE_BUNDLE_INSTALL: "true" GIT_DEPTH: "20" + GIT_SUBMODULE_STRATEGY: "none" PHANTOMJS_VERSION: "2.1.1" + GET_SOURCES_ATTEMPTS: "3" + KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json + KNAPSACK_SPINACH_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/spinach_report-master.json before_script: - - source ./scripts/prepare_build.sh - - cp config/gitlab.yml.example config/gitlab.yml - bundle --version - - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"' - - retry gem install knapsack - - '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate add_limits_mysql' + - source scripts/utils.sh + - source scripts/prepare_build.sh stages: +- build - prepare - test - post-test - pages -# Prepare and merge knapsack tests +# Predefined scopes +.dedicated-runner: &dedicated-runner + tags: + - gitlab-org + .knapsack-state: &knapsack-state services: [] variables: SETUP_DB: "false" USE_BUNDLE_INSTALL: "false" + KNAPSACK_S3_BUCKET: "gitlab-ce-cache" cache: key: "knapsack" paths: - - knapsack/ + - knapsack/ artifacts: expire_in: 31d paths: - - knapsack/ + - knapsack/ -knapsack: - <<: *knapsack-state - stage: prepare - script: - - mkdir -p knapsack/ - - '[[ -f knapsack/rspec_report.json ]] || echo "{}" > knapsack/rspec_report.json' - - '[[ -f knapsack/spinach_report.json ]] || echo "{}" > knapsack/spinach_report.json' +.use-pg: &use-pg + services: + - postgres:9.2 + - redis:alpine -update-knapsack: - <<: *knapsack-state - stage: post-test - script: - - scripts/merge-reports knapsack/rspec_report.json knapsack/rspec_node_*.json - - scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json - - rm -f knapsack/*_node_*.json - only: - - master - -# Execute all testing suites - -.use-db: &use-db +.use-mysql: &use-mysql services: - mysql:latest - redis:alpine +.only-master-and-ee-or-mysql: &only-master-and-ee-or-mysql + only: + - /mysql/ + - master@gitlab-org/gitlab-ce + - master@gitlab/gitlabhq + - tags@gitlab-org/gitlab-ce + - tags@gitlab/gitlabhq + - //@gitlab-org/gitlab-ee + - //@gitlab/gitlab-ee + +# Skip all jobs except the ones that begin with 'docs/'. +# Used for commits including ONLY documentation changes. +# https://docs.gitlab.com/ce/development/writing_documentation.html#testing +.except-docs: &except-docs + except: + - /^docs\/.*/ + .rspec-knapsack: &rspec-knapsack stage: test - <<: *use-db + <<: *dedicated-runner script: - - bundle exec rake assets:precompile 2>/dev/null - - JOB_NAME=( $CI_BUILD_NAME ) - - export CI_NODE_INDEX=${JOB_NAME[1]} - - export CI_NODE_TOTAL=${JOB_NAME[2]} - - export KNAPSACK_REPORT_PATH=knapsack/rspec_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json + - JOB_NAME=( $CI_JOB_NAME ) + - export CI_NODE_INDEX=${JOB_NAME[-2]} + - export CI_NODE_TOTAL=${JOB_NAME[-1]} + - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_${JOB_NAME[1]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json - export KNAPSACK_GENERATE_REPORT=true - - cp knapsack/rspec_report.json ${KNAPSACK_REPORT_PATH} + - export CACHE_CLASSES=true + - cp ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH} - knapsack rspec "--color --format documentation" artifacts: expire_in: 31d + when: always paths: - - knapsack/ - - coverage/ + - coverage/ + - knapsack/ + - tmp/capybara/ + +.rspec-knapsack-pg: &rspec-knapsack-pg + <<: *rspec-knapsack + <<: *use-pg + <<: *except-docs + +.rspec-knapsack-mysql: &rspec-knapsack-mysql + <<: *rspec-knapsack + <<: *use-mysql + <<: *only-master-and-ee-or-mysql + <<: *except-docs .spinach-knapsack: &spinach-knapsack stage: test - <<: *use-db + <<: *dedicated-runner script: - - bundle exec rake assets:precompile 2>/dev/null - - JOB_NAME=( $CI_BUILD_NAME ) - - export CI_NODE_INDEX=${JOB_NAME[1]} - - export CI_NODE_TOTAL=${JOB_NAME[2]} - - export KNAPSACK_REPORT_PATH=knapsack/spinach_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json + - JOB_NAME=( $CI_JOB_NAME ) + - export CI_NODE_INDEX=${JOB_NAME[-2]} + - export CI_NODE_TOTAL=${JOB_NAME[-1]} + - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_${JOB_NAME[1]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json - export KNAPSACK_GENERATE_REPORT=true - - cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH} + - export CACHE_CLASSES=true + - cp ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH} - knapsack spinach "-r rerun" || retry '[[ -e tmp/spinach-rerun.txt ]] && bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)' artifacts: expire_in: 31d + when: always paths: - - knapsack/ - - coverage/ + - coverage/ + - knapsack/ + - tmp/capybara/ -rspec 0 20: *rspec-knapsack -rspec 1 20: *rspec-knapsack -rspec 2 20: *rspec-knapsack -rspec 3 20: *rspec-knapsack -rspec 4 20: *rspec-knapsack -rspec 5 20: *rspec-knapsack -rspec 6 20: *rspec-knapsack -rspec 7 20: *rspec-knapsack -rspec 8 20: *rspec-knapsack -rspec 9 20: *rspec-knapsack -rspec 10 20: *rspec-knapsack -rspec 11 20: *rspec-knapsack -rspec 12 20: *rspec-knapsack -rspec 13 20: *rspec-knapsack -rspec 14 20: *rspec-knapsack -rspec 15 20: *rspec-knapsack -rspec 16 20: *rspec-knapsack -rspec 17 20: *rspec-knapsack -rspec 18 20: *rspec-knapsack -rspec 19 20: *rspec-knapsack - -spinach 0 10: *spinach-knapsack -spinach 1 10: *spinach-knapsack -spinach 2 10: *spinach-knapsack -spinach 3 10: *spinach-knapsack -spinach 4 10: *spinach-knapsack -spinach 5 10: *spinach-knapsack -spinach 6 10: *spinach-knapsack -spinach 7 10: *spinach-knapsack -spinach 8 10: *spinach-knapsack -spinach 9 10: *spinach-knapsack - -# Execute all testing suites against Ruby 2.1 -.ruby-21: &ruby-21 - image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.1-git-2.7-phantomjs-2.1" - <<: *use-db - only: - - master - cache: - key: "ruby21" - paths: - - vendor/ruby - -.rspec-knapsack-ruby21: &rspec-knapsack-ruby21 - <<: *rspec-knapsack - <<: *ruby-21 - -.spinach-knapsack-ruby21: &spinach-knapsack-ruby21 +.spinach-knapsack-pg: &spinach-knapsack-pg <<: *spinach-knapsack - <<: *ruby-21 + <<: *use-pg + <<: *except-docs -rspec 0 20 ruby21: *rspec-knapsack-ruby21 -rspec 1 20 ruby21: *rspec-knapsack-ruby21 -rspec 2 20 ruby21: *rspec-knapsack-ruby21 -rspec 3 20 ruby21: *rspec-knapsack-ruby21 -rspec 4 20 ruby21: *rspec-knapsack-ruby21 -rspec 5 20 ruby21: *rspec-knapsack-ruby21 -rspec 6 20 ruby21: *rspec-knapsack-ruby21 -rspec 7 20 ruby21: *rspec-knapsack-ruby21 -rspec 8 20 ruby21: *rspec-knapsack-ruby21 -rspec 9 20 ruby21: *rspec-knapsack-ruby21 -rspec 10 20 ruby21: *rspec-knapsack-ruby21 -rspec 11 20 ruby21: *rspec-knapsack-ruby21 -rspec 12 20 ruby21: *rspec-knapsack-ruby21 -rspec 13 20 ruby21: *rspec-knapsack-ruby21 -rspec 14 20 ruby21: *rspec-knapsack-ruby21 -rspec 15 20 ruby21: *rspec-knapsack-ruby21 -rspec 16 20 ruby21: *rspec-knapsack-ruby21 -rspec 17 20 ruby21: *rspec-knapsack-ruby21 -rspec 18 20 ruby21: *rspec-knapsack-ruby21 -rspec 19 20 ruby21: *rspec-knapsack-ruby21 +.spinach-knapsack-mysql: &spinach-knapsack-mysql + <<: *spinach-knapsack + <<: *use-mysql + <<: *only-master-and-ee-or-mysql + <<: *except-docs -spinach 0 10 ruby21: *spinach-knapsack-ruby21 -spinach 1 10 ruby21: *spinach-knapsack-ruby21 -spinach 2 10 ruby21: *spinach-knapsack-ruby21 -spinach 3 10 ruby21: *spinach-knapsack-ruby21 -spinach 4 10 ruby21: *spinach-knapsack-ruby21 -spinach 5 10 ruby21: *spinach-knapsack-ruby21 -spinach 6 10 ruby21: *spinach-knapsack-ruby21 -spinach 7 10 ruby21: *spinach-knapsack-ruby21 -spinach 8 10 ruby21: *spinach-knapsack-ruby21 -spinach 9 10 ruby21: *spinach-knapsack-ruby21 +# Trigger a package build on omnibus-gitlab repository + +build-package: + services: [] + variables: + SETUP_DB: "false" + USE_BUNDLE_INSTALL: "false" + stage: build + when: manual + script: + # If no branch in omnibus is specified, trigger pipeline against master + - if [ -z "$OMNIBUS_BRANCH" ] ; then export OMNIBUS_BRANCH=master ;fi + - echo "token=${BUILD_TRIGGER_TOKEN}" > version_details + - echo "ref=${OMNIBUS_BRANCH}" >> version_details + - echo "variables[ALTERNATIVE_SOURCES]=true" >> version_details + - echo "variables[GITLAB_VERSION]=${CI_COMMIT_SHA}" >> version_details + # Collect version details of all components + - for f in *_VERSION; do echo "variables[$f]=$(cat $f)" >> version_details; done + # Trigger the API and pass values collected above as parameters to it + - cat version_details | tr '\n' '&' | curl -X POST https://gitlab.com/api/v4/projects/20699/trigger/pipeline --data-binary @- + - rm version_details + +# Prepare and merge knapsack tests +knapsack: + <<: *knapsack-state + <<: *dedicated-runner + <<: *except-docs + stage: prepare + script: + - mkdir -p knapsack/${CI_PROJECT_NAME}/ + - wget -O $KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${KNAPSACK_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $KNAPSACK_RSPEC_SUITE_REPORT_PATH + - wget -O $KNAPSACK_SPINACH_SUITE_REPORT_PATH http://${KNAPSACK_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_SPINACH_SUITE_REPORT_PATH || rm $KNAPSACK_SPINACH_SUITE_REPORT_PATH + - '[[ -f $KNAPSACK_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH}' + - '[[ -f $KNAPSACK_SPINACH_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_SPINACH_SUITE_REPORT_PATH}' + +update-knapsack: + <<: *knapsack-state + <<: *dedicated-runner + stage: post-test + script: + - scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec_pg_node_*.json + - scripts/merge-reports ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/spinach_pg_node_*.json + - '[[ -z ${KNAPSACK_S3_BUCKET} ]] || scripts/sync-reports put $KNAPSACK_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH $KNAPSACK_SPINACH_SUITE_REPORT_PATH' + - rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json + only: + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + - master@gitlab/gitlabhq + - master@gitlab/gitlab-ee + +setup-test-env: + <<: *use-pg + <<: *dedicated-runner + <<: *except-docs + stage: prepare + script: + - node --version + - yarn install --pure-lockfile + - bundle exec rake gitlab:assets:compile + - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' + artifacts: + expire_in: 7d + paths: + - node_modules + - public/assets + - tmp/tests + +rspec pg 0 20: *rspec-knapsack-pg +rspec pg 1 20: *rspec-knapsack-pg +rspec pg 2 20: *rspec-knapsack-pg +rspec pg 3 20: *rspec-knapsack-pg +rspec pg 4 20: *rspec-knapsack-pg +rspec pg 5 20: *rspec-knapsack-pg +rspec pg 6 20: *rspec-knapsack-pg +rspec pg 7 20: *rspec-knapsack-pg +rspec pg 8 20: *rspec-knapsack-pg +rspec pg 9 20: *rspec-knapsack-pg +rspec pg 10 20: *rspec-knapsack-pg +rspec pg 11 20: *rspec-knapsack-pg +rspec pg 12 20: *rspec-knapsack-pg +rspec pg 13 20: *rspec-knapsack-pg +rspec pg 14 20: *rspec-knapsack-pg +rspec pg 15 20: *rspec-knapsack-pg +rspec pg 16 20: *rspec-knapsack-pg +rspec pg 17 20: *rspec-knapsack-pg +rspec pg 18 20: *rspec-knapsack-pg +rspec pg 19 20: *rspec-knapsack-pg + +rspec mysql 0 20: *rspec-knapsack-mysql +rspec mysql 1 20: *rspec-knapsack-mysql +rspec mysql 2 20: *rspec-knapsack-mysql +rspec mysql 3 20: *rspec-knapsack-mysql +rspec mysql 4 20: *rspec-knapsack-mysql +rspec mysql 5 20: *rspec-knapsack-mysql +rspec mysql 6 20: *rspec-knapsack-mysql +rspec mysql 7 20: *rspec-knapsack-mysql +rspec mysql 8 20: *rspec-knapsack-mysql +rspec mysql 9 20: *rspec-knapsack-mysql +rspec mysql 10 20: *rspec-knapsack-mysql +rspec mysql 11 20: *rspec-knapsack-mysql +rspec mysql 12 20: *rspec-knapsack-mysql +rspec mysql 13 20: *rspec-knapsack-mysql +rspec mysql 14 20: *rspec-knapsack-mysql +rspec mysql 15 20: *rspec-knapsack-mysql +rspec mysql 16 20: *rspec-knapsack-mysql +rspec mysql 17 20: *rspec-knapsack-mysql +rspec mysql 18 20: *rspec-knapsack-mysql +rspec mysql 19 20: *rspec-knapsack-mysql + +spinach pg 0 10: *spinach-knapsack-pg +spinach pg 1 10: *spinach-knapsack-pg +spinach pg 2 10: *spinach-knapsack-pg +spinach pg 3 10: *spinach-knapsack-pg +spinach pg 4 10: *spinach-knapsack-pg +spinach pg 5 10: *spinach-knapsack-pg +spinach pg 6 10: *spinach-knapsack-pg +spinach pg 7 10: *spinach-knapsack-pg +spinach pg 8 10: *spinach-knapsack-pg +spinach pg 9 10: *spinach-knapsack-pg + +spinach mysql 0 10: *spinach-knapsack-mysql +spinach mysql 1 10: *spinach-knapsack-mysql +spinach mysql 2 10: *spinach-knapsack-mysql +spinach mysql 3 10: *spinach-knapsack-mysql +spinach mysql 4 10: *spinach-knapsack-mysql +spinach mysql 5 10: *spinach-knapsack-mysql +spinach mysql 6 10: *spinach-knapsack-mysql +spinach mysql 7 10: *spinach-knapsack-mysql +spinach mysql 8 10: *spinach-knapsack-mysql +spinach mysql 9 10: *spinach-knapsack-mysql # Other generic tests - .ruby-static-analysis: &ruby-static-analysis variables: SIMPLECOV: "false" SETUP_DB: "false" USE_BUNDLE_INSTALL: "true" -.exec: &exec +.rake-exec: &rake-exec <<: *ruby-static-analysis + <<: *dedicated-runner + <<: *except-docs stage: test script: - - bundle exec $CI_BUILD_NAME + - bundle exec rake $CI_JOB_NAME -rubocop: *exec -rake haml_lint: *exec -rake scss_lint: *exec -rake brakeman: *exec -rake flay: *exec -license_finder: *exec -rake downtime_check: *exec -rake ce_to_ee_merge_check: - <<: *exec - only: - - branches +static-analysis: + <<: *ruby-static-analysis + <<: *dedicated-runner + <<: *except-docs + stage: test + script: + - rm -r node_modules + - yarn install --pure-lockfile + - scripts/static-analysis + +# Documentation checks: +# - Check validity of relative links +# - Make sure cURL examples in API docs use the full switches +docs lint: + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:nanoc-bootstrap-ruby-2.4-alpine" + stage: test + <<: *dedicated-runner + cache: {} + dependencies: [] + before_script: [] + script: + - scripts/lint-doc.sh + - mv doc/ /nanoc/content/ + - cd /nanoc + # Build HTML from Markdown + - bundle exec nanoc + # Check the internal links + - bundle exec nanoc check internal_links + +downtime_check: + <<: *rake-exec except: + - master - tags + - /^[\d-]+-stable(-ee)?$/ + - /^docs\/*/ + +ee_compat_check: + <<: *rake-exec + only: + - branches@gitlab-org/gitlab-ce + except: + - master + - tags + - /^[\d-]+-stable(-ee)?$/ allow_failure: yes + cache: + key: "ee_compat_check_repo" + paths: + - ee_compat_check/ee-repo/ + artifacts: + name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}" + when: on_failure + expire_in: 10d + paths: + - ee_compat_check/patches/*.patch -rake db:migrate:reset: +.db-migrate-reset: &db-migrate-reset stage: test - <<: *use-db + <<: *dedicated-runner + <<: *except-docs script: - - rake db:migrate:reset + - bundle exec rake db:migrate:reset -rake db:seed_fu: +rake pg db:migrate:reset: + <<: *db-migrate-reset + <<: *use-pg + +rake mysql db:migrate:reset: + <<: *db-migrate-reset + <<: *use-mysql + +.db-rollback: &db-rollback stage: test - <<: *use-db + <<: *dedicated-runner + <<: *except-docs + script: + - bundle exec rake db:rollback STEP=120 + - bundle exec rake db:migrate + +rake pg db:rollback: + <<: *db-rollback + <<: *use-pg + +rake mysql db:rollback: + <<: *db-rollback + <<: *use-mysql + +.db-seed_fu: &db-seed_fu + stage: test + <<: *dedicated-runner + <<: *except-docs variables: SIZE: "1" SETUP_DB: "false" @@ -241,64 +390,91 @@ rake db:seed_fu: paths: - log/development.log -teaspoon: +rake pg db:seed_fu: + <<: *db-seed_fu + <<: *use-pg + +rake mysql db:seed_fu: + <<: *db-seed_fu + <<: *use-mysql + +rake gitlab:assets:compile: stage: test - <<: *use-db + <<: *dedicated-runner + <<: *except-docs + dependencies: [] + variables: + NODE_ENV: "production" + RAILS_ENV: "production" + SETUP_DB: "false" + USE_DB: "false" + SKIP_STORAGE_VALIDATION: "true" + WEBPACK_REPORT: "true" script: - - curl --silent --location https://deb.nodesource.com/setup_6.x | bash - - - apt-get install --assume-yes nodejs - - npm install --global istanbul - - teaspoon + - bundle exec rake yarn:install gitlab:assets:compile + artifacts: + name: webpack-report + expire_in: 31d + paths: + - webpack-report/ + +rake karma: + stage: test + <<: *use-pg + <<: *dedicated-runner + <<: *except-docs + variables: + BABEL_ENV: "coverage" + script: + - rm -r node_modules + - yarn install --pure-lockfile + - bundle exec rake karma + coverage: '/^Statements *: (\d+\.\d+%)/' artifacts: name: coverage-javascript expire_in: 31d paths: - - coverage-javascript/default/ + - coverage-javascript/ -lint-doc: +.migration-paths: &migration-paths stage: test - image: "phusion/baseimage:latest" - before_script: [] - script: - - scripts/lint-doc.sh - -bundler:check: - stage: test - <<: *ruby-static-analysis - script: - - bundle check - -bundler:audit: - stage: test - <<: *ruby-static-analysis - only: - - master - script: - - "bundle exec bundle-audit check --update --ignore OSVDB-115941" - -migration paths: - stage: test - <<: *use-db + <<: *dedicated-runner + variables: + SETUP_DB: "false" only: - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + - master@gitlab/gitlabhq + - master@gitlab/gitlab-ee script: - - git checkout HEAD . - - git fetch --tags - - git checkout v8.5.9 - - 'echo test: unix:/var/opt/gitlab/redis/redis.socket > config/resque.yml' - - bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}" --retry=3 - - rake db:drop db:create db:schema:load db:seed_fu - - git checkout $CI_BUILD_REF - - rake db:migrate + - git fetch origin v8.14.10 + - git checkout -f FETCH_HEAD + - bundle install $BUNDLE_INSTALL_FLAGS + - bundle exec rake db:drop db:create db:schema:load db:seed_fu + - git checkout $CI_COMMIT_SHA + - bundle install $BUNDLE_INSTALL_FLAGS + - . scripts/prepare_build.sh + - bundle exec rake db:migrate + +migration pg paths: + <<: *migration-paths + <<: *use-pg + +migration mysql paths: + <<: *migration-paths + <<: *use-mysql coverage: stage: post-test services: [] + <<: *dedicated-runner + <<: *except-docs variables: SETUP_DB: "false" USE_BUNDLE_INSTALL: "true" script: - bundle exec scripts/merge-simplecov + coverage: '/LOC \((\d+\.\d+%)\) covered.$/' artifacts: name: coverage expire_in: 31d @@ -306,53 +482,66 @@ coverage: - coverage/index.html - coverage/assets/ -# Trigger docs build -trigger_docs: +lint:javascript:report: + <<: *dedicated-runner + <<: *except-docs stage: post-test before_script: [] + script: + - find app/ spec/ -name '*.js' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files + - yarn run eslint-report || true # ignore exit code + artifacts: + name: eslint-report + expire_in: 31d + paths: + - eslint-report.html + +# Trigger docs build +# https://gitlab.com/gitlab-com/doc-gitlab-com/blob/master/README.md#deployment-process +trigger_docs: + stage: post-test + image: "alpine" + <<: *dedicated-runner + before_script: + - apk update && apk add curl + variables: + GIT_STRATEGY: "none" cache: {} artifacts: {} script: - - "curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master https://gitlab.com/api/v3/projects/38069/trigger/builds" - only: - - master - -# Notify slack in the end - -notify:slack: - stage: post-test - variables: - SETUP_DB: "false" - USE_BUNDLE_INSTALL: "false" - script: - - ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See " - when: on_failure + - "HTTP_STATUS=$(curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master -F variables[PROJECT]=${CI_PROJECT_NAME} --silent --output curl.log --write-out '%{http_code}' https://gitlab.com/api/v3/projects/1794617/trigger/builds)" + - if [ "${HTTP_STATUS}" -ne "201" ]; then echo "Error ${HTTP_STATUS}"; cat curl.log; echo; exit 1; fi only: - master@gitlab-org/gitlab-ce - - tags@gitlab-org/gitlab-ce - master@gitlab-org/gitlab-ee - - tags@gitlab-org/gitlab-ee pages: before_script: [] stage: pages + <<: *dedicated-runner dependencies: - coverage - - teaspoon + - rake karma + - rake gitlab:assets:compile + - lint:javascript:report script: - mv public/ .public/ - mkdir public/ - - mv coverage public/coverage-ruby - - mv coverage-javascript/default/ public/coverage-javascript/ + - mv coverage/ public/coverage-ruby/ || true + - mv coverage-javascript/ public/coverage-javascript/ || true + - mv eslint-report.html public/ || true + - mv webpack-report/ public/webpack-report/ || true artifacts: paths: - public only: - - master + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee # Insurance in case a gem needed by one of our releases gets yanked from # rubygems.org in the future. cache gems: + <<: *dedicated-runner only: - tags variables: @@ -362,3 +551,6 @@ cache gems: artifacts: paths: - vendor/cache + only: + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md index ac38f0c952..66e1e0e20b 100644 --- a/.gitlab/issue_templates/Bug.md +++ b/.gitlab/issue_templates/Bug.md @@ -1,3 +1,17 @@ +Please read this! + +Before opening a new issue, make sure to search for keywords in the issues +filtered by the "regression" or "bug" label: + +- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=regression +- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=bug + +and verify the issue you're about to submit isn't a duplicate. + +Please remove this notice if you're confident your issue isn't a duplicate. + +------ + ### Summary (Summarize the bug encountered concisely) @@ -6,14 +20,14 @@ (How one can reproduce the issue - this is very important) -### Expected behavior - -(What you should see instead) - -### Actual behavior +### What is the current *bug* behavior? (What actually happens) +### What is the expected *correct* behavior? + +(What you should see instead) + ### Relevant logs and/or screenshots (Paste any relevant logs - please use code blocks (```) to format console output, @@ -21,8 +35,27 @@ logs, and code as it's very hard to read otherwise.) ### Output of checks +(If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com) + +#### Results of GitLab environment info + +
+
+
+(For installations with omnibus-gitlab package run and paste the output of:
+`sudo gitlab-rake gitlab:env:info`)
+
+(For installations from source run and paste the output of:
+`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
+
+
+
+ #### Results of GitLab application Check +
+
+
 (For installations with omnibus-gitlab package run and paste the output of:
 `sudo gitlab-rake gitlab:check SANITIZE=true`)
 
@@ -31,14 +64,11 @@ logs, and code as it's very hard to read otherwise.)
 
 (we will only investigate if the tests are passing)
 
-#### Results of GitLab environment info
-
-(For installations with omnibus-gitlab package run and paste the output of:
-`sudo gitlab-rake gitlab:env:info`)
-
-(For installations from source run and paste the output of:
-`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
+
+
### Possible fixes (If you can, link to the line of code that might be responsible for the problem) + +/label ~bug diff --git a/.gitlab/issue_templates/Feature Proposal.md b/.gitlab/issue_templates/Feature Proposal.md index ea895ee627..d96c9ad59e 100644 --- a/.gitlab/issue_templates/Feature Proposal.md +++ b/.gitlab/issue_templates/Feature Proposal.md @@ -1,3 +1,16 @@ +Please read this! + +Before opening a new issue, make sure to search for keywords in the issues +filtered by the "feature proposal" label: + +- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=feature+proposal + +and verify the issue you're about to submit isn't a duplicate. + +Please remove this notice if you're confident your issue isn't a duplicate. + +------ + ### Description (Include problem, use cases, benefits, and/or goals) @@ -5,3 +18,15 @@ ### Proposal ### Links / references + +### Documentation blurb + +(Write the start of the documentation of this feature here, include: + +1. Why should someone use it; what's the underlying problem. +2. What is the solution. +3. How does someone use this + +During implementation, this can then be copied and used as a starter for the documentation.) + +/label ~"feature proposal" diff --git a/.gitlab/issue_templates/Research Proposal.md b/.gitlab/issue_templates/Research Proposal.md new file mode 100644 index 0000000000..5676656793 --- /dev/null +++ b/.gitlab/issue_templates/Research Proposal.md @@ -0,0 +1,17 @@ +### Background: + +(Include problem, use cases, benefits, and/or goals) + +**What questions are you trying to answer?** + +**Are you looking to verify an existing hypothesis or uncover new issues you should be exploring?** + +**What is the backstory of this project and how does it impact the approach?** + +**What do you already know about the areas you are exploring?** + +**What does success look like at the end of the project?** + +### Links / references: + +/label ~"UX research" diff --git a/.haml-lint.yml b/.haml-lint.yml index da9a43d9c6..528f99d08d 100644 --- a/.haml-lint.yml +++ b/.haml-lint.yml @@ -7,10 +7,10 @@ exclude: linters: AltText: - enabled: false + enabled: true ClassAttributeWithStaticValue: - enabled: false + enabled: true ClassesBeforeIds: enabled: false @@ -29,14 +29,14 @@ linters: enabled: true FinalNewline: - enabled: false + enabled: true present: true HtmlAttributes: - enabled: false + enabled: true ImplicitDiv: - enabled: false + enabled: true LeadingCommentSpace: enabled: false @@ -46,7 +46,7 @@ linters: max: 80 MultilinePipe: - enabled: false + enabled: true MultilineScript: enabled: true @@ -77,13 +77,13 @@ linters: - Style/WhileUntilModifier RubyComments: - enabled: false + enabled: true SpaceBeforeScript: - enabled: false + enabled: true SpaceInsideHashAttributes: - enabled: false + enabled: true style: space Indentation: @@ -94,10 +94,10 @@ linters: enabled: true TrailingWhitespace: - enabled: false + enabled: true UnnecessaryInterpolation: - enabled: false + enabled: true UnnecessaryStringOutput: - enabled: false + enabled: true diff --git a/.rubocop.yml b/.rubocop.yml index bec2464c74..e53af97a92 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -17,21 +17,19 @@ AllCops: # Exclude some GitLab files Exclude: - 'vendor/**/*' + - 'node_modules/**/*' - 'db/*' - 'db/fixtures/**/*' - 'tmp/**/*' - 'bin/**/*' - - 'lib/backup/**/*' - - 'lib/ci/backup/**/*' - - 'lib/tasks/**/*' - - 'lib/ci/migrate/**/*' - - 'lib/email_validator.rb' - - 'lib/gitlab/upgrader.rb' - - 'lib/gitlab/seeder.rb' - 'generator_templates/**/*' + - 'builds/**/*' +# Gems in consecutive lines should be alphabetically sorted +Bundler/OrderedGems: + Enabled: false -##################### Style ################################## +# Style ####################################################################### # Check indentation of private/protected visibility modifiers. Style/AccessModifierIndentation: @@ -54,6 +52,16 @@ Style/AlignArray: Style/AlignHash: Enabled: true +# Here we check if the parameters on a multi-line method call or +# definition are aligned. +Style/AlignParameters: + Enabled: false + +# Whether `and` and `or` are banned only in conditionals (conditionals) +# or completely (always). +Style/AndOr: + Enabled: true + # Use `Array#join` instead of `Array#*`. Style/ArrayJoin: Enabled: true @@ -78,15 +86,24 @@ Style/BeginBlock: Style/BlockComments: Enabled: true -# Put end statement of multiline block on its own line. -Style/BlockEndNewline: - Enabled: true - # Avoid using {...} for multi-line blocks (multiline chaining is # always # ugly). Prefer {...} over do...end for single-line blocks. Style/BlockDelimiters: Enabled: true +# Put end statement of multiline block on its own line. +Style/BlockEndNewline: + Enabled: true + + # This cop checks for braces around the last parameter in a method call +# if the last parameter is a hash. +Style/BracesAroundHashParameters: + Enabled: false + +# This cop checks for uses of the case equality operator(===). +Style/CaseEquality: + Enabled: false + # Indentation of when in a case/when/[else/]end. Style/CaseIndentation: Enabled: true @@ -105,7 +122,7 @@ Style/ClassAndModuleChildren: # Enforces consistent use of `Object#is_a?` or `Object#kind_of?`. Style/ClassCheck: - Enabled: false + Enabled: true # Use self when defining module/class methods. Style/ClassMethods: @@ -115,10 +132,26 @@ Style/ClassMethods: Style/ClassVars: Enabled: true +# This cop checks for methods invoked via the :: operator instead +# of the . operator (like FileUtils::rmdir instead of FileUtils.rmdir). +Style/ColonMethodCall: + Enabled: true + +# This cop checks that comment annotation keywords are written according +# to guidelines. +Style/CommentAnnotation: + Enabled: false + # Indentation of comments. Style/CommentIndentation: Enabled: true +# Check for `if` and `case` statements where each branch is used for +# assignment to the same variable when using the return of the +# condition can be used instead. +Style/ConditionalAssignment: + Enabled: true + # Constants should use SCREAMING_SNAKE_CASE. Style/ConstantName: Enabled: true @@ -131,13 +164,19 @@ Style/DefWithParentheses: Style/Documentation: Enabled: false +# This cop checks for uses of double negation (!!) to convert something +# to a boolean value. As this is both cryptic and usually redundant, it +# should be avoided. +Style/DoubleNegation: + Enabled: false + # Align elses and elsifs correctly. Style/ElseAlignment: Enabled: true # Use empty lines between defs. Style/EmptyLineBetweenDefs: - Enabled: false + Enabled: true # Don't use several empty lines in a row. Style/EmptyLines: @@ -155,14 +194,14 @@ Style/EmptyLinesAroundBlockBody: Style/EmptyLinesAroundClassBody: Enabled: true -# Keeps track of empty lines around module bodies. -Style/EmptyLinesAroundModuleBody: - Enabled: true - # Keeps track of empty lines around method bodies. Style/EmptyLinesAroundMethodBody: Enabled: true +# Keeps track of empty lines around module bodies. +Style/EmptyLinesAroundModuleBody: + Enabled: true + # Avoid the use of END blocks. Style/EndBlock: Enabled: true @@ -195,24 +234,28 @@ Style/For: # Checks if there is a magic comment to enforce string literals Style/FrozenStringLiteralComment: Enabled: false + # Do not introduce global variables. Style/GlobalVars: Enabled: true + Exclude: + - 'lib/backup/**/*' + - 'lib/tasks/**/*' # Prefer Ruby 1.9 hash syntax `{ a: 1, b: 2 }` # over 1.8 syntax `{ :a => 1, :b => 2 }`. Style/HashSyntax: Enabled: true -# Do not use if x; .... Use the ternary operator instead. -Style/IfWithSemicolon: - Enabled: true - # Checks that conditional statements do not have an identical line at the # end of each branch, which can validly be moved out of the conditional. Style/IdenticalConditionalBranches: Enabled: true +# Do not use if x; .... Use the ternary operator instead. +Style/IfWithSemicolon: + Enabled: true + # Checks the indentation of the first line of the right-hand-side of a # multi-line assignment. Style/IndentAssignment: @@ -253,7 +296,7 @@ Style/ModuleFunction: # Checks that the closing brace in an array literal is either on the same line # as the last array element, or a new line. Style/MultilineArrayBraceLayout: - Enabled: false + Enabled: true EnforcedStyle: symmetrical # Avoid multi-line chains of blocks. @@ -267,7 +310,7 @@ Style/MultilineBlockLayout: # Checks that the closing brace in a hash literal is either on the same line as # the last hash element, or a new line. Style/MultilineHashBraceLayout: - Enabled: false + Enabled: true EnforcedStyle: symmetrical # Do not use then for multi-line if/unless. @@ -292,12 +335,21 @@ Style/MultilineMethodDefinitionBraceLayout: # Checks indentation of binary operations that span more than one line. Style/MultilineOperationIndentation: - Enabled: false + Enabled: true + EnforcedStyle: indented # Avoid multi-line `? :` (the ternary operator), use if/unless instead. Style/MultilineTernaryOperator: Enabled: true +# This cop checks whether some constant value isn't a +# mutable literal (e.g. array or hash). +Style/MutableConstant: + Enabled: true + Exclude: + - 'db/migrate/**/*' + - 'db/post_migrate/**/*' + # Favor unless over if for negative conditions (or control flow or). Style/NegatedIf: Enabled: true @@ -338,12 +390,12 @@ Style/OpMethod: Style/ParenthesesAroundCondition: Enabled: true -# Checks for parentheses that seem not to serve any purpose. -Style/RedundantParentheses: +# Checks for an obsolete RuntimeException argument in raise/fail. +Style/RedundantException: Enabled: true -# Don't use return where it's not required. -Style/RedundantReturn: +# Checks for parentheses that seem not to serve any purpose. +Style/RedundantParentheses: Enabled: true # Don't use semicolons to terminate expressions. @@ -400,6 +452,10 @@ Style/SpaceBeforeComment: Style/SpaceBeforeSemicolon: Enabled: true +# Checks for spaces inside square brackets. +Style/SpaceInsideBrackets: + Enabled: true + # Use spaces inside hash literal braces - or don't. Style/SpaceInsideHashLiteralBraces: Enabled: true @@ -436,6 +492,10 @@ Style/Tab: Style/TrailingBlankLines: Enabled: true +# This cop checks for trailing comma in array and hash literals. +Style/TrailingCommaInLiteral: + Enabled: false + # Checks for %W when interpolation is not needed. Style/UnneededCapitalW: Enabled: true @@ -471,15 +531,23 @@ Style/WhileUntilModifier: # Use %w or %W for arrays of words. Style/WordArray: - Enabled: false + Enabled: true -#################### Metrics ################################ +# Use `proc` instead of `Proc.new`. +Style/Proc: + Enabled: true + +# Metrics ##################################################################### # A calculated magnitude based on number of assignments, # branches, and conditions. Metrics/AbcSize: Enabled: true - Max: 60 + Max: 57.08 + +# This cop checks if the length of a block exceeds some maximum value. +Metrics/BlockLength: + Enabled: false # Avoid excessive block nesting. Metrics/BlockNesting: @@ -494,7 +562,7 @@ Metrics/ClassLength: # of test cases needed to validate a method. Metrics/CyclomaticComplexity: Enabled: true - Max: 17 + Max: 16 # Limit lines to 80 characters. Metrics/LineLength: @@ -518,23 +586,23 @@ Metrics/PerceivedComplexity: Enabled: true Max: 18 - -#################### Lint ################################ - -# Checks for useless access modifiers. -Lint/UselessAccessModifier: - Enabled: true - -# Checks for attempts to use `private` or `protected` to set the visibility -# of a class method, which does not work. -Lint/IneffectiveAccessModifier: - Enabled: false +# Lint ######################################################################## # Checks for ambiguous operators in the first argument of a method invocation # without parentheses. Lint/AmbiguousOperator: Enabled: true +# This cop checks for ambiguous regexp literals in the first argument of +# a method invocation without parentheses. +Lint/AmbiguousRegexpLiteral: + Enabled: false + +# This cop checks for assignments in the conditions of +# if/while/until. +Lint/AssignmentInCondition: + Enabled: false + # Align block ends correctly. Lint/BlockAlignment: Enabled: true @@ -572,6 +640,10 @@ Lint/ElseLayout: Lint/EmptyEnsure: Enabled: true +# Checks for the presence of `when` branches without a body. +Lint/EmptyWhen: + Enabled: true + # Align ends correctly. Lint/EndAlignment: Enabled: true @@ -584,10 +656,6 @@ Lint/EndInMethod: Lint/EnsureReturn: Enabled: true -# The use of eval represents a serious security risk. -Lint/Eval: - Enabled: true - # Catches floating-point literals too large or small for Ruby to represent. Lint/FloatOutOfRange: Enabled: true @@ -596,11 +664,20 @@ Lint/FloatOutOfRange: Lint/FormatParameterMismatch: Enabled: true +# This cop checks for *rescue* blocks with no body. +Lint/HandleExceptions: + Enabled: false + # Checks for adjacent string literals on the same line, which could better be # represented as a single string literal. Lint/ImplicitStringConcatenation: Enabled: true +# Checks for attempts to use `private` or `protected` to set the visibility +# of a class method, which does not work. +Lint/IneffectiveAccessModifier: + Enabled: false + # Checks for invalid character literals with a non-escaped whitespace # character. Lint/InvalidCharacterLiteral: @@ -614,6 +691,10 @@ Lint/LiteralInCondition: Lint/LiteralInInterpolation: Enabled: true +# This cop checks for uses of *begin...end while/until something*. +Lint/Loop: + Enabled: false + # Do not use nested method definitions. Lint/NestedMethodDefinition: Enabled: true @@ -643,6 +724,11 @@ Lint/RescueException: Lint/ShadowedException: Enabled: false +# This cop looks for use of the same name as outer local variables +# for block arguments or block local variables. +Lint/ShadowingOuterLocalVariable: + Enabled: false + # Checks for Object#to_s usage in string interpolation. Lint/StringConversionInInterpolation: Enabled: true @@ -651,16 +737,36 @@ Lint/StringConversionInInterpolation: Lint/UnderscorePrefixedVariableName: Enabled: true +# This cop checks for using Fixnum or Bignum constant +Lint/UnifiedInteger: + Enabled: true + # Checks for rubocop:disable comments that can be removed. # Note: this cop is not disabled when disabling all cops. # It must be explicitly disabled. Lint/UnneededDisable: Enabled: false +# This cop checks for unneeded usages of splat expansion +Lint/UnneededSplatExpansion: + Enabled: false + # Unreachable code. Lint/UnreachableCode: Enabled: true +# This cop checks for unused block arguments. +Lint/UnusedBlockArgument: + Enabled: false + +# This cop checks for unused method arguments. +Lint/UnusedMethodArgument: + Enabled: false + +# Checks for useless access modifiers. +Lint/UselessAccessModifier: + Enabled: true + # Checks for useless assignment to a local variable. Lint/UselessAssignment: Enabled: true @@ -681,8 +787,7 @@ Lint/UselessSetterCall: Lint/Void: Enabled: true - -##################### Performance ############################ +# Performance ################################################################# # Use `casecmp` rather than `downcase ==`. Performance/Casecmp: @@ -701,6 +806,22 @@ Performance/LstripRstrip: Performance/RangeInclude: Enabled: true +# This cop identifies the use of a `&block` parameter and `block.call` +# where `yield` would do just as well. +Performance/RedundantBlockCall: + Enabled: true + +# This cop identifies use of `Regexp#match` or `String#match in a context +# where the integral return value of `=~` would do just as well. +Performance/RedundantMatch: + Enabled: true + +# This cop identifies places where `Hash#merge!` can be replaced by +# `Hash#[]=`. +Performance/RedundantMerge: + Enabled: true + MaxKeyValuePairs: 1 + # Use `sort` instead of `sort_by { |x| x }`. Performance/RedundantSortBy: Enabled: true @@ -720,8 +841,18 @@ Performance/StringReplacement: Performance/TimesMap: Enabled: true +# Security #################################################################### -##################### Rails ################################## +# This cop checks for the use of JSON class methods which have potential +# security issues. +Security/JSONLoad: + Enabled: true + +# This cop checks for the use of *Kernel#eval*. +Security/Eval: + Enabled: true + +# Rails ####################################################################### # Enables Rails cops. Rails: @@ -739,8 +870,19 @@ Rails/Date: # Prefer delegate method for delegations. Rails/Delegate: + Enabled: true + +# This cop checks dynamic `find_by_*` methods. +Rails/DynamicFindBy: Enabled: false +# This cop enforces that 'exit' calls are not used within a rails app. +Rails/Exit: + Enabled: true + Exclude: + - lib/gitlab/upgrader.rb + - 'lib/backup/**/*' + # Prefer `find_by` over `where.first`. Rails/FindBy: Enabled: true @@ -753,9 +895,25 @@ Rails/FindEach: Rails/HasAndBelongsToMany: Enabled: true +# This cop is used to identify usages of http methods like `get`, `post`, +# `put`, `patch` without the usage of keyword arguments in your tests and +# change them to use keyword args. +Rails/HttpPositionalArguments: + Enabled: false + # Checks for calls to puts, print, etc. Rails/Output: Enabled: true + Exclude: + - lib/gitlab/seeder.rb + - lib/gitlab/upgrader.rb + - 'lib/backup/**/*' + - 'lib/tasks/**/*' + +# This cop checks for the use of output safety calls like html_safe and +# raw. +Rails/OutputSafety: + Enabled: false # Checks for incorrect grammar when using methods like `3.day.ago`. Rails/PluralizationGrammar: @@ -769,12 +927,24 @@ Rails/ReadWriteAttribute: Rails/ScopeArgs: Enabled: true -##################### RSpec ################################## +# This cop checks for the use of Time methods without zone. +Rails/TimeZone: + Enabled: false + +# This cop checks for the use of old-style attribute validation macros. +Rails/Validation: + Enabled: true + +# RSpec ####################################################################### # Check that instances are not being stubbed globally. RSpec/AnyInstance: Enabled: false +# Check for expectations where `be(...)` can replace `eql(...)`. +RSpec/BeEql: + Enabled: true + # Check that the first argument to the top level describe is the tested class or # module. RSpec/DescribeClass: @@ -784,10 +954,14 @@ RSpec/DescribeClass: RSpec/DescribeMethod: Enabled: false +# Avoid describing symbols. +RSpec/DescribeSymbol: + Enabled: true + # Checks that the second argument to top level describe is the tested method # name. RSpec/DescribedClass: - Enabled: false + Enabled: true # Checks for long example. RSpec/ExampleLength: @@ -803,12 +977,18 @@ RSpec/ExampleWording: not: does not IgnoredWords: [] +# Checks for `expect(...)` calls containing literal values. +RSpec/ExpectActual: + Enabled: true + # Checks the file and folder naming of the spec file. RSpec/FilePath: - Enabled: false - CustomTransform: - RuboCop: rubocop - RSpec: rspec + Enabled: true + IgnoreMethods: true + Exclude: + - 'qa/**/*' + - 'spec/javascripts/fixtures/*' + - 'spec/requests/api/v3/*' # Checks if there are focused specs. RSpec/Focus: @@ -818,15 +998,51 @@ RSpec/Focus: RSpec/InstanceVariable: Enabled: false +# Checks for `subject` definitions that come after `let` definitions. +RSpec/LeadingSubject: + Enabled: false + +# Checks unreferenced `let!` calls being used for test setup. +RSpec/LetSetup: + Enabled: false + +# Check that chains of messages are not being stubbed. +RSpec/MessageChain: + Enabled: false + +# Checks that message expectations are set using spies. +RSpec/MessageSpies: + Enabled: false + # Checks for multiple top-level describes. RSpec/MultipleDescribes: Enabled: false +# Checks if examples contain too many `expect` calls. +RSpec/MultipleExpectations: + Enabled: false + +# Checks for explicitly referenced test subjects. +RSpec/NamedSubject: + Enabled: false + +# Checks for nested example groups. +RSpec/NestedGroups: + Enabled: false + # Enforces the usage of the same method on all negative message expectations. RSpec/NotToNot: EnforcedStyle: not_to Enabled: true +# Check for repeated description strings in example groups. +RSpec/RepeatedDescription: + Enabled: false + +# Checks for stubbed test subjects. +RSpec/SubjectStub: + Enabled: false + # Prefer using verifying doubles over normal doubles. RSpec/VerifiedDoubles: Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 11b34fafa2..38b22afdf8 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,342 +1,243 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 0` -# on 2016-10-04 13:16:20 +0200 using RuboCop version 0.43.0. +# on 2017-04-07 20:17:35 -0400 using RuboCop version 0.47.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 160 -Lint/AmbiguousRegexpLiteral: +# Offense count: 54 +RSpec/BeforeAfterAll: Enabled: false -# Offense count: 40 -# Configuration parameters: AllowSafeAssignment. -Lint/AssignmentInCondition: - Enabled: false - -# Offense count: 18 -Lint/HandleExceptions: - Enabled: false - -# Offense count: 2 -Lint/Loop: - Enabled: false - -# Offense count: 19 -Lint/ShadowingOuterLocalVariable: - Enabled: false - -# Offense count: 9 -# Cop supports --auto-correct. -Lint/UnifiedInteger: - Enabled: false - -# Offense count: 13 -# Cop supports --auto-correct. -Lint/UnneededSplatExpansion: - Enabled: false - -# Offense count: 69 -# Cop supports --auto-correct. -# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. -Lint/UnusedBlockArgument: - Enabled: false - -# Offense count: 144 -# Cop supports --auto-correct. -# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. -Lint/UnusedMethodArgument: - Enabled: false - -# Offense count: 2 -# Cop supports --auto-correct. -Performance/RedundantBlockCall: - Enabled: false - -# Offense count: 5 -# Cop supports --auto-correct. -Performance/RedundantMatch: - Enabled: false - -# Offense count: 26 -# Cop supports --auto-correct. -# Configuration parameters: MaxKeyValuePairs. -Performance/RedundantMerge: - Enabled: false - -# Offense count: 7 -RSpec/BeEql: - Enabled: false - -# Offense count: 20 +# Offense count: 15 # Configuration parameters: CustomIncludeMethods. RSpec/EmptyExampleGroup: Enabled: false -# Offense count: 16 -RSpec/ExpectActual: +# Offense count: 233 +RSpec/EmptyLineAfterFinalLet: Enabled: false -# Offense count: 34 +# Offense count: 167 +RSpec/EmptyLineAfterSubject: + Enabled: false + +# Offense count: 3 +RSpec/ExpectOutput: + Enabled: false + +# Offense count: 72 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: implicit, each, example RSpec/HookArgument: Enabled: false -# Offense count: 168 -RSpec/LeadingSubject: - Enabled: false - -# Offense count: 162 -RSpec/LetSetup: - Enabled: false - -# Offense count: 10 -RSpec/MessageChain: - Enabled: false - -# Offense count: 714 +# Offense count: 12 # Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: allow, expect -RSpec/MessageExpectation: +# SupportedStyles: is_expected, should +RSpec/ImplicitExpect: Enabled: false -# Offense count: 2423 -RSpec/MultipleExpectations: - Max: 36 - -# Offense count: 1504 -RSpec/NamedSubject: - Enabled: false - -# Offense count: 1335 -# Configuration parameters: MaxNesting. -RSpec/NestedGroups: - Enabled: false - -# Offense count: 99 -RSpec/SubjectStub: - Enabled: false - -# Offense count: 64 -Rails/OutputSafety: - Enabled: false - -# Offense count: 151 +# Offense count: 11 # Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: strict, flexible -Rails/TimeZone: +# SupportedStyles: it_behaves_like, it_should_behave_like +RSpec/ItBehavesLike: Enabled: false -# Offense count: 15 -# Cop supports --auto-correct. -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/Validation: +# Offense count: 4 +RSpec/IteratedExpectation: + Enabled: false + +# Offense count: 3 +RSpec/OverwritingSetup: + Enabled: false + +# Offense count: 34 +RSpec/RepeatedExample: + Enabled: false + +# Offense count: 43 +RSpec/ScatteredLet: + Enabled: false + +# Offense count: 32 +RSpec/ScatteredSetup: + Enabled: false + +# Offense count: 1 +RSpec/SharedContext: + Enabled: false + +# Offense count: 150 +Rails/FilePath: Enabled: false # Offense count: 2 -# Cop supports --auto-correct. -Security/JSONLoad: +# Configuration parameters: Include. +# Include: db/migrate/*.rb +Rails/ReversibleMigration: Enabled: false -# Offense count: 284 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: with_first_parameter, with_fixed_indentation -Style/AlignParameters: +# Offense count: 302 +# Configuration parameters: Blacklist. +# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters +Rails/SkipsModelValidations: Enabled: false -# Offense count: 28 +# Offense count: 7 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: always, conditionals -Style/AndOr: +Security/YAMLLoad: Enabled: false -# Offense count: 52 +# Offense count: 59 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: percent_q, bare_percent Style/BarePercentLiterals: Enabled: false -# Offense count: 291 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: braces, no_braces, context_dependent -Style/BracesAroundHashParameters: - Enabled: false - -# Offense count: 6 -Style/CaseEquality: - Enabled: false - -# Offense count: 26 -# Cop supports --auto-correct. -Style/ColonMethodCall: - Enabled: false - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: Keywords. -# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW -Style/CommentAnnotation: - Enabled: false - -# Offense count: 30 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly. -# SupportedStyles: assign_to_condition, assign_inside_condition -Style/ConditionalAssignment: - Enabled: false - -# Offense count: 957 +# Offense count: 1403 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: leading, trailing Style/DotPosition: Enabled: false -# Offense count: 13 -Style/DoubleNegation: - Enabled: false - -# Offense count: 6 +# Offense count: 5 # Cop supports --auto-correct. Style/EachWithObject: Enabled: false -# Offense count: 26 +# Offense count: 28 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: empty, nil, both Style/EmptyElse: Enabled: false -# Offense count: 3 +# Offense count: 4 # Cop supports --auto-correct. Style/EmptyLiteral: Enabled: false -# Offense count: 140 +# Offense count: 59 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: compact, expanded +Style/EmptyMethod: + Enabled: false + +# Offense count: 214 # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. Style/ExtraSpacing: Enabled: false -# Offense count: 6 +# Offense count: 9 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: format, sprintf, percent Style/FormatString: Enabled: false -# Offense count: 201 +# Offense count: 285 # Configuration parameters: MinBodyLength. Style/GuardClause: Enabled: false -# Offense count: 11 +# Offense count: 16 Style/IfInsideElse: Enabled: false -# Offense count: 174 +# Offense count: 186 # Cop supports --auto-correct. # Configuration parameters: MaxLineLength. Style/IfUnlessModifier: Enabled: false -# Offense count: 53 +# Offense count: 99 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_brackets Style/IndentArray: Enabled: false -# Offense count: 95 +# Offense count: 160 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_braces Style/IndentHash: Enabled: false -# Offense count: 29 +# Offense count: 50 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: line_count_dependent, lambda, literal Style/Lambda: Enabled: false -# Offense count: 5 +# Offense count: 6 # Cop supports --auto-correct. Style/LineEndConcatenation: Enabled: false -# Offense count: 15 +# Offense count: 34 # Cop supports --auto-correct. -Style/MethodCallParentheses: +Style/MethodCallWithoutArgsParentheses: Enabled: false -# Offense count: 8 +# Offense count: 10 Style/MethodMissing: Enabled: false -# Offense count: 95 +# Offense count: 3 # Cop supports --auto-correct. -Style/MutableConstant: +Style/MultilineIfModifier: Enabled: false -# Offense count: 8 +# Offense count: 24 # Cop supports --auto-correct. Style/NestedParenthesizedCalls: Enabled: false -# Offense count: 13 +# Offense count: 18 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. # SupportedStyles: skip_modifier_ifs, always Style/Next: Enabled: false -# Offense count: 12 +# Offense count: 37 # Cop supports --auto-correct. # Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. # SupportedOctalStyles: zero_with_o, zero_only Style/NumericLiteralPrefix: Enabled: false -# Offense count: 53 +# Offense count: 88 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles. # SupportedStyles: predicate, comparison Style/NumericPredicate: Enabled: false -# Offense count: 29 +# Offense count: 36 # Cop supports --auto-correct. Style/ParallelAssignment: Enabled: false -# Offense count: 294 +# Offense count: 570 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: Enabled: false -# Offense count: 11 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: lower_case_q, upper_case_q -Style/PercentQLiterals: - Enabled: false - -# Offense count: 13 +# Offense count: 14 # Cop supports --auto-correct. Style/PerlBackrefs: Enabled: false -# Offense count: 38 +# Offense count: 83 # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. # NamePrefix: is_, has_, have_ # NamePrefixBlacklist: is_, has_, have_ @@ -344,178 +245,161 @@ Style/PerlBackrefs: Style/PredicateName: Enabled: false -# Offense count: 26 +# Offense count: 45 # Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: short, verbose Style/PreferredHashMethods: Enabled: false -# Offense count: 6 -# Cop supports --auto-correct. -Style/Proc: - Enabled: false - -# Offense count: 22 +# Offense count: 65 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: compact, exploded Style/RaiseArgs: Enabled: false -# Offense count: 4 +# Offense count: 5 # Cop supports --auto-correct. Style/RedundantBegin: Enabled: false -# Offense count: 1 -# Cop supports --auto-correct. -Style/RedundantException: - Enabled: false - -# Offense count: 24 +# Offense count: 32 # Cop supports --auto-correct. Style/RedundantFreeze: Enabled: false -# Offense count: 427 +# Offense count: 15 +# Cop supports --auto-correct. +# Configuration parameters: AllowMultipleReturnValues. +Style/RedundantReturn: + Enabled: false + +# Offense count: 382 # Cop supports --auto-correct. Style/RedundantSelf: Enabled: false -# Offense count: 97 +# Offense count: 111 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. # SupportedStyles: slashes, percent_r, mixed Style/RegexpLiteral: Enabled: false -# Offense count: 18 +# Offense count: 24 # Cop supports --auto-correct. Style/RescueModifier: Enabled: false -# Offense count: 114 -# Cop supports --auto-correct. -Style/SafeNavigation: - Enabled: false - # Offense count: 7 # Cop supports --auto-correct. Style/SelfAssignment: Enabled: false -# Offense count: 2 -# Configuration parameters: Methods. -# Methods: {"reduce"=>["a", "e"]}, {"inject"=>["a", "e"]} -Style/SingleLineBlockParams: - Enabled: false - # Offense count: 50 # Cop supports --auto-correct. # Configuration parameters: AllowIfMethodIsEmpty. Style/SingleLineMethods: Enabled: false -# Offense count: 125 +# Offense count: 168 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: space, no_space Style/SpaceBeforeBlockBraces: Enabled: false -# Offense count: 10 +# Offense count: 8 # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment. Style/SpaceBeforeFirstArg: Enabled: false -# Offense count: 145 +# Offense count: 46 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: require_no_space, require_space +Style/SpaceInLambdaLiteral: + Enabled: false + +# Offense count: 229 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. # SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space Style/SpaceInsideBlockBraces: Enabled: false -# Offense count: 99 -# Cop supports --auto-correct. -Style/SpaceInsideBrackets: - Enabled: false - -# Offense count: 65 +# Offense count: 116 # Cop supports --auto-correct. Style/SpaceInsideParens: Enabled: false -# Offense count: 7 +# Offense count: 12 # Cop supports --auto-correct. Style/SpaceInsidePercentLiteralDelimiters: Enabled: false -# Offense count: 41 +# Offense count: 57 # Cop supports --auto-correct. # Configuration parameters: SupportedStyles. # SupportedStyles: use_perl_names, use_english_names Style/SpecialGlobalVars: EnforcedStyle: use_perl_names -# Offense count: 31 +# Offense count: 42 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: single_quotes, double_quotes Style/StringLiteralsInInterpolation: Enabled: false -# Offense count: 33 +# Offense count: 64 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. # IgnoredMethods: respond_to, define_method Style/SymbolProc: Enabled: false -# Offense count: 5 +# Offense count: 6 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment. -# SupportedStyles: require_parentheses, require_no_parentheses +# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex Style/TernaryParentheses: Enabled: false -# Offense count: 29 +# Offense count: 53 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. -# SupportedStyles: comma, consistent_comma, no_comma +# Configuration parameters: EnforcedStyleForMultiline, SupportedStylesForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma Style/TrailingCommaInArguments: Enabled: false -# Offense count: 102 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. -# SupportedStyles: comma, consistent_comma, no_comma -Style/TrailingCommaInLiteral: - Enabled: false - -# Offense count: 7 +# Offense count: 18 # Cop supports --auto-correct. # Configuration parameters: AllowNamedUnderscoreVariables. Style/TrailingUnderscoreVariable: Enabled: false -# Offense count: 76 +# Offense count: 78 # Cop supports --auto-correct. Style/TrailingWhitespace: Enabled: false -# Offense count: 2 +# Offense count: 3 # Cop supports --auto-correct. # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist. # Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym Style/TrivialAccessors: Enabled: false -# Offense count: 2 +# Offense count: 6 # Cop supports --auto-correct. Style/UnlessElse: Enabled: false -# Offense count: 14 +# Offense count: 24 # Cop supports --auto-correct. Style/UnneededInterpolation: Enabled: false diff --git a/.ruby-version b/.ruby-version index 2bf1c1ccf3..0bee604df7 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.3.1 +2.3.3 diff --git a/.scss-lint.yml b/.scss-lint.yml index 5093702519..83c68309fa 100644 --- a/.scss-lint.yml +++ b/.scss-lint.yml @@ -30,7 +30,7 @@ linters: # variable declarations. They should be referred to via variables everywhere # else. ColorVariable: - enabled: false + enabled: true # Which form of comments to prefer in CSS. Comment: @@ -143,7 +143,7 @@ linters: # with two colons. Pseudo-classes, like :hover and :first-child, should # be declared with one colon. PseudoElement: - enabled: false + enabled: true # Avoid qualifying elements in selectors (also known as "tag-qualifying"). QualifyingElement: @@ -172,7 +172,7 @@ linters: # Split selectors onto separate lines after each comma, and have each # individual selector occupy a single line. SingleLinePerSelector: - enabled: false + enabled: true # Commas in lists should be followed by a space. SpaceAfterComma: @@ -191,7 +191,7 @@ linters: # Variables should be formatted with a single space separating the colon # from the variable's value. SpaceAfterVariableColon: - enabled: false + enabled: true # Variables should be formatted with no space between the name and the # colon. @@ -201,7 +201,7 @@ linters: # Operators should be formatted with a single space on both sides of an # infix operator. SpaceAroundOperator: - enabled: false + enabled: true # Opening braces should be preceded by a single space. SpaceBeforeBrace: @@ -223,7 +223,7 @@ linters: # Reports lines containing trailing whitespace. TrailingWhitespace: - enabled: false + enabled: true # Don't write trailing zeros for numeric values with a decimal point. TrailingZero: diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c49f44f84..9a9aa6319c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,1934 @@ -Please view this file on the master branch, on stable branches it's out of date. +**Note:** This file is automatically generated. Please see the [developer +documentation](doc/development/changelog.md) for instructions on adding your own +entry. + +## 9.2.10 (2017-08-09) + +- Remove hidden symlinks from project import files. +- Disallow Git URLs that include a username or hostname beginning with a non-alphanumeric character. + +## 9.2.9 (2017-07-20) + +- Fix an infinite loop when handling user-supplied regular expressions. + +## 9.2.8 (2017-07-19) + +- Improve support for external issue references. !12485 +- Renders 404 if given project is not readable by the user on Todos dashboard. +- Fix incorrect project authorizations. +- Remove uploads/appearance symlink. A leftover from a previous migration. + +## 9.2.7 (2017-06-21) + +- Reinstate is_admin flag in users api when authenticated user is an admin. !12211 (rickettm) + +## 9.2.6 (2017-06-16) + +- Fix the last coverage in trace log should be extracted. !11128 (dosuken123) +- Respect merge, instead of push, permissions for protected actions. !11648 +- Fix pipeline_schedules pages throwing error 500. !11706 (dosuken123) +- Make backup task to continue on corrupt repositories. !11962 +- Fix incorrect ETag cache key when relative instance URL is used. !11964 +- Fix math rendering on blob pages. +- Invalidate cache for issue and MR counters more granularly. +- Fix terminals support for Kubernetes Service. +- Fix LFS timeouts when trying to save large files. +- Strip trailing whitespaces in submodule URLs. +- Make sure reCAPTCHA configuration is loaded when spam checks are initiated. +- Remove foreigh key on ci_trigger_schedules only if it exists. + +## 9.2.5 (2017-06-07) + +- No changes. + +## 9.2.4 (2017-06-02) + +- Fix visibility when referencing snippets. + +## 9.2.3 (2017-05-31) + +- Move uploads from 'public/uploads' to 'public/uploads/system'. +- Escapes html content before appending it to the DOM. +- Restrict API X-Frame-Options to same origin. +- Allow users autocomplete by author_id only for authenticated users. + +## 9.2.2 (2017-05-25) + +- Fix issue where real time pipelines were not cached. !11615 +- Make all notes use equal padding. + +## 9.2.1 (2017-05-23) + +- Fix placement of note emoji on hover. +- Fix migration for older PostgreSQL versions. + +## 9.2.0 (2017-05-22) + +- API: Filter merge requests by milestone and labels. (10924) +- Reset New branch button when issue state changes. !5962 (winniehell) +- Frontend prevent authored votes. !6260 (Barthc) +- Change issues list in MR to natural sorting. !7110 (Jeff Stubler) +- Add animations to all the dropdowns. !8419 +- Add update time to project lists. !8514 (Jeff Stubler) +- Remove view fragment caching for project READMEs. !8838 +- API: Add parameters to allow filtering project pipelines. !9367 (dosuken123) +- Database SSL support for backup script. !9715 (Guillaume Simon) +- Fix UI inconsistency different files view (find file button missing). !9847 (TM Lee) +- Display slash commands outcome when previewing Markdown. !10054 (Rares Sfirlogea) +- Resolve "Add more tests for spec/controllers/projects/builds_controller_spec.rb". !10244 (dosuken123) +- Add keyboard edit shotcut for wiki. !10245 (George Andrinopoulos) +- Redirect old links after renaming a user/group/project. !10370 +- Add system note on description change of issue/merge request. !10392 (blackst0ne) +- Improve validation of namespace & project paths. !10413 +- Add board_move slash command. !10433 (Alex Sanford) +- Update all instances of the old loading icon. !10490 (Andrew Torres) +- Implement protected manual actions. !10494 +- Implement search by extern_uid in Users API. !10509 (Robin Bobbitt) +- add support for .vue templates. !10517 +- Only add newlines between multiple uploads. !10545 +- Added balsamiq file viewer. !10564 +- Remove unnecessary test helpers includes. !10567 (Jacopo Beschi @jacopo-beschi) +- Add tooltip to header of Done board. !10574 (Andy Brown) +- Fix redundant cache expiration in Repository. !10575 (blackst0ne) +- Add hashie-forbidden_attributes gem. !10579 (Andy Brown) +- Add spec for schema.rb. !10580 (blackst0ne) +- Keep webpack-dev-server process functional across branch changes. !10581 +- Turns true value and false value database methods from instance to class methods. !10583 +- Improve text on todo list when the todo action comes from yourself. !10594 (Jacopo Beschi @jacopo-beschi) +- Replace rake cache:clear:db with an automatic mechanism. !10597 +- Remove heading and trailing spaces from label's color and title. !10603 (blackst0ne) +- Add webpack_bundle_tag helper to improve non-localhost GDK configurations. !10604 +- Added quick-update (fade-in) animation to newly rendered notes. !10623 +- Fix rendering emoji inside a string. !10647 (blackst0ne) +- Dockerfiles templates are imported from gitlab.com/gitlab-org/Dockerfile. !10663 +- Add support for i18n on Cycle Analytics page. !10669 +- Allow OAuth clients to push code. !10677 +- Add configurable timeout for git fetch and clone operations. !10697 +- Move labels of search results from bottom to title. !10705 (dr) +- Added build failures summary page for pipelines. !10719 +- Expand/collapse button -> Change to make it look like a toggle. !10720 (Jacopo Beschi @jacopo-beschi) +- Decrease ABC threshold to 57.08. !10724 (Rydkin Maxim) +- Removed target blank from the metrics action inside the environments list. !10726 +- Remove Repository#version method and tests. !10734 +- Refactor Admin::GroupsController#members_update method and add some specs. !10735 +- Refactor code that creates project/group members. !10735 +- Add Slack slash command api to services documentation and rearrange order and cases. !10757 (TM Lee) +- Disable test settings on chat notification services when repository is empty. !10759 +- Add support for instantly updating comments. !10760 +- Show checkmark on current assignee in assignee dropdown. !10767 +- Remove pipeline controls for last deployment from Environment monitoring page. !10769 +- Pipeline view updates in near real time. !10777 +- Fetch pipeline status in batch from redis. !10785 +- Add username to activity atom feed. !10802 (winniehell) +- Support Markdown previews for personal snippets. !10810 +- Implement ability to edit hooks. !10816 (Alexander Randa) +- Allow admins to sudo to blocked users via the API. !10842 +- Don't display the is_admin flag in most API responses. !10846 +- Refactor add_users method for project and group. !10850 +- Pipeline schedules got a new and improved UI. !10853 +- Fix updating merge_when_build_succeeds via merge API endpoint. !10873 +- Add index on ci_builds.user_id. !10874 (blackst0ne) +- Improves test settings for chat notification services for empty projects. !10886 +- Change Git commit command in Existing folder to git commit -m. !10900 (TM Lee) +- Show group name on flash container when group is created from Admin area. !10905 +- Make markdown tables thinner. !10909 (blackst0ne) +- Ensure namespace owner is Master of project upon creation. !10910 +- Updated CI status favicons to include the tanuki. !10923 +- Decrease Cyclomatic Complexity threshold to 16. !10928 (Rydkin Maxim) +- Replace header merge request icon. !10932 (blackst0ne) +- Fix error on CI/CD Settings page related to invalid pipeline trigger. !10948 (dosuken123) +- rickettm Add repo parameter to gitaly:install and workhorse:install rake tasks. !10979 (M. Ricketts) +- Generate and handle a gl_repository param to pass around components. !10992 +- Prevent 500 errors caused by testing the Prometheus service. !10994 +- Disable navigation to Project-level pages configuration when Pages disabled. !11008 +- Fix caching large snippet HTML content on MySQL databases. !11024 +- Hide external environment URL button on terminal page if URL is not defined. !11029 +- Always show the latest pipeline information in the commit box. !11038 +- Fix misaligned buttons in wiki pages. !11043 +- Colorize labels in search field. !11047 +- Sort the network graph both by commit date and topographically. !11057 +- Remove carriage returns from commit messages. !11077 +- Add tooltips to user contribution graph key. !11138 +- Add German translation for Cycle Analytics. !11161 +- Fix skipped manual actions problem when processing the pipeline. !11164 +- Fix cross referencing for private and internal projects. !11243 +- Add state to MR widget that prevent merges when branch changes after page load. !11316 +- Fixes the 500 when accessing customized appearance logos. !11479 (Alexis Reigel) +- Implement Users::BuildService. !30349 (George Andrinopoulos) +- Display comments for personal snippets. +- Support comments for personal snippets. +- Support uploaders for personal snippets comments. +- Handle incoming emails from aliases correctly. +- Re-rewrites pipeline graph in vue to support realtime data updates. +- Add issues/:iid/closed_by api endpoint. (mhasbini) +- Disallow merge requests from fork when source project have disabled merge requests. (mhasbini) +- Improved UX on project members settings view. +- Clear emoji search in awards menu after picking emoji. +- Cleanup markdown spacing. +- Separate CE params on Grape API. +- Allow to create new branch and empty WIP merge request from issue page. +- Prevent people from creating branches if they don't have persmission to push. +- Redesign auth 422 page. +- 29595 Update callout design. +- Detect already enabled DeployKeys in EnableDeployKeyService. +- Add transparent top-border to the hover state of done todos. +- Refactor all CI vue badges to use the same vue component. +- Update note edits in real-time. +- Add button to delete filters from filtered search bar. +- Added profile name to user dropdown. +- Display GitLab Pages status in Admin Dashboard. +- Fix label creation from issuable for subgroup projects. +- Vertically align mini pipeline stage container. +- prevent nav tabs from wrapping to new line. +- Fix environments vue architecture to match documentation. +- Enforce project features when searching blobs and wikis. +- fix inline diff copy in firefox. +- Note Ghost user and refer to user deletion documentation. +- Expose project statistics on single requests via the API. +- Job dropdown of pipeline mini graph updates in realtime when its opened. +- Add default margin-top to user request table on project members page. +- Add tooltips to note action buttons. +- Remove `#` being added on commit sha in MR widget. +- Remove spinner from loading comment. +- Fixes an issue preventing screen readers from reading some icons. +- Load milestone tabs asynchronously to increase initial load performance. +- [BB Importer] Save the error trace and the whole raw document to debug problems easier. +- Fixed branches dropdown rendering branch names as HTML. +- Make Asciidoc & other markup go through pipeline to prevent XSS. +- Validate URLs in markdown using URI to detect the host correctly. +- Side-by-side view in commits correcly expands full window width. +- Deploy keys load are loaded async. +- Fixed spacing of discussion submit buttons. +- Add hostname to usage ping. +- Allow usage ping to be disabled completely in gitlab.yml. +- Add artifact file page that uses the blob viewer. +- Add breadcrumb, build header and pipelines submenu to artifacts browser. +- Show Raw button as Download for binary files. +- Add Source/Rendered switch to blobs for SVG, Markdown, Asciidoc and other text files that can be rendered. +- Catch all URI errors in ExternalLinkFilter. +- Allow commenting on older versions of the diff and comparisons between diff versions. +- Paste a copied MR source branch name as code when pasted into a GFM form. +- Fix commenting on an existing discussion on an unchanged line that is no longer in the diff. +- Link to outdated diff in older MR version from outdated diff discussion. +- Bump Sidekiq to 5.0.0. +- Use blob viewers for snippets. +- Add download button to project snippets. +- Display video blobs in-line like images. +- Gracefully handle failures for incoming emails which do not match on the To header, and have no References header. +- Added title to award emoji buttons. +- Fixed alignment of empty task list items. +- Removed the target=_blank from the monitoring component to prevent opening a new tab. +- Fix new admin integrations not taking effect on existing projects. +- Prevent further repository corruption when resolving conflicts from a fork where both the fork and upstream projects require housekeeping. +- Add missing project attributes to Import/Export. +- Remove N+1 queries in processing MR references. +- Fixed wrong method call on notify_post_receive. (Luigi Leoni) +- Fixed search terms not correctly highlighting. +- Refactored the anchor tag to remove the trailing space in the target branch. +- Prevent user profile tabs to display raw json when going back and forward in browser history. +- Add index to webhooks type column. +- Change line-height on build-header so elements don't overlap. (Dino Maric) +- Fix dead link to GDK on the README page. (Dino Maric) +- Fixued preview shortcut focusing wrong preview tab. +- Issue assignees are now removed without loading unnecessary data into memory. +- Refactor backup/restore docs. +- Fixed group issues assignee dropdown loading all users. +- Fix for XSS in project import view caused by Hamlit filter usage. +- Fixed avatar not display on issue boards when Gravatar is disabled. +- Fixed create new label form in issue boards sidebar. +- Add realtime descriptions to issue show pages. +- Issue API change: assignee_id parameter and assignee object in a response have been deprecated. +- Fixed bug where merge request JSON would be displayed. +- Fixed Prometheus monitoring graphs not showing empty states in certain scenarios. +- Removed the milestone references from the milestone views. +- Show sizes correctly in merge requests when diffs overflow. +- Fix notify_only_default_branch check for Slack service. +- Make the `gitlab:gitlab_shell:check` task check that the repositories storage path are owned by the `root` group. +- Optimise pipelines.json endpoint. +- Pass docsUrl to pipeline schedules callout component. +- Fixed alignment of CI icon in issues related branches. +- Set the issuable sidebar to remain closed for mobile devices. +- Sanitize submodule URLs before linking to them in the file tree view. +- Upgrade Sidekiq to 4.2.10. +- Cache Routable#full_path in RequestStore to reduce duplicate route loads. +- Refactor snippets finder & dont return internal snippets for external users. +- Fix snippets visibility for show action - external users can not see internal snippets. +- Store retried in database for CI Builds. +- repository browser: handle submodule urls that don't end with .git. (David Turner) +- Fixed tags sort from defaulting to empty. +- Do not show private groups on subgroups page if user doesn't have access to. +- Make MR link in build sidebar bold. +- Unassign all Issues and Merge Requests when member leaves a team. +- Fix preemptive scroll bar on user activity calendar. +- Pipeline chat notifications convert seconds to minutes and hours. + +## 9.1.3 (2017-05-05) + +- Do not show private groups on subgroups page if user doesn't have access to. +- Enforce project features when searching blobs and wikis. +- Fixed branches dropdown rendering branch names as HTML. +- Make Asciidoc & other markup go through pipeline to prevent XSS. +- Validate URLs in markdown using URI to detect the host correctly. +- Fix for XSS in project import view caused by Hamlit filter usage. +- Sanitize submodule URLs before linking to them in the file tree view. +- Refactor snippets finder & dont return internal snippets for external users. +- Fix snippets visibility for show action - external users can not see internal snippets. + +## 9.1.2 (2017-05-01) + +- Add index on ci_runners.contacted_at. !10876 (blackst0ne) +- Fix pipeline events description for Slack and Mattermost integration. !10908 +- Fixed milestone sidebar showing incorrect number of MRs when collapsed. !10933 +- Fix ordering of commits in the network graph. !10936 +- Ensure the chat notifications service properly saves the "Notify only default branch" setting. !10959 +- Lazily sets UUID in ApplicationSetting for new installations. +- Skip validation when creating internal (ghost, service desk) users. +- Use GitLab Pages v0.4.1. + +## 9.1.1 (2017-04-26) + +- Add a transaction around move_issues_to_ghost_user. !10465 +- Properly expire cache for all MRs of a pipeline. !10770 +- Add sub-nav for Project Integration Services edit page. !10813 +- Fix missing duration for blocked pipelines. !10856 +- Fix lastest commit status text on main project page. !10863 +- Add index on ci_builds.updated_at. !10870 (blackst0ne) +- Fix 500 error due to trying to show issues from pending deleting projects. !10906 +- Ensures that OAuth/LDAP/SAML users don't need to be confirmed. +- Ensure replying to an individual note by email creates a note with its own discussion ID. +- Fix OAuth, LDAP and SAML SSO when regular sign-ups are disabled. +- Fix usage ping docs link from empty cohorts page. +- Eliminate N+1 queries in loading namespaces for every issuable in milestones. + +## 9.1.0 (2017-04-22) + +- Added merge requests empty state. !7342 +- Add option to start a new resolvable discussion in an MR. !7527 +- Hide form inputs for group member without editing rights. !7816 +- Create a new issue for a single discussion in a Merge Request. !8266 (Bob Van Landuyt) +- Adding non_archived scope for counting projects. !8305 (Naveen Kumar) +- Don't show links to tag a commit for users that are not permitted. !8407 +- New file from interface on existing branch. !8427 (Jacopo Beschi @jacopo-beschi) +- Strip reference prefixes on branch creation. !8498 (Matthieu Tardy) +- Support 2FA requirement per-group. !8763 (Markus Koller) +- Add Undo to Todos in the Done tab. !8782 (Jacopo Beschi @jacopo-beschi) +- Shows 'Go Back' link only when browser history is available. !9017 +- Implement user create service. !9220 (George Andrinopoulos) +- Incorporate Gitaly client for refs service. !9291 +- Cancel pending pipelines if commits not HEAD. !9362 (Rydkin Maxim) +- Add indication for closed or merged issuables in GFM. !9462 (Adam Buckland) +- Periodically clean up temporary upload files to recover storage space. !9466 (blackst0ne) +- Use toggle button to expand / collapse mulit-nested groups. !9501 +- Fixes dismissable error close is not visible enough. !9516 +- Fixes an issue in the new merge request form, where a tag would be selected instead of a branch when they have the same names. !9535 (Weiqing Chu) +- Expose CI/CD status API endpoints with Gitlab::Ci::Status facility on pipeline, job and merge request for favicon. !9561 (dosuken123) +- Use Gitaly for CommitController#show. !9629 +- Order milestone issues by position ascending in api. !9635 (George Andrinopoulos) +- Convert Issue into ES6 class. !9636 (winniehell) +- Link issuable reference to itself in meta-header. !9641 (mhasbini) +- Add ability to disable Merge Request URL on push. !9663 (Alex Sanford) +- ProjectsFinder should handle more options. !9682 (Jacopo Beschi @jacopo-beschi) +- Fix create issue form buttons are misaligned on mobile. !9706 (TM Lee) +- Labels support color names in backend. !9725 (Dongqing Hu) +- Standardize on core-js for es2015 polyfills. !9749 +- Fix GitHub Import deleting branches for open PRs from a fork. !9758 +- Do not show LFS object when LFS is disabled. !9779 (Christopher Bartz) +- Fix symlink icon in project tree. !9780 (mhasbini) +- Fix bug when system hook for deploy key. !9796 (billy.lb) +- Make authorized projects worker use a specific queue instead of the default one. !9813 +- Simplify trigger_docs build job for CE and EE. !9820 (winniehell) +- Add `aria-label` for feature status accessibility. !9830 +- Add dashboard and group milestones count badges. !9836 (Alex Braha Stoll) +- Use Gitaly for Repository#is_ancestor. !9864 +- After copying a diff file or blob path, pasting it into a comment field will format it as Markdown. !9876 +- Fix visibility level on new project page. !9885 (blackst0ne) +- Fix xml.updated field in rss/atom feeds. !9889 (blackst0ne) +- Add Undo mark all as done to Todos. !9890 (Jacopo Beschi @jacopo-beschi) +- Add a name field to the group form. !9891 (Douglas Lovell) +- Add custom attributes in factories. !9892 (George Andrinopoulos) +- Resolve project pipeline status caching problem on dashboard. !9895 +- Display error message when deleting tag in web UI fails. !9906 +- Add quick submit for snippet forms. !9911 (blackst0ne) +- New directory from interface on existing branch. !9921 (Jacopo Beschi @jacopo-beschi) +- Removes UJS from pipelines tables. !9929 +- Fix project title validation, prevent clicking on disabled button. !9931 +- Show correct user & creation time in heading of the pipeline page. !9936 +- Include time tracking attributes in webhooks payload. !9942 +- Add `requirements: { id: /.+/ }` for all projects and groups namespaced API routes. !9944 +- Improved UX for the environments metrics view. !9946 +- Remove whitespace in group links. !9947 (Xurxo Méndez Pérez) +- Adds Frontend Styleguide to documentation. !9961 +- Add metadata to system notes. !9964 +- When viewing old wiki page version, edit button should be disabled. !9966 (TM Lee) +- Added labels array to the issue web hook returned object. !9972 +- Upgrade VueJS to v2.2.4 and disable dev mode warnings. !9981 +- Only add code coverage instrumentation when generating coverage report. !9987 +- Fix Project Wiki update. !9990 (Dongqing Hu) +- Fix trigger webhook for ref with a dot. !10001 (George Andrinopoulos) +- Fix quick submit short-cut on preview tab for comments. !10002 +- Add option to receive email notifications about your own activity. !10032 (Richard Macklin) +- Rename 'All issues' to 'Open issues' in Add issues modal. !10042 (blackst0ne) +- Disable pipeline and environment actions that are not playable. !10052 +- Added clarification to the Jira integration documentation. !10066 (Matthew Bender) +- Move milestone summary content into the sidebar. !10096 +- Replace closing MR icon. !10103 (blackst0ne) +- Add support for multi-level container image repository names. !10109 (André Guede) +- Add ECMAScript polyfills for Symbol and Array.find. !10120 +- Add tooltip to user's calendar activities. !10123 (Alex Argunov) +- Resolve "Run CI/CD pipelines on a schedule" - "Basic backend implementation". !10133 (dosuken123) +- Change hint on first row of filters dropdown to `Press Enter or click to search`. !10138 +- Remove useless queries with false conditions (e.g 1=0). !10141 (mhasbini) +- Show CI status as Favicon on Pipelines, Job and MR pages. !10144 +- Update color palette to a more harmonious and consistent one. !10154 +- Add tooltip and accessibility for profile cover buttons. !10182 +- Change Done column to Closed in issue boards. !10198 (blackst0ne) +- Add metrics button to environments overview page. !10234 +- Force unlimited terminal size when checking processes via call to ps. !10246 (Sebastian Reitenbach) +- Fix sub-nav highlighting for `Environments` and `Jobs` pages. !10254 +- Drop support for correctly processing legacy pipelines. !10266 +- Fix project creation failure due to race condition in namespace directory creation. !10268 (Robin Bobbitt) +- Introduced error/empty states for the environments performance metrics. !10271 +- Improve performance of GitHub importer for large repositories. !10273 +- Introduce "polling_interval_multiplier" as application setting. !10280 +- Prevent users from disconnecting GitLab account from CAS. !10282 +- Clearly show who triggered the pipeline in email. !10283 +- Make user mentions case-insensitive. !10285 (blackst0ne) +- Update rugged to 0.25.1.1. !10286 (Elan Ruusamäe) +- Handle parsing OpenBSD ps output properly to display sidekiq infos on admin->monitoring->background. !10303 (Sebastian Reitenbach) +- Log errors during generating of Gitlab Pages to debug log. !10335 (Danilo Bargen) +- Update issue board cards design. !10353 +- Tags can be protected, restricting creation of matching tags by user role. !10356 +- Set GIT_TERMINAL_PROMPT env variable in initializer. !10372 +- Remove index for users.current sign in at. !10401 (blackst0ne) +- Include reopened MRs when searching for opened ones. !10407 +- Integrates Microsoft Teams webhooks with GitLab. !10412 +- Fix subgroup repository disappearance if group was moved. !10414 +- Add /-/readiness /-/liveness and /-/metrics endpoints to track application health. !10416 +- Changed capitalisation of buttons across GitLab. !10418 +- Fix blob highlighting in search. !10420 +- Add remove_concurrent_index to database helper. !10441 (blackst0ne) +- Fix wiki commit message. !10464 (blackst0ne) +- Deleting a user should not delete associated records. !10467 +- Include endpoint in metrics for ETag caching middleware. !10495 +- Change project view default for existing users and anonymous visitors to files+readme. !10498 +- Hide header counters for issue/mr/todos if zero. !10506 +- Remove the User#is_admin? method. !10520 (blackst0ne) +- Removed Milestone#is_empty?. !10523 (Jacopo Beschi @jacopo-beschi) +- Add UI for Trigger Schedule. !10533 (dosuken123) +- Add foreign key for ci_trigger_requests on ci_triggers. !10537 +- Upgrade webpack to v2.3.3 and webpack-dev-server to v2.4.2. !10552 +- Bugfix: POST /projects/:id/hooks and PUT /projects/:id/hook/:hook_id no longer ignore the the job_events param in the V4 API. !10586 +- Fix MR widget bug that merged a MR when Merge when pipeline succeeds was clicked via the dropdown. !10611 +- Hide new subgroup button if user has no permission to create one. !10627 +- Fix PlantUML integration in GFM. !10651 +- Show sub-nav under Merge Requests when issue tracker is non-default. !10658 +- Fix bad query for PostgreSQL showing merge requests list. !10666 +- Fix invalid encoding when showing some traces. !10681 +- Add lighter colors and fix existing light colors. !10690 +- Fix another case where trace does not have proper encoding set. !10728 +- Fix trace cannot be written due to encoding. !10758 +- Replace builds_enabled with jobs_enabled in projects API v4. !10786 (winniehell) +- Add retry to system hook worker. !10801 +- Fix error when an issue reference has a pending deleting project. !10843 +- Update permalink/blame buttons with line number fragment hash. +- Limit line length for project home page. +- Fix filtered search input width for IE. +- Update wikis_controller.rb to use strong params. +- Fix API group/issues default state filter. (Alexander Randa) +- Prevent builds dropdown to close when the user clicks in a build. +- Display all closed issues in “done” board list. +- Remove no-new annotation from file_template_mediator.js. +- Changed dropdown style slightly. +- Change gfm textarea to use monospace font. +- Prevent filtering issues by multiple Milestones or Authors. +- Recent search history for issues. +- Remove duplicated tokens in issuable search bar. +- Adds empty and error state to pipelines. +- Allow admin to view all namespaces. (George Andrinopoulos) +- allow offset query parameter for infinite list pages. +- Fix wrong message on starred projects filtering. (George Andrinopoulos) +- Adds pipeline mini-graph to system information box in Commit View. +- Remove confusing placeholder for JIRA transition_id. +- Remove extra margin at bottom of todos page. +- Add back expandable folder behavior. +- Create todos only for new mentions. +- Linking to blob edit page handles anonymous users and users without enough permissions to edit directly. +- Fix projects_limit RangeError on user create. (Alexander Randa) +- Add helpful icons to profile events. +- Refactor dropdown_milestone_spec.rb. (George Andrinopoulos) +- Fix alignment of resolve button. +- Change label for name on sign up form. +- Don’t show source project name when user does not have access. +- Update toggle buttons to be + + `).join('\n')} + + `; +} + +function AwardsHandler() { + this.eventListeners = []; + this.aliases = emojiAliases; + // If the user shows intent let's pre-build the menu + this.registerEventListener('one', $(document), 'mouseenter focus', '.js-add-award', 'mouseenter focus', () => { + const $menu = $('.emoji-menu'); + if ($menu.length === 0) { + requestAnimationFrame(() => { + this.createEmojiMenu(); }); - }; + } + // Prebuild the categoryMap + categoryMap = categoryMap || buildCategoryMap(); + }); + this.registerEventListener('on', $(document), 'click', '.js-add-award', (e) => { + e.stopPropagation(); + e.preventDefault(); + this.showEmojiMenu($(e.currentTarget)); + }); - AwardsHandler.prototype.positionMenu = function($menu, $addBtn) { - var css, position; - position = $addBtn.data('position'); - // The menu could potentially be off-screen or in a hidden overflow element - // So we position the element absolute in the body - css = { - top: ($addBtn.offset().top + $addBtn.outerHeight()) + "px" - }; - if ((position != null) && position === 'right') { - css.left = (($addBtn.offset().left - $menu.outerWidth()) + 20) + "px"; - $menu.addClass('is-aligned-right'); - } else { - css.left = ($addBtn.offset().left) + "px"; - $menu.removeClass('is-aligned-right'); + this.registerEventListener('on', $('html'), 'click', (e) => { + const $target = $(e.target); + if (!$target.closest('.emoji-menu-content').length) { + $('.js-awards-block.current').removeClass('current'); + } + if (!$target.closest('.emoji-menu').length) { + if ($('.emoji-menu').is(':visible')) { + $('.js-add-award.is-active').removeClass('is-active'); + $('.emoji-menu').removeClass('is-visible'); } - return $menu.css(css); - }; + } + }); + this.registerEventListener('on', $(document), 'click', '.js-emoji-btn', (e) => { + e.preventDefault(); + const $target = $(e.currentTarget); + const $glEmojiElement = $target.find('gl-emoji'); + const $spriteIconElement = $target.find('.icon'); + const emoji = ($glEmojiElement.length ? $glEmojiElement : $spriteIconElement).data('name'); - AwardsHandler.prototype.addAward = function(votesBlock, awardUrl, emoji, checkMutuality, callback) { - if (checkMutuality == null) { - checkMutuality = true; + $target.closest('.js-awards-block').addClass('current'); + this.addAward(this.getVotesBlock(), this.getAwardUrl(), emoji); + }); +} + +AwardsHandler.prototype.registerEventListener = function registerEventListener(method = 'on', element, ...args) { + element[method].call(element, ...args); + this.eventListeners.push({ + element, + args, + }); +}; + +AwardsHandler.prototype.showEmojiMenu = function showEmojiMenu($addBtn) { + if ($addBtn.hasClass('js-note-emoji')) { + $addBtn.closest('.note').find('.js-awards-block').addClass('current'); + } else { + $addBtn.closest('.js-awards-block').addClass('current'); + } + + const $menu = $('.emoji-menu'); + const $thumbsBtn = $menu.find('[data-name="thumbsup"], [data-name="thumbsdown"]').parent(); + const $userAuthored = this.isUserAuthored($addBtn); + if ($menu.length) { + if ($menu.is('.is-visible')) { + $addBtn.removeClass('is-active'); + $menu.removeClass('is-visible'); + $('.js-emoji-menu-search').blur(); + } else { + $addBtn.addClass('is-active'); + this.positionMenu($menu, $addBtn); + $menu.addClass('is-visible'); + $('.js-emoji-menu-search').focus(); + } + } else { + $addBtn.addClass('is-loading is-active'); + this.createEmojiMenu(() => { + const $createdMenu = $('.emoji-menu'); + $addBtn.removeClass('is-loading'); + this.positionMenu($createdMenu, $addBtn); + return setTimeout(() => { + $createdMenu.addClass('is-visible'); + $('.js-emoji-menu-search').focus(); + }, 200); + }); + } + + $thumbsBtn.toggleClass('disabled', $userAuthored); +}; + +// Create the emoji menu with the first category of emojis. +// Then render the remaining categories of emojis one by one to avoid jank. +AwardsHandler.prototype.createEmojiMenu = function createEmojiMenu(callback) { + if (this.isCreatingEmojiMenu) { + return; + } + this.isCreatingEmojiMenu = true; + + // Render the first category + categoryMap = categoryMap || buildCategoryMap(); + const categoryNameKey = Object.keys(categoryMap)[0]; + const emojisInCategory = categoryMap[categoryNameKey]; + const firstCategory = renderCategory(categoryLabelMap[categoryNameKey], emojisInCategory); + + // Render the frequently used + const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); + let frequentlyUsedCatgegory = ''; + if (frequentlyUsedEmojis.length > 0) { + frequentlyUsedCatgegory = renderCategory('Frequently used', frequentlyUsedEmojis, { + menuListClass: 'frequent-emojis', + }); + } + + const emojiMenuMarkup = ` +
+ + +
+ ${frequentlyUsedCatgegory} + ${firstCategory} +
+
+ `; + + document.body.insertAdjacentHTML('beforeend', emojiMenuMarkup); + + this.addRemainingEmojiMenuCategories(); + this.setupSearch(); + if (callback) { + callback(); + } +}; + +AwardsHandler + .prototype + .addRemainingEmojiMenuCategories = function addRemainingEmojiMenuCategories() { + if (this.isAddingRemainingEmojiMenuCategories) { + return; + } + this.isAddingRemainingEmojiMenuCategories = true; + + categoryMap = categoryMap || buildCategoryMap(); + + // Avoid the jank and render the remaining categories separately + // This will take more time, but makes UI more responsive + const menu = document.querySelector('.emoji-menu'); + const emojiContentElement = menu.querySelector('.emoji-menu-content'); + const remainingCategories = Object.keys(categoryMap).slice(1); + const allCategoriesAddedPromise = remainingCategories.reduce( + (promiseChain, categoryNameKey) => + promiseChain.then(() => + new Promise((resolve) => { + const emojisInCategory = categoryMap[categoryNameKey]; + const categoryMarkup = renderCategory( + categoryLabelMap[categoryNameKey], + emojisInCategory, + ); + requestAnimationFrame(() => { + emojiContentElement.insertAdjacentHTML('beforeend', categoryMarkup); + resolve(); + }); + }), + ), + Promise.resolve(), + ); + + allCategoriesAddedPromise.then(() => { + // Used for tests + // We check for the menu in case it was destroyed in the meantime + if (menu) { + menu.dispatchEvent(new CustomEvent('build-emoji-menu-finish')); } - emoji = this.normilizeEmojiName(emoji); - this.postEmoji(awardUrl, emoji, (function(_this) { - return function() { - _this.addAwardToEmojiBar(votesBlock, emoji, checkMutuality); - return typeof callback === "function" ? callback() : void 0; - }; - })(this)); - return $('.emoji-menu').removeClass('is-visible'); - }; + }).catch((err) => { + emojiContentElement.insertAdjacentHTML('beforeend', '

We encountered an error while adding the remaining categories

'); + throw new Error(`Error occurred in addRemainingEmojiMenuCategories: ${err.message}`); + }); + }; - AwardsHandler.prototype.addAwardToEmojiBar = function(votesBlock, emoji, checkForMutuality) { - var $emojiButton, counter; - if (checkForMutuality == null) { - checkForMutuality = true; - } - if (checkForMutuality) { - this.checkMutuality(votesBlock, emoji); - } - this.addEmojiToFrequentlyUsedList(emoji); - emoji = this.normilizeEmojiName(emoji); - $emojiButton = this.findEmojiIcon(votesBlock, emoji).parent(); - if ($emojiButton.length > 0) { - if (this.isActive($emojiButton)) { - return this.decrementCounter($emojiButton, emoji); - } else { - counter = $emojiButton.find('.js-counter'); - counter.text(parseInt(counter.text()) + 1); - $emojiButton.addClass('active'); - this.addYouToUserList(votesBlock, emoji); - return this.animateEmoji($emojiButton); - } - } else { - votesBlock.removeClass('hidden'); - return this.createEmoji(votesBlock, emoji); - } - }; +AwardsHandler.prototype.positionMenu = function positionMenu($menu, $addBtn) { + const position = $addBtn.data('position'); + // The menu could potentially be off-screen or in a hidden overflow element + // So we position the element absolute in the body + const css = { + top: `${$addBtn.offset().top + $addBtn.outerHeight()}px`, + }; + if (position === 'right') { + css.left = `${($addBtn.offset().left - $menu.outerWidth()) + 20}px`; + $menu.addClass('is-aligned-right'); + } else { + css.left = `${$addBtn.offset().left}px`; + $menu.removeClass('is-aligned-right'); + } + return $menu.css(css); +}; - AwardsHandler.prototype.getVotesBlock = function() { - var currentBlock; - currentBlock = $('.js-awards-block.current'); - if (currentBlock.length) { - return currentBlock; - } else { - return $('.js-awards-block').eq(0); - } - }; +AwardsHandler.prototype.addAward = function addAward( + votesBlock, + awardUrl, + emoji, + checkMutuality, + callback, +) { + const normalizedEmoji = this.normalizeEmojiName(emoji); + const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent(); + this.postEmoji($emojiButton, awardUrl, normalizedEmoji, () => { + this.addAwardToEmojiBar(votesBlock, normalizedEmoji, checkMutuality); + return typeof callback === 'function' ? callback() : undefined; + }); + $('.emoji-menu').removeClass('is-visible'); + $('.js-add-award.is-active').removeClass('is-active'); +}; - AwardsHandler.prototype.getAwardUrl = function() { - return this.getVotesBlock().data('award-url'); - }; - - AwardsHandler.prototype.checkMutuality = function(votesBlock, emoji) { - var $emojiButton, awardUrl, isAlreadyVoted, mutualVote; - awardUrl = this.getAwardUrl(); - if (emoji === 'thumbsup' || emoji === 'thumbsdown') { - mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup'; - $emojiButton = votesBlock.find("[data-emoji=" + mutualVote + "]").parent(); - isAlreadyVoted = $emojiButton.hasClass('active'); - if (isAlreadyVoted) { - this.addAward(votesBlock, awardUrl, mutualVote, false); - } - } - }; - - AwardsHandler.prototype.isActive = function($emojiButton) { - return $emojiButton.hasClass('active'); - }; - - AwardsHandler.prototype.decrementCounter = function($emojiButton, emoji) { - var counter, counterNumber; - counter = $('.js-counter', $emojiButton); - counterNumber = parseInt(counter.text(), 10); - if (counterNumber > 1) { - counter.text(counterNumber - 1); - this.removeYouFromUserList($emojiButton, emoji); - } else if (emoji === 'thumbsup' || emoji === 'thumbsdown') { - $emojiButton.tooltip('destroy'); - counter.text('0'); - this.removeYouFromUserList($emojiButton, emoji); - if ($emojiButton.parents('.note').length) { - this.removeEmoji($emojiButton); - } - } else { - this.removeEmoji($emojiButton); - } - return $emojiButton.removeClass('active'); - }; - - AwardsHandler.prototype.removeEmoji = function($emojiButton) { - var $votesBlock; - $emojiButton.tooltip('destroy'); - $emojiButton.remove(); - $votesBlock = this.getVotesBlock(); - if ($votesBlock.find('.js-emoji-btn').length === 0) { - return $votesBlock.addClass('hidden'); - } - }; - - AwardsHandler.prototype.getAwardTooltip = function($awardBlock) { - return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || ''; - }; - - AwardsHandler.prototype.toSentence = function(list) { - if(list.length <= 2){ - return list.join(' and '); - } - else{ - return list.slice(0, -1).join(', ') + ', and ' + list[list.length - 1]; - } - }; - - AwardsHandler.prototype.removeYouFromUserList = function($emojiButton, emoji) { - var authors, awardBlock, newAuthors, originalTitle; - awardBlock = $emojiButton; - originalTitle = this.getAwardTooltip(awardBlock); - authors = originalTitle.split(FROM_SENTENCE_REGEX); - authors.splice(authors.indexOf('You'), 1); - return awardBlock - .closest('.js-emoji-btn') - .removeData('title') - .removeAttr('data-title') - .removeAttr('data-original-title') - .attr('title', this.toSentence(authors)) - .tooltip('fixTitle'); - }; - - AwardsHandler.prototype.addYouToUserList = function(votesBlock, emoji) { - var awardBlock, origTitle, users; - awardBlock = this.findEmojiIcon(votesBlock, emoji).parent(); - origTitle = this.getAwardTooltip(awardBlock); - users = []; - if (origTitle) { - users = origTitle.trim().split(FROM_SENTENCE_REGEX); - } - users.unshift('You'); - return awardBlock - .attr('title', this.toSentence(users)) - .tooltip('fixTitle'); - }; - - AwardsHandler.prototype.createEmoji_ = function(votesBlock, emoji) { - var $emojiButton, buttonHtml, emojiCssClass; - emojiCssClass = this.resolveNameToCssClass(emoji); - buttonHtml = ""; - $emojiButton = $(buttonHtml); - $emojiButton.insertBefore(votesBlock.find('.js-award-holder')).find('.emoji-icon').data('emoji', emoji); +AwardsHandler.prototype.addAwardToEmojiBar = function addAwardToEmojiBar( + votesBlock, + emoji, + checkForMutuality, +) { + if (checkForMutuality || checkForMutuality === null) { + this.checkMutuality(votesBlock, emoji); + } + this.addEmojiToFrequentlyUsedList(emoji); + const normalizedEmoji = this.normalizeEmojiName(emoji); + const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent(); + if ($emojiButton.length > 0) { + if (this.isActive($emojiButton)) { + this.decrementCounter($emojiButton, normalizedEmoji); + } else { + const counter = $emojiButton.find('.js-counter'); + counter.text(parseInt(counter.text(), 10) + 1); + $emojiButton.addClass('active'); + this.addYouToUserList(votesBlock, normalizedEmoji); this.animateEmoji($emojiButton); - $('.award-control').tooltip(); - return votesBlock.removeClass('current'); - }; + } + } else { + votesBlock.removeClass('hidden'); + this.createEmoji(votesBlock, normalizedEmoji); + } +}; - AwardsHandler.prototype.animateEmoji = function($emoji) { - var className = 'pulse animated once short'; - $emoji.addClass(className); +AwardsHandler.prototype.getVotesBlock = function getVotesBlock() { + const currentBlock = $('.js-awards-block.current'); + let resultantVotesBlock = currentBlock; + if (currentBlock.length === 0) { + resultantVotesBlock = $('.js-awards-block').eq(0); + } - $emoji.on('webkitAnimationEnd animationEnd', function() { - $(this).removeClass(className); - }); - }; + return resultantVotesBlock; +}; - AwardsHandler.prototype.createEmoji = function(votesBlock, emoji) { - if ($('.emoji-menu').length) { - return this.createEmoji_(votesBlock, emoji); +AwardsHandler.prototype.getAwardUrl = function getAwardUrl() { + return this.getVotesBlock().data('award-url'); +}; + +AwardsHandler.prototype.checkMutuality = function checkMutuality(votesBlock, emoji) { + const awardUrl = this.getAwardUrl(); + if (emoji === 'thumbsup' || emoji === 'thumbsdown') { + const mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup'; + const $emojiButton = votesBlock.find(`[data-name="${mutualVote}"]`).parent(); + const isAlreadyVoted = $emojiButton.hasClass('active'); + if (isAlreadyVoted) { + this.addAward(votesBlock, awardUrl, mutualVote, false); + } + } +}; + +AwardsHandler.prototype.isActive = function isActive($emojiButton) { + return $emojiButton.hasClass('active'); +}; + +AwardsHandler.prototype.isUserAuthored = function isUserAuthored($button) { + return $button.hasClass('js-user-authored'); +}; + +AwardsHandler.prototype.decrementCounter = function decrementCounter($emojiButton, emoji) { + const counter = $('.js-counter', $emojiButton); + const counterNumber = parseInt(counter.text(), 10); + if (counterNumber > 1) { + counter.text(counterNumber - 1); + this.removeYouFromUserList($emojiButton); + } else if (emoji === 'thumbsup' || emoji === 'thumbsdown') { + $emojiButton.tooltip('destroy'); + counter.text('0'); + this.removeYouFromUserList($emojiButton); + if ($emojiButton.parents('.note').length) { + this.removeEmoji($emojiButton); + } + } else { + this.removeEmoji($emojiButton); + } + return $emojiButton.removeClass('active'); +}; + +AwardsHandler.prototype.removeEmoji = function removeEmoji($emojiButton) { + $emojiButton.tooltip('destroy'); + $emojiButton.remove(); + const $votesBlock = this.getVotesBlock(); + if ($votesBlock.find('.js-emoji-btn').length === 0) { + $votesBlock.addClass('hidden'); + } +}; + +AwardsHandler.prototype.getAwardTooltip = function getAwardTooltip($awardBlock) { + return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || ''; +}; + +AwardsHandler.prototype.toSentence = function toSentence(list) { + let sentence; + if (list.length <= 2) { + sentence = list.join(' and '); + } else { + sentence = `${list.slice(0, -1).join(', ')}, and ${list[list.length - 1]}`; + } + + return sentence; +}; + +AwardsHandler.prototype.removeYouFromUserList = function removeYouFromUserList($emojiButton) { + const awardBlock = $emojiButton; + const originalTitle = this.getAwardTooltip(awardBlock); + const authors = originalTitle.split(FROM_SENTENCE_REGEX); + authors.splice(authors.indexOf('You'), 1); + return awardBlock + .closest('.js-emoji-btn') + .removeData('title') + .removeAttr('data-title') + .removeAttr('data-original-title') + .attr('title', this.toSentence(authors)) + .tooltip('fixTitle'); +}; + +AwardsHandler.prototype.addYouToUserList = function addYouToUserList(votesBlock, emoji) { + const awardBlock = this.findEmojiIcon(votesBlock, emoji).parent(); + const origTitle = this.getAwardTooltip(awardBlock); + let users = []; + if (origTitle) { + users = origTitle.trim().split(FROM_SENTENCE_REGEX); + } + users.unshift('You'); + return awardBlock + .attr('title', this.toSentence(users)) + .tooltip('fixTitle'); +}; + +AwardsHandler + .prototype + .createAwardButtonForVotesBlock = function createAwardButtonForVotesBlock(votesBlock, emojiName) { + const buttonHtml = ` + + `; + const $emojiButton = $(buttonHtml); + $emojiButton.insertBefore(votesBlock.find('.js-award-holder')).find('.emoji-icon').data('name', emojiName); + this.animateEmoji($emojiButton); + $('.award-control').tooltip(); + votesBlock.removeClass('current'); + }; + +AwardsHandler.prototype.animateEmoji = function animateEmoji($emoji) { + const className = 'pulse animated once short'; + $emoji.addClass(className); + + this.registerEventListener('on', $emoji, animationEndEventString, (e) => { + $(e.currentTarget).removeClass(className); + }); +}; + +AwardsHandler.prototype.createEmoji = function createEmoji(votesBlock, emoji) { + if ($('.emoji-menu').length) { + this.createAwardButtonForVotesBlock(votesBlock, emoji); + } + this.createEmojiMenu(() => { + this.createAwardButtonForVotesBlock(votesBlock, emoji); + }); +}; + +AwardsHandler.prototype.postEmoji = function postEmoji($emojiButton, awardUrl, emoji, callback) { + if (this.isUserAuthored($emojiButton)) { + this.userAuthored($emojiButton); + } else { + $.post(awardUrl, { + name: emoji, + }, (data) => { + if (data.ok) { + callback(); } - return this.createEmojiMenu(this.getAwardMenuUrl(), (function(_this) { - return function() { - return _this.createEmoji_(votesBlock, emoji); - }; - })(this)); - }; + }).fail(() => new Flash('Something went wrong on our end.')); + } +}; - AwardsHandler.prototype.getAwardMenuUrl = function() { - return gon.award_menu_url; - }; +AwardsHandler.prototype.findEmojiIcon = function findEmojiIcon(votesBlock, emoji) { + return votesBlock.find(`.js-emoji-btn [data-name="${emoji}"]`); +}; - AwardsHandler.prototype.resolveNameToCssClass = function(emoji) { - var emojiIcon, unicodeName; - emojiIcon = $(".emoji-menu-content [data-emoji='" + emoji + "']"); - if (emojiIcon.length > 0) { - unicodeName = emojiIcon.data('unicode-name'); - } else { - // Find by alias - unicodeName = $(".emoji-menu-content [data-aliases*=':" + emoji + ":']").data('unicode-name'); - } - return "emoji-" + unicodeName; - }; +AwardsHandler.prototype.userAuthored = function userAuthored($emojiButton) { + const oldTitle = this.getAwardTooltip($emojiButton); + const newTitle = 'You cannot vote on your own issue, MR and note'; + gl.utils.updateTooltipTitle($emojiButton, newTitle).tooltip('show'); + // Restore tooltip back to award list + return setTimeout(() => { + $emojiButton.tooltip('hide'); + gl.utils.updateTooltipTitle($emojiButton, oldTitle); + }, 2800); +}; - AwardsHandler.prototype.postEmoji = function(awardUrl, emoji, callback) { - return $.post(awardUrl, { - name: emoji - }, function(data) { - if (data.ok) { - return callback(); - } - }); - }; +AwardsHandler.prototype.scrollToAwards = function scrollToAwards() { + const options = { + scrollTop: $('.awards').offset().top - 110, + }; + return $('body, html').animate(options, 200); +}; - AwardsHandler.prototype.findEmojiIcon = function(votesBlock, emoji) { - return votesBlock.find(".js-emoji-btn [data-emoji='" + emoji + "']"); - }; +AwardsHandler.prototype.normalizeEmojiName = function normalizeEmojiName(emoji) { + return Object.prototype.hasOwnProperty.call(this.aliases, emoji) ? this.aliases[emoji] : emoji; +}; - AwardsHandler.prototype.scrollToAwards = function() { - var options; - options = { - scrollTop: $('.awards').offset().top - 110 - }; - return $('body, html').animate(options, 200); - }; +AwardsHandler + .prototype + .addEmojiToFrequentlyUsedList = function addEmojiToFrequentlyUsedList(emoji) { + if (isEmojiNameValid(emoji)) { + this.frequentlyUsedEmojis = _.uniq(this.getFrequentlyUsedEmojis().concat(emoji)); + Cookies.set('frequently_used_emojis', this.frequentlyUsedEmojis.join(','), { expires: 365 }); + } + }; - AwardsHandler.prototype.normilizeEmojiName = function(emoji) { - return this.aliases[emoji] || emoji; - }; - - AwardsHandler.prototype.addEmojiToFrequentlyUsedList = function(emoji) { - var frequentlyUsedEmojis; - frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); - frequentlyUsedEmojis.push(emoji); - return $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), { - path: gon.relative_url_root || '/', - expires: 365 - }); - }; - - AwardsHandler.prototype.getFrequentlyUsedEmojis = function() { - var frequentlyUsedEmojis; - frequentlyUsedEmojis = ($.cookie('frequently_used_emojis') || '').split(','); - return _.compact(_.uniq(frequentlyUsedEmojis)); - }; - - AwardsHandler.prototype.renderFrequentlyUsedBlock = function() { - var emoji, frequentlyUsedEmojis, i, len, ul; - if ($.cookie('frequently_used_emojis')) { - frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); - ul = $("