summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/dev-fixtures.gitlab-ci.yml60
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml565
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_row.vue17
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue9
-rw-r--r--app/assets/javascripts/ide/components/ide_file_row.vue17
-rw-r--r--app/assets/javascripts/ide/components/ide_tree_list.vue9
-rw-r--r--app/assets/javascripts/monitoring/components/panel_type.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue78
-rw-r--r--app/assets/javascripts/vue_shared/components/file_tree.vue47
-rw-r--r--changelogs/unreleased/remove-issue_link_types.yml5
-rw-r--r--db/post_migrate/20191115115522_migrate_epic_notes_mentions_to_db.rb2
-rw-r--r--doc/administration/logs.md7
-rw-r--r--doc/api/issue_links.md2
-rw-r--r--doc/development/integrations/secure.md (renamed from doc/development/integrations/secure.md.md)0
-rw-r--r--doc/user/permissions.md3
-rw-r--r--lib/gitlab/background_migration/user_mentions/create_resource_user_mention.rb4
-rw-r--r--lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb4
-rw-r--r--lib/gitlab/background_migration/user_mentions/models/note.rb4
-rw-r--r--spec/frontend/diffs/components/diff_file_row_spec.js25
-rw-r--r--spec/frontend/ide/components/ide_file_row_spec.js25
-rw-r--r--spec/frontend/monitoring/components/dashboard_spec.js48
-rw-r--r--spec/frontend/monitoring/components/panel_type_spec.js (renamed from spec/frontend/monitoring/panel_type_spec.js)27
-rw-r--r--spec/frontend/vue_shared/components/file_tree_spec.js88
-rw-r--r--spec/javascripts/vue_shared/components/file_row_spec.js7
-rw-r--r--spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb82
25 files changed, 803 insertions, 334 deletions
diff --git a/.gitlab/ci/dev-fixtures.gitlab-ci.yml b/.gitlab/ci/dev-fixtures.gitlab-ci.yml
index a5dab5d8708..a0b5100992b 100644
--- a/.gitlab/ci/dev-fixtures.gitlab-ci.yml
+++ b/.gitlab/ci/dev-fixtures.gitlab-ci.yml
@@ -1,6 +1,54 @@
+# Make sure to update all the similar conditions in other CI config files if you modify these conditions
+.if-not-ee: &if-not-ee
+ if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/'
+
+# Make sure to update all the similar conditions in other CI config files if you modify these conditions
+.if-default-refs: &if-default-refs
+ if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG'
+
+# Make sure to update all the similar patterns in other CI config files if you modify these patterns
+.code-backstage-patterns: &code-backstage-patterns
+ - ".gitlab/ci/**/*"
+ - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
+ - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
+ - ".csscomb.json"
+ - "Dockerfile.assets"
+ - "*_VERSION"
+ - "Gemfile{,.lock}"
+ - "Rakefile"
+ - "{babel.config,jest.config}.js"
+ - "config.ru"
+ - "{package.json,yarn.lock}"
+ - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
+ - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
+ # Backstage changes
+ - "Dangerfile"
+ - "danger/**/*"
+ - "{,ee/}fixtures/**/*"
+ - "{,ee/}rubocop/**/*"
+ - "{,ee/}spec/**/*"
+ - "doc/README.md" # Some RSpec test rely on this file
+
+.dev-fixtures:rules:ee-and-foss:
+ rules:
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
+ when: on_success
+
+.dev-fixtures:rules:ee-only:
+ rules:
+ - <<: *if-not-ee
+ when: never
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
+ when: on_success
+
.run-dev-fixtures:
extends:
- - .only-code-rails-job-base
+ - .default-tags
+ - .default-retry
+ - .default-cache
+ - .default-before_script
- .use-pg9
stage: test
needs: ["setup-test-env"]
@@ -13,17 +61,19 @@
SIZE: 0 # number of external projects to fork, requires network connection
# SEED_NESTED_GROUPS: "false" # requires network connection
-run-dev-fixtures-foss:
- extends: .run-dev-fixtures
+run-dev-fixtures:
+ extends:
+ - .run-dev-fixtures
+ - .dev-fixtures:rules:ee-and-foss
script:
- scripts/gitaly-test-spawn
- RAILS_ENV=test bundle exec rake db:seed_fu
run-dev-fixtures-ee:
extends:
- - .only-ee
- - .use-pg9-ee
- .run-dev-fixtures
+ - .dev-fixtures:rules:ee-only
+ - .use-pg9-ee
script:
- scripts/gitaly-test-spawn
- cp ee/db/fixtures/development/* $FIXTURE_PATH
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 03685d1f6a8..3d890dfea7e 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -1,41 +1,120 @@
-.only-master:
- only:
- refs:
- - master
-
-.rake-exec:
+# Make sure to update all the similar conditions in other CI config files if you modify these conditions
+.if-not-ee: &if-not-ee
+ if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/'
+
+# Make sure to update all the similar conditions in other CI config files if you modify these conditions
+.if-master-refs: &if-master-refs
+ if: '$CI_COMMIT_REF_NAME == "master"'
+
+# Make sure to update all the similar conditions in other CI config files if you modify these conditions
+.if-default-refs: &if-default-refs
+ if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG'
+
+# Make sure to update all the similar conditions in other CI config files if you modify these conditions
+.if-merge-request: &if-merge-request
+ if: '$CI_MERGE_REQUEST_IID'
+
+# Make sure to update all the similar patterns in other CI config files if you modify these patterns
+.code-backstage-patterns: &code-backstage-patterns
+ - ".gitlab/ci/**/*"
+ - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
+ - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
+ - ".csscomb.json"
+ - "Dockerfile.assets"
+ - "*_VERSION"
+ - "Gemfile{,.lock}"
+ - "Rakefile"
+ - "{babel.config,jest.config}.js"
+ - "config.ru"
+ - "{package.json,yarn.lock}"
+ - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
+ - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
+ # Backstage changes
+ - "Dangerfile"
+ - "danger/**/*"
+ - "{,ee/}fixtures/**/*"
+ - "{,ee/}rubocop/**/*"
+ - "{,ee/}spec/**/*"
+ - "doc/README.md" # Some RSpec test rely on this file
+
+# Make sure to update all the similar patterns in other CI config files if you modify these patterns
+.code-backstage-qa-patterns: &code-backstage-qa-patterns
+ - ".gitlab/ci/**/*"
+ - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
+ - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
+ - ".csscomb.json"
+ - "Dockerfile.assets"
+ - "*_VERSION"
+ - "Gemfile{,.lock}"
+ - "Rakefile"
+ - "{babel.config,jest.config}.js"
+ - "config.ru"
+ - "{package.json,yarn.lock}"
+ - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
+ - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
+ # Backstage changes
+ - "Dangerfile"
+ - "danger/**/*"
+ - "{,ee/}fixtures/**/*"
+ - "{,ee/}rubocop/**/*"
+ - "{,ee/}spec/**/*"
+ - "doc/README.md" # Some RSpec test rely on this file
+ # QA changes
+ - ".dockerignore"
+ - "qa/**/*"
+
+.rails:rules:ee-and-foss:
+ rules:
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
+ when: on_success
+
+.rails:rules:default-refs-code-backstage-qa:
+ rules:
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
+ when: on_success
+
+.rails:rules:master-refs:
+ rules:
+ - <<: *if-master-refs
+ when: on_success
+
+.rails:rules:master-refs-ee-only:
+ rules:
+ - <<: *if-not-ee
+ when: never
+ - <<: *if-master-refs
+ when: on_success
+
+.rails:rules:ee-only:
+ rules:
+ - <<: *if-not-ee
+ when: never
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
+ when: on_success
+
+.rails:needs:setup-and-assets:
+ needs:
+ - job: setup-test-env
+ artifacts: true
+ - job: compile-assets pull-cache
+ artifacts: true
+
+.rails-job-base:
extends:
- .default-tags
- .default-retry
- .default-cache
- - .default-only
- .default-before_script
- variables:
- SETUP_DB: "false"
- script:
- - bundle exec rake $CI_JOB_NAME
-
-.only-code-rails-job-base:
- extends:
- - .default-tags
- - .default-retry
- - .default-cache
- - .default-only
- - .default-before_script
- - .only:changes-code-backstage
-
-.only-code-qa-rails-job-base:
- extends:
- - .default-tags
- - .default-retry
- - .default-cache
- - .default-only
- - .default-before_script
- - .only:changes-code-backstage-qa
+####################
+# ee and foss jobs #
setup-test-env:
extends:
- - .only-code-qa-rails-job-base
+ - .rails-job-base
+ - .rails:rules:default-refs-code-backstage-qa
- .use-pg9
stage: prepare
script:
@@ -50,11 +129,48 @@ setup-test-env:
cache:
policy: pull-push
+static-analysis:
+ extends:
+ - .rails-job-base
+ - .rails:rules:default-refs-code-backstage-qa
+ - .rails:needs:setup-and-assets
+ stage: test
+ variables:
+ SETUP_DB: "false"
+ parallel: 2
+ script:
+ - scripts/static-analysis
+ cache:
+ key: "debian-stretch-ruby-2.6-and-rubocop"
+ paths:
+ - vendor/ruby
+ - tmp/rubocop_cache
+ policy: pull-push
+
+downtime_check:
+ extends:
+ - .rails-job-base
+ - .rails:needs:setup-and-assets
+ stage: test
+ rules:
+ - <<: *if-merge-request
+ changes: *code-backstage-patterns
+ when: on_success
+ variables:
+ SETUP_DB: "false"
+ script:
+ - bundle exec rake downtime_check
+
.rspec-base:
- extends: .only-code-rails-job-base
+ extends: .rails-job-base
stage: test
- needs: ["setup-test-env", "retrieve-tests-metadata", "compile-assets pull-cache"]
- dependencies: ["setup-test-env", "retrieve-tests-metadata", "compile-assets pull-cache"]
+ needs:
+ - job: setup-test-env
+ artifacts: true
+ - job: retrieve-tests-metadata
+ artifacts: true
+ - job: compile-assets pull-cache
+ artifacts: true
script:
- source scripts/rspec_helpers.sh
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag ~level:migration"
@@ -72,26 +188,22 @@ setup-test-env:
reports:
junit: junit_rspec.xml
-.rspec-base-foss:
- extends: [".rspec-base", ".only-ee-as-if-foss"]
- needs: ["setup-test-env", "retrieve-tests-metadata", "compile-assets pull-cache foss"]
- dependencies: ["setup-test-env", "retrieve-tests-metadata", "compile-assets pull-cache foss"]
-
-.rspec-base-pg9:
+.rspec-base-quarantine:
extends:
- .rspec-base
- .use-pg9
+ variables:
+ RSPEC_OPTS: "--tag quarantine -- spec/"
+ script:
+ - source scripts/rspec_helpers.sh
+ - rspec_simple_job "${RSPEC_OPTS}"
+ allow_failure: true
-.rspec-base-pg9-foss:
- extends:
- - .rspec-base-foss
- - .use-pg9
-
-.rspec-base-pg10:
+.rspec-base-pg9:
extends:
- .rspec-base
- - .use-pg10
- - .only-master
+ - .rails:rules:ee-and-foss
+ - .use-pg9
.rspec-base-migration:
script:
@@ -104,200 +216,33 @@ rspec migration pg9:
- .rspec-base-migration
parallel: 5
-rspec migration pg9-foss:
- extends:
- - .rspec-base-pg9-foss
- - .rspec-base-migration
- parallel: 5
-
rspec unit pg9:
extends: .rspec-base-pg9
parallel: 20
-rspec unit pg9-foss:
- extends: .rspec-base-pg9-foss
- parallel: 20
-
rspec integration pg9:
extends: .rspec-base-pg9
parallel: 8
-rspec integration pg9-foss:
- extends: .rspec-base-pg9-foss
- parallel: 8
-
rspec system pg9:
extends: .rspec-base-pg9
parallel: 24
-rspec system pg9-foss:
- extends: .rspec-base-pg9-foss
- parallel: 24
-
-rspec unit pg10:
- extends: .rspec-base-pg10
- parallel: 20
-
-rspec integration pg10:
- extends: .rspec-base-pg10
- parallel: 8
-
-rspec system pg10:
- extends: .rspec-base-pg10
- parallel: 24
-
-.rspec-ee-base-pg9:
- extends:
- - .rspec-base
- - .only-ee
- - .use-pg9-ee
-
-.rspec-ee-base-pg10:
- extends:
- - .rspec-base
- - .only-ee
- - .use-pg10-ee
-
-rspec-ee migration pg9:
- extends:
- - .rspec-ee-base-pg9
- - .rspec-base-migration
- parallel: 2
-
-rspec-ee unit pg9:
- extends: .rspec-ee-base-pg9
- parallel: 10
-
-rspec-ee integration pg9:
- extends: .rspec-ee-base-pg9
- parallel: 4
-
-rspec-ee system pg9:
- extends: .rspec-ee-base-pg9
- parallel: 6
-
-rspec-ee migration pg10:
- extends:
- - .rspec-ee-base-pg10
- - .rspec-base-migration
- - .only-master
- parallel: 2
-
-rspec-ee unit pg10:
- extends:
- - .rspec-ee-base-pg10
- - .only-master
- parallel: 10
-
-rspec-ee integration pg10:
- extends:
- - .rspec-ee-base-pg10
- - .only-master
- parallel: 3
-
-rspec-ee system pg10:
- extends:
- - .rspec-ee-base-pg10
- - .only-master
- parallel: 5
-
-.rspec-ee-base-geo:
- extends:
- - .rspec-base
- - .only-ee
- script:
- - source scripts/rspec_helpers.sh
- - scripts/prepare_postgres_fdw.sh
- - rspec_paralellized_job "--tag ~quarantine --tag geo"
-
-.rspec-ee-base-geo-pg9:
- extends:
- - .rspec-ee-base-geo
- - .use-pg9-ee
-
-.rspec-ee-base-geo-pg10:
- extends:
- - .rspec-ee-base-geo
- - .use-pg10-ee
-
-rspec-ee unit pg9 geo:
- extends: .rspec-ee-base-geo-pg9
- parallel: 2
-
-rspec-ee integration pg9 geo:
- extends: .rspec-ee-base-geo-pg9
-
-rspec-ee system pg9 geo:
- extends: .rspec-ee-base-geo-pg9
-
-rspec-ee unit pg10 geo:
- extends: .rspec-ee-base-geo-pg10
- parallel: 2
-
-rspec-ee integration pg10 geo:
- extends: .rspec-ee-base-geo-pg10
-
-rspec-ee system pg10 geo:
- extends: .rspec-ee-base-geo-pg10
-
-rspec quarantine pg9:
- extends:
- - .rspec-base-pg9
- - .only-master
- variables:
- RSPEC_OPTS: "--tag quarantine -- spec/"
- script:
- - source scripts/rspec_helpers.sh
- - rspec_simple_job "${RSPEC_OPTS}"
- allow_failure: true
-
-rspec-ee quarantine pg9:
- extends:
- - rspec quarantine pg9
- - .only-ee
- variables:
- RSPEC_OPTS: "--tag quarantine -- ee/spec/"
-
rspec fast_spec_helper:
extends: .rspec-base-pg9
script:
- bin/rspec spec/fast_spec_helper.rb
-static-analysis:
- extends: .only-code-qa-rails-job-base
- stage: test
- needs: ["setup-test-env", "compile-assets pull-cache"]
- dependencies: ["setup-test-env", "compile-assets pull-cache"]
- variables:
- SETUP_DB: "false"
- parallel: 2
- script:
- - scripts/static-analysis
- cache:
- key: "debian-stretch-ruby-2.6-and-rubocop"
- paths:
- - vendor/ruby
- - tmp/rubocop_cache
- policy: pull-push
-
-downtime_check:
- extends:
- - .rake-exec
- - .only:changes-code-backstage
- - .except:refs-master-tags-stable-deploy
- stage: test
- needs: ["setup-test-env"]
- dependencies: ["setup-test-env"]
-
.db-job-base:
extends:
- - .only-code-rails-job-base
+ - .rails-job-base
+ - .rails:rules:ee-and-foss
- .use-pg9
stage: test
- needs: ["setup-test-env"]
- dependencies: ["setup-test-env"]
+ needs:
+ - job: setup-test-env
+ artifacts: true
-# DB migration, rollback, and seed jobs
db:migrate:reset:
extends: .db-job-base
script:
@@ -358,12 +303,14 @@ gitlab:setup:
- log/development.log
coverage:
- extends: .only-code-rails-job-base
- cache:
- policy: pull
+ extends:
+ - .rails-job-base
+ - .rails:rules:ee-and-foss
+ stage: post-test
variables:
SETUP_DB: "false"
- stage: post-test
+ cache:
+ policy: pull
script:
- bundle exec scripts/merge-simplecov
- bundle exec scripts/gather-test-memory-data
@@ -375,11 +322,181 @@ coverage:
- coverage/index.html
- coverage/assets/
- tmp/memory_test/
+# ee and foss jobs #
+####################
+
+####################
+# master-only jobs #
+rspec quarantine pg9:
+ extends:
+ - .rspec-base-quarantine
+ - .rails:rules:master-refs
+
+.rspec-base-pg10:
+ extends:
+ - .rspec-base
+ - .rails:rules:master-refs
+ - .use-pg10
+
+rspec unit pg10:
+ extends: .rspec-base-pg10
+ parallel: 20
+
+rspec integration pg10:
+ extends: .rspec-base-pg10
+ parallel: 8
+
+rspec system pg10:
+ extends: .rspec-base-pg10
+ parallel: 24
+# master-only jobs #
+####################
+
+#########################
+# ee + master-only jobs #
+rspec-ee quarantine pg9:
+ extends:
+ - .rspec-base-quarantine
+ - .rails:rules:master-refs-ee-only
+ variables:
+ RSPEC_OPTS: "--tag quarantine -- ee/spec/"
+
+rspec-ee migration pg10:
+ extends:
+ - .rspec-ee-base-pg10
+ - .rspec-base-migration
+ - .rails:rules:master-refs
+ parallel: 2
+
+rspec-ee unit pg10:
+ extends:
+ - .rspec-ee-base-pg10
+ - .rails:rules:master-refs
+ parallel: 10
+
+rspec-ee integration pg10:
+ extends:
+ - .rspec-ee-base-pg10
+ - .rails:rules:master-refs
+ parallel: 3
+
+rspec-ee system pg10:
+ extends:
+ - .rspec-ee-base-pg10
+ - .rails:rules:master-refs
+ parallel: 5
+# ee + master-only jobs #
+#########################
+
+#################
+# ee-only jobs #
+.rspec-base-ee:
+ extends:
+ - .rspec-base
+ - .rails:rules:ee-only
+
+.rspec-base-pg9-as-if-foss:
+ extends:
+ - .rspec-base-ee
+ - .as-if-foss
+ - .use-pg9
+ needs:
+ - job: setup-test-env
+ artifacts: true
+ - job: retrieve-tests-metadata
+ artifacts: true
+ - job: compile-assets pull-cache foss
+ artifacts: true
+
+.rspec-ee-base-pg9:
+ extends:
+ - .rspec-base-ee
+ - .use-pg9-ee
+
+.rspec-ee-base-pg10:
+ extends:
+ - .rspec-base-ee
+ - .use-pg10-ee
+
+rspec migration pg9-as-if-foss:
+ extends:
+ - .rspec-base-pg9-as-if-foss
+ - .rspec-base-migration
+ parallel: 5
+
+rspec unit pg9-as-if-foss:
+ extends: .rspec-base-pg9-as-if-foss
+ parallel: 20
+
+rspec integration pg9-as-if-foss:
+ extends: .rspec-base-pg9-as-if-foss
+ parallel: 8
+
+rspec system pg9-as-if-foss:
+ extends: .rspec-base-pg9-as-if-foss
+ parallel: 24
+
+rspec-ee migration pg9:
+ extends:
+ - .rspec-ee-base-pg9
+ - .rspec-base-migration
+ parallel: 2
+
+rspec-ee unit pg9:
+ extends: .rspec-ee-base-pg9
+ parallel: 10
+
+rspec-ee integration pg9:
+ extends: .rspec-ee-base-pg9
+ parallel: 4
+
+rspec-ee system pg9:
+ extends: .rspec-ee-base-pg9
+ parallel: 6
+
+.rspec-ee-base-geo:
+ extends: .rspec-base-ee
+ script:
+ - source scripts/rspec_helpers.sh
+ - scripts/prepare_postgres_fdw.sh
+ - rspec_paralellized_job "--tag ~quarantine --tag geo"
+
+.rspec-ee-base-geo-pg9:
+ extends:
+ - .rspec-ee-base-geo
+ - .use-pg9-ee
+
+.rspec-ee-base-geo-pg10:
+ extends:
+ - .rspec-ee-base-geo
+ - .use-pg10-ee
+
+rspec-ee unit pg9 geo:
+ extends: .rspec-ee-base-geo-pg9
+ parallel: 2
+
+rspec-ee integration pg9 geo:
+ extends: .rspec-ee-base-geo-pg9
+
+rspec-ee system pg9 geo:
+ extends: .rspec-ee-base-geo-pg9
+
+rspec-ee unit pg10 geo:
+ extends: .rspec-ee-base-geo-pg10
+ parallel: 2
+
+rspec-ee integration pg10 geo:
+ extends: .rspec-ee-base-geo-pg10
+
+rspec-ee system pg10 geo:
+ extends: .rspec-ee-base-geo-pg10
db:rollback geo:
extends:
- db:rollback
- - .only-ee
+ - .rails:rules:ee-only
script:
- bundle exec rake geo:db:migrate VERSION=20170627195211
- bundle exec rake geo:db:migrate
+# ee-only jobs #
+################
diff --git a/app/assets/javascripts/diffs/components/diff_file_row.vue b/app/assets/javascripts/diffs/components/diff_file_row.vue
new file mode 100644
index 00000000000..f41337762fd
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/diff_file_row.vue
@@ -0,0 +1,17 @@
+<script>
+/**
+ * This component is an iterative step towards refactoring and simplifying `vue_shared/components/file_row.vue`
+ * https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23720
+ */
+import FileRow from '~/vue_shared/components/file_row.vue';
+
+export default {
+ components: {
+ FileRow,
+ },
+};
+</script>
+
+<template>
+ <file-row v-bind="$attrs" v-on="$listeners" />
+</template>
diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue
index b13619a5471..18c3002825e 100644
--- a/app/assets/javascripts/diffs/components/tree_list.vue
+++ b/app/assets/javascripts/diffs/components/tree_list.vue
@@ -3,7 +3,8 @@ import { mapActions, mapGetters, mapState } from 'vuex';
import { GlTooltipDirective } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
-import FileRow from '~/vue_shared/components/file_row.vue';
+import FileTree from '~/vue_shared/components/file_tree.vue';
+import DiffFileRow from './diff_file_row.vue';
import FileRowStats from './file_row_stats.vue';
export default {
@@ -12,7 +13,7 @@ export default {
},
components: {
Icon,
- FileRow,
+ FileTree,
},
props: {
hideFileStats: {
@@ -61,6 +62,7 @@ export default {
searchPlaceholder: sprintf(s__('MergeRequest|Search files (%{modifier_key}P)'), {
modifier_key: /Mac/i.test(navigator.userAgent) ? '⌘' : 'Ctrl+',
}),
+ DiffFileRow,
};
</script>
@@ -91,7 +93,7 @@ export default {
</div>
<div :class="{ 'pt-0 tree-list-blobs': !renderTreeList }" class="tree-list-scroll">
<template v-if="filteredTreeList.length">
- <file-row
+ <file-tree
v-for="file in filteredTreeList"
:key="file.key"
:file="file"
@@ -99,6 +101,7 @@ export default {
:hide-extra-on-tree="true"
:extra-component="fileRowExtraComponent"
:show-changed-icon="true"
+ :file-row-component="$options.DiffFileRow"
@toggleTreeOpen="toggleTreeOpen"
@clickFile="scrollToFile"
/>
diff --git a/app/assets/javascripts/ide/components/ide_file_row.vue b/app/assets/javascripts/ide/components/ide_file_row.vue
new file mode 100644
index 00000000000..f41337762fd
--- /dev/null
+++ b/app/assets/javascripts/ide/components/ide_file_row.vue
@@ -0,0 +1,17 @@
+<script>
+/**
+ * This component is an iterative step towards refactoring and simplifying `vue_shared/components/file_row.vue`
+ * https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23720
+ */
+import FileRow from '~/vue_shared/components/file_row.vue';
+
+export default {
+ components: {
+ FileRow,
+ },
+};
+</script>
+
+<template>
+ <file-row v-bind="$attrs" v-on="$listeners" />
+</template>
diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue
index bacdfc7c05e..151f7f0c421 100644
--- a/app/assets/javascripts/ide/components/ide_tree_list.vue
+++ b/app/assets/javascripts/ide/components/ide_tree_list.vue
@@ -1,7 +1,8 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlSkeletonLoading } from '@gitlab/ui';
-import FileRow from '~/vue_shared/components/file_row.vue';
+import FileTree from '~/vue_shared/components/file_tree.vue';
+import IdeFileRow from './ide_file_row.vue';
import NavDropdown from './nav_dropdown.vue';
import FileRowExtra from './file_row_extra.vue';
@@ -9,7 +10,7 @@ export default {
components: {
GlSkeletonLoading,
NavDropdown,
- FileRow,
+ FileTree,
},
props: {
viewerType: {
@@ -36,6 +37,7 @@ export default {
...mapActions(['updateViewer', 'toggleTreeOpen']),
},
FileRowExtra,
+ IdeFileRow,
};
</script>
@@ -53,12 +55,13 @@ export default {
</header>
<div class="ide-tree-body h-100">
<template v-if="currentTree.tree.length">
- <file-row
+ <file-tree
v-for="file in currentTree.tree"
:key="file.key"
:file="file"
:level="0"
:extra-component="$options.FileRowExtra"
+ :file-row-component="$options.IdeFileRow"
@toggleTreeOpen="toggleTreeOpen"
/>
</template>
diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue
index 0258a62b390..22fab1b03f2 100644
--- a/app/assets/javascripts/monitoring/components/panel_type.vue
+++ b/app/assets/javascripts/monitoring/components/panel_type.vue
@@ -195,8 +195,8 @@ export default {
</gl-dropdown-item>
<gl-dropdown-item
v-if="clipboardText"
+ ref="copyChartLink"
v-track-event="generateLinkToChartOptions(clipboardText)"
- class="js-chart-link"
:data-clipboard-text="clipboardText"
@click="showToast(clipboardText)"
>
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 611001df32f..d962f644ff8 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -62,9 +62,6 @@ export default {
'is-open': this.file.opened,
};
},
- childFilesLevel() {
- return this.file.isHeader ? 0 : this.level + 1;
- },
},
watch: {
'file.active': function fileActiveWatch(active) {
@@ -131,53 +128,38 @@ export default {
</script>
<template>
- <div>
- <file-header v-if="file.isHeader" :path="file.path" />
- <div
- v-else
- :class="fileClass"
- :title="file.name"
- class="file-row"
- role="button"
- @click="clickFile"
- @mouseleave="toggleDropdown(false)"
- >
- <div class="file-row-name-container">
- <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated">
- <file-icon
- v-if="!showChangedIcon || file.type === 'tree'"
- class="file-row-icon"
- :file-name="file.name"
- :loading="file.loading"
- :folder="isTree"
- :opened="file.opened"
- :size="16"
- />
- <changed-file-icon v-else :file="file" :size="16" class="append-right-5" />
- {{ file.name }}
- </span>
- <component
- :is="extraComponent"
- v-if="extraComponent && !(hideExtraOnTree && file.type === 'tree')"
- :file="file"
- :dropdown-open="dropdownOpen"
- @toggle="toggleDropdown($event)"
+ <file-header v-if="file.isHeader" :path="file.path" />
+ <div
+ v-else
+ :class="fileClass"
+ :title="file.name"
+ class="file-row"
+ role="button"
+ @click="clickFile"
+ @mouseleave="toggleDropdown(false)"
+ >
+ <div class="file-row-name-container">
+ <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated">
+ <file-icon
+ v-if="!showChangedIcon || file.type === 'tree'"
+ class="file-row-icon"
+ :file-name="file.name"
+ :loading="file.loading"
+ :folder="isTree"
+ :opened="file.opened"
+ :size="16"
/>
- </div>
- </div>
- <template v-if="file.opened || file.isHeader">
- <file-row
- v-for="childFile in file.tree"
- :key="childFile.key"
- :file="childFile"
- :level="childFilesLevel"
- :hide-extra-on-tree="hideExtraOnTree"
- :extra-component="extraComponent"
- :show-changed-icon="showChangedIcon"
- @toggleTreeOpen="toggleTreeOpen"
- @clickFile="clickedFile"
+ <changed-file-icon v-else :file="file" :size="16" class="append-right-5" />
+ {{ file.name }}
+ </span>
+ <component
+ :is="extraComponent"
+ v-if="extraComponent && !(hideExtraOnTree && file.type === 'tree')"
+ :file="file"
+ :dropdown-open="dropdownOpen"
+ @toggle="toggleDropdown($event)"
/>
- </template>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/file_tree.vue b/app/assets/javascripts/vue_shared/components/file_tree.vue
new file mode 100644
index 00000000000..e7817b8f910
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/file_tree.vue
@@ -0,0 +1,47 @@
+<script>
+export default {
+ name: 'FileTree',
+ props: {
+ fileRowComponent: {
+ type: Object,
+ required: true,
+ },
+ level: {
+ type: Number,
+ required: true,
+ },
+ file: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ childFilesLevel() {
+ return this.file.isHeader ? 0 : this.level + 1;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <component
+ :is="fileRowComponent"
+ :level="level"
+ :file="file"
+ v-bind="$attrs"
+ v-on="$listeners"
+ />
+ <template v-if="file.opened || file.isHeader">
+ <file-tree
+ v-for="childFile in file.tree"
+ :key="childFile.key"
+ :file-row-component="fileRowComponent"
+ :level="childFilesLevel"
+ :file="childFile"
+ v-bind="$attrs"
+ v-on="$listeners"
+ />
+ </template>
+ </div>
+</template>
diff --git a/changelogs/unreleased/remove-issue_link_types.yml b/changelogs/unreleased/remove-issue_link_types.yml
new file mode 100644
index 00000000000..f123327de13
--- /dev/null
+++ b/changelogs/unreleased/remove-issue_link_types.yml
@@ -0,0 +1,5 @@
+---
+title: Expose issue link type in REST API
+merge_request: 24175
+author:
+type: added
diff --git a/db/post_migrate/20191115115522_migrate_epic_notes_mentions_to_db.rb b/db/post_migrate/20191115115522_migrate_epic_notes_mentions_to_db.rb
index e0b3c36b57d..7914ff59dbd 100644
--- a/db/post_migrate/20191115115522_migrate_epic_notes_mentions_to_db.rb
+++ b/db/post_migrate/20191115115522_migrate_epic_notes_mentions_to_db.rb
@@ -14,7 +14,7 @@ class MigrateEpicNotesMentionsToDb < ActiveRecord::Migration[5.2]
INDEX_NAME = 'epic_mentions_temp_index'
INDEX_CONDITION = "note LIKE '%@%'::text AND notes.noteable_type = 'Epic'"
QUERY_CONDITIONS = "#{INDEX_CONDITION} AND epic_user_mentions.epic_id IS NULL"
- JOIN = 'LEFT JOIN epic_user_mentions ON notes.id = epic_user_mentions.note_id'
+ JOIN = 'INNER JOIN epics ON epics.id = notes.noteable_id LEFT JOIN epic_user_mentions ON notes.id = epic_user_mentions.note_id'
class Note < ActiveRecord::Base
include EachBatch
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 51d5c758084..b98f02ccc98 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -288,10 +288,13 @@ For source installations, edit the `gitlab.yml` and set the Sidekiq
## `gitlab-shell.log`
-This file lives in `/var/log/gitlab/gitlab-shell/gitlab-shell.log` for
-Omnibus GitLab packages or in `/home/git/gitlab-shell/gitlab-shell.log` for
+This file lives in `/var/log/gitlab/gitaly/gitlab-shell.log` for
+Omnibus GitLab packages or in `/home/git/gitaly/gitlab-shell.log` for
installations from source.
+NOTE: **Note**
+For GitLab 12.5 and earlier the file lives in `/var/log/gitlab/gitlab-shell/gitlab-shell.log`.
+
GitLab Shell is used by GitLab for executing Git commands and provide
SSH access to Git repositories. For example:
diff --git a/doc/api/issue_links.md b/doc/api/issue_links.md
index 941cc0b1347..2a64c2370fc 100644
--- a/doc/api/issue_links.md
+++ b/doc/api/issue_links.md
@@ -67,7 +67,7 @@ POST /projects/:id/issues/:issue_iid/links
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `target_project_id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) of a target project |
| `target_issue_iid` | integer/string | yes | The internal ID of a target project's issue |
-| `link_type` | string | no | The type of the relation ("relates_to", "blocks", "is_blocked_by"), defaults to "relates_to"). Ignored unless `issue_link_types` feature flag is enabled. |
+| `link_type` | string | no | The type of the relation ("relates_to", "blocks", "is_blocked_by"), defaults to "relates_to"). |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues/1/links?target_project_id=5&target_issue_iid=1"
diff --git a/doc/development/integrations/secure.md.md b/doc/development/integrations/secure.md
index b9b37a7e298..b9b37a7e298 100644
--- a/doc/development/integrations/secure.md.md
+++ b/doc/development/integrations/secure.md
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 25672d510c7..41040258e01 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -95,7 +95,7 @@ The following table depicts the various user permission levels in a project.
| Stop environments | | | ✓ | ✓ | ✓ |
| Add tags | | | ✓ | ✓ | ✓ |
| Cancel and retry jobs | | | ✓ | ✓ | ✓ |
-| Create or update commit status | | | ✓ | ✓ | ✓ |
+| Create or update commit status | | | ✓ (*5*) | ✓ | ✓ |
| Update a container registry | | | ✓ | ✓ | ✓ |
| Remove a container registry image | | | ✓ | ✓ | ✓ |
| Create/edit/delete project milestones | | | ✓ | ✓ | ✓ |
@@ -144,6 +144,7 @@ The following table depicts the various user permission levels in a project.
(*2*): Guest users can only view the confidential issues they created themselves.
(*3*): If **Public pipelines** is enabled in **Project Settings > CI/CD**.
(*4*): Not allowed for Guest, Reporter, Developer, Maintainer, or Owner. See [Protected Branches](./project/protected_branches.md).
+(*5*): If the [branch is protected](./project/protected_branches.md#using-the-allowed-to-merge-and-allowed-to-push-settings), this depends on the access Developers and Maintainers are given.
## Project features permissions
diff --git a/lib/gitlab/background_migration/user_mentions/create_resource_user_mention.rb b/lib/gitlab/background_migration/user_mentions/create_resource_user_mention.rb
index 7d40dfbcdc4..40f45301727 100644
--- a/lib/gitlab/background_migration/user_mentions/create_resource_user_mention.rb
+++ b/lib/gitlab/background_migration/user_mentions/create_resource_user_mention.rb
@@ -13,7 +13,7 @@ module Gitlab
def perform(resource_model, join, conditions, with_notes, start_id, end_id)
resource_model = "#{ISOLATION_MODULE}::#{resource_model}".constantize if resource_model.is_a?(String)
- model = with_notes ? "#{ISOLATION_MODULE}::Note".constantize : resource_model
+ model = with_notes ? Gitlab::BackgroundMigration::UserMentions::Models::Note : resource_model
resource_user_mention_model = resource_model.user_mention_model
records = model.joins(join).where(conditions).where(id: start_id..end_id)
@@ -21,7 +21,7 @@ module Gitlab
records.in_groups_of(BULK_INSERT_SIZE, false).each do |records|
mentions = []
records.each do |record|
- mentions << record.build_mention_values
+ mentions << record.build_mention_values(resource_user_mention_model.resource_foreign_key)
end
Gitlab::Database.bulk_insert(
diff --git a/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb b/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb
index 40aab896212..b7fa92a6686 100644
--- a/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb
+++ b/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb
@@ -65,11 +65,11 @@ module Gitlab
false
end
- def build_mention_values
+ def build_mention_values(resource_foreign_key)
refs = all_references(author)
{
- "#{self.user_mention_model.resource_foreign_key}": user_mention_resource_id,
+ "#{resource_foreign_key}": user_mention_resource_id,
note_id: user_mention_note_id,
mentioned_users_ids: array_to_sql(refs.mentioned_users.pluck(:id)),
mentioned_projects_ids: array_to_sql(refs.mentioned_projects.pluck(:id)),
diff --git a/lib/gitlab/background_migration/user_mentions/models/note.rb b/lib/gitlab/background_migration/user_mentions/models/note.rb
index c2828202907..dc364d7af5a 100644
--- a/lib/gitlab/background_migration/user_mentions/models/note.rb
+++ b/lib/gitlab/background_migration/user_mentions/models/note.rb
@@ -19,10 +19,6 @@ module Gitlab
belongs_to :noteable, polymorphic: true
belongs_to :project
- def user_mention_model
- "#{CreateResourceUserMention::ISOLATION_MODULE}::#{noteable.class}".constantize.user_mention_model
- end
-
def for_personal_snippet?
noteable.class.name == 'PersonalSnippet'
end
diff --git a/spec/frontend/diffs/components/diff_file_row_spec.js b/spec/frontend/diffs/components/diff_file_row_spec.js
new file mode 100644
index 00000000000..3e95d1d55bd
--- /dev/null
+++ b/spec/frontend/diffs/components/diff_file_row_spec.js
@@ -0,0 +1,25 @@
+import { shallowMount } from '@vue/test-utils';
+import DiffFileRow from '~/diffs/components/diff_file_row.vue';
+import FileRow from '~/vue_shared/components/file_row.vue';
+
+describe('Diff File Row component', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(DiffFileRow, {
+ propsData: { ...props },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders file row component', () => {
+ createComponent({
+ level: 4,
+ file: {},
+ });
+ expect(wrapper.find(FileRow).exists()).toEqual(true);
+ });
+});
diff --git a/spec/frontend/ide/components/ide_file_row_spec.js b/spec/frontend/ide/components/ide_file_row_spec.js
new file mode 100644
index 00000000000..7531bc3e144
--- /dev/null
+++ b/spec/frontend/ide/components/ide_file_row_spec.js
@@ -0,0 +1,25 @@
+import { shallowMount } from '@vue/test-utils';
+import IdeFileRow from '~/ide/components/ide_file_row.vue';
+import FileRow from '~/vue_shared/components/file_row.vue';
+
+describe('Ide File Row component', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(IdeFileRow, {
+ propsData: { ...props },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders file row component', () => {
+ createComponent({
+ level: 4,
+ file: {},
+ });
+ expect(wrapper.find(FileRow).exists()).toEqual(true);
+ });
+});
diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js
index 70b2c9cf527..7a039d46d39 100644
--- a/spec/frontend/monitoring/components/dashboard_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_spec.js
@@ -1,5 +1,5 @@
import { shallowMount, createLocalVue, mount } from '@vue/test-utils';
-import { GlDropdownItem, GlButton, GlToast } from '@gitlab/ui';
+import { GlDropdownItem, GlButton } from '@gitlab/ui';
import VueDraggable from 'vuedraggable';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
@@ -10,6 +10,7 @@ import Dashboard from '~/monitoring/components/dashboard.vue';
import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
import DashboardsDropdown from '~/monitoring/components/dashboards_dropdown.vue';
import GroupEmptyState from '~/monitoring/components/group_empty_state.vue';
+import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue';
import { createStore } from '~/monitoring/stores';
import * as types from '~/monitoring/stores/mutation_types';
import { setupComponentStore, propsData } from '../init_utils';
@@ -540,37 +541,36 @@ describe('Dashboard', () => {
});
});
- // https://gitlab.com/gitlab-org/gitlab-ce/issues/66922
- // eslint-disable-next-line jest/no-disabled-tests
- describe.skip('link to chart', () => {
+ describe('Clipboard text in panels', () => {
const currentDashboard = 'TEST_DASHBOARD';
- localVue.use(GlToast);
- const link = () => wrapper.find('.js-chart-link');
- const clipboardText = () => link().element.dataset.clipboardText;
+
+ const getClipboardTextAt = i =>
+ wrapper
+ .findAll(PanelType)
+ .at(i)
+ .props('clipboardText');
beforeEach(done => {
createShallowWrapper({ hasMetrics: true, currentDashboard });
- setTimeout(done);
- });
+ setupComponentStore(wrapper);
- it('adds a copy button to the dropdown', () => {
- expect(link().text()).toContain('Generate link to chart');
+ wrapper.vm.$nextTick(done);
});
it('contains a link to the dashboard', () => {
- expect(clipboardText()).toContain(`dashboard=${currentDashboard}`);
- expect(clipboardText()).toContain(`group=`);
- expect(clipboardText()).toContain(`title=`);
- expect(clipboardText()).toContain(`y_label=`);
+ expect(getClipboardTextAt(0)).toContain(`dashboard=${currentDashboard}`);
+ expect(getClipboardTextAt(0)).toContain(`group=`);
+ expect(getClipboardTextAt(0)).toContain(`title=`);
+ expect(getClipboardTextAt(0)).toContain(`y_label=`);
});
- it('undefined parameter is stripped', done => {
+ it('strips the undefined parameter', done => {
wrapper.setProps({ currentDashboard: undefined });
wrapper.vm.$nextTick(() => {
- expect(clipboardText()).not.toContain(`dashboard=`);
- expect(clipboardText()).toContain(`y_label=`);
+ expect(getClipboardTextAt(0)).not.toContain(`dashboard=`);
+ expect(getClipboardTextAt(0)).toContain(`y_label=`);
done();
});
});
@@ -579,18 +579,10 @@ describe('Dashboard', () => {
wrapper.setProps({ currentDashboard: null });
wrapper.vm.$nextTick(() => {
- expect(clipboardText()).not.toContain(`dashboard=`);
- expect(clipboardText()).toContain(`y_label=`);
+ expect(getClipboardTextAt(0)).not.toContain(`dashboard=`);
+ expect(getClipboardTextAt(0)).toContain(`y_label=`);
done();
});
});
-
- it('creates a toast when clicked', () => {
- jest.spyOn(wrapper.vm.$toast, 'show').and.stub();
-
- link().vm.$emit('click');
-
- expect(wrapper.vm.$toast.show).toHaveBeenCalled();
- });
});
});
diff --git a/spec/frontend/monitoring/panel_type_spec.js b/spec/frontend/monitoring/components/panel_type_spec.js
index 730d67f79d8..6d8bd1d3a30 100644
--- a/spec/frontend/monitoring/panel_type_spec.js
+++ b/spec/frontend/monitoring/components/panel_type_spec.js
@@ -3,22 +3,29 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import { setTestTimeout } from 'helpers/timeout';
import invalidUrl from '~/lib/utils/invalid_url';
import axios from '~/lib/utils/axios_utils';
+
import PanelType from '~/monitoring/components/panel_type.vue';
import EmptyChart from '~/monitoring/components/charts/empty_chart.vue';
import TimeSeriesChart from '~/monitoring/components/charts/time_series.vue';
import AnomalyChart from '~/monitoring/components/charts/anomaly.vue';
-import { graphDataPrometheusQueryRange } from '../../javascripts/monitoring/mock_data';
-import { anomalyMockGraphData } from '../../frontend/monitoring/mock_data';
+import { anomalyMockGraphData, graphDataPrometheusQueryRange } from 'jest/monitoring/mock_data';
import { createStore } from '~/monitoring/stores';
global.IS_EE = true;
global.URL.createObjectURL = jest.fn();
+const mocks = {
+ $toast: {
+ show: jest.fn(),
+ },
+};
+
describe('Panel Type component', () => {
let axiosMock;
let store;
let state;
let wrapper;
+
const exampleText = 'example_text';
const createWrapper = props => {
@@ -27,6 +34,7 @@ describe('Panel Type component', () => {
...props,
},
store,
+ mocks,
});
};
@@ -88,7 +96,7 @@ describe('Panel Type component', () => {
});
it('sets no clipboard copy link on dropdown by default', () => {
- const link = () => wrapper.find('.js-chart-link');
+ const link = () => wrapper.find({ ref: 'copyChartLink' });
expect(link().exists()).toBe(false);
});
@@ -196,6 +204,7 @@ describe('Panel Type component', () => {
});
describe('when cliboard data is available', () => {
+ const link = () => wrapper.find({ ref: 'copyChartLink' });
const clipboardText = 'A value to copy.';
beforeEach(() => {
@@ -210,11 +219,19 @@ describe('Panel Type component', () => {
});
it('sets clipboard text on the dropdown', () => {
- const link = () => wrapper.find('.js-chart-link');
-
expect(link().exists()).toBe(true);
expect(link().element.dataset.clipboardText).toBe(clipboardText);
});
+
+ it('adds a copy button to the dropdown', () => {
+ expect(link().text()).toContain('Generate link to chart');
+ });
+
+ it('opens a toast on click', () => {
+ link().vm.$emit('click');
+
+ expect(wrapper.vm.$toast.show).toHaveBeenCalled();
+ });
});
describe('when downloading metrics data as CSV', () => {
diff --git a/spec/frontend/vue_shared/components/file_tree_spec.js b/spec/frontend/vue_shared/components/file_tree_spec.js
new file mode 100644
index 00000000000..38979d9d844
--- /dev/null
+++ b/spec/frontend/vue_shared/components/file_tree_spec.js
@@ -0,0 +1,88 @@
+import { pick } from 'lodash';
+import { shallowMount } from '@vue/test-utils';
+import FileTree from '~/vue_shared/components/file_tree.vue';
+
+const MockFileRow = {
+ name: 'MockFileRow',
+ render() {
+ return this.$slots.default;
+ },
+};
+
+const TEST_LEVEL = 4;
+const TEST_EXTA_ARGS = {
+ foo: 'lorem-ipsum',
+ bar: 'zoo',
+};
+
+describe('File Tree component', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(FileTree, {
+ propsData: { level: TEST_LEVEL, fileRowComponent: MockFileRow, ...props },
+ attrs: { ...TEST_EXTA_ARGS },
+ });
+ };
+
+ const findFileRow = () => wrapper.find(MockFileRow);
+ const findChildrenTrees = () => wrapper.findAll(FileTree).wrappers.slice(1);
+ const findChildrenTreeProps = () =>
+ findChildrenTrees().map(x => ({
+ ...x.props(),
+ ...pick(x.attributes(), Object.keys(TEST_EXTA_ARGS)),
+ }));
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('file row component', () => {
+ beforeEach(() => {
+ createComponent({ file: {} });
+ });
+
+ it('renders file row component', () => {
+ expect(findFileRow().exists()).toEqual(true);
+ });
+
+ it('contains the required attribute keys', () => {
+ const fileRow = findFileRow();
+
+ // Checking strings b/c value in attributes are always strings
+ expect(fileRow.attributes()).toEqual({
+ file: {}.toString(),
+ level: TEST_LEVEL.toString(),
+ ...TEST_EXTA_ARGS,
+ });
+ });
+ });
+
+ describe('file tree', () => {
+ const createChildren = () => [{ id: 1 }, { id: 2 }];
+ const createChildrenExpectation = (props = {}) =>
+ createChildren().map(file => ({
+ fileRowComponent: MockFileRow,
+ file,
+ ...TEST_EXTA_ARGS,
+ ...props,
+ }));
+
+ it.each`
+ key | value | desc | expectedChildren
+ ${'isHeader'} | ${true} | ${'is shown if file is header'} | ${createChildrenExpectation({ level: 0 })}
+ ${'opened'} | ${true} | ${'is shown if file is open'} | ${createChildrenExpectation({ level: TEST_LEVEL + 1 })}
+ ${'isHeader'} | ${false} | ${'is hidden if file is header'} | ${[]}
+ ${'opened'} | ${false} | ${'is hidden if file is open'} | ${[]}
+ `('$desc', ({ key, value, expectedChildren }) => {
+ createComponent({
+ file: {
+ [key]: value,
+ tree: createChildren(),
+ },
+ });
+
+ expect(findChildrenTreeProps()).toEqual(expectedChildren);
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/file_row_spec.js b/spec/javascripts/vue_shared/components/file_row_spec.js
index 2d80099fafe..071a09f8b93 100644
--- a/spec/javascripts/vue_shared/components/file_row_spec.js
+++ b/spec/javascripts/vue_shared/components/file_row_spec.js
@@ -19,7 +19,6 @@ describe('File row component', () => {
const findNewDropdown = () => vm.$el.querySelector('.ide-new-btn .dropdown');
const findNewDropdownButton = () => vm.$el.querySelector('.ide-new-btn .dropdown button');
- const findFileRow = () => vm.$el.querySelector('.file-row');
it('renders name', () => {
createComponent({
@@ -42,7 +41,7 @@ describe('File row component', () => {
});
spyOn(vm, '$emit').and.stub();
- vm.$el.querySelector('.file-row').click();
+ vm.$el.click();
expect(vm.$emit).toHaveBeenCalledWith('toggleTreeOpen', vm.file.path);
});
@@ -87,7 +86,7 @@ describe('File row component', () => {
level: 0,
});
- expect(vm.$el.querySelector('.js-file-row-header')).not.toBe(null);
+ expect(vm.$el.classList).toContain('js-file-row-header');
});
describe('new dropdown', () => {
@@ -138,7 +137,7 @@ describe('File row component', () => {
});
it('closes when row triggers mouseleave', () => {
- findFileRow().dispatchEvent(new Event('mouseleave'));
+ vm.$el.dispatchEvent(new Event('mouseleave'));
expect(vm.dropdownOpen).toBe(false);
});
diff --git a/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb
new file mode 100644
index 00000000000..f90e1a1ebab
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+shared_examples 'resource mentions migration' do |migration_class, resource_class|
+ it 'migrates resource mentions' do
+ join = migration_class::JOIN
+ conditions = migration_class::QUERY_CONDITIONS
+
+ expect do
+ subject.perform(resource_class.name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id))
+ end.to change { user_mentions.count }.by(1)
+
+ user_mention = user_mentions.last
+ expect(user_mention.mentioned_users_ids.sort).to eq(mentioned_users.pluck(:id).sort)
+ expect(user_mention.mentioned_groups_ids.sort).to eq([group.id])
+ expect(user_mention.mentioned_groups_ids.sort).not_to include(inaccessible_group.id)
+
+ # check that performing the same job twice does not fail and does not change counts
+ expect do
+ subject.perform(resource_class.name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id))
+ end.to change { user_mentions.count }.by(0)
+ end
+end
+
+shared_examples 'resource notes mentions migration' do |migration_class, resource_class|
+ before do
+ note1.becomes(Note).save!
+ note2.becomes(Note).save!
+ note3.becomes(Note).save!
+ # note4.becomes(Note).save(validate: false)
+ end
+
+ it 'migrates mentions from note' do
+ join = migration_class::JOIN
+ conditions = migration_class::QUERY_CONDITIONS
+
+ # there are 4 notes for each noteable_type, but one does not have mentions and
+ # another one's noteable_id points to an inexistent resource
+ expect(notes.where(noteable_type: resource_class.to_s).count).to eq 4
+
+ expect do
+ subject.perform(resource_class.name, join, conditions, true, Note.minimum(:id), Note.maximum(:id))
+ end.to change { user_mentions.count }.by(2)
+
+ # check that the user_mention for regular note is created
+ user_mention = user_mentions.first
+ expect(Note.find(user_mention.note_id).system).to be false
+ expect(user_mention.mentioned_users_ids.sort).to eq(users.pluck(:id).sort)
+ expect(user_mention.mentioned_groups_ids.sort).to eq([group.id])
+ expect(user_mention.mentioned_groups_ids.sort).not_to include(inaccessible_group.id)
+
+ # check that the user_mention for system note is created
+ user_mention = user_mentions.second
+ expect(Note.find(user_mention.note_id).system).to be true
+ expect(user_mention.mentioned_users_ids.sort).to eq(users.pluck(:id).sort)
+ expect(user_mention.mentioned_groups_ids.sort).to eq([group.id])
+ expect(user_mention.mentioned_groups_ids.sort).not_to include(inaccessible_group.id)
+
+ # check that performing the same job twice does not fail and does not change counts
+ expect do
+ subject.perform(resource_class.name, join, conditions, true, Note.minimum(:id), Note.maximum(:id))
+ end.to change { user_mentions.count }.by(0)
+ end
+end
+
+shared_examples 'schedules resource mentions migration' do |resource_class, is_for_notes|
+ it 'schedules background migrations' do
+ Sidekiq::Testing.fake! do
+ Timecop.freeze do
+ migrate!
+
+ migration = described_class::MIGRATION
+ join = described_class::JOIN
+ conditions = described_class::QUERY_CONDITIONS
+
+ expect(migration).to be_scheduled_delayed_migration(2.minutes, resource_class.name, join, conditions, is_for_notes, resource1.id, resource1.id)
+ expect(migration).to be_scheduled_delayed_migration(4.minutes, resource_class.name, join, conditions, is_for_notes, resource2.id, resource2.id)
+ expect(migration).to be_scheduled_delayed_migration(6.minutes, resource_class.name, join, conditions, is_for_notes, resource3.id, resource3.id)
+ expect(BackgroundMigrationWorker.jobs.size).to eq 3
+ end
+ end
+ end
+end