New upstream version 12.2.8

This commit is contained in:
Sruthi Chandran 2019-10-12 21:52:04 +05:30
parent e7ff6cc2ae
commit fa176ca292
3607 changed files with 48534 additions and 20423 deletions

72
.dockerignore Normal file
View file

@ -0,0 +1,72 @@
# `build_from_dir` can't find Dockerfile when `.dockerignore` is "*"
# See https://github.com/swipely/docker-api/issues/484
# Ignore all folders except qa/, config/initializers and the root of lib/ since
# the files we need to build the QA image are in these folders.
# Following are the files we need:
# - ./config/initializers/0_inject_enterprise_edition_module.rb
# - ./lib/gitlab.rb
# - ./qa/
# - ./INSTALLATION_TYPE
# - ./VERSION
/app/
/bin/
/builds/
/changelogs/
/config/environments/
/config/helpers/
/config/knative/
/config/locales/
/config/prometheus/
/config/routes/
/danger/
/db/
/doc/
/docker/
/ee/
/fixtures/
/templates/
/lint/
/lib/api/
/lib/assets/
/lib/backup/
/lib/banzai/
/lib/bitbucket/
/lib/server/
/lib/constraints/
/lib/registry/
/lib/policy/
/lib/feature/
/lib/flowdock/
/lib/generators/
/lib/gitaly/
/lib/gitlab/
/lib/api/
/lib/token/
/lib/mattermost/
/lib/teams/
/lib/storage/
/lib/auth/
/lib/peek/
/lib/prometheus/
/lib/quality/
/lib/rouge/
/lib/flaky/
/lib/zip/
/lib/sentry/
/lib/serializers/
/lib/support/
/lib/check/
/lib/tasks/
/locale/
/log/
/modules/
/plugins/
/public/
/rubocop/
/scripts/
/shared/
/spec/
/symbol/
/tmp/
/vendor/

View file

@ -10,12 +10,15 @@ plugins:
- import - import
- html - html
- "@gitlab/i18n" - "@gitlab/i18n"
- "@gitlab/vue-i18n"
settings: settings:
import/resolver: import/resolver:
webpack: webpack:
config: './config/webpack.config.js' config: './config/webpack.config.js'
rules: rules:
"@gitlab/i18n/no-non-i18n-strings": error "@gitlab/i18n/no-non-i18n-strings": error
"@gitlab/vue-i18n/no-bare-strings": error
"@gitlab/vue-i18n/no-bare-attribute-strings": error
import/no-commonjs: error import/no-commonjs: error
no-underscore-dangle: no-underscore-dangle:
- error - error
@ -36,9 +39,6 @@ rules:
vue/use-v-on-exact: off vue/use-v-on-exact: off
overrides: overrides:
files: files:
# Vue is temporarily being disabled until the autofix errors are resolved
# Follow up issue https://gitlab.com/gitlab-org/gitlab-ce/issues/57969
- '*.vue'
- '**/spec/**/*' - '**/spec/**/*'
rules: rules:
"@gitlab/i18n/no-non-i18n-strings": off "@gitlab/i18n/no-non-i18n-strings": off

View file

@ -1,4 +1,4 @@
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.21-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.29" image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33"
variables: variables:
RAILS_ENV: "test" RAILS_ENV: "test"
@ -29,7 +29,6 @@ stages:
- qa - qa
- post-test - post-test
- pages - pages
- post-cleanup
include: include:
- local: .gitlab/ci/global.gitlab-ci.yml - local: .gitlab/ci/global.gitlab-ci.yml

View file

@ -1,16 +1,20 @@
# Backend Maintainers are the default for all ruby files # Backend Maintainers are the default for all ruby files
*.rb @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @mayra-cabrera @nick.thomas @rspeicher @rymai @reprazent @smcgivern @tkuah *.rb @gitlab-org/maintainers/rails-backend
*.rake @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @mayra-cabrera @nick.thomas @rspeicher @rymai @reprazent @smcgivern @tkuah *.rake @gitlab-org/maintainers/rails-backend
# Technical writing team are the default reviewers for everything in `doc/` # Technical writing team are the default reviewers for everything in `doc/`
/doc/ @axil @marcia @eread @mikelewis /doc/ @axil @marcia @eread @mikelewis
# Frontend maintainers should see everything in `app/assets/` # Frontend maintainers should see everything in `app/assets/`
app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter app/assets/ @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter
*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter *.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter
# Someone from the database team should review changes in `db/` # Maintainers from the Database team should review changes in `db/`
db/ @abrandl @NikolayS db/ @gl-database
lib/gitlab/background_migration/ @gl-database
lib/gitlab/database/ @gl-database
lib/gitlab/sql/ @gl-database
/ee/db/ @gl-database
# Feature specific owners # Feature specific owners
/ee/lib/gitlab/code_owners/ @reprazent /ee/lib/gitlab/code_owners/ @reprazent

View file

@ -15,7 +15,7 @@ review-docs-deploy-manual:
extends: extends:
- .review-docs - .review-docs
- .no-docs-and-no-qa - .no-docs-and-no-qa
stage: build stage: review
script: script:
- gem install gitlab --no-document - gem install gitlab --no-document
- ./$SCRIPT_NAME deploy - ./$SCRIPT_NAME deploy
@ -28,20 +28,20 @@ review-docs-deploy-manual:
# Useful to preview the docs changes live. # Useful to preview the docs changes live.
review-docs-deploy: review-docs-deploy:
<<: *review-docs <<: *review-docs
stage: post-test stage: review
script: script:
- gem install gitlab --no-document - gem install gitlab --no-document
- ./$SCRIPT_NAME deploy - ./$SCRIPT_NAME deploy
only: only:
- /(^docs[\/-].*|.*-docs$)/@gitlab-org/gitlab-ce - /(^docs[\/-].+|.+-docs$)/@gitlab-org/gitlab-ce
- /(^docs[\/-].*|.*-docs$)/@gitlab-org/gitlab-ee - /(^docs[\/-].+|.+-docs$)/@gitlab-org/gitlab-ee
except: except:
- /(^qa[\/-].*|.*-qa$)/ - /(^qa[\/-].*|.*-qa$)/
# Cleanup remote environment of gitlab-docs # Cleanup remote environment of gitlab-docs
review-docs-cleanup: review-docs-cleanup:
<<: *review-docs <<: *review-docs
stage: post-cleanup stage: review
environment: environment:
name: review-docs/$CI_COMMIT_REF_SLUG name: review-docs/$CI_COMMIT_REF_SLUG
action: stop action: stop
@ -62,7 +62,6 @@ docs lint:
before_script: [] before_script: []
script: script:
- scripts/lint-doc.sh - scripts/lint-doc.sh
- scripts/lint-changelog-yaml
- mv doc/ /tmp/gitlab-docs/content/$DOCS_GITLAB_REPO_SUFFIX - mv doc/ /tmp/gitlab-docs/content/$DOCS_GITLAB_REPO_SUFFIX
- cd /tmp/gitlab-docs - cd /tmp/gitlab-docs
# Lint Markdown # Lint Markdown

View file

@ -8,14 +8,14 @@
.use-pg: &use-pg .use-pg: &use-pg
services: services:
- name: postgres:9.6.11 - name: postgres:9.6.14
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
.gitlab:assets:compile-metadata: .gitlab:assets:compile-metadata:
<<: *assets-compile-cache <<: *assets-compile-cache
extends: .dedicated-no-docs-pull-cache-job extends: .dedicated-no-docs-pull-cache-job
image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-git-2.21-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.29-docker-18.06.1 image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-git-2.22-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-18.06.1
dependencies: dependencies:
- setup-test-env - setup-test-env
services: services:
@ -73,7 +73,7 @@ gitlab:assets:compile pull-cache:
refs: refs:
- master@gitlab-org/gitlab-ce - master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee - master@gitlab-org/gitlab-ee
- /(^docs[\/-].*|.*-docs$)/ - /(^docs[\/-].+|.+-docs$)/
.compile-assets-metadata: .compile-assets-metadata:
extends: .dedicated-runner extends: .dedicated-runner
@ -111,38 +111,7 @@ compile-assets pull-cache:
refs: refs:
- master@gitlab-org/gitlab-ce - master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee - master@gitlab-org/gitlab-ee
- /(^docs[\/-].*|.*-docs$)/ - /(^docs[\/-].+|.+-docs$)/
gitlab:ui:visual:
extends: .dedicated-runner
before_script: []
allow_failure: true
dependencies:
- compile-assets
- compile-assets pull-cache
script:
# Remove node modules from GitLab that may conflict with gitlab-ui
- rm -r node_modules
- git clone https://gitlab.com/gitlab-org/gitlab-ui.git
- cp public/assets/application-*.css gitlab-ui/styles/application.css
- cd gitlab-ui
- yarn install
- CSS_URL=./application.css yarn test
only:
changes:
- app/assets/stylesheets/*.scss
- app/assets/stylesheets/**/*.scss
- app/assets/stylesheets/**/**/*.scss
except:
refs:
- /(^docs[\/-].*|.*-docs$)/
- master
variables:
- $CI_COMMIT_MESSAGE =~ /\[skip visual\]/i
artifacts:
paths:
- gitlab-ui/tests/__image_snapshots__/
when: always
karma: karma:
extends: .dedicated-no-docs-pull-cache-job extends: .dedicated-no-docs-pull-cache-job
@ -168,8 +137,9 @@ karma:
paths: paths:
- chrome_debug.log - chrome_debug.log
- coverage-javascript/ - coverage-javascript/
# reports: - tmp/tests/frontend/
# junit: junit_karma.xml reports:
junit: junit_karma.xml
jest: jest:
extends: .dedicated-no-docs-and-no-qa-pull-cache-job extends: .dedicated-no-docs-and-no-qa-pull-cache-job
@ -181,7 +151,7 @@ jest:
script: script:
- scripts/gitaly-test-spawn - scripts/gitaly-test-spawn
- date - date
- bundle exec rake karma:fixtures - bundle exec rake frontend:fixtures
- date - date
- yarn jest --ci --coverage - yarn jest --ci --coverage
artifacts: artifacts:
@ -191,8 +161,9 @@ jest:
paths: paths:
- coverage-frontend/ - coverage-frontend/
- junit_jest.xml - junit_jest.xml
# reports: - tmp/tests/frontend/
# junit: junit_jest.xml reports:
junit: junit_jest.xml
cache: cache:
key: jest key: jest
paths: paths:
@ -237,15 +208,15 @@ qa:selectors:
qa-frontend-node:8: qa-frontend-node:8:
<<: *qa-frontend-node <<: *qa-frontend-node
image: node:8-alpine image: node:carbon
qa-frontend-node:10: qa-frontend-node:10:
<<: *qa-frontend-node <<: *qa-frontend-node
image: node:10-alpine image: node:dubnium
qa-frontend-node:latest: qa-frontend-node:latest:
<<: *qa-frontend-node <<: *qa-frontend-node
image: node:alpine image: node:latest
allow_failure: true allow_failure: true
lint:javascript:report: lint:javascript:report:

View file

@ -31,12 +31,12 @@
.no-docs: .no-docs:
except: except:
refs: refs:
- /(^docs[\/-].*|.*-docs$)/ - /(^docs[\/-].+|.+-docs$)/
.no-docs-and-no-qa: .no-docs-and-no-qa:
except: except:
refs: refs:
- /(^docs[\/-].*|.*-docs$)/ - /(^docs[\/-].+|.+-docs$)/
- /(^qa[\/-].*|.*-qa$)/ - /(^qa[\/-].*|.*-qa$)/
.dedicated-no-docs-pull-cache-job: .dedicated-no-docs-pull-cache-job:

View file

@ -33,7 +33,7 @@ memory-on-boot:
NODE_OPTIONS: --max_old_space_size=3584 NODE_OPTIONS: --max_old_space_size=3584
script: script:
# Both bootsnap and derailed monkey-patch Kernel#require, which leads to circular dependency # Both bootsnap and derailed monkey-patch Kernel#require, which leads to circular dependency
- DISABLE_BOOTSNAP=true PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> 'tmp/memory_on_boot.txt' - ENABLE_BOOTSNAP=false PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> 'tmp/memory_on_boot.txt'
- scripts/generate-memory-metrics-on-boot tmp/memory_on_boot.txt >> 'tmp/memory_on_boot_metrics.txt' - scripts/generate-memory-metrics-on-boot tmp/memory_on_boot.txt >> 'tmp/memory_on_boot_metrics.txt'
artifacts: artifacts:
paths: paths:

View file

@ -1,7 +1,6 @@
package-and-qa: .package-and-qa-base:
image: ruby:2.6-alpine image: ruby:2.6-alpine
stage: review # So even if review-deploy failed we can still run this stage: review # So even if review-deploy failed we can still run this
when: manual
before_script: [] before_script: []
dependencies: [] dependencies: []
cache: {} cache: {}
@ -13,5 +12,18 @@ package-and-qa:
- install_gitlab_gem - install_gitlab_gem
- ./scripts/trigger-build omnibus - ./scripts/trigger-build omnibus
only: only:
- /.+/@gitlab-org/gitlab-ce - branches@gitlab-org/gitlab-ce
- /.+/@gitlab-org/gitlab-ee - branches@gitlab-org/gitlab-ee
package-and-qa:
extends: .package-and-qa-base
when: manual
except:
- /(^qa[\/-].*|.*-qa$)/
package-and-qa-always:
extends: .package-and-qa-base
allow_failure: true
only:
- /(^qa[\/-].*|.*-qa$)/@gitlab-org/gitlab-ce
- /(^qa[\/-].*|.*-qa$)/@gitlab-org/gitlab-ee

View file

@ -1,12 +1,12 @@
.use-pg: &use-pg .use-pg: &use-pg
services: services:
- name: postgres:9.6.11 - name: postgres:9.6.14
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
.use-pg-10: &use-pg-10 .use-pg-10: &use-pg-10
services: services:
- name: postgres:10.7 - name: postgres:10.9
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
@ -80,8 +80,8 @@
- rspec_profiling/ - rspec_profiling/
- tmp/capybara/ - tmp/capybara/
- tmp/memory_test/ - tmp/memory_test/
# reports: reports:
# junit: junit_rspec.xml junit: junit_rspec.xml
.rspec-metadata-pg: &rspec-metadata-pg .rspec-metadata-pg: &rspec-metadata-pg
<<: *rspec-metadata <<: *rspec-metadata
@ -90,7 +90,7 @@
.rspec-metadata-pg-10: &rspec-metadata-pg-10 .rspec-metadata-pg-10: &rspec-metadata-pg-10
<<: *rspec-metadata <<: *rspec-metadata
<<: *use-pg-10 <<: *use-pg-10
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.21-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.29" image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
# DB migration, rollback, and seed jobs # DB migration, rollback, and seed jobs
.db-migrate-reset: &db-migrate-reset .db-migrate-reset: &db-migrate-reset
@ -207,7 +207,7 @@ downtime_check:
- master - master
- tags - tags
- /^[\d-]+-stable(-ee)?$/ - /^[\d-]+-stable(-ee)?$/
- /(^docs[\/-].*|.*-docs$)/ - /(^docs[\/-].+|.+-docs$)/
- /(^qa[\/-].*|.*-qa$)/ - /(^qa[\/-].*|.*-qa$)/
dependencies: dependencies:
- setup-test-env - setup-test-env
@ -223,6 +223,7 @@ ee_compat_check:
- /^security-/ - /^security-/
- branches@gitlab-org/gitlab-ee - branches@gitlab-org/gitlab-ee
- branches@gitlab/gitlab-ee - branches@gitlab/gitlab-ee
- /(^docs[\/-].+|.+-docs$)/
retry: 0 retry: 0
artifacts: artifacts:
name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}" name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}"

View file

@ -7,7 +7,8 @@
except: except:
refs: refs:
- master - master
- /(^docs[\/-].*|.*-docs$)/ - /^\d+-\d+-auto-deploy-\d+$/
- /(^docs[\/-].+|.+-docs$)/
.review-schedules-only: &review-schedules-only .review-schedules-only: &review-schedules-only
only: only:
@ -20,7 +21,7 @@
except: except:
refs: refs:
- tags - tags
- /(^docs[\/-].*|.*-docs$)/ - /(^docs[\/-].+|.+-docs$)/
.review-base: &review-base .review-base: &review-base
extends: .dedicated-runner extends: .dedicated-runner
@ -49,7 +50,7 @@ build-qa-image:
<<: *review-docker <<: *review-docker
stage: test stage: test
script: script:
- time docker build --cache-from ${LATEST_QA_IMAGE} --tag ${QA_IMAGE} ./qa/ - time docker build --cache-from ${LATEST_QA_IMAGE} --tag ${QA_IMAGE} --file ./qa/Dockerfile ./
- echo "${CI_JOB_TOKEN}" | docker login --username gitlab-ci-token --password-stdin ${CI_REGISTRY} - echo "${CI_JOB_TOKEN}" | docker login --username gitlab-ci-token --password-stdin ${CI_REGISTRY}
- time docker push ${QA_IMAGE} - time docker push ${QA_IMAGE}
@ -101,8 +102,7 @@ schedule:review-build-cng:
- install_tiller - install_tiller
- install_external_dns - install_external_dns
- download_chart - download_chart
- deploy || display_deployment_debug - deploy || (display_deployment_debug && exit 1)
- wait_for_review_app_to_be_accessible
- add_license - add_license
artifacts: artifacts:
paths: [review_app_url.txt] paths: [review_app_url.txt]
@ -117,17 +117,21 @@ schedule:review-deploy:
<<: *review-schedules-only <<: *review-schedules-only
review-stop: review-stop:
<<: *review-base <<: *review-only
extends: .single-script-job-dedicated-runner
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
stage: review stage: review
when: manual when: manual
allow_failure: true allow_failure: true
variables: variables:
GIT_DEPTH: "1" SCRIPT_NAME: review_apps/review-apps.sh
environment: environment:
<<: *review-environment <<: *review-environment
action: stop action: stop
script: script:
- source scripts/review_apps/review-apps.sh - wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/utils.sh
- source utils.sh
- source $(basename $SCRIPT_NAME)
- delete - delete
.review-qa-base: &review-qa-base .review-qa-base: &review-qa-base
@ -261,6 +265,7 @@ danger-review:
except: except:
refs: refs:
- master - master
- /^\d+-\d+-auto-deploy-\d+$/
- /^[\d-]+-stable(-ee)?$/ - /^[\d-]+-stable(-ee)?$/
variables: variables:
- $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/ - $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/

View file

@ -39,6 +39,7 @@ update-tests-metadata:
policy: push policy: push
script: script:
- retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document - retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document
- echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH}
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec_*_pg_node_*.json - scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec_*_pg_node_*.json
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH' - '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH'
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json - rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
@ -70,7 +71,7 @@ flaky-examples-check:
except: except:
refs: refs:
- master - master
- /(^docs[\/-].*|.*-docs$)/ - /(^docs[\/-].+|.+-docs$)/
- /(^qa[\/-].*|.*-qa$)/ - /(^qa[\/-].*|.*-qa$)/
artifacts: artifacts:
expire_in: 30d expire_in: 30d

View file

@ -6,4 +6,4 @@ lint-ci-gitlab:
dependencies: [] dependencies: []
image: sdesbure/yamllint:latest image: sdesbure/yamllint:latest
script: script:
- yamllint .gitlab-ci.yml .gitlab/ci lib/gitlab/ci/templates - yamllint .gitlab-ci.yml .gitlab/ci lib/gitlab/ci/templates changelogs

View file

@ -39,5 +39,6 @@ If applicable, any groups/projects that are happy to have this feature turned on
- [ ] Cross post chatops slack command to `#support_gitlab-com` and in your team channel - [ ] Cross post chatops slack command to `#support_gitlab-com` and in your team channel
- [ ] Announce on the issue that the flag has been enabled - [ ] Announce on the issue that the flag has been enabled
- [ ] Remove feature flag and add changelog entry - [ ] Remove feature flag and add changelog entry
- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
/label ~"feature flag" /label ~"feature flag"

View file

@ -26,7 +26,7 @@ Add all known Documentation Requirements here, per https://docs.gitlab.com/ee/de
### Testing ### Testing
<!-- What risks does this change pose? How might it affect the quality of the product? What additional test coverage or changes to tests will be needed? Will it require cross-browser testing? See the test engineering process for further guidelines: https://about.gitlab.com/handbook/engineering/quality/guidelines/test-engineering/ --> <!-- What risks does this change pose? How might it affect the quality of the product? What additional test coverage or changes to tests will be needed? Will it require cross-browser testing? See the test engineering process for further help: https://about.gitlab.com/handbook/engineering/quality/test-engineering/ -->
### What does success look like, and how can we measure that? ### What does success look like, and how can we measure that?

View file

@ -1,7 +1,7 @@
<!-- <!--
# Read me first! # Read me first!
Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X` Set the title to: `Security Release: 12.2.X, 12.1.X, and 12.0.X`
--> -->
## Releases tasks ## Releases tasks
@ -12,9 +12,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
## Version issues: ## Version issues:
* 11.4.X: {release task link} * 12.2.X: {release task link}
* 11.3.X: {release task link} * 12.1.X: {release task link}
* 11.2.X: {release task link} * 12.0.X: {release task link}
## Security Issues: ## Security Issues:
@ -34,9 +34,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
| Version | MR | | Version | MR |
|---------|----| |---------|----|
| 11.4 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} | | 12.2 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
| 11.3 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} | | 12.1 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
| 11.2 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} | | 12.0 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
| master | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} | | master | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
@ -48,9 +48,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
| Version | MR | | Version | MR |
|---------|----| |---------|----|
| 11.4| {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} | | 12.2 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
| 11.3 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} | | 12.1 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
| 11.2 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} | | 12.0 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
| master | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} | | master | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |

View file

@ -17,7 +17,7 @@ Set the title to: `Description of the original issue`
#### Backports #### Backports
- [ ] Once the MR is ready to be merged, create MRs targeting the last 3 releases, plus the current RC if between the 7th and 22nd of the month. - [ ] Once the MR is ready to be merged, create MRs targeting the latest 3 stable branches
- [ ] At this point, it might be easy to squash the commits from the MR into one - [ ] At this point, it might be easy to squash the commits from the MR into one
- You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation] - You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the "Security Release" merge request template. - [ ] Create each MR targeting the stable branch `X-Y-stable`, using the "Security Release" merge request template.

View file

@ -89,7 +89,7 @@ New end-to-end and integration tests (Selenium and API) should be added to the
Please note if automated tests already exist. Please note if automated tests already exist.
When adding new automated tests, please keep [testing levels](https://docs.gitlab.com/ce/development/testing_guide/testing_levels.html) When adding new automated tests, please keep [testing levels](https://docs.gitlab.com/ee/development/testing_guide/testing_levels.html)
in mind. in mind.
--> -->

View file

@ -39,20 +39,11 @@ When adding tables:
- [ ] Ordered columns based on the [Ordering Table Columns](https://docs.gitlab.com/ee/development/ordering_table_columns.html#ordering-table-columns) guidelines - [ ] Ordered columns based on the [Ordering Table Columns](https://docs.gitlab.com/ee/development/ordering_table_columns.html#ordering-table-columns) guidelines
- [ ] Added foreign keys to any columns pointing to data in other tables - [ ] Added foreign keys to any columns pointing to data in other tables
- [ ] Added indexes for fields that are used in statements such as WHERE, ORDER BY, GROUP BY, and JOINs - [ ] Added indexes for fields that are used in statements such as `WHERE`, `ORDER BY`, `GROUP BY`, and `JOIN`s
When removing columns, tables, indexes or other structures: When removing columns, tables, indexes or other structures:
- [ ] Removed these in a post-deployment migration - [ ] Removed these in a post-deployment migration
- [ ] Made sure the application no longer uses (or ignores) these structures - [ ] Made sure the application no longer uses (or ignores) these structures
## General checklist /label ~database ~"database::review pending"
- [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) added, if necessary
- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/)
- [ ] [Tests added for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html)
- [ ] Conforms to the [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)
- [ ] Conforms to the [merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)
- [ ] Conforms to the [style guides](https://docs.gitlab.com/ee/development/contributing/style_guides.html)
/label ~database

View file

@ -118,7 +118,6 @@ linters:
- Lint/ParenthesesAsGroupedExpression - Lint/ParenthesesAsGroupedExpression
- Lint/RedundantWithIndex - Lint/RedundantWithIndex
- Lint/SafeNavigationConsistency - Lint/SafeNavigationConsistency
- Lint/Syntax
- Metrics/BlockNesting - Metrics/BlockNesting
- Naming/VariableName - Naming/VariableName
- Performance/RedundantMatch - Performance/RedundantMatch
@ -155,6 +154,9 @@ linters:
enabled: true enabled: true
style: space style: space
Syntax:
enabled: true
Indentation: Indentation:
enabled: true enabled: true
character: space # or tab character: space # or tab

File diff suppressed because it is too large Load diff

View file

@ -5,12 +5,23 @@
# for more detailed information on the rules and styles. # for more detailed information on the rules and styles.
rule "MD001" rule "MD001"
rule "MD002"
rule "MD003", :style => :atx rule "MD003", :style => :atx
rule "MD006"
rule "MD010"
rule "MD011" rule "MD011"
rule "MD012"
rule "MD019"
rule "MD022"
rule "MD023" rule "MD023"
rule "MD025"
rule "MD028"
rule "MD029", :style => :one
rule "MD030"
rule "MD032" rule "MD032"
rule "MD034" rule "MD034"
rule "MD037" rule "MD037"
rule "MD038"
# Should not be used currently: # Should not be used currently:

View file

@ -7,3 +7,4 @@
# ignore stylesheets for now as this clashes with our linter # ignore stylesheets for now as this clashes with our linter
*.css *.css
*.scss *.scss
*.md

View file

@ -8,7 +8,7 @@ require:
- rubocop-rspec - rubocop-rspec
AllCops: AllCops:
TargetRubyVersion: 2.5 TargetRubyVersion: 2.6
TargetRailsVersion: 5.0 TargetRailsVersion: 5.0
Exclude: Exclude:
- 'vendor/**/*' - 'vendor/**/*'
@ -60,8 +60,8 @@ Style/FrozenStringLiteralComment:
RSpec/FilePath: RSpec/FilePath:
Exclude: Exclude:
- 'qa/**/*' - 'qa/**/*'
- 'spec/javascripts/fixtures/*' - 'spec/frontend/fixtures/*'
- 'ee/spec/javascripts/fixtures/*' - 'ee/spec/frontend/fixtures/*'
- 'spec/requests/api/v3/*' - 'spec/requests/api/v3/*'
Naming/FileName: Naming/FileName:

View file

@ -262,25 +262,6 @@ Naming/HeredocDelimiterNaming:
Naming/RescuedExceptionsVariableName: Naming/RescuedExceptionsVariableName:
Enabled: false Enabled: false
# Offense count: 6
# Cop supports --auto-correct.
Performance/InefficientHashSearch:
Exclude:
- 'app/controllers/concerns/sessionless_authentication.rb'
- 'app/models/note.rb'
- 'app/models/user_preference.rb'
- 'ee/app/models/ee/project.rb'
- 'lib/gitlab/import_export/members_mapper.rb'
- 'qa/spec/spec_helper.rb'
# Offense count: 3
# Cop supports --auto-correct.
Performance/ReverseEach:
Exclude:
- 'app/models/commit.rb'
- 'db/migrate/20190222051615_add_indexes_for_merge_request_diffs_query.rb'
- 'lib/gitlab/profiler.rb'
# Offense count: 7081 # Offense count: 7081
# Configuration parameters: Prefixes. # Configuration parameters: Prefixes.
# Prefixes: when, with, without # Prefixes: when, with, without

View file

@ -2,20 +2,20 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 12.1.14 ## 12.2.8
- No changes. - No changes.
## 12.1.13 ## 12.2.7
### Security (1 change) ### Security (1 change)
- Fix private feature Elasticsearch leak. - Fix private feature Elasticsearch leak.
## 12.1.12 ## 12.2.6
### Security (11 changes) ### Security (10 changes)
- Add a policy check for system notes that may not be visible due to cross references to private items. - Add a policy check for system notes that may not be visible due to cross references to private items.
- Display only participants that user has permission to see on milestone page. - Display only participants that user has permission to see on milestone page.
@ -24,32 +24,41 @@ entry.
- Prevent bypassing email verification using Salesforce. - Prevent bypassing email verification using Salesforce.
- Do not show resource label events referencing not accessible labels. - Do not show resource label events referencing not accessible labels.
- Cancel all running CI jobs triggered by the user who is just blocked. - Cancel all running CI jobs triggered by the user who is just blocked.
- Fix Gitaly SearchBlobs flag RPC injection. - Fix Gitaly SearchBlobs flag RPC injection [Gitaly v1.59.3].
- Only render fixed number of mermaid blocks. - Only render fixed number of mermaid blocks.
- Prevent GitLab accounts takeover if SAML is configured. - Prevent GitLab accounts takeover if SAML is configured.
- Upgrade mermaid to prevent XSS.
## 12.1.11 ## 12.2.5
- No changes.
## 12.1.10
- No changes.
## 12.1.9
### Security (1 change) ### Security (1 change)
- Upgrade pages to 1.7.2. - Upgrade pages to 1.7.2.
## 12.1.8 ## 12.2.4
### Security (21 changes) ### Fixed (7 changes)
- Add syntax highlighting for line expansion. !31821
- Fix issuable sidebar icon on notification disabled. !32134
- Upgrade Mermaid to v8.2.4. !32186
- Fix Piwik not working. !32234
- Fix snippets API not working with visibility level. !32286
- Fix upload URLs in Markdown for users without access to project repository. !32448
- Update Mermaid to v8.2.6. !32502
### Performance (1 change)
- Fix N+1 Gitaly calls in /api/v4/projects/:id/issues. !32171
## 12.2.3
### Security (22 changes)
- Ensure only authorised users can create notes on Merge Requests and Issues. - Ensure only authorised users can create notes on Merge Requests and Issues.
- Gitaly: ignore git redirects.
- Add :login_recaptcha_protection_enabled setting to prevent bots from brute-force attacks. - Add :login_recaptcha_protection_enabled setting to prevent bots from brute-force attacks.
- Speed up regexp in namespace format by failing fast after reaching maximum namespace depth. - Speed up regexp in namespace format by failing fast after reaching maximum namespace depth.
- Limit the size of issuable description and comments. - Limit the size of issuable description and comments.
@ -72,20 +81,270 @@ entry.
- Fix SSRF via DNS rebinding in Kubernetes Integration. - Fix SSRF via DNS rebinding in Kubernetes Integration.
## 12.1.7 ## 12.2.2
- Unreleased due to QA failure. - Unreleased due to QA failure.
## 12.1.6 ## 12.2.1
### Fixed (3 changes)
- Fix for embedded metrics undefined params. !31975
- Fix "ERR value is not an integer or out of range" errors. !32126
- Prevent duplicated trigger action button.
### Performance (1 change)
- Fix Gitaly N+1 calls with listing issues/MRs via API. !31938
## 12.2.0
### Security (4 changes, 1 of them is from the community)
- Update mini_magick to 4.9.5. !31505 (Takuya Noguchi)
- Upgrade Rugged to 0.28.3. !31794
- Queries for Upload should be scoped by model.
- Restrict slash commands to users who can log in.
### Removed (3 changes)
- Remove Kubernetes service integration page. !31365
- Remove line profiler from performance bar.
- Remove GC metrics from performance bar.
### Fixed (74 changes, 4 of them are from the community)
- Resolve Incorrect empty state message on Explore projects. !25578
- Search issuables by iids. !28302 (Riccardo Padovani)
- Make it easier to find invited group members. !28436
- fix: updates to include units for the y axis label. !30330
- Align access permissions for wiki history to those of wiki pages. !30470
- Add index for issues on relative position, project, and state for manual sorting. !30542
- Fix suggestion on lines that are not part of an MR. !30606
- Add empty chart component. !30682
- Remove blank block from job sidebar. !30754
- Remove duplicate buttons in diff discussion. !30757
- Order projects in 'Move issue' dropdown by name. !30778
- Fix bug in dashboard display of closed milestones. !30820
- Fixes alignment issues with reports. !30839
- Ensure visibility icons in group/project listings are grey. !30858
- Fix admin labels page when there are invalid records. !30885
- Extra logging for new live trace architecture. !30892
- Fix pipeline emails not respecting group notification email setting. !30907
- Handle trailing slashes when generating Jira issue URLs. !30911
- Optimize relative re-positioning when moving issues. !30938
- Better support clickable tasklists inside blockquotes. !30952
- Add space to "merged by" widget. !30972
- Remove duplicated mapping key in config/locales/en.yml. !30980 (Peter Dave Hello)
- Update Mermaid to v8.2.3. !30985
- Use persistent Redis cluster for Workhorse pub/sub notifications. !30990
- Remove :livesum from RubySampler metrics. !31047
- Fix pid discovery for Unicorn processes in `PidProvider`. !31056
- Respect group notification email when sending group access notifications. !31089
- Default dependency job stage index to Infinity, and correctly report it as undefined in prior stages. !31116
- Fix incorrect use of message interpolation. !31121
- Moved labels out of fields on Search page. !31137
- Ensure Warden triggers after_authentication callback. !31138
- Fix admin area user access level radio button labels. !31154
- Ignore Gitaly errors if cache flushing fails on project destruction. !31164
- Prevent double slash in review apps path. !31212
- Make pdf.js render CJK characters. !31220
- Prevent discussion filter from persisting to `Show all activity` when opening links to notes. !31229
- Improve layout of dropdowns in the metrics dashboard page. !31239
- Remove pdf.js deprecation warnings. !31253
- Fix GC::Profiler metrics fetching. !31331
- Jupyter fixes. !31332 (Amit Rathi)
- Fix first-time contributor notes not rendering. !31340
- Fix inline rendering of relative paths to SVGs from the current repository. !31352
- Make `bin/web_puma` consider RAILS_ENV. !31378
- Removed extrenal dashboard legend border. !31407
- Fix visual review app storage keys. !31427
- Fix flashing conflict warning when editing issues. !31469
- Fix broken issue links and possible 500 error on cycle analytics page when project name and path are different. !31471
- Prevent turning plain links into embedded when moving issues. !31489
- Add a field for released_at to GH importer. !31496
- Adjust size and align MR-widget loading icon. !31503
- Fix an issue where clicking outside the MR/branch search box in WebIDE closed the dropdown. !31523
- Don't attempt to contact registry if it is disabled. !31553
- Fix IDE new files icon in tree. !31560
- Fix missing author line (`Created by: <user>`) in MRs/issues/comments of imported Bitbucket Cloud project. !31579
- Add missing report-uri to CSP config. !31593
- Fixed display of some sections and externalized all text in the shortcuts modal overlay. !31594
- Remove extra padding from disabled comment box. !31603
- Allow CI to clone public projects when HTTP protocol is disabled. !31632
- error message for general settings. !31636 (Mesut Güneş)
- Invalidate branches cache on PostReceive. !31653
- Fix active metric files being wiped after the app starts. !31668
- Fix :wiki_can_not_be_created_total counter. !31673
- Fix job logs where style changes were broken down into separate lines. !31674
- Properly save suggestions in project exports. !31690
- Fix project avatar image in Slack pipeline notifications. !31788
- Fix empty error flash message on profile:account page when updating username with username that has already been taken. !31809
- Fix starrers counts after searching. !31823
- Fix pipelines not always being created after a push. !31927
- Fix 500 errors in commits api caused by empty ref_name parameter.
- Center loading icon in CI action component.
- Prevents showing 2 tooltips in pipelines table.
- Fix tag page layout.
- Prevent duplicated trigger action button.
- Hides loading spinner in pipelines actions after request has been fullfiled.
### Changed (31 changes, 5 of them are from the community)
- Update cluster page automatically when cluster is created. !27189
- Add branch/tags/commits dropdown filter on the search page for searching codes. !28282 (minghuan lei)
- Add support for start_sha to commits API. !29598
- Maintainers can create subgroups. !29718 (Fabio Papa)
- Extract Auto DevOps deploy functions into a base image. !30404
- Add MR form to Visual Review (EE) runtime configuration. !30481
- Adjust redis cache metrics. !30572
- Add DS_PIP_DEPENDENCY_PATH option to configure Dependency Scanning for projects using pip. !30762
- Bring scoped environment variables to core. !30779
- Add Web IDE Usage Ping for Create SMAU. !30800
- Update the container scanning CI template to use v12 of the clair scanner. !30809
- Multiple pipeline support for Commit status. !30828 (Gaetan Semet)
- Add support for exporting repository type data for LFS objects. !30830
- Avoid increasing redis counters when usage_ping is disabled. !30949
- Added navbar searches usage ping counter. !30953
- Convert githost.log to JSON format. !30967
- Adjusted the clickable area of collapsed sidebar elements. !30974 (Michel Engelen)
- Mark push mirrors as failed after 1 hour. !30999
- Allows masking @ and : characters. !31065
- Remove incorrect fallback when determining which cluster to use when retrieving MR performance metrics. !31126
- Retry push mirrors faster when running concurrently, improve error handling when push mirrors fail. !31247
- Make issue boards importable. !31434 (Jason Colyer)
- Allow users to resend a confirmation link when the grace period has expired. !31476
- Remove counts from default labels API responses. !31543
- Upgrade to Gitaly v1.57.0. !31568
- Rename githost.log -> git_json.log. !31634
- Load search result counts asynchronously. !31663
- feat: adds a download to csv functionality to the dropdown in prometheus metrics. !31679
- Adjust copy for adding additional members. !31726
- Upgrade to Gitaly v1.59.0. !31743
- Filter title, description, and body parameters from logs.
### Performance (17 changes, 1 of them is from the community)
- Add partial index on identities table to speed up LDAP lookups. !26710
- Improve MembersFinder query performance using UNION. !30451 (Jacopo Beschi @jacopo-beschi)
- Rake task to cleanup expired ActiveSession lookup keys. !30668
- Update usage ping cron behavior. !30842
- Make Bootsnap available via ENABLE_BOOTSNAP=1. !30963
- Batch processing of commit refs in markdown processing. !31037
- Use tablesample approximate counting by default. !31048
- Create index on environments by state. !31231
- Split MR widget into etag-cached and non-cached serializers. !31354
- Speed up loading and filtering deploy keys and their projects. !31384
- Only track Redis calls if Peek is enabled. !31438
- Only expire tag cache once per push. !31641
- Reduce Gitaly calls in PostReceive. !31741
- Eliminate many Gitaly calls in discussions API. !31834
- Optimize DB indexes for ES indexing of notes. !31846
- Expire project caches once per push instead of once per ref. !31876
- Look up upstream commits once before queuing ProcessCommitWorkers.
### Added (51 changes, 11 of them are from the community)
- Make starred projects and starrers of a project publicly visible. !24690
- Make quick action commands applied banner more useful. !26672 (Jacopo Beschi @jacopo-beschi)
- Allow Helm to be uninstalled from the UI. !27359
- Improve pipeline status Slack notifications. !27683
- Add links to relevant configuration areas in admin area overview. !29306
- Display project id on project admin page. !29734 (Zsolt Kovari)
- Display group id on group admin page. !29735 (Zsolt Kovari)
- Resolve Keyboard shortcut for jump to NEXT unresolved discussion. !30144
- Personal access tokens are accepted using OAuth2 header format. !30277
- Add Outbound requests whitelist for local networks. !30350 (Istvan Szalai)
- Allow multiple Auto DevOps projects to deploy to a single namespace within a k8s cluster. !30360 (James Keogh)
- Allow Knative to be uninstalled from the UI. !30458
- Add admin-configurable "Support page URL" link to top Help dropdown menu. !30459 (Diego Louzán)
- Allow specifying variables when running manual jobs. !30485
- Use predictable environment slugs. !30551
- Return an ETag header for the archive endpoint. !30581
- Add Rate Request Limiter to RawController#show endpoint. !30635
- Add git blame to GitLab API. !30675 (Oleg Zubchenko)
- Use separate Kubernetes namespaces per environment. !30711
- Support remove source branch on merge w/ push options. !30728
- Deploy serverless apps with gitlabktl. !30740
- Adjust group level analytics to accept multiple ids. !30744
- Adds event enum column to DesignsVersions join table. !30745
- Allow email notifications to be disabled for all members of a group or project. !30755 (Dustin Spicuzza)
- Export and download CSV from metrics charts. !30760
- Add API endpoints to return container repositories and tags from the group level. !30817
- Add support for deferred links in persistent user callouts. !30818
- Add system notes for when a Zoom call was added/removed from an issue. !30857 (Jacopo Beschi @jacopo-beschi)
- Count wiki creation, update and delete events. !30864
- Add new expansion options for merge request diffs. !30927
- Count snippet creation, update and comment events. !30930
- Update namespace label for GitLab-managed clusters. !30935
- UI for disabling group/project email notifications. !30961 (Dustin Spicuzza)
- Support setting of merge request title and description using git push options. !31068
- Add new table to store email domain per group. !31071
- Redirect from a project wiki git route to the project wiki home. !31085
- Link and embed metrics in GitLab Flavored Markdown. !31106
- Moves snowplow tracking from ee to ce. !31160 (jejacks0n)
- Allow Cert-Manager to be uninstalled. !31166
- Add new outbound network requests application setting for system hooks. !31177
- Allow links to metrics dashboard at a specific time. !31283
- Enable embedding of specific metrics charts in GFM. !31304
- Support creating DAGs in CI config through the `needs` key. !31328
- Generate shareable link for specific metric charts. !31339
- Add support for Content-Security-Policy. !31402
- Add BitBucketServer project import filtering. !31420
- Embed specific metrics chart in issue. !31644
- Track page views for cycle analytics show page. !31717
- Add usage pings for source code pushes. !31734
- Makes collapsible title clickable in job log.
- Adds highlight to the collapsible section.
### Other (36 changes, 9 of them are from the community)
- Rewrite `if:` argument in before_action and alike when `only:` is also used. !24412 (George Thomas @thegeorgeous)
- Create rake tasks for migrating legacy uploads out of deprecated paths. !29409
- Remove the warning style from the U2F device message in user settings > account. !30119 (matejlatin)
- Set visibility level 'Private' for restricted 'Internal' imported projects when 'Internal' visibility setting is restricted in admin settings. !30522
- Change BoardService in favor of boardsStore on board blank state of the component board. !30546 (eduarmreyes)
- Adds Sidekiq scheduling latency structured logging field. !30784
- Adds chaos endpoints to Sidekiq. !30814
- Added multi-select deletion of container registry images. !30837
- When GitLab import fails during importer user mapping step, add an explicit error message mentioning importer. !30838
- Add Rugged calls and duration to API and Rails logs. !30871
- Fixed distorted avatars when resource not reachable. !30904 (Marc Schwede)
- Update GitLab Runner Helm Chart to 0.7.0. !30950
- Use Rails 5.2 Redis caching store. !30966
- Add Rugged calls to performance bar. !30983
- add color selector to broadcast messages form. !30988
- Harmonize selections in user settings. !31110 (Marc Schwede)
- Update rouge to v3.7.0. !31254
- Update 'Ruby on Rails' project template. !31310
- Fix mirroring help text. !31348 (jramsay)
- Enhance style of the shared runners limit. !31386
- Enables storage statistics for root namespaces on database. !31392
- Improve quick action error messages. !31451
- Enable authenticated cookie encryption. !31463
- Update karma to 4.2.0. !31495 (Takuya Noguchi)
- Add max_replication_slots to PG HA documentation. !31534
- Create database tables for the new cycle analytics backend. !31621
- Updated the detached pipeline badge tooltip text to offer a better explanation. !31626
- Add Gitaly and Rugged call timing in Sidekiq logs. !31651
- Fix the style-lint errors and warnings for `app/assets/stylesheets/pages/wiki.scss`. !31656
- Update GraphicsMagick from 1.3.29 to 1.3.33 for CI tests. !31692 (Takuya Noguchi)
- Migrate remaining users with null private_profile. !31708
- Bump Helm to 2.14.3 and kubectl to 1.11.10 for Kubernetes integration. !31716
- Updated the personal access token api scope description to reflect the permissions it grants. !31759
- Add finished_at to the internal API Deployment entity. !31808
- Remove Security Dashboard feature flag. !31820
- Update Packer.gitlab-ci.yml to use latest image. (Kelly Hair)
## 12.1.5
### Security (2 changes) ### Security (2 changes)
- Upgrade Gitaly to 1.53.2 to prevent revision flag injection exploits. - Upgrade Gitaly to 1.53.2 to prevent revision flag injection exploits.
- Upgrade pages to 1.7.1 to prevent gitlab api token recovery from cookie. - Upgrade pages to 1.7.1 to prevent gitlab api token recovery from cookie.
## 12.1.5
- No changes.
## 12.1.4 ## 12.1.4
@ -415,6 +674,10 @@ entry.
- Removes EE differences for app/views/admin/users/show.html.haml. - Removes EE differences for app/views/admin/users/show.html.haml.
## 12.0.6
- No changes.
## 12.0.3 (2019-06-27) ## 12.0.3 (2019-06-27)
- No changes. - No changes.
@ -763,6 +1026,29 @@ entry.
- Moves snowplow to CE repo. - Moves snowplow to CE repo.
## 11.11.8
### Security (2 changes)
- Upgrade Gitaly to 1.42.7 to prevent revision flag injection exploits.
- Upgrade pages to 1.5.1 to prevent gitlab api token recovery from cookie.
## 11.11.7
### Security (9 changes)
- Restrict slash commands to users who can log in.
- Patch XSS issue in wiki links.
- Filter merge request params on the new merge request page.
- Fix Server Side Request Forgery mitigation bypass.
- Show badges if pipelines are public otherwise default to project permissions.
- Do not allow localhost url redirection in GitHub Integration.
- Do not show moved issue id for users that cannot read issue.
- Use source project as permissions reference for MergeRequestsController#pipelines.
- Drop feature to take ownership of trigger token.
## 11.11.4 (2019-06-26) ## 11.11.4 (2019-06-26)
### Fixed (3 changes) ### Fixed (3 changes)

View file

@ -1 +1 @@
1.53.4 1.59.3

View file

@ -1 +1 @@
8.7.1 8.8.1

36
Gemfile
View file

@ -2,6 +2,8 @@ source 'https://rubygems.org'
gem 'rails', '5.2.3' gem 'rails', '5.2.3'
gem 'bootsnap', '~> 1.4'
# Improves copy-on-write performance for MRI # Improves copy-on-write performance for MRI
gem 'nakayoshi_fork', '~> 0.0.4' gem 'nakayoshi_fork', '~> 0.0.4'
@ -14,8 +16,7 @@ gem 'sprockets', '~> 3.7.0'
gem 'default_value_for', '~> 3.2.0' gem 'default_value_for', '~> 3.2.0'
# Supported DBs # Supported DBs
gem 'mysql2', '~> 0.4.10', group: :mysql gem 'pg', '~> 1.1'
gem 'pg', '~> 1.1', group: :postgres
gem 'rugged', '~> 0.28' gem 'rugged', '~> 0.28'
gem 'grape-path-helpers', '~> 1.1' gem 'grape-path-helpers', '~> 1.1'
@ -50,6 +51,7 @@ gem 'jwt', '~> 2.1.0'
# Spam and anti-bot protection # Spam and anti-bot protection
gem 'recaptcha', '~> 4.11', require: 'recaptcha/rails' gem 'recaptcha', '~> 4.11', require: 'recaptcha/rails'
gem 'akismet', '~> 2.0' gem 'akismet', '~> 2.0'
gem 'invisible_captcha', '~> 0.12.1'
# Two-factor authentication # Two-factor authentication
gem 'devise-two-factor', '~> 3.0.0' gem 'devise-two-factor', '~> 3.0.0'
@ -133,10 +135,10 @@ gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 2.0.10' gem 'asciidoctor', '~> 2.0.10'
gem 'asciidoctor-include-ext', '~> 0.3.1', require: false gem 'asciidoctor-include-ext', '~> 0.3.1', require: false
gem 'asciidoctor-plantuml', '0.0.9' gem 'asciidoctor-plantuml', '0.0.9'
gem 'rouge', '~> 3.5' gem 'rouge', '~> 3.7'
gem 'truncato', '~> 0.7.11' gem 'truncato', '~> 0.7.11'
gem 'bootstrap_form', '~> 4.2.0' gem 'bootstrap_form', '~> 4.2.0'
gem 'nokogiri', '~> 1.10.3' gem 'nokogiri', '~> 1.10.4'
gem 'escape_utils', '~> 1.1' gem 'escape_utils', '~> 1.1'
# Calendar rendering # Calendar rendering
@ -169,7 +171,7 @@ gem 'acts-as-taggable-on', '~> 6.0'
gem 'sidekiq', '~> 5.2.7' gem 'sidekiq', '~> 5.2.7'
gem 'sidekiq-cron', '~> 1.0' gem 'sidekiq-cron', '~> 1.0'
gem 'redis-namespace', '~> 1.6.0' gem 'redis-namespace', '~> 1.6.0'
gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch' gem 'gitlab-sidekiq-fetcher', '0.5.1', require: 'sidekiq-reliable-fetch'
# Cron Parser # Cron Parser
gem 'fugit', '~> 1.2.1' gem 'fugit', '~> 1.2.1'
@ -199,13 +201,13 @@ gem 'js_regex', '~> 3.1'
# User agent parsing # User agent parsing
gem 'device_detector' gem 'device_detector'
# Cache
gem 'redis-rails', '~> 5.0.2'
# Redis # Redis
gem 'redis', '~> 3.2' gem 'redis', '~> 4.0'
gem 'connection_pool', '~> 2.0' gem 'connection_pool', '~> 2.0'
# Redis session store
gem 'redis-rails', '~> 5.0.2'
# Discord integration # Discord integration
gem 'discordrb-webhooks-blackst0ne', '~> 3.3', require: false gem 'discordrb-webhooks-blackst0ne', '~> 3.3', require: false
@ -282,7 +284,7 @@ gem 'sentry-raven', '~> 2.9'
gem 'premailer-rails', '~> 1.9.7' gem 'premailer-rails', '~> 1.9.7'
# LabKit: Tracing and Correlation # LabKit: Tracing and Correlation
gem 'gitlab-labkit', '~> 0.3.0' gem 'gitlab-labkit', '~> 0.4.2'
# I18n # I18n
gem 'ruby_parser', '~> 3.8', require: false gem 'ruby_parser', '~> 3.8', require: false
@ -295,11 +297,9 @@ gem 'batch-loader', '~> 1.4.0'
# Perf bar # Perf bar
gem 'peek', '~> 1.0.1' gem 'peek', '~> 1.0.1'
gem 'peek-gc', '~> 0.0.2'
gem 'peek-mysql2', '~> 1.2.0', group: :mysql # Snowplow events tracking
gem 'peek-pg', '~> 1.3.0', group: :postgres gem 'snowplow-tracker', '~> 0.6.1'
gem 'peek-rblineprof', '~> 0.2.0'
gem 'peek-redis', '~> 1.2.0'
# Memory benchmarks # Memory benchmarks
gem 'derailed_benchmarks', require: false gem 'derailed_benchmarks', require: false
@ -330,7 +330,6 @@ group :development do
end end
group :development, :test do group :development, :test do
gem 'bootsnap', '~> 1.4'
gem 'bullet', '~> 5.5.0', require: !!ENV['ENABLE_BULLET'] gem 'bullet', '~> 5.5.0', require: !!ENV['ENABLE_BULLET']
gem 'pry-byebug', '~> 3.5.1', platform: :mri gem 'pry-byebug', '~> 3.5.1', platform: :mri
gem 'pry-rails', '~> 0.3.4' gem 'pry-rails', '~> 0.3.4'
@ -391,7 +390,6 @@ group :test do
gem 'json-schema', '~> 2.8.0' gem 'json-schema', '~> 2.8.0'
gem 'webmock', '~> 3.5.1' gem 'webmock', '~> 3.5.1'
gem 'rails-controller-testing' gem 'rails-controller-testing'
gem 'sham_rack', '~> 1.3.6'
gem 'concurrent-ruby', '~> 1.1' gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 0.2.5' gem 'test-prof', '~> 0.2.5'
gem 'rspec_junit_formatter' gem 'rspec_junit_formatter'
@ -430,8 +428,8 @@ group :ed25519 do
gem 'bcrypt_pbkdf', '~> 1.0' gem 'bcrypt_pbkdf', '~> 1.0'
end end
# Gitaly GRPC client # Gitaly GRPC protocol definitions
gem 'gitaly-proto', '~> 1.37.0', require: 'gitaly' gem 'gitaly', '~> 1.58.0'
gem 'grpc', '~> 1.19.0' gem 'grpc', '~> 1.19.0'

View file

@ -76,7 +76,6 @@ GEM
asciidoctor-plantuml (0.0.9) asciidoctor-plantuml (0.0.9)
asciidoctor (>= 1.5.6, < 3.0.0) asciidoctor (>= 1.5.6, < 3.0.0)
ast (2.4.0) ast (2.4.0)
atomic (1.1.99)
attr_encrypted (3.1.0) attr_encrypted (3.1.0)
encryptor (~> 3.0.0) encryptor (~> 3.0.0)
attr_required (1.0.1) attr_required (1.0.1)
@ -101,7 +100,7 @@ GEM
binding_ninja (0.2.3) binding_ninja (0.2.3)
binding_of_caller (0.8.0) binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
bootsnap (1.4.1) bootsnap (1.4.4)
msgpack (~> 1.0) msgpack (~> 1.0)
bootstrap_form (4.2.0) bootstrap_form (4.2.0)
actionpack (>= 5.0) actionpack (>= 5.0)
@ -153,6 +152,7 @@ GEM
concurrent-ruby-ext (1.1.5) concurrent-ruby-ext (1.1.5)
concurrent-ruby (= 1.1.5) concurrent-ruby (= 1.1.5)
connection_pool (2.2.2) connection_pool (2.2.2)
contracts (0.11.0)
crack (0.4.3) crack (0.4.3)
safe_yaml (~> 1.0.0) safe_yaml (~> 1.0.0)
crass (1.0.4) crass (1.0.4)
@ -237,7 +237,7 @@ GEM
fast_blank (1.0.0) fast_blank (1.0.0)
fast_gettext (1.6.0) fast_gettext (1.6.0)
ffaker (2.10.0) ffaker (2.10.0)
ffi (1.10.0) ffi (1.11.1)
flipper (0.13.0) flipper (0.13.0)
flipper-active_record (0.13.0) flipper-active_record (0.13.0)
activerecord (>= 3.2, < 6) activerecord (>= 3.2, < 6)
@ -310,19 +310,19 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gitaly-proto (1.37.0) gitaly (1.58.0)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab-labkit (0.3.0) gitlab-labkit (0.4.2)
actionpack (~> 5) actionpack (~> 5)
activesupport (~> 5) activesupport (~> 5)
grpc (~> 1.19.0) grpc (~> 1.19)
jaeger-client (~> 0.10) jaeger-client (~> 0.10)
opentracing (~> 0.4) opentracing (~> 0.4)
gitlab-markup (1.7.0) gitlab-markup (1.7.0)
gitlab-sidekiq-fetcher (0.4.0) gitlab-sidekiq-fetcher (0.5.1)
sidekiq (~> 5) sidekiq (~> 5)
gitlab-styles (2.7.0) gitlab-styles (2.8.0)
rubocop (~> 0.69.0) rubocop (~> 0.69.0)
rubocop-gitlab-security (~> 0.1.0) rubocop-gitlab-security (~> 0.1.0)
rubocop-performance (~> 1.1.0) rubocop-performance (~> 1.1.0)
@ -438,11 +438,13 @@ GEM
influxdb (0.2.3) influxdb (0.2.3)
cause cause
json json
invisible_captcha (0.12.1)
rails (>= 3.2.0)
ipaddress (0.8.3) ipaddress (0.8.3)
jaeger-client (0.10.0) jaeger-client (0.10.0)
opentracing (~> 0.3) opentracing (~> 0.3)
thrift thrift
jaro_winkler (1.5.2) jaro_winkler (1.5.3)
jira-ruby (1.4.1) jira-ruby (1.4.1)
activesupport activesupport
multipart-post multipart-post
@ -523,27 +525,26 @@ GEM
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2019.0331) mime-types-data (3.2019.0331)
mimemagic (0.3.2) mimemagic (0.3.2)
mini_magick (4.8.0) mini_magick (4.9.5)
mini_mime (1.0.1) mini_mime (1.0.1)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
minitest (5.11.3) minitest (5.11.3)
mixlib-cli (1.7.0) mixlib-cli (1.7.0)
mixlib-config (2.2.18) mixlib-config (2.2.18)
tomlrb tomlrb
msgpack (1.2.10) msgpack (1.3.0)
multi_json (1.13.1) multi_json (1.13.1)
multi_xml (0.6.0) multi_xml (0.6.0)
multipart-post (2.0.0) multipart-post (2.0.0)
mustermann (1.0.3) mustermann (1.0.3)
mustermann-grape (1.0.0) mustermann-grape (1.0.0)
mustermann (~> 1.0.0) mustermann (~> 1.0.0)
mysql2 (0.4.10)
nakayoshi_fork (0.0.4) nakayoshi_fork (0.0.4)
net-ldap (0.16.0) net-ldap (0.16.0)
net-ssh (5.2.0) net-ssh (5.2.0)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.3.1) nio4r (2.3.1)
nokogiri (1.10.3) nokogiri (1.10.4)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
nokogumbo (1.5.0) nokogumbo (1.5.0)
nokogiri nokogiri
@ -643,25 +644,6 @@ GEM
concurrent-ruby (>= 0.9.0) concurrent-ruby (>= 0.9.0)
concurrent-ruby-ext (>= 0.9.0) concurrent-ruby-ext (>= 0.9.0)
railties (>= 4.0.0) railties (>= 4.0.0)
peek-gc (0.0.2)
peek
peek-mysql2 (1.2.0)
concurrent-ruby
concurrent-ruby-ext
mysql2
peek
peek-pg (1.3.0)
concurrent-ruby
concurrent-ruby-ext
peek
pg
peek-rblineprof (0.2.0)
peek
rblineprof
peek-redis (1.2.0)
atomic (>= 1.0.0)
peek
redis
pg (1.1.4) pg (1.1.4)
po_to_json (1.0.1) po_to_json (1.0.1)
json (>= 1.6.0) json (>= 1.6.0)
@ -760,17 +742,17 @@ GEM
recaptcha (4.13.1) recaptcha (4.13.1)
json json
recursive-open-struct (1.1.0) recursive-open-struct (1.1.0)
redis (3.3.5) redis (4.1.2)
redis-actionpack (5.0.2) redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6) actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3) redis-rack (>= 1, < 3)
redis-store (>= 1.1.0, < 2) redis-store (>= 1.1.0, < 2)
redis-activesupport (5.0.4) redis-activesupport (5.0.7)
activesupport (>= 3, < 6) activesupport (>= 3, < 6)
redis-store (>= 1.3, < 2) redis-store (>= 1.3, < 2)
redis-namespace (1.6.0) redis-namespace (1.6.0)
redis (>= 3.0.4) redis (>= 3.0.4)
redis-rack (2.0.4) redis-rack (2.0.5)
rack (>= 1.5, < 3) rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2) redis-store (>= 1.2, < 2)
redis-rails (5.0.2) redis-rails (5.0.2)
@ -796,7 +778,7 @@ GEM
retriable (3.1.2) retriable (3.1.2)
rinku (2.0.0) rinku (2.0.0)
rotp (2.1.2) rotp (2.1.2)
rouge (3.5.1) rouge (3.7.0)
rqrcode (0.7.0) rqrcode (0.7.0)
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
@ -856,7 +838,7 @@ GEM
ruby-fogbugz (0.2.1) ruby-fogbugz (0.2.1)
crack (~> 0.4) crack (~> 0.4)
ruby-prof (0.17.0) ruby-prof (0.17.0)
ruby-progressbar (1.10.0) ruby-progressbar (1.10.1)
ruby-saml (1.7.2) ruby-saml (1.7.2)
nokogiri (>= 1.5.10) nokogiri (>= 1.5.10)
ruby_parser (3.13.1) ruby_parser (3.13.1)
@ -864,7 +846,7 @@ GEM
rubyntlm (0.6.2) rubyntlm (0.6.2)
rubypants (0.2.0) rubypants (0.2.0)
rubyzip (1.2.2) rubyzip (1.2.2)
rugged (0.28.1) rugged (0.28.3.1)
safe_yaml (1.0.4) safe_yaml (1.0.4)
sanitize (4.6.6) sanitize (4.6.6)
crass (~> 1.0.2) crass (~> 1.0.2)
@ -900,8 +882,6 @@ GEM
faraday (>= 0.7.6, < 1.0) faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9) settingslogic (2.0.9)
sexp_processor (4.12.0) sexp_processor (4.12.0)
sham_rack (1.3.6)
rack
shoulda-matchers (4.0.1) shoulda-matchers (4.0.1)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
sidekiq (5.2.7) sidekiq (5.2.7)
@ -924,6 +904,8 @@ GEM
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.2) simplecov-html (0.10.2)
slack-notifier (1.5.1) slack-notifier (1.5.1)
snowplow-tracker (0.6.1)
contracts (~> 0.7, <= 0.11)
spring (2.0.2) spring (2.0.2)
activesupport (>= 4.2) activesupport (>= 4.2)
spring-commands-rspec (1.0.4) spring-commands-rspec (1.0.4)
@ -1119,11 +1101,11 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 1.37.0) gitaly (~> 1.58.0)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-labkit (~> 0.3.0) gitlab-labkit (~> 0.4.2)
gitlab-markup (~> 1.7.0) gitlab-markup (~> 1.7.0)
gitlab-sidekiq-fetcher (~> 0.4.0) gitlab-sidekiq-fetcher (= 0.5.1)
gitlab-styles (~> 2.7) gitlab-styles (~> 2.7)
gitlab_omniauth-ldap (~> 2.1.1) gitlab_omniauth-ldap (~> 2.1.1)
gon (~> 6.2) gon (~> 6.2)
@ -1149,6 +1131,7 @@ DEPENDENCIES
httparty (~> 0.16.4) httparty (~> 0.16.4)
icalendar icalendar
influxdb (~> 0.2) influxdb (~> 0.2)
invisible_captcha (~> 0.12.1)
jira-ruby (~> 1.4) jira-ruby (~> 1.4)
js_regex (~> 3.1) js_regex (~> 3.1)
json-schema (~> 2.8.0) json-schema (~> 2.8.0)
@ -1168,11 +1151,10 @@ DEPENDENCIES
mimemagic (~> 0.3.2) mimemagic (~> 0.3.2)
mini_magick mini_magick
minitest (~> 5.11.0) minitest (~> 5.11.0)
mysql2 (~> 0.4.10)
nakayoshi_fork (~> 0.0.4) nakayoshi_fork (~> 0.0.4)
net-ldap net-ldap
net-ssh (~> 5.2) net-ssh (~> 5.2)
nokogiri (~> 1.10.3) nokogiri (~> 1.10.4)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.9) octokit (~> 4.9)
omniauth (~> 1.8) omniauth (~> 1.8)
@ -1195,11 +1177,6 @@ DEPENDENCIES
omniauth_openid_connect (~> 0.3.1) omniauth_openid_connect (~> 0.3.1)
org-ruby (~> 0.9.12) org-ruby (~> 0.9.12)
peek (~> 1.0.1) peek (~> 1.0.1)
peek-gc (~> 0.0.2)
peek-mysql2 (~> 1.2.0)
peek-pg (~> 1.3.0)
peek-rblineprof (~> 0.2.0)
peek-redis (~> 1.2.0)
pg (~> 1.1) pg (~> 1.1)
premailer-rails (~> 1.9.7) premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.9.8) prometheus-client-mmap (~> 0.9.8)
@ -1223,12 +1200,12 @@ DEPENDENCIES
rdoc (~> 6.0) rdoc (~> 6.0)
re2 (~> 1.1.1) re2 (~> 1.1.1)
recaptcha (~> 4.11) recaptcha (~> 4.11)
redis (~> 3.2) redis (~> 4.0)
redis-namespace (~> 1.6.0) redis-namespace (~> 1.6.0)
redis-rails (~> 5.0.2) redis-rails (~> 5.0.2)
request_store (~> 1.3) request_store (~> 1.3)
responders (~> 2.0) responders (~> 2.0)
rouge (~> 3.5) rouge (~> 3.7)
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-parameterized rspec-parameterized
rspec-rails (~> 3.8.0) rspec-rails (~> 3.8.0)
@ -1252,13 +1229,13 @@ DEPENDENCIES
selenium-webdriver (~> 3.141) selenium-webdriver (~> 3.141)
sentry-raven (~> 2.9) sentry-raven (~> 2.9)
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6)
shoulda-matchers (~> 4.0.1) shoulda-matchers (~> 4.0.1)
sidekiq (~> 5.2.7) sidekiq (~> 5.2.7)
sidekiq-cron (~> 1.0) sidekiq-cron (~> 1.0)
simple_po_parser (~> 1.1.2) simple_po_parser (~> 1.1.2)
simplecov (~> 0.16.1) simplecov (~> 0.16.1)
slack-notifier (~> 1.5.1) slack-notifier (~> 1.5.1)
snowplow-tracker (~> 0.6.1)
spring (~> 2.0.0) spring (~> 2.0.0)
spring-commands-rspec (~> 1.0.4) spring-commands-rspec (~> 1.0.4)
sprockets (~> 3.7.0) sprockets (~> 3.7.0)

10
LICENSE
View file

@ -1,4 +1,12 @@
Copyright GitLab B.V. Copyright (c) 2011-present GitLab B.V.
Portions of this software are licensed as follows:
* All content residing under the "doc/" directory of this repository is licensed under "Creative Commons: CC BY-SA 4.0 license".
* All content that resides under the "ee/" directory of this repository, if that directory exists, is licensed under the license defined in "ee/LICENSE".
* All client-side JavaScript (when served directly or after being compiled, arranged, augmented, or combined), is licensed under the "MIT Expat" license.
* All third party components incorporated into the GitLab Software are licensed under the original license provided by the owner of the applicable component.
* Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -20,10 +20,6 @@ To see how GitLab looks please see the [features page on our website](https://ab
- Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises - Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises
- Completely free and open source (MIT Expat license) - Completely free and open source (MIT Expat license)
## Hiring
We're hiring developers, support people, and production engineers all the time, please see our [jobs page](https://about.gitlab.com/jobs/).
## Editions ## Editions
There are two editions of GitLab: There are two editions of GitLab:
@ -31,6 +27,15 @@ There are two editions of GitLab:
- GitLab Community Edition (CE) is available freely under the MIT Expat license. - GitLab Community Edition (CE) is available freely under the MIT Expat license.
- GitLab Enterprise Edition (EE) includes [extra features](https://about.gitlab.com/pricing/#compare-options) that are more useful for organizations with more than 100 users. To use EE and get official support please [become a subscriber](https://about.gitlab.com/pricing/). - GitLab Enterprise Edition (EE) includes [extra features](https://about.gitlab.com/pricing/#compare-options) that are more useful for organizations with more than 100 users. To use EE and get official support please [become a subscriber](https://about.gitlab.com/pricing/).
## Licensing
See the [LICENSE](LICENSE) file for licensing information as it pertains to
files in this repository.
## Hiring
We're hiring developers, support people, and production engineers all the time, please see our [jobs page](https://about.gitlab.com/jobs/).
## Website ## Website
On [about.gitlab.com](https://about.gitlab.com/) you can find more information about: On [about.gitlab.com](https://about.gitlab.com/) you can find more information about:
@ -58,14 +63,6 @@ There are various other options to install GitLab, please refer to the [installa
GitLab is an open source project and we are very happy to accept community contributions. Please refer to [Contributing to GitLab page](https://about.gitlab.com/contributing/) for more details. GitLab is an open source project and we are very happy to accept community contributions. Please refer to [Contributing to GitLab page](https://about.gitlab.com/contributing/) for more details.
## Licensing
GitLab Community Edition (CE) is available freely under the MIT Expat license.
All third party components incorporated into the GitLab Software are licensed under the original license provided by the owner of the applicable component.
All Documentation content that resides under the `doc/` directory of this repository is licensed under Creative Commons: CC BY-SA 4.0.
## Install a development environment ## Install a development environment
To work on GitLab itself, we recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit). To work on GitLab itself, we recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
@ -81,7 +78,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the
GitLab is a Ruby on Rails application that runs on the following software: GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL/OpenSUSE - Ubuntu/Debian/CentOS/RHEL/OpenSUSE
- Ruby (MRI) 2.4 - Ruby (MRI) 2.6.3
- Git 2.8.4+ - Git 2.8.4+
- Redis 2.8+ - Redis 2.8+
- PostgreSQL (preferred) or MySQL - PostgreSQL (preferred) or MySQL

View file

@ -1 +1 @@
12.1.14 12.2.8

View file

@ -0,0 +1 @@
export default {};

View file

@ -3,6 +3,8 @@ import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui'; import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
export default { export default {
// name: 'Badge' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/25
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
name: 'Badge', name: 'Badge',
components: { components: {
Icon, Icon,

View file

@ -2,6 +2,7 @@ import $ from 'jquery';
import syntaxHighlight from '~/syntax_highlight'; import syntaxHighlight from '~/syntax_highlight';
import renderMath from './render_math'; import renderMath from './render_math';
import renderMermaid from './render_mermaid'; import renderMermaid from './render_mermaid';
import renderMetrics from './render_metrics';
import highlightCurrentUser from './highlight_current_user'; import highlightCurrentUser from './highlight_current_user';
import initUserPopovers from '../../user_popovers'; import initUserPopovers from '../../user_popovers';
import initMRPopovers from '../../mr_popover'; import initMRPopovers from '../../mr_popover';
@ -17,6 +18,7 @@ $.fn.renderGFM = function renderGFM() {
highlightCurrentUser(this.find('.gfm-project_member').get()); highlightCurrentUser(this.find('.gfm-project_member').get());
initUserPopovers(this.find('.gfm-project_member').get()); initUserPopovers(this.find('.gfm-project_member').get());
initMRPopovers(this.find('.gfm-merge_request').get()); initMRPopovers(this.find('.gfm-merge_request').get());
renderMetrics(this.find('.js-render-metrics').get());
return this; return this;
}; };

View file

@ -0,0 +1,24 @@
import Vue from 'vue';
import Metrics from '~/monitoring/components/embed.vue';
import { createStore } from '~/monitoring/stores';
// TODO: Handle copy-pasting - https://gitlab.com/gitlab-org/gitlab-ce/issues/64369.
export default function renderMetrics(elements) {
if (!elements.length) {
return;
}
elements.forEach(element => {
const { dashboardUrl } = element.dataset;
const MetricsComponent = Vue.extend(Metrics);
// eslint-disable-next-line no-new
new MetricsComponent({
el: element,
store: createStore(),
propsData: {
dashboardUrl,
},
});
});
}

View file

@ -36,6 +36,10 @@ MarkdownPreview.prototype.showPreview = function($form) {
mdText = $form.find('textarea.markdown-area').val(); mdText = $form.find('textarea.markdown-area').val();
if (mdText === undefined) {
return;
}
if (mdText.trim().length === 0) { if (mdText.trim().length === 0) {
preview.text(this.emptyMessage); preview.text(this.emptyMessage);
this.hideReferencedUsers($form); this.hideReferencedUsers($form);

View file

@ -4,7 +4,7 @@ import Mousetrap from 'mousetrap';
import axios from '../../lib/utils/axios_utils'; import axios from '../../lib/utils/axios_utils';
import { refreshCurrentPage, visitUrl } from '../../lib/utils/url_utility'; import { refreshCurrentPage, visitUrl } from '../../lib/utils/url_utility';
import findAndFollowLink from '../../lib/utils/navigation_utility'; import findAndFollowLink from '../../lib/utils/navigation_utility';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean, getCspNonceValue } from '~/lib/utils/common_utils';
const defaultStopCallback = Mousetrap.stopCallback; const defaultStopCallback = Mousetrap.stopCallback;
Mousetrap.stopCallback = (e, element, combo) => { Mousetrap.stopCallback = (e, element, combo) => {
@ -94,7 +94,7 @@ export default class Shortcuts {
responseType: 'text', responseType: 'text',
}) })
.then(({ data }) => { .then(({ data }) => {
$.globalEval(data); $.globalEval(data, { nonce: getCspNonceValue() });
if (location && location.length > 0) { if (location && location.length > 0) {
const results = []; const results = [];

View file

@ -6,6 +6,8 @@ export default class ShortcutsWiki extends ShortcutsNavigation {
constructor() { constructor() {
super(); super();
Mousetrap.bind('e', ShortcutsWiki.editWiki); Mousetrap.bind('e', ShortcutsWiki.editWiki);
this.enabledHelp.push('.hidden-shortcut.wiki');
} }
static editWiki() { static editWiki() {

View file

@ -1,6 +1,6 @@
<script> <script>
import { __ } from '~/locale'; import { __ } from '~/locale';
/* global ListLabel */ import ListLabel from '~/boards/models/label';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
@ -30,13 +30,17 @@ export default {
}); });
// Save the labels // Save the labels
gl.boardService boardsStore
.generateDefaultLists() .generateDefaultLists()
.then(res => res.data) .then(res => res.data)
.then(data => { .then(data => {
data.forEach(listObj => { data.forEach(listObj => {
const list = boardsStore.findList('title', listObj.title); const list = boardsStore.findList('title', listObj.title);
if (!list) {
return;
}
list.id = listObj.id; list.id = listObj.id;
list.label.id = listObj.label.id; list.label.id = listObj.label.id;
list.getIssues().catch(() => { list.getIssues().catch(() => {
@ -69,8 +73,7 @@ export default {
<span <span
:style="{ backgroundColor: label.color }" :style="{ backgroundColor: label.color }"
class="label-color position-relative d-inline-block rounded" class="label-color position-relative d-inline-block rounded"
> ></span>
</span>
{{ label.title }} {{ label.title }}
</li> </li>
</ul> </ul>

View file

@ -1,4 +1,5 @@
<script> <script>
import { __ } from '~/locale';
import Flash from '~/flash'; import Flash from '~/flash';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue'; import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
@ -86,12 +87,12 @@ export default {
}, },
buttonText() { buttonText() {
if (this.isNewForm) { if (this.isNewForm) {
return 'Create board'; return __('Create board');
} }
if (this.isDeleteForm) { if (this.isDeleteForm) {
return 'Delete'; return __('Delete');
} }
return 'Save changes'; return __('Save changes');
}, },
buttonKind() { buttonKind() {
if (this.isNewForm) { if (this.isNewForm) {
@ -104,15 +105,15 @@ export default {
}, },
title() { title() {
if (this.isNewForm) { if (this.isNewForm) {
return 'Create new board'; return __('Create new board');
} }
if (this.isDeleteForm) { if (this.isDeleteForm) {
return 'Delete board'; return __('Delete board');
} }
if (this.readonly) { if (this.readonly) {
return 'Board scope'; return __('Board scope');
} }
return 'Edit board'; return __('Edit board');
}, },
readonly() { readonly() {
return !this.canAdminBoard; return !this.canAdminBoard;
@ -138,7 +139,7 @@ export default {
visitUrl(boardsStore.rootPath); visitUrl(boardsStore.rootPath);
}) })
.catch(() => { .catch(() => {
Flash('Failed to delete board. Please try again.'); Flash(__('Failed to delete board. Please try again.'));
this.isLoading = false; this.isLoading = false;
}); });
} else { } else {
@ -149,7 +150,7 @@ export default {
visitUrl(data.board_path); visitUrl(data.board_path);
}) })
.catch(() => { .catch(() => {
Flash('Unable to save your changes. Please try again.'); Flash(__('Unable to save your changes. Please try again.'));
this.isLoading = false; this.isLoading = false;
}); });
} }
@ -182,17 +183,19 @@ export default {
@submit="submit" @submit="submit"
> >
<template slot="body"> <template slot="body">
<p v-if="isDeleteForm">Are you sure you want to delete this board?</p> <p v-if="isDeleteForm">{{ __('Are you sure you want to delete this board?') }}</p>
<form v-else class="js-board-config-modal" @submit.prevent> <form v-else class="js-board-config-modal" @submit.prevent>
<div v-if="!readonly" class="append-bottom-20"> <div v-if="!readonly" class="append-bottom-20">
<label class="form-section-title label-bold" for="board-new-name"> Board name </label> <label class="form-section-title label-bold" for="board-new-name">{{
__('Board name')
}}</label>
<input <input
id="board-new-name" id="board-new-name"
ref="name" ref="name"
v-model="board.name" v-model="board.name"
class="form-control" class="form-control"
type="text" type="text"
placeholder="Enter board name" :placeholder="__('Enter board name')"
@keyup.enter="submit" @keyup.enter="submit"
/> />
</div> </div>

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import Sortable from 'sortablejs'; import Sortable from 'sortablejs';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import boardNewIssue from './board_new_issue.vue'; import boardNewIssue from './board_new_issue.vue';

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { __ } from '~/locale'; import { __ } from '~/locale';
import ModalFilters from './filters'; import ModalFilters from './filters';
import ModalTabs from './tabs.vue'; import ModalTabs from './tabs.vue';

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import ModalStore from '../../stores/modal_store'; import ModalStore from '../../stores/modal_store';
import modalMixin from '../../mixins/modal_mixins'; import modalMixin from '../../mixins/modal_mixins';

View file

@ -68,13 +68,15 @@ export default {
<li> <li>
<a href='#' class='dropdown-menu-link' data-project-id="${ <a href='#' class='dropdown-menu-link' data-project-id="${
project.id project.id
}" data-project-name="${project.name}"> }" data-project-name="${project.name}" data-project-name-with-namespace="${
${_.escape(project.name)} project.name_with_namespace
}">
${_.escape(project.name_with_namespace)}
</a> </a>
</li> </li>
`; `;
}, },
text: project => project.name, text: project => project.name_with_namespace,
}); });
}, },
}; };

View file

@ -0,0 +1,7 @@
export const setPromotionState = () => {};
export const setWeigthFetchingState = () => {};
export const setEpicFetchingState = () => {};
export const getMilestoneTitle = () => ({});
export const getBoardsModalData = () => ({});

View file

@ -30,6 +30,13 @@ import {
} from '~/lib/utils/common_utils'; } from '~/lib/utils/common_utils';
import boardConfigToggle from 'ee_else_ce/boards/config_toggle'; import boardConfigToggle from 'ee_else_ce/boards/config_toggle';
import toggleFocusMode from 'ee_else_ce/boards/toggle_focus'; import toggleFocusMode from 'ee_else_ce/boards/toggle_focus';
import {
setPromotionState,
setWeigthFetchingState,
setEpicFetchingState,
getMilestoneTitle,
getBoardsModalData,
} from 'ee_else_ce/boards/ee_functions';
import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher'; import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher';
let issueBoardsApp; let issueBoardsApp;
@ -129,6 +136,7 @@ export default () => {
}); });
boardsStore.addBlankState(); boardsStore.addBlankState();
setPromotionState(boardsStore);
this.loading = false; this.loading = false;
}) })
.catch(() => { .catch(() => {
@ -143,6 +151,8 @@ export default () => {
const { sidebarInfoEndpoint } = newIssue; const { sidebarInfoEndpoint } = newIssue;
if (sidebarInfoEndpoint && newIssue.subscribed === undefined) { if (sidebarInfoEndpoint && newIssue.subscribed === undefined) {
newIssue.setFetchingState('subscriptions', true); newIssue.setFetchingState('subscriptions', true);
setWeigthFetchingState(newIssue, true);
setEpicFetchingState(newIssue, true);
BoardService.getIssueInfo(sidebarInfoEndpoint) BoardService.getIssueInfo(sidebarInfoEndpoint)
.then(res => res.data) .then(res => res.data)
.then(data => { .then(data => {
@ -157,6 +167,8 @@ export default () => {
} = convertObjectPropsToCamelCase(data); } = convertObjectPropsToCamelCase(data);
newIssue.setFetchingState('subscriptions', false); newIssue.setFetchingState('subscriptions', false);
setWeigthFetchingState(newIssue, false);
setEpicFetchingState(newIssue, false);
newIssue.updateData({ newIssue.updateData({
humanTimeSpent: humanTotalTimeSpent, humanTimeSpent: humanTotalTimeSpent,
timeSpent: totalTimeSpent, timeSpent: totalTimeSpent,
@ -169,6 +181,7 @@ export default () => {
}) })
.catch(() => { .catch(() => {
newIssue.setFetchingState('subscriptions', false); newIssue.setFetchingState('subscriptions', false);
setWeigthFetchingState(newIssue, false);
Flash(__('An error occurred while fetching sidebar data')); Flash(__('An error occurred while fetching sidebar data'));
}); });
} }
@ -203,6 +216,7 @@ export default () => {
el: document.getElementById('js-add-list'), el: document.getElementById('js-add-list'),
data: { data: {
filters: boardsStore.state.filters, filters: boardsStore.state.filters,
...getMilestoneTitle($boardApp),
}, },
mounted() { mounted() {
initNewListDropdown(); initNewListDropdown();
@ -222,6 +236,7 @@ export default () => {
return { return {
modal: ModalStore.store, modal: ModalStore.store,
store: boardsStore.state, store: boardsStore.state,
...getBoardsModalData($boardApp),
canAdminList: this.$options.el.hasAttribute('data-can-admin-list'), canAdminList: this.$options.el.hasAttribute('data-can-admin-list'),
}; };
}, },
@ -285,6 +300,6 @@ export default () => {
}); });
} }
toggleFocusMode(ModalStore, boardsStore); toggleFocusMode(ModalStore, boardsStore, $boardApp);
mountMultipleBoardsSwitcher(); mountMultipleBoardsSwitcher();
}; };

View file

@ -1,4 +1,9 @@
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
/**
* This file is intended to be deleted.
* The existing functions will removed one by one in favor of using the board store directly.
* see https://gitlab.com/gitlab-org/gitlab-ce/issues/61621
*/
import boardsStore from '~/boards/stores/boards_store'; import boardsStore from '~/boards/stores/boards_store';

View file

@ -48,6 +48,9 @@ export default class Clusters {
} = document.querySelector('.js-edit-cluster-form').dataset; } = document.querySelector('.js-edit-cluster-form').dataset;
this.clusterId = clusterId; this.clusterId = clusterId;
this.clusterNewlyCreatedKey = `cluster_${this.clusterId}_newly_created`;
this.clusterBannerDismissedKey = `cluster_${this.clusterId}_banner_dismissed`;
this.store = new ClustersStore(); this.store = new ClustersStore();
this.store.setHelpPaths(helpPath, ingressHelpPath, ingressDnsHelpPath); this.store.setHelpPaths(helpPath, ingressHelpPath, ingressDnsHelpPath);
this.store.setManagePrometheusPath(managePrometheusPath); this.store.setManagePrometheusPath(managePrometheusPath);
@ -81,18 +84,19 @@ export default class Clusters {
this.showTokenButton = document.querySelector('.js-show-cluster-token'); this.showTokenButton = document.querySelector('.js-show-cluster-token');
this.tokenField = document.querySelector('.js-cluster-token'); this.tokenField = document.querySelector('.js-cluster-token');
this.ingressDomainHelpText = document.querySelector('.js-ingress-domain-help-text'); this.ingressDomainHelpText = document.querySelector('.js-ingress-domain-help-text');
this.ingressDomainSnippet = this.ingressDomainHelpText.querySelector( this.ingressDomainSnippet =
'.js-ingress-domain-snippet', this.ingressDomainHelpText &&
); this.ingressDomainHelpText.querySelector('.js-ingress-domain-snippet');
Clusters.initDismissableCallout(); Clusters.initDismissableCallout();
initSettingsPanels(); initSettingsPanels();
setupToggleButtons(document.querySelector('.js-cluster-enable-toggle-area')); const toggleButtonsContainer = document.querySelector('.js-cluster-enable-toggle-area');
if (toggleButtonsContainer) {
setupToggleButtons(toggleButtonsContainer);
}
this.initApplications(clusterType); this.initApplications(clusterType);
if (this.store.state.status !== 'created') {
this.updateContainer(null, this.store.state.status, this.store.state.statusReason); this.updateContainer(null, this.store.state.status, this.store.state.statusReason);
}
this.addListeners(); this.addListeners();
if (statusPath) { if (statusPath) {
@ -247,35 +251,56 @@ export default class Clusters {
setBannerDismissedState(status, isDismissed) { setBannerDismissedState(status, isDismissed) {
if (AccessorUtilities.isLocalStorageAccessSafe()) { if (AccessorUtilities.isLocalStorageAccessSafe()) {
window.localStorage.setItem( window.localStorage.setItem(this.clusterBannerDismissedKey, `${status}_${isDismissed}`);
`cluster_${this.clusterId}_banner_dismissed`,
`${status}_${isDismissed}`,
);
} }
} }
isBannerDismissed(status) { isBannerDismissed(status) {
let bannerState; let bannerState;
if (AccessorUtilities.isLocalStorageAccessSafe()) { if (AccessorUtilities.isLocalStorageAccessSafe()) {
bannerState = window.localStorage.getItem(`cluster_${this.clusterId}_banner_dismissed`); bannerState = window.localStorage.getItem(this.clusterBannerDismissedKey);
} }
return bannerState === `${status}_true`; return bannerState === `${status}_true`;
} }
updateContainer(prevStatus, status, error) { setClusterNewlyCreated(state) {
this.hideAll(); if (AccessorUtilities.isLocalStorageAccessSafe()) {
window.localStorage.setItem(this.clusterNewlyCreatedKey, Boolean(state));
}
}
if (this.isBannerDismissed(status)) { isClusterNewlyCreated() {
// once this is true, it will always be true for a given page load
if (!this.isNewlyCreated) {
let newlyCreated;
if (AccessorUtilities.isLocalStorageAccessSafe()) {
newlyCreated = window.localStorage.getItem(this.clusterNewlyCreatedKey);
}
this.isNewlyCreated = newlyCreated === 'true';
}
return this.isNewlyCreated;
}
updateContainer(prevStatus, status, error) {
if (status !== 'created' && this.isBannerDismissed(status)) {
return; return;
} }
this.setBannerDismissedState(status, false); this.setBannerDismissedState(status, false);
// We poll all the time but only want the `created` banner to show when newly created if (prevStatus !== status) {
if (this.store.state.status !== 'created' || prevStatus !== this.store.state.status) { this.hideAll();
switch (status) { switch (status) {
case 'created': case 'created':
if (this.isClusterNewlyCreated()) {
this.setClusterNewlyCreated(false);
this.successContainer.classList.remove('hidden'); this.successContainer.classList.remove('hidden');
} else if (prevStatus) {
this.setClusterNewlyCreated(true);
window.location.reload();
}
break; break;
case 'errored': case 'errored':
this.errorContainer.classList.remove('hidden'); this.errorContainer.classList.remove('hidden');
@ -292,7 +317,6 @@ export default class Clusters {
this.creatingContainer.classList.remove('hidden'); this.creatingContainer.classList.remove('hidden');
break; break;
default: default:
this.hideAll();
} }
} }
} }

View file

@ -1,5 +1,6 @@
<script> <script>
/* eslint-disable vue/require-default-prop */ /* eslint-disable vue/require-default-prop */
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { GlLink, GlModalDirective } from '@gitlab/ui'; import { GlLink, GlModalDirective } from '@gitlab/ui';
import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
import { s__, __, sprintf } from '~/locale'; import { s__, __, sprintf } from '~/locale';

View file

@ -2,18 +2,23 @@
import { GlModal } from '@gitlab/ui'; import { GlModal } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import trackUninstallButtonClickMixin from 'ee_else_ce/clusters/mixins/track_uninstall_button_click'; import trackUninstallButtonClickMixin from 'ee_else_ce/clusters/mixins/track_uninstall_button_click';
import { INGRESS, CERT_MANAGER, PROMETHEUS, RUNNER, KNATIVE, JUPYTER } from '../constants'; import { HELM, INGRESS, CERT_MANAGER, PROMETHEUS, RUNNER, KNATIVE, JUPYTER } from '../constants';
const CUSTOM_APP_WARNING_TEXT = { const CUSTOM_APP_WARNING_TEXT = {
[HELM]: s__(
'ClusterIntegration|The associated Tiller pod will be deleted and cannot be restored.',
),
[INGRESS]: s__( [INGRESS]: s__(
'ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored.', 'ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored.',
), ),
[CERT_MANAGER]: s__( [CERT_MANAGER]: s__(
'ClusterIntegration|The associated certifcate will be deleted and cannot be restored.', 'ClusterIntegration|The associated private key will be deleted and cannot be restored.',
), ),
[PROMETHEUS]: s__('ClusterIntegration|All data will be deleted and cannot be restored.'), [PROMETHEUS]: s__('ClusterIntegration|All data will be deleted and cannot be restored.'),
[RUNNER]: s__('ClusterIntegration|Any running pipelines will be canceled.'), [RUNNER]: s__('ClusterIntegration|Any running pipelines will be canceled.'),
[KNATIVE]: s__('ClusterIntegration|The associated IP will be deleted and cannot be restored.'), [KNATIVE]: s__(
'ClusterIntegration|The associated IP and all deployed services will be deleted and cannot be restored. Uninstalling Knative will also remove Istio from your cluster. This will not effect any other applications.',
),
[JUPYTER]: s__( [JUPYTER]: s__(
'ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored.', 'ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored.',
), ),

View file

@ -171,6 +171,7 @@ export default class ClusterStore {
this.state.applications.cert_manager.email || serverAppEntry.email; this.state.applications.cert_manager.email || serverAppEntry.email;
} else if (appId === JUPYTER) { } else if (appId === JUPYTER) {
this.state.applications.jupyter.hostname = this.state.applications.jupyter.hostname =
this.state.applications.jupyter.hostname ||
serverAppEntry.hostname || serverAppEntry.hostname ||
(this.state.applications.ingress.externalIp (this.state.applications.ingress.externalIp
? `jupyter.${this.state.applications.ingress.externalIp}.nip.io` ? `jupyter.${this.state.applications.ingress.externalIp}.nip.io`

View file

@ -1,5 +1,5 @@
import $ from 'jquery'; import $ from 'jquery';
import { pluralize } from './lib/utils/text_utility'; import { n__ } from '~/locale';
import { localTimeAgo } from './lib/utils/datetime_utility'; import { localTimeAgo } from './lib/utils/datetime_utility';
import Pager from './pager'; import Pager from './pager';
import axios from './lib/utils/axios_utils'; import axios from './lib/utils/axios_utils';
@ -90,9 +90,10 @@ export default class CommitsList {
.first() .first()
.find('li.commit').length, .find('li.commit').length,
); );
$commitsHeadersLast $commitsHeadersLast
.find('span.commits-count') .find('span.commits-count')
.text(`${commitsCount} ${pluralize('commit', commitsCount)}`); .text(n__('%d commit', '%d commits', commitsCount));
} }
localTimeAgo($processedData.find('.js-timeago')); localTimeAgo($processedData.find('.js-timeago'));

View file

@ -13,6 +13,7 @@ import 'core-js/es/string/code-point-at';
import 'core-js/es/string/from-code-point'; import 'core-js/es/string/from-code-point';
import 'core-js/es/string/includes'; import 'core-js/es/string/includes';
import 'core-js/es/string/starts-with'; import 'core-js/es/string/starts-with';
import 'core-js/es/string/ends-with';
import 'core-js/es/symbol'; import 'core-js/es/symbol';
import 'core-js/es/map'; import 'core-js/es/map';
import 'core-js/es/weak-map'; import 'core-js/es/weak-map';

View file

@ -1,7 +1,10 @@
import $ from 'jquery'; import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { GlEmptyState } from '@gitlab/ui';
import filterMixins from 'ee_else_ce/analytics/cycle_analytics/mixins/filter_mixins';
import Flash from '../flash'; import Flash from '../flash';
import { __ } from '~/locale';
import Translate from '../vue_shared/translate'; import Translate from '../vue_shared/translate';
import banner from './components/banner.vue'; import banner from './components/banner.vue';
import stageCodeComponent from './components/stage_code_component.vue'; import stageCodeComponent from './components/stage_code_component.vue';
@ -11,7 +14,6 @@ import stageStagingComponent from './components/stage_staging_component.vue';
import stageTestComponent from './components/stage_test_component.vue'; import stageTestComponent from './components/stage_test_component.vue';
import CycleAnalyticsService from './cycle_analytics_service'; import CycleAnalyticsService from './cycle_analytics_service';
import CycleAnalyticsStore from './cycle_analytics_store'; import CycleAnalyticsStore from './cycle_analytics_store';
import { __ } from '~/locale';
Vue.use(Translate); Vue.use(Translate);
@ -24,6 +26,7 @@ export default () => {
el: '#cycle-analytics', el: '#cycle-analytics',
name: 'CycleAnalytics', name: 'CycleAnalytics',
components: { components: {
GlEmptyState,
banner, banner,
'stage-issue-component': stageComponent, 'stage-issue-component': stageComponent,
'stage-plan-component': stageComponent, 'stage-plan-component': stageComponent,
@ -32,12 +35,15 @@ export default () => {
'stage-review-component': stageReviewComponent, 'stage-review-component': stageReviewComponent,
'stage-staging-component': stageStagingComponent, 'stage-staging-component': stageStagingComponent,
'stage-production-component': stageComponent, 'stage-production-component': stageComponent,
GroupsDropdownFilter: () =>
import('ee_component/analytics/shared/components/groups_dropdown_filter.vue'),
ProjectsDropdownFilter: () =>
import('ee_component/analytics/shared/components/projects_dropdown_filter.vue'),
DateRangeDropdown: () =>
import('ee_component/analytics/shared/components/date_range_dropdown.vue'),
}, },
mixins: [filterMixins],
data() { data() {
const cycleAnalyticsService = new CycleAnalyticsService({
requestPath: cycleAnalyticsEl.dataset.requestPath,
});
return { return {
store: CycleAnalyticsStore, store: CycleAnalyticsStore,
state: CycleAnalyticsStore.state, state: CycleAnalyticsStore.state,
@ -47,7 +53,7 @@ export default () => {
hasError: false, hasError: false,
startDate: 30, startDate: 30,
isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE), isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE),
service: cycleAnalyticsService, service: this.createCycleAnalyticsService(cycleAnalyticsEl.dataset.requestPath),
}; };
}, },
computed: { computed: {
@ -124,6 +130,7 @@ export default () => {
.fetchStageData({ .fetchStageData({
stage, stage,
startDate: this.startDate, startDate: this.startDate,
projectIds: this.selectedProjectIds,
}) })
.then(response => { .then(response => {
this.isEmptyStage = !response.events.length; this.isEmptyStage = !response.events.length;
@ -139,6 +146,11 @@ export default () => {
this.isOverviewDialogDismissed = true; this.isOverviewDialogDismissed = true;
Cookies.set(OVERVIEW_DIALOG_COOKIE, '1', { expires: 365 }); Cookies.set(OVERVIEW_DIALOG_COOKIE, '1', { expires: 365 });
}, },
createCycleAnalyticsService(requestPath) {
return new CycleAnalyticsService({
requestPath,
});
},
}, },
}); });
}; };

View file

@ -8,22 +8,26 @@ export default class CycleAnalyticsService {
} }
fetchCycleAnalyticsData(options = { startDate: 30 }) { fetchCycleAnalyticsData(options = { startDate: 30 }) {
const { startDate, projectIds } = options;
return this.axios return this.axios
.get('', { .get('', {
params: { params: {
'cycle_analytics[start_date]': options.startDate, 'cycle_analytics[start_date]': startDate,
'cycle_analytics[project_ids]': projectIds,
}, },
}) })
.then(x => x.data); .then(x => x.data);
} }
fetchStageData(options) { fetchStageData(options) {
const { stage, startDate } = options; const { stage, startDate, projectIds } = options;
return this.axios return this.axios
.get(`events/${stage.name}.json`, { .get(`events/${stage.name}.json`, {
params: { params: {
'cycle_analytics[start_date]': startDate, 'cycle_analytics[start_date]': startDate,
'cycle_analytics[project_ids]': projectIds,
}, },
}) })
.then(x => x.data); .then(x => x.data);

View file

@ -49,8 +49,8 @@ export default {
return this.author.id ? this.author.id : ''; return this.author.id ? this.author.id : '';
}, },
authorUrl() { authorUrl() {
// TODO: when the vue i18n rules are merged need to disable @gitlab/i18n/no-non-i18n-strings
// name: 'mailto:' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives // name: 'mailto:' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
return this.author.web_url || `mailto:${this.commit.author_email}`; return this.author.web_url || `mailto:${this.commit.author_email}`;
}, },
authorAvatar() { authorAvatar() {

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui'; import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';

View file

@ -44,7 +44,6 @@ export default {
class="d-none d-sm-block" class="d-none d-sm-block"
/> />
<reply-placeholder <reply-placeholder
class="qa-discussion-reply"
:button-text="__('Start a new discussion...')" :button-text="__('Start a new discussion...')"
@onClick="$emit('showNewDiscussionForm')" @onClick="$emit('showNewDiscussionForm')"
/> />

View file

@ -0,0 +1,246 @@
<script>
import createFlash from '~/flash';
import { s__ } from '~/locale';
import { mapState, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import { UNFOLD_COUNT } from '../constants';
import * as utils from '../store/utils';
import tooltip from '../../vue_shared/directives/tooltip';
const EXPAND_ALL = 0;
const EXPAND_UP = 1;
const EXPAND_DOWN = 2;
export default {
directives: {
tooltip,
},
components: {
Icon,
},
props: {
fileHash: {
type: String,
required: true,
},
contextLinesPath: {
type: String,
required: true,
},
line: {
type: Object,
required: true,
},
isTop: {
type: Boolean,
required: false,
default: false,
},
isBottom: {
type: Boolean,
required: false,
default: false,
},
colspan: {
type: Number,
required: false,
default: 3,
},
},
computed: {
...mapState({
diffViewType: state => state.diffs.diffViewType,
diffFiles: state => state.diffs.diffFiles,
}),
canExpandUp() {
return !this.isBottom;
},
canExpandDown() {
return this.isBottom || !this.isTop;
},
},
created() {
this.EXPAND_DOWN = EXPAND_DOWN;
this.EXPAND_UP = EXPAND_UP;
},
methods: {
...mapActions('diffs', ['loadMoreLines']),
getPrevLineNumber(oldLineNumber, newLineNumber) {
const diffFile = utils.findDiffFile(this.diffFiles, this.fileHash);
const indexForInline = utils.findIndexInInlineLines(diffFile.highlighted_diff_lines, {
oldLineNumber,
newLineNumber,
});
const prevLine = diffFile.highlighted_diff_lines[indexForInline - 2];
return (prevLine && prevLine.new_line) || 0;
},
callLoadMoreLines(
endpoint,
params,
lineNumbers,
fileHash,
isExpandDown = false,
nextLineNumbers = {},
) {
this.loadMoreLines({ endpoint, params, lineNumbers, fileHash, isExpandDown, nextLineNumbers })
.then(() => {
this.isRequesting = false;
})
.catch(() => {
createFlash(s__('Diffs|Something went wrong while fetching diff lines.'));
this.isRequesting = false;
});
},
handleExpandLines(type = EXPAND_ALL) {
if (this.isRequesting) {
return;
}
this.isRequesting = true;
const endpoint = this.contextLinesPath;
const { fileHash } = this;
const view = this.diffViewType;
const oldLineNumber = this.line.meta_data.old_pos || 0;
const newLineNumber = this.line.meta_data.new_pos || 0;
const offset = newLineNumber - oldLineNumber;
const expandOptions = { endpoint, fileHash, view, oldLineNumber, newLineNumber, offset };
if (type === EXPAND_UP) {
this.handleExpandUpLines(expandOptions);
} else if (type === EXPAND_DOWN) {
this.handleExpandDownLines(expandOptions);
} else {
this.handleExpandAllLines(expandOptions);
}
},
handleExpandUpLines(expandOptions = EXPAND_ALL) {
const { endpoint, fileHash, view, oldLineNumber, newLineNumber, offset } = expandOptions;
const bottom = this.isBottom;
const lineNumber = newLineNumber - 1;
const to = lineNumber;
let since = lineNumber - UNFOLD_COUNT;
let unfold = true;
const prevLineNumber = this.getPrevLineNumber(oldLineNumber, newLineNumber);
if (since <= prevLineNumber + 1) {
since = prevLineNumber + 1;
unfold = false;
}
const params = { since, to, bottom, offset, unfold, view };
const lineNumbers = { oldLineNumber, newLineNumber };
this.callLoadMoreLines(endpoint, params, lineNumbers, fileHash);
},
handleExpandDownLines(expandOptions) {
const {
endpoint,
fileHash,
view,
oldLineNumber: metaOldPos,
newLineNumber: metaNewPos,
offset,
} = expandOptions;
const bottom = true;
const nextLineNumbers = {
old_line: metaOldPos,
new_line: metaNewPos,
};
let unfold = true;
let isExpandDown = false;
let oldLineNumber = metaOldPos;
let newLineNumber = metaNewPos;
let lineNumber = metaNewPos + 1;
let since = lineNumber;
let to = lineNumber + UNFOLD_COUNT;
if (!this.isBottom) {
const prevLineNumber = this.getPrevLineNumber(oldLineNumber, newLineNumber);
isExpandDown = true;
oldLineNumber = prevLineNumber - offset;
newLineNumber = prevLineNumber;
lineNumber = prevLineNumber + 1;
since = lineNumber;
to = lineNumber + UNFOLD_COUNT;
if (to >= metaNewPos) {
to = metaNewPos - 1;
unfold = false;
}
}
const params = { since, to, bottom, offset, unfold, view };
const lineNumbers = { oldLineNumber, newLineNumber };
this.callLoadMoreLines(
endpoint,
params,
lineNumbers,
fileHash,
isExpandDown,
nextLineNumbers,
);
},
handleExpandAllLines(expandOptions) {
const { endpoint, fileHash, view, oldLineNumber, newLineNumber, offset } = expandOptions;
const bottom = this.isBottom;
const unfold = false;
let since;
let to;
if (this.isTop) {
since = 1;
to = newLineNumber - 1;
} else if (bottom) {
since = newLineNumber + 1;
to = -1;
} else {
const prevLineNumber = this.getPrevLineNumber(oldLineNumber, newLineNumber);
since = prevLineNumber + 1;
to = newLineNumber - 1;
}
const params = { since, to, bottom, offset, unfold, view };
const lineNumbers = { oldLineNumber, newLineNumber };
this.callLoadMoreLines(endpoint, params, lineNumbers, fileHash);
},
},
};
</script>
<template>
<td :colspan="colspan" class="text-center">
<div class="content js-line-expansion-content">
<a
v-if="canExpandUp"
v-tooltip
class="cursor-pointer js-unfold unfold-icon d-inline-block pt-2 pb-2"
data-placement="top"
data-container="body"
:title="__('Expand up')"
@click="handleExpandLines(EXPAND_UP)"
>
<!-- TODO: remove style & replace with correct icon, waiting for MR https://gitlab.com/gitlab-org/gitlab-design/issues/499 -->
<icon :size="12" name="expand-left" aria-hidden="true" style="transform: rotate(270deg);" />
</a>
<a class="mx-2 cursor-pointer js-unfold-all" @click="handleExpandLines()">
<span>{{ s__('Diffs|Show all lines') }}</span>
</a>
<a
v-if="canExpandDown"
v-tooltip
class="cursor-pointer js-unfold-down has-tooltip unfold-icon d-inline-block pt-2 pb-2"
data-placement="top"
data-container="body"
:title="__('Expand down')"
@click="handleExpandLines(EXPAND_DOWN)"
>
<!-- TODO: remove style & replace with correct icon, waiting for MR https://gitlab.com/gitlab-org/gitlab-design/issues/499 -->
<icon :size="12" name="expand-left" aria-hidden="true" style="transform: rotate(90deg);" />
</a>
</div>
</td>
</template>

View file

@ -263,6 +263,7 @@ export default {
:disabled="!diffHasDiscussions(diffFile)" :disabled="!diffHasDiscussions(diffFile)"
:class="{ active: hasExpandedDiscussions }" :class="{ active: hasExpandedDiscussions }"
class="js-btn-vue-toggle-comments btn" class="js-btn-vue-toggle-comments btn"
data-qa-selector="toggle_comments_button"
type="button" type="button"
@click="handleToggleDiscussions" @click="handleToggleDiscussions"
> >

View file

@ -1,6 +1,7 @@
<script> <script>
import { n__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { pluralize, truncate } from '~/lib/utils/text_utility'; import { truncate } from '~/lib/utils/text_utility';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import { GlTooltipDirective } from '@gitlab/ui'; import { GlTooltipDirective } from '@gitlab/ui';
import { COUNT_OF_AVATARS_IN_GUTTER, LENGTH_OF_AVATAR_TOOLTIP } from '../constants'; import { COUNT_OF_AVATARS_IN_GUTTER, LENGTH_OF_AVATAR_TOOLTIP } from '../constants';
@ -42,7 +43,7 @@ export default {
return ''; return '';
} }
return pluralize(`${this.moreCount} more comment`, this.moreCount); return n__('%d more comment', '%d more comments', this.moreCount);
}, },
}, },
methods: { methods: {

View file

@ -1,11 +1,8 @@
<script> <script>
import createFlash from '~/flash';
import { s__ } from '~/locale';
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import DiffGutterAvatars from './diff_gutter_avatars.vue'; import DiffGutterAvatars from './diff_gutter_avatars.vue';
import { LINE_POSITION_RIGHT, UNFOLD_COUNT } from '../constants'; import { LINE_POSITION_RIGHT } from '../constants';
import * as utils from '../store/utils';
export default { export default {
components: { components: {
@ -115,64 +112,12 @@ export default {
handleCommentButton() { handleCommentButton() {
this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.fileHash }); this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.fileHash });
}, },
handleLoadMoreLines() {
if (this.isRequesting) {
return;
}
this.isRequesting = true;
const endpoint = this.contextLinesPath;
const oldLineNumber = this.line.meta_data.old_pos || 0;
const newLineNumber = this.line.meta_data.new_pos || 0;
const offset = newLineNumber - oldLineNumber;
const bottom = this.isBottom;
const { fileHash } = this;
const view = this.diffViewType;
let unfold = true;
let lineNumber = newLineNumber - 1;
let since = lineNumber - UNFOLD_COUNT;
let to = lineNumber;
if (bottom) {
lineNumber = newLineNumber + 1;
since = lineNumber;
to = lineNumber + UNFOLD_COUNT;
} else {
const diffFile = utils.findDiffFile(this.diffFiles, this.fileHash);
const indexForInline = utils.findIndexInInlineLines(diffFile.highlighted_diff_lines, {
oldLineNumber,
newLineNumber,
});
const prevLine = diffFile.highlighted_diff_lines[indexForInline - 2];
const prevLineNumber = (prevLine && prevLine.new_line) || 0;
if (since <= prevLineNumber + 1) {
since = prevLineNumber + 1;
unfold = false;
}
}
const params = { since, to, bottom, offset, unfold, view };
const lineNumbers = { oldLineNumber, newLineNumber };
this.loadMoreLines({ endpoint, params, lineNumbers, fileHash })
.then(() => {
this.isRequesting = false;
})
.catch(() => {
createFlash(s__('Diffs|Something went wrong while fetching diff lines.'));
this.isRequesting = false;
});
},
}, },
}; };
</script> </script>
<template> <template>
<div> <div>
<span v-if="isMatchLine" class="context-cell" role="button" @click="handleLoadMoreLines"
>...</span
>
<template v-else>
<button <button
v-if="shouldRenderCommentButton" v-if="shouldRenderCommentButton"
v-show="shouldShowCommentButton" v-show="shouldShowCommentButton"
@ -198,6 +143,5 @@ export default {
toggleLineDiscussions({ lineCode, fileHash, expanded: !line.discussionsExpanded }) toggleLineDiscussions({ lineCode, fileHash, expanded: !line.discussionsExpanded })
" "
/> />
</template>
</div> </div>
</template> </template>

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
export default { export default {
props: { props: {
total: { total: {

View file

@ -0,0 +1,53 @@
<script>
import Icon from '~/vue_shared/components/icon.vue';
import DiffExpansionCell from './diff_expansion_cell.vue';
import { MATCH_LINE_TYPE } from '../constants';
export default {
components: {
Icon,
DiffExpansionCell,
},
props: {
fileHash: {
type: String,
required: true,
},
contextLinesPath: {
type: String,
required: true,
},
line: {
type: Object,
required: true,
},
isTop: {
type: Boolean,
required: false,
default: false,
},
isBottom: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
isMatchLine() {
return this.line.type === MATCH_LINE_TYPE;
},
},
};
</script>
<template>
<tr v-if="isMatchLine" class="line_expansion match">
<diff-expansion-cell
:file-hash="fileHash"
:context-lines-path="contextLinesPath"
:line="line"
:is-top="isTop"
:is-bottom="isBottom"
/>
</tr>
</template>

View file

@ -2,6 +2,7 @@
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import DiffTableCell from './diff_table_cell.vue'; import DiffTableCell from './diff_table_cell.vue';
import { import {
MATCH_LINE_TYPE,
NEW_LINE_TYPE, NEW_LINE_TYPE,
OLD_LINE_TYPE, OLD_LINE_TYPE,
CONTEXT_LINE_TYPE, CONTEXT_LINE_TYPE,
@ -58,6 +59,9 @@ export default {
inlineRowId() { inlineRowId() {
return this.line.line_code || `${this.fileHash}_${this.line.old_line}_${this.line.new_line}`; return this.line.line_code || `${this.fileHash}_${this.line.old_line}_${this.line.new_line}`;
}, },
isMatchLine() {
return this.line.type === MATCH_LINE_TYPE;
},
}, },
created() { created() {
this.newLineType = NEW_LINE_TYPE; this.newLineType = NEW_LINE_TYPE;
@ -81,6 +85,7 @@ export default {
<template> <template>
<tr <tr
v-if="!isMatchLine"
:id="inlineRowId" :id="inlineRowId"
:class="classNameMap" :class="classNameMap"
class="line_holder" class="line_holder"

View file

@ -3,6 +3,7 @@ import { mapGetters } from 'vuex';
import draftCommentsMixin from 'ee_else_ce/diffs/mixins/draft_comments'; import draftCommentsMixin from 'ee_else_ce/diffs/mixins/draft_comments';
import inlineDiffTableRow from './inline_diff_table_row.vue'; import inlineDiffTableRow from './inline_diff_table_row.vue';
import inlineDiffCommentRow from './inline_diff_comment_row.vue'; import inlineDiffCommentRow from './inline_diff_comment_row.vue';
import inlineDiffExpansionRow from './inline_diff_expansion_row.vue';
export default { export default {
components: { components: {
@ -10,6 +11,7 @@ export default {
inlineDiffTableRow, inlineDiffTableRow,
InlineDraftCommentRow: () => InlineDraftCommentRow: () =>
import('ee_component/batch_comments/components/inline_draft_comment_row.vue'), import('ee_component/batch_comments/components/inline_draft_comment_row.vue'),
inlineDiffExpansionRow,
}, },
mixins: [draftCommentsMixin], mixins: [draftCommentsMixin],
props: { props: {
@ -43,10 +45,24 @@ export default {
:data-commit-id="commitId" :data-commit-id="commitId"
class="code diff-wrap-lines js-syntax-highlight text-file js-diff-inline-view" class="code diff-wrap-lines js-syntax-highlight text-file js-diff-inline-view"
> >
<!-- Need to insert an empty row to solve "table-layout:fixed" equal width when expansion row is the first line -->
<tr>
<td style="width: 50px;"></td>
<td style="width: 50px;"></td>
<td></td>
</tr>
<tbody> <tbody>
<template v-for="(line, index) in diffLines"> <template v-for="(line, index) in diffLines">
<inline-diff-expansion-row
:key="`expand-${index}`"
:file-hash="diffFile.file_hash"
:context-lines-path="diffFile.context_lines_path"
:line="line"
:is-top="index === 0"
:is-bottom="index + 1 === diffLinesLength"
/>
<inline-diff-table-row <inline-diff-table-row
:key="line.line_code" :key="`${line.line_code || index}`"
:file-hash="diffFile.file_hash" :file-hash="diffFile.file_hash"
:context-lines-path="diffFile.context_lines_path" :context-lines-path="diffFile.context_lines_path"
:line="line" :line="line"

View file

@ -0,0 +1,56 @@
<script>
import { MATCH_LINE_TYPE } from '../constants';
import DiffExpansionCell from './diff_expansion_cell.vue';
export default {
components: {
DiffExpansionCell,
},
props: {
fileHash: {
type: String,
required: true,
},
contextLinesPath: {
type: String,
required: true,
},
line: {
type: Object,
required: true,
},
isTop: {
type: Boolean,
required: false,
default: false,
},
isBottom: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
isMatchLineLeft() {
return this.line.left && this.line.left.type === MATCH_LINE_TYPE;
},
isMatchLineRight() {
return this.line.right && this.line.right.type === MATCH_LINE_TYPE;
},
},
};
</script>
<template>
<tr class="line_expansion match">
<template v-if="isMatchLineLeft || isMatchLineRight">
<diff-expansion-cell
:file-hash="fileHash"
:context-lines-path="contextLinesPath"
:line="line.left"
:is-top="isTop"
:is-bottom="isBottom"
:colspan="4"
/>
</template>
</tr>
</template>

View file

@ -3,6 +3,7 @@ import { mapActions, mapState } from 'vuex';
import $ from 'jquery'; import $ from 'jquery';
import DiffTableCell from './diff_table_cell.vue'; import DiffTableCell from './diff_table_cell.vue';
import { import {
MATCH_LINE_TYPE,
NEW_LINE_TYPE, NEW_LINE_TYPE,
OLD_LINE_TYPE, OLD_LINE_TYPE,
CONTEXT_LINE_TYPE, CONTEXT_LINE_TYPE,
@ -75,6 +76,12 @@ export default {
}, },
]; ];
}, },
isMatchLineLeft() {
return this.line.left && this.line.left.type === MATCH_LINE_TYPE;
},
isMatchLineRight() {
return this.line.right && this.line.right.type === MATCH_LINE_TYPE;
},
}, },
created() { created() {
this.newLineType = NEW_LINE_TYPE; this.newLineType = NEW_LINE_TYPE;
@ -122,7 +129,7 @@ export default {
@mouseover="handleMouseMove" @mouseover="handleMouseMove"
@mouseout="handleMouseMove" @mouseout="handleMouseMove"
> >
<template v-if="line.left"> <template v-if="line.left && !isMatchLineLeft">
<diff-table-cell <diff-table-cell
:file-hash="fileHash" :file-hash="fileHash"
:context-lines-path="contextLinesPath" :context-lines-path="contextLinesPath"
@ -148,7 +155,7 @@ export default {
<td class="diff-line-num old_line empty-cell"></td> <td class="diff-line-num old_line empty-cell"></td>
<td class="line_content parallel left-side empty-cell"></td> <td class="line_content parallel left-side empty-cell"></td>
</template> </template>
<template v-if="line.right"> <template v-if="line.right && !isMatchLineRight">
<diff-table-cell <diff-table-cell
:file-hash="fileHash" :file-hash="fileHash"
:context-lines-path="contextLinesPath" :context-lines-path="contextLinesPath"

View file

@ -3,9 +3,11 @@ import { mapGetters } from 'vuex';
import draftCommentsMixin from 'ee_else_ce/diffs/mixins/draft_comments'; import draftCommentsMixin from 'ee_else_ce/diffs/mixins/draft_comments';
import parallelDiffTableRow from './parallel_diff_table_row.vue'; import parallelDiffTableRow from './parallel_diff_table_row.vue';
import parallelDiffCommentRow from './parallel_diff_comment_row.vue'; import parallelDiffCommentRow from './parallel_diff_comment_row.vue';
import parallelDiffExpansionRow from './parallel_diff_expansion_row.vue';
export default { export default {
components: { components: {
parallelDiffExpansionRow,
parallelDiffTableRow, parallelDiffTableRow,
parallelDiffCommentRow, parallelDiffCommentRow,
ParallelDraftCommentRow: () => ParallelDraftCommentRow: () =>
@ -43,8 +45,23 @@ export default {
:data-commit-id="commitId" :data-commit-id="commitId"
class="code diff-wrap-lines js-syntax-highlight text-file" class="code diff-wrap-lines js-syntax-highlight text-file"
> >
<!-- Need to insert an empty row to solve "table-layout:fixed" equal width when expansion row is the first line -->
<tr>
<td style="width: 50px;"></td>
<td></td>
<td style="width: 50px;"></td>
<td></td>
</tr>
<tbody> <tbody>
<template v-for="(line, index) in diffLines"> <template v-for="(line, index) in diffLines">
<parallel-diff-expansion-row
:key="`expand-${index}`"
:file-hash="diffFile.file_hash"
:context-lines-path="diffFile.context_lines_path"
:line="line"
:is-top="index === 0"
:is-bottom="index + 1 === diffLinesLength"
/>
<parallel-diff-table-row <parallel-diff-table-row
:key="line.line_code" :key="line.line_code"
:file-hash="diffFile.file_hash" :file-hash="diffFile.file_hash"

View file

@ -109,7 +109,7 @@ export const toggleLineDiscussions = ({ commit }, options) => {
export const renderFileForDiscussionId = ({ commit, rootState, state }, discussionId) => { export const renderFileForDiscussionId = ({ commit, rootState, state }, discussionId) => {
const discussion = rootState.notes.discussions.find(d => d.id === discussionId); const discussion = rootState.notes.discussions.find(d => d.id === discussionId);
if (discussion) { if (discussion && discussion.diff_file) {
const file = state.diffFiles.find(f => f.file_hash === discussion.diff_file.file_hash); const file = state.diffFiles.find(f => f.file_hash === discussion.diff_file.file_hash);
if (file) { if (file) {
@ -183,7 +183,7 @@ export const cancelCommentForm = ({ commit }, { lineCode, fileHash }) => {
}; };
export const loadMoreLines = ({ commit }, options) => { export const loadMoreLines = ({ commit }, options) => {
const { endpoint, params, lineNumbers, fileHash } = options; const { endpoint, params, lineNumbers, fileHash, isExpandDown, nextLineNumbers } = options;
params.from_merge_request = true; params.from_merge_request = true;
@ -195,6 +195,8 @@ export const loadMoreLines = ({ commit }, options) => {
contextLines, contextLines,
params, params,
fileHash, fileHash,
isExpandDown,
nextLineNumbers,
}); });
}); });
}; };

View file

@ -71,18 +71,30 @@ export default {
}, },
[types.ADD_CONTEXT_LINES](state, options) { [types.ADD_CONTEXT_LINES](state, options) {
const { lineNumbers, contextLines, fileHash } = options; const { lineNumbers, contextLines, fileHash, isExpandDown, nextLineNumbers } = options;
const { bottom } = options.params; const { bottom } = options.params;
const diffFile = findDiffFile(state.diffFiles, fileHash); const diffFile = findDiffFile(state.diffFiles, fileHash);
removeMatchLine(diffFile, lineNumbers, bottom); removeMatchLine(diffFile, lineNumbers, bottom);
const lines = addLineReferences(contextLines, lineNumbers, bottom).map(line => ({ const lines = addLineReferences(
contextLines,
lineNumbers,
bottom,
isExpandDown,
nextLineNumbers,
).map(line => {
const lineCode =
line.type === 'match'
? `${fileHash}_${line.meta_data.old_pos}_${line.meta_data.new_pos}_match`
: line.line_code || `${fileHash}_${line.old_line}_${line.new_line}`;
return {
...line, ...line,
line_code: line.line_code || `${fileHash}_${line.old_line}_${line.new_line}`, line_code: lineCode,
discussions: line.discussions || [], discussions: line.discussions || [],
hasForm: false, hasForm: false,
})); };
});
addContextLines({ addContextLines({
inlineLines: diffFile.highlighted_diff_lines, inlineLines: diffFile.highlighted_diff_lines,
@ -90,6 +102,7 @@ export default {
contextLines: lines, contextLines: lines,
bottom, bottom,
lineNumbers, lineNumbers,
isExpandDown,
}); });
}, },

View file

@ -121,7 +121,7 @@ export function removeMatchLine(diffFile, lineNumbers, bottom) {
diffFile.parallel_diff_lines.splice(indexForParallel + factor, 1); diffFile.parallel_diff_lines.splice(indexForParallel + factor, 1);
} }
export function addLineReferences(lines, lineNumbers, bottom) { export function addLineReferences(lines, lineNumbers, bottom, isExpandDown, nextLineNumbers) {
const { oldLineNumber, newLineNumber } = lineNumbers; const { oldLineNumber, newLineNumber } = lineNumbers;
const lineCount = lines.length; const lineCount = lines.length;
let matchLineIndex = -1; let matchLineIndex = -1;
@ -135,15 +135,20 @@ export function addLineReferences(lines, lineNumbers, bottom) {
new_line: bottom ? newLineNumber + index + 1 : newLineNumber + index - lineCount, new_line: bottom ? newLineNumber + index + 1 : newLineNumber + index - lineCount,
}); });
} }
return l; return l;
}); });
if (matchLineIndex > -1) { if (matchLineIndex > -1) {
const line = linesWithNumbers[matchLineIndex]; const line = linesWithNumbers[matchLineIndex];
const targetLine = bottom let targetLine;
? linesWithNumbers[matchLineIndex - 1]
: linesWithNumbers[matchLineIndex + 1]; if (isExpandDown) {
targetLine = nextLineNumbers;
} else if (bottom) {
targetLine = linesWithNumbers[matchLineIndex - 1];
} else {
targetLine = linesWithNumbers[matchLineIndex + 1];
}
Object.assign(line, { Object.assign(line, {
meta_data: { meta_data: {
@ -152,26 +157,27 @@ export function addLineReferences(lines, lineNumbers, bottom) {
}, },
}); });
} }
return linesWithNumbers; return linesWithNumbers;
} }
export function addContextLines(options) { export function addContextLines(options) {
const { inlineLines, parallelLines, contextLines, lineNumbers } = options; const { inlineLines, parallelLines, contextLines, lineNumbers, isExpandDown } = options;
const normalizedParallelLines = contextLines.map(line => ({ const normalizedParallelLines = contextLines.map(line => ({
left: line, left: line,
right: line, right: line,
line_code: line.line_code, line_code: line.line_code,
})); }));
const factor = isExpandDown ? 1 : 0;
if (options.bottom) { if (!isExpandDown && options.bottom) {
inlineLines.push(...contextLines); inlineLines.push(...contextLines);
parallelLines.push(...normalizedParallelLines); parallelLines.push(...normalizedParallelLines);
} else { } else {
const inlineIndex = findIndexInInlineLines(inlineLines, lineNumbers); const inlineIndex = findIndexInInlineLines(inlineLines, lineNumbers);
const parallelIndex = findIndexInParallelLines(parallelLines, lineNumbers); const parallelIndex = findIndexInParallelLines(parallelLines, lineNumbers);
inlineLines.splice(inlineIndex, 0, ...contextLines);
parallelLines.splice(parallelIndex, 0, ...normalizedParallelLines); inlineLines.splice(inlineIndex + factor, 0, ...contextLines);
parallelLines.splice(parallelIndex + factor, 0, ...normalizedParallelLines);
} }
} }

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
import Timeago from 'timeago.js'; import Timeago from 'timeago.js';
import _ from 'underscore'; import _ from 'underscore';
@ -286,9 +287,9 @@ export default {
* @returns {Boolean|Undefined} * @returns {Boolean|Undefined}
*/ */
isLastDeployment() { isLastDeployment() {
// TODO: when the vue i18n rules are merged need to disable @gitlab/i18n/no-non-i18n-strings
// name: 'last?' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives // name: 'last?' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
// Vue i18n ESLint rules issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/63560 // Vue i18n ESLint rules issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/63560
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
return this.model && this.model.last_deployment && this.model.last_deployment['last?']; return this.model && this.model.last_deployment && this.model.last_deployment['last?'];
}, },

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { GlTooltipDirective } from '@gitlab/ui'; import { GlTooltipDirective } from '@gitlab/ui';
import GlModal from '~/vue_shared/components/gl_modal.vue'; import GlModal from '~/vue_shared/components/gl_modal.vue';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';

View file

@ -36,12 +36,14 @@ export default {
<label class="label-bold" for="error-tracking-api-host">{{ __('Sentry API URL') }}</label> <label class="label-bold" for="error-tracking-api-host">{{ __('Sentry API URL') }}</label>
<div class="row"> <div class="row">
<div class="col-8 col-md-9 gl-pr-0"> <div class="col-8 col-md-9 gl-pr-0">
<!-- eslint-disable @gitlab/vue-i18n/no-bare-attribute-strings -->
<gl-form-input <gl-form-input
id="error-tracking-api-host" id="error-tracking-api-host"
:value="apiHost" :value="apiHost"
placeholder="https://mysentryserver.com" placeholder="https://mysentryserver.com"
@input="$emit('update-api-host', $event)" @input="$emit('update-api-host', $event)"
/> />
<!-- eslint-enable @gitlab/vue-i18n/no-bare-attribute-strings -->
</div> </div>
</div> </div>
<p class="form-text text-muted"> <p class="form-text text-muted">

View file

@ -0,0 +1,4 @@
fragment PageInfo on PageInfo {
hasNextPage
endCursor
}

View file

@ -129,7 +129,7 @@ export default {
<item-stats-value <item-stats-value
:icon-name="visibilityIcon" :icon-name="visibilityIcon"
:title="visibilityTooltip" :title="visibilityTooltip"
css-class="item-visibility d-inline-flex align-items-center prepend-top-8 append-right-4" css-class="item-visibility d-inline-flex align-items-center prepend-top-8 append-right-4 text-secondary"
/> />
<span v-if="group.permission" class="user-access-role prepend-top-8"> <span v-if="group.permission" class="user-access-role prepend-top-8">
{{ group.permission }} {{ group.permission }}

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import Timeago from '~/vue_shared/components/time_ago_tooltip.vue'; import Timeago from '~/vue_shared/components/time_ago_tooltip.vue';
import router from '../../ide_router'; import router from '../../ide_router';

View file

@ -58,8 +58,7 @@ export default {
<template> <template>
<div> <div>
<div class="dropdown-input mt-3 pb-3 mb-0 border-bottom"> <label class="dropdown-input pt-3 pb-3 mb-0 border-bottom block position-relative" @click.stop>
<div class="position-relative">
<input <input
ref="searchInput" ref="searchInput"
v-model="search" v-model="search"
@ -68,16 +67,15 @@ export default {
class="form-control dropdown-input-field" class="form-control dropdown-input-field"
@input="searchBranches" @input="searchBranches"
/> />
<icon :size="18" name="search" class="input-icon" /> <icon :size="18" name="search" class="ml-3 input-icon" />
</div> </label>
</div>
<div class="dropdown-content ide-merge-requests-dropdown-content d-flex"> <div class="dropdown-content ide-merge-requests-dropdown-content d-flex">
<gl-loading-icon <gl-loading-icon
v-if="isLoading" v-if="isLoading"
:size="2" :size="2"
class="mt-3 mb-3 align-self-center ml-auto mr-auto" class="mt-3 mb-3 align-self-center ml-auto mr-auto"
/> />
<ul v-else class="mb-3 w-100"> <ul v-else class="mb-0 w-100">
<template v-if="hasBranches"> <template v-if="hasBranches">
<li v-for="item in branches" :key="item.name"> <li v-for="item in branches" :key="item.name">
<item :item="item" :project-id="currentProjectId" :is-active="isActiveBranch(item)" /> <item :item="item" :project-id="currentProjectId" :is-active="isActiveBranch(item)" />

View file

@ -45,6 +45,8 @@ export default {
}, },
computed: { computed: {
iconName() { iconName() {
// name: '-solid' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
const suffix = this.stagedList ? '-solid' : ''; const suffix = this.stagedList ? '-solid' : '';
return `${getCommitIconMap(this.file).icon}${suffix}`; return `${getCommitIconMap(this.file).icon}${suffix}`;

View file

@ -10,7 +10,9 @@ export default {
<template> <template>
<div class="multi-file-commit-panel-success-message" aria-live="assertive"> <div class="multi-file-commit-panel-success-message" aria-live="assertive">
<div class="svg-content svg-80"><img :src="committedStateSvgPath" alt="" /></div> <div class="svg-content svg-80">
<img :src="committedStateSvgPath" :alt="s__('IDE|Successful commit')" />
</div>
<div class="append-right-default prepend-left-default"> <div class="append-right-default prepend-left-default">
<div class="text-content text-center"> <div class="text-content text-center">
<h4>{{ __('All changes are committed') }}</h4> <h4>{{ __('All changes are committed') }}</h4>

View file

@ -87,7 +87,6 @@ export default {
:file="file" :file="file"
:show-tooltip="true" :show-tooltip="true"
:show-staged-icon="true" :show-staged-icon="true"
:force-modified-icon="true"
/> />
<new-dropdown <new-dropdown
:type="file.type" :type="file.type"

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { mapActions, mapState, mapGetters } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import IdeStatusList from 'ee_else_ce/ide/components/ide_status_list.vue'; import IdeStatusList from 'ee_else_ce/ide/components/ide_status_list.vue';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';

View file

@ -76,8 +76,7 @@ export default {
<template> <template>
<div> <div>
<div class="dropdown-input mt-3 pb-3 mb-0 border-bottom"> <label class="dropdown-input pt-3 pb-3 mb-0 border-bottom block" @click.stop>
<div class="position-relative">
<tokened-input <tokened-input
v-model="search" v-model="search"
:tokens="searchTokens" :tokens="searchTokens"
@ -86,9 +85,8 @@ export default {
@input="searchMergeRequests" @input="searchMergeRequests"
@removeToken="setSearchType(null)" @removeToken="setSearchType(null)"
/> />
<icon :size="18" name="search" class="input-icon" /> <icon :size="18" name="search" class="ml-3 input-icon" />
</div> </label>
</div>
<div class="dropdown-content ide-merge-requests-dropdown-content d-flex"> <div class="dropdown-content ide-merge-requests-dropdown-content d-flex">
<gl-loading-icon <gl-loading-icon
v-if="isLoading" v-if="isLoading"
@ -96,7 +94,7 @@ export default {
class="mt-3 mb-3 align-self-center ml-auto mr-auto" class="mt-3 mb-3 align-self-center ml-auto mr-auto"
/> />
<template v-else> <template v-else>
<ul class="mb-3 w-100"> <ul class="mb-0 w-100">
<template v-if="showSearchTypes"> <template v-if="showSearchTypes">
<li v-for="searchType in $options.searchTypes" :key="searchType.type"> <li v-for="searchType in $options.searchTypes" :key="searchType.type">
<button <button

View file

@ -4,7 +4,12 @@ import { viewerInformationForPath } from '~/vue_shared/components/content_viewer
import flash from '~/flash'; import flash from '~/flash';
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue'; import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import { activityBarViews, viewerTypes } from '../constants'; import {
activityBarViews,
viewerTypes,
FILE_VIEW_MODE_EDITOR,
FILE_VIEW_MODE_PREVIEW,
} from '../constants';
import Editor from '../lib/editor'; import Editor from '../lib/editor';
import ExternalLink from './external_link.vue'; import ExternalLink from './external_link.vue';
import FileTemplatesBar from './file_templates/bar.vue'; import FileTemplatesBar from './file_templates/bar.vue';
@ -49,10 +54,10 @@ export default {
return this.shouldHideEditor && this.file.mrChange && this.viewer === viewerTypes.mr; return this.shouldHideEditor && this.file.mrChange && this.viewer === viewerTypes.mr;
}, },
isEditorViewMode() { isEditorViewMode() {
return this.file.viewMode === 'editor'; return this.file.viewMode === FILE_VIEW_MODE_EDITOR;
}, },
isPreviewViewMode() { isPreviewViewMode() {
return this.file.viewMode === 'preview'; return this.file.viewMode === FILE_VIEW_MODE_PREVIEW;
}, },
editTabCSS() { editTabCSS() {
return { return {
@ -85,7 +90,7 @@ export default {
if (this.currentActivityView !== activityBarViews.edit) { if (this.currentActivityView !== activityBarViews.edit) {
this.setFileViewMode({ this.setFileViewMode({
file: this.file, file: this.file,
viewMode: 'editor', viewMode: FILE_VIEW_MODE_EDITOR,
}); });
} }
} }
@ -94,7 +99,7 @@ export default {
if (this.currentActivityView !== activityBarViews.edit) { if (this.currentActivityView !== activityBarViews.edit) {
this.setFileViewMode({ this.setFileViewMode({
file: this.file, file: this.file,
viewMode: 'editor', viewMode: FILE_VIEW_MODE_EDITOR,
}); });
} }
}, },
@ -244,6 +249,8 @@ export default {
}, },
}, },
viewerTypes, viewerTypes,
FILE_VIEW_MODE_EDITOR,
FILE_VIEW_MODE_PREVIEW,
}; };
</script> </script>
@ -255,7 +262,7 @@ export default {
<a <a
href="javascript:void(0);" href="javascript:void(0);"
role="button" role="button"
@click.prevent="setFileViewMode({ file, viewMode: 'editor' })" @click.prevent="setFileViewMode({ file, viewMode: $options.FILE_VIEW_MODE_EDITOR })"
> >
<template v-if="viewer === $options.viewerTypes.edit">{{ __('Edit') }}</template> <template v-if="viewer === $options.viewerTypes.edit">{{ __('Edit') }}</template>
<template v-else>{{ __('Review') }}</template> <template v-else>{{ __('Review') }}</template>
@ -265,7 +272,7 @@ export default {
<a <a
href="javascript:void(0);" href="javascript:void(0);"
role="button" role="button"
@click.prevent="setFileViewMode({ file, viewMode: 'preview' })" @click.prevent="setFileViewMode({ file, viewMode: $options.FILE_VIEW_MODE_PREVIEW })"
>{{ file.previewMode.previewTitle }}</a >{{ file.previewMode.previewTitle }}</a
> >
</li> </li>

View file

@ -4,6 +4,10 @@ export const MAX_WINDOW_HEIGHT_COMPACT = 750;
export const MAX_TITLE_LENGTH = 50; export const MAX_TITLE_LENGTH = 50;
export const MAX_BODY_LENGTH = 72; export const MAX_BODY_LENGTH = 72;
// File view modes
export const FILE_VIEW_MODE_EDITOR = 'editor';
export const FILE_VIEW_MODE_PREVIEW = 'preview';
export const activityBarViews = { export const activityBarViews = {
edit: 'ide-tree', edit: 'ide-tree',
commit: 'commit-section', commit: 'commit-section',

View file

@ -56,13 +56,7 @@ export default {
return Api.branchSingle(projectId, currentBranchId); return Api.branchSingle(projectId, currentBranchId);
}, },
commit(projectId, payload) { commit(projectId, payload) {
// Currently the `commit` endpoint does not support `start_sha` so we return Api.commitMultiple(projectId, payload);
// have to make the request in the FE. This is not ideal and will be
// resolved soon. https://gitlab.com/gitlab-org/gitlab-ce/issues/59023
const { branch, start_sha: ref } = payload;
const branchPromise = ref ? Api.createBranch(projectId, { ref, branch }) : Promise.resolve();
return branchPromise.then(() => Api.commitMultiple(projectId, payload));
}, },
getFiles(projectUrl, branchId) { getFiles(projectUrl, branchId) {
const url = `${projectUrl}/files/${branchId}`; const url = `${projectUrl}/files/${branchId}`;

View file

@ -43,10 +43,14 @@ export default {
[stateEntry, stagedFile, openFile, changedFile].forEach(f => { [stateEntry, stagedFile, openFile, changedFile].forEach(f => {
if (f) { if (f) {
Object.assign(f, convertObjectPropsToCamelCase(data, { dropKeys: ['raw', 'baseRaw'] }), { Object.assign(
f,
convertObjectPropsToCamelCase(data, { dropKeys: ['path', 'name', 'raw', 'baseRaw'] }),
{
raw: (stateEntry && stateEntry.raw) || null, raw: (stateEntry && stateEntry.raw) || null,
baseRaw: null, baseRaw: null,
}); },
);
} }
}); });
}, },

View file

@ -1,4 +1,4 @@
import { commitActionTypes } from '../constants'; import { commitActionTypes, FILE_VIEW_MODE_EDITOR } from '../constants';
export const dataStructure = () => ({ export const dataStructure = () => ({
id: '', id: '',
@ -43,7 +43,7 @@ export const dataStructure = () => ({
editorColumn: 1, editorColumn: 1,
fileLanguage: '', fileLanguage: '',
eol: '', eol: '',
viewMode: 'editor', viewMode: FILE_VIEW_MODE_EDITOR,
previewMode: null, previewMode: null,
size: 0, size: 0,
parentPath: null, parentPath: null,
@ -155,11 +155,11 @@ export const createCommitPayload = ({
last_commit_id: last_commit_id:
newBranch || f.deleted || f.prevPath || f.replaces ? undefined : f.lastCommitSha, newBranch || f.deleted || f.prevPath || f.replaces ? undefined : f.lastCommitSha,
})), })),
start_sha: newBranch ? rootGetters.lastCommit.short_id : undefined, start_sha: newBranch ? rootGetters.lastCommit.id : undefined,
}); });
export const createNewMergeRequestUrl = (projectUrl, source, target) => export const createNewMergeRequestUrl = (projectUrl, source, target) =>
`${projectUrl}/merge_requests/new?merge_request[source_branch]=${source}&merge_request[target_branch]=${target}`; `${projectUrl}/merge_requests/new?merge_request[source_branch]=${source}&merge_request[target_branch]=${target}&nav_source=webide`;
const sortTreesByTypeAndName = (a, b) => { const sortTreesByTypeAndName = (a, b) => {
if (a.type === 'tree' && b.type === 'blob') { if (a.type === 'tree' && b.type === 'blob') {

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import _ from 'underscore'; import _ from 'underscore';
import { GlLink, GlTooltip, GlTooltipDirective } from '@gitlab/ui'; import { GlLink, GlTooltip, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
import updateMixin from '../mixins/update'; import updateMixin from '../mixins/update';
import eventHub from '../event_hub'; import eventHub from '../event_hub';

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
export default { export default {

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import $ from 'jquery'; import $ from 'jquery';
import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors'; import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors';

View file

@ -70,6 +70,9 @@ export default {
hasIssuableTemplates() { hasIssuableTemplates() {
return this.issuableTemplates.length; return this.issuableTemplates.length;
}, },
showLockedWarning() {
return this.formState.lockedWarningVisible && !this.formState.updateLoading;
},
}, },
created() { created() {
eventHub.$on('delete.issuable', this.resetAutosave); eventHub.$on('delete.issuable', this.resetAutosave);
@ -117,7 +120,7 @@ export default {
<template> <template>
<form> <form>
<locked-warning v-if="formState.lockedWarningVisible" /> <locked-warning v-if="showLockedWarning" />
<div class="row"> <div class="row">
<div v-if="hasIssuableTemplates" class="col-sm-4 col-lg-3"> <div v-if="hasIssuableTemplates" class="col-sm-4 col-lg-3">
<description-template <description-template

View file

@ -1,4 +1,5 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';

View file

@ -1,9 +1,11 @@
<script> <script>
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import ManualVariablesForm from './manual_variables_form.vue';
export default { export default {
components: { components: {
GlLink, GlLink,
ManualVariablesForm,
}, },
props: { props: {
illustrationPath: { illustrationPath: {
@ -23,6 +25,21 @@ export default {
required: false, required: false,
default: null, default: null,
}, },
playable: {
type: Boolean,
required: true,
default: false,
},
scheduled: {
type: Boolean,
required: false,
default: false,
},
variablesSettingsUrl: {
type: String,
required: false,
default: null,
},
action: { action: {
type: Object, type: Object,
required: false, required: false,
@ -37,28 +54,40 @@ export default {
}, },
}, },
}, },
computed: {
shouldRenderManualVariables() {
return this.playable && !this.scheduled;
},
},
}; };
</script> </script>
<template> <template>
<div class="row empty-state"> <div class="row empty-state">
<div class="col-12"> <div class="col-12">
<div :class="illustrationSizeClass" class="svg-content"><img :src="illustrationPath" /></div> <div :class="illustrationSizeClass" class="svg-content">
<img :src="illustrationPath" />
</div>
</div> </div>
<div class="col-12"> <div class="col-12">
<div class="text-content"> <div class="text-content">
<h4 class="js-job-empty-state-title text-center">{{ title }}</h4> <h4 class="js-job-empty-state-title text-center">{{ title }}</h4>
<p v-if="content" class="js-job-empty-state-content text-center">{{ content }}</p> <p v-if="content" class="js-job-empty-state-content">{{ content }}</p>
</div>
<div v-if="action" class="text-center"> <manual-variables-form
v-if="shouldRenderManualVariables"
:action="action"
:variables-settings-url="variablesSettingsUrl"
/>
<div class="text-content">
<div v-if="action && !shouldRenderManualVariables" class="text-center">
<gl-link <gl-link
:href="action.path" :href="action.path"
:data-method="action.method" :data-method="action.method"
class="js-job-empty-state-action btn btn-primary" class="js-job-empty-state-action btn btn-primary"
>{{ action.button_title }}</gl-link
> >
{{ action.button_title }}
</gl-link>
</div> </div>
</div> </div>
</div> </div>

View file

@ -45,6 +45,11 @@ export default {
required: false, required: false,
default: null, default: null,
}, },
variablesSettingsUrl: {
type: String,
required: false,
default: null,
},
runnerHelpUrl: { runnerHelpUrl: {
type: String, type: String,
required: false, required: false,
@ -68,6 +73,10 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
projectPath: {
type: String,
required: true,
},
logState: { logState: {
type: String, type: String,
required: true, required: true,
@ -253,6 +262,7 @@ export default {
:quota-used="job.runners.quota.used" :quota-used="job.runners.quota.used"
:quota-limit="job.runners.quota.limit" :quota-limit="job.runners.quota.limit"
:runners-path="runnerHelpUrl" :runners-path="runnerHelpUrl"
:project-path="projectPath"
/> />
<environments-block <environments-block
@ -313,6 +323,9 @@ export default {
:title="emptyStateTitle" :title="emptyStateTitle"
:content="emptyStateIllustration.content" :content="emptyStateIllustration.content"
:action="emptyStateAction" :action="emptyStateAction"
:playable="job.playable"
:scheduled="job.scheduled"
:variables-settings-url="variablesSettingsUrl"
/> />
<!-- EO empty state --> <!-- EO empty state -->

View file

@ -48,9 +48,14 @@ export default {
} }
}, },
removeEventListener() { removeEventListener() {
this.$el this.$el.querySelectorAll('.js-section-start').forEach(el => {
.querySelectorAll('.js-section-start') const titleSection = el.nextSibling;
.forEach(el => el.removeEventListener('click', this.handleSectionClick)); titleSection.removeEventListener(
'click',
this.handleHeaderClick.bind(this, el, el.dataset.section),
);
el.removeEventListener('click', this.handleSectionClick);
});
}, },
/** /**
* The collapsible rows are sent in HTML from the backend * The collapsible rows are sent in HTML from the backend
@ -58,9 +63,28 @@ export default {
* *
*/ */
handleCollapsibleRows() { handleCollapsibleRows() {
this.$el this.$el.querySelectorAll('.js-section-start').forEach(el => {
.querySelectorAll('.js-section-start') const titleSection = el.nextSibling;
.forEach(el => el.addEventListener('click', this.handleSectionClick)); titleSection.addEventListener(
'click',
this.handleHeaderClick.bind(this, el, el.dataset.section),
);
el.addEventListener('click', this.handleSectionClick);
});
},
handleHeaderClick(arrowElement, section) {
this.updateToggleSection(arrowElement, section);
},
updateToggleSection(arrow, section) {
// toggle the arrow class
arrow.classList.toggle('fa-caret-right');
arrow.classList.toggle('fa-caret-down');
// hide the sections
const sibilings = this.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`);
sibilings.forEach(row => row.classList.toggle('hidden'));
}, },
/** /**
* On click, we toggle the hidden class of * On click, we toggle the hidden class of
@ -68,14 +92,7 @@ export default {
*/ */
handleSectionClick(evt) { handleSectionClick(evt) {
const clickedArrow = evt.currentTarget; const clickedArrow = evt.currentTarget;
// toggle the arrow class this.updateToggleSection(clickedArrow, clickedArrow.dataset.section);
clickedArrow.classList.toggle('fa-caret-right');
clickedArrow.classList.toggle('fa-caret-down');
const { section } = clickedArrow.dataset;
const sibilings = this.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`);
sibilings.forEach(row => row.classList.toggle('hidden'));
}, },
}, },
}; };

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