summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml296
-rw-r--r--.gitlab/merge_request_templates/Database Changes.md10
-rw-r--r--CONTRIBUTING.md3
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock23
-rw-r--r--Gemfile.rails5.lock17
-rw-r--r--app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue77
-rw-r--r--app/assets/javascripts/pages/projects/wikis/index.js28
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue20
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue (renamed from app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js)6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/dependencies.js5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue (renamed from app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js)166
-rw-r--r--app/controllers/concerns/send_file_upload.rb4
-rw-r--r--app/controllers/projects/notes_controller.rb13
-rw-r--r--app/controllers/projects/pipelines_controller.rb4
-rw-r--r--app/models/ci/pipeline.rb12
-rw-r--r--app/policies/ci/build_policy.rb9
-rw-r--r--app/policies/ci/pipeline_policy.rb8
-rw-r--r--app/policies/project_policy.rb4
-rw-r--r--app/views/projects/wikis/edit.html.haml11
-rwxr-xr-xbin/secpick5
-rwxr-xr-xbin/spinach13
-rw-r--r--changelogs/unreleased/46010-add-index-to-runner-type.yml5
-rw-r--r--changelogs/unreleased/46286-fix-ingress-rbac-default-value.yml5
-rw-r--r--changelogs/unreleased/46345-kubernetes-popover-illustration-skewed.yml5
-rw-r--r--changelogs/unreleased/blackst0ne-remove-spinach.yml5
-rw-r--r--changelogs/unreleased/jprovazn-null-byte.yml5
-rw-r--r--changelogs/unreleased/jprovazn-pipeline-policy.yml6
-rw-r--r--changelogs/unreleased/refactor-move-squash-before-merge-vue-component.yml5
-rw-r--r--changelogs/unreleased/sh-fix-blocked-user-account-ldap.yml5
-rw-r--r--changelogs/unreleased/sh-fix-cross-site-origin-uploads-js.yml5
-rw-r--r--changelogs/unreleased/update-wiki-modal.yml5
-rw-r--r--config/initializers/deprecations.rb8
-rw-r--r--db/migrate/20180511090724_add_index_on_ci_runners_runner_type.rb15
-rw-r--r--db/schema.rb3
-rw-r--r--doc/README.md2
-rw-r--r--doc/api/jobs.md4
-rw-r--r--doc/development/code_review.md5
-rw-r--r--doc/development/database_debugging.md2
-rw-r--r--doc/development/rake_tasks.md5
-rw-r--r--doc/development/testing_guide/best_practices.md3
-rw-r--r--doc/development/testing_guide/ci.md3
-rw-r--r--doc/development/testing_guide/frontend_testing.md20
-rw-r--r--doc/development/testing_guide/index.md15
-rw-r--r--doc/development/testing_guide/testing_levels.md1
-rw-r--r--doc/user/project/merge_requests/maintainer_access.md2
-rw-r--r--features/steps/group/members.rb68
-rw-r--r--features/steps/profile/notifications.rb20
-rw-r--r--features/steps/project/commits/branches.rb32
-rw-r--r--features/steps/project/commits/comments.rb6
-rw-r--r--features/steps/project/commits/diff_comments.rb6
-rw-r--r--features/steps/project/create.rb23
-rw-r--r--features/steps/project/issues/filter_labels.rb61
-rw-r--r--features/steps/project/issues/issues.rb175
-rw-r--r--features/steps/project/issues/milestones.rb20
-rw-r--r--features/steps/project/issues/references.rb7
-rw-r--r--features/steps/project/merge_requests/references.rb7
-rw-r--r--features/steps/project/source/browse_files.rb435
-rw-r--r--features/steps/shared/active_tab.rb32
-rw-r--r--features/steps/shared/admin.rb11
-rw-r--r--features/steps/shared/authentication.rb56
-rw-r--r--features/steps/shared/diff_note.rb44
-rw-r--r--features/steps/shared/group.rb46
-rw-r--r--features/steps/shared/issuable.rb78
-rw-r--r--features/steps/shared/markdown.rb11
-rw-r--r--features/steps/shared/note.rb21
-rw-r--r--features/steps/shared/paths.rb413
-rw-r--r--features/steps/shared/project.rb102
-rw-r--r--features/steps/shared/project_tab.rb66
-rw-r--r--features/steps/shared/shortcuts.rb18
-rw-r--r--features/steps/shared/sidebar_active_tab.rb31
-rw-r--r--features/steps/shared/user.rb41
-rw-r--r--features/support/capybara.rb50
-rw-r--r--features/support/db_cleaner.rb11
-rw-r--r--features/support/env.rb60
-rw-r--r--features/support/gitaly.rb3
-rw-r--r--features/support/login_helpers.rb19
-rw-r--r--features/support/rerun.rb16
-rw-r--r--lib/gitlab/auth/blocked_user_tracker.rb4
-rw-r--r--lib/gitlab/project_search_results.rb2
-rw-r--r--lib/gitlab/untrusted_regexp.rb19
-rw-r--r--lib/tasks/gitlab/test.rake1
-rw-r--r--lib/tasks/spinach.rake60
-rw-r--r--package.json2
-rw-r--r--spec/controllers/concerns/send_file_upload_spec.rb15
-rw-r--r--spec/factories/clusters/clusters.rb4
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb1
-rw-r--r--spec/features/projects/wiki/user_deletes_wiki_page_spec.rb3
-rw-r--r--spec/javascripts/helpers/vue_mount_component_helper.js22
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js40
-rw-r--r--spec/javascripts/vue_mr_widget/mr_widget_options_spec.js2
-rw-r--r--spec/lib/gitlab/auth/blocked_user_tracker_spec.rb44
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb12
-rw-r--r--spec/lib/gitlab/untrusted_regexp_spec.rb8
-rw-r--r--spec/policies/ci/build_policy_spec.rb13
-rw-r--r--spec/policies/ci/pipeline_policy_spec.rb12
-rw-r--r--spec/policies/project_policy_spec.rb2
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb21
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb29
-rw-r--r--spec/services/clusters/create_service_spec.rb68
-rw-r--r--spec/support/services/clusters/create_service_shared.rb57
-rw-r--r--vendor/ingress/values.yaml5
-rw-r--r--yarn.lock6
103 files changed, 718 insertions, 2601 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9c1eb2736b1..b1445feee58 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -31,7 +31,6 @@ variables:
GIT_SUBMODULE_STRATEGY: "none"
GET_SOURCES_ATTEMPTS: "3"
KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
- KNAPSACK_SPINACH_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/spinach_report-master.json
FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json
before_script:
@@ -179,46 +178,6 @@ stages:
<<: *rspec-metadata-mysql
<<: *rails5
-.spinach-metadata: &spinach-metadata
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
- <<: *rails5-variables
- stage: test
- script:
- - JOB_NAME=( $CI_JOB_NAME )
- - export CI_NODE_INDEX=${JOB_NAME[-2]}
- - export CI_NODE_TOTAL=${JOB_NAME[-1]}
- - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- - export KNAPSACK_GENERATE_REPORT=true
- - export CACHE_CLASSES=true
- - cp ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
- - scripts/gitaly-test-spawn
- - knapsack spinach "-r rerun" -b || retry '[[ -e tmp/spinach-rerun.txt ]] && bundle exec spinach -b -r rerun $(cat tmp/spinach-rerun.txt)'
- artifacts:
- expire_in: 31d
- when: always
- paths:
- - coverage/
- - knapsack/
- - tmp/capybara/
-
-.spinach-metadata-pg: &spinach-metadata-pg
- <<: *spinach-metadata
- <<: *use-pg
-
-.spinach-metadata-pg-rails5: &spinach-metadata-pg-rails5
- <<: *spinach-metadata-pg
- <<: *rails5
-
-.spinach-metadata-mysql: &spinach-metadata-mysql
- <<: *spinach-metadata
- <<: *use-mysql
-
-.spinach-metadata-mysql-rails5: &spinach-metadata-mysql-rails5
- <<: *spinach-metadata-mysql
- <<: *rails5
-
.only-canonical-masters: &only-canonical-masters
only:
- master@gitlab-org/gitlab-ce
@@ -350,9 +309,7 @@ retrieve-tests-metadata:
script:
- mkdir -p knapsack/${CI_PROJECT_NAME}/
- wget -O $KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $KNAPSACK_RSPEC_SUITE_REPORT_PATH
- - wget -O $KNAPSACK_SPINACH_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_SPINACH_SUITE_REPORT_PATH || rm $KNAPSACK_SPINACH_SUITE_REPORT_PATH
- '[[ -f $KNAPSACK_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH}'
- - '[[ -f $KNAPSACK_SPINACH_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_SPINACH_SUITE_REPORT_PATH}'
- mkdir -p rspec_flaky/
- wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH
- '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}'
@@ -370,10 +327,9 @@ update-tests-metadata:
script:
- retry gem install fog-aws mime-types activesupport
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
- - scripts/merge-reports ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/spinach-pg_node_*.json
- scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json
- FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
- - '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH $KNAPSACK_SPINACH_SUITE_REPORT_PATH'
+ - '[[ -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 $FLAKY_RSPEC_SUITE_REPORT_PATH'
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
- rm -f rspec_flaky/all_*.json rspec_flaky/new_*.json
@@ -441,133 +397,129 @@ setup-test-env:
- config/secrets.yml
- vendor/gitaly-ruby
-rspec-pg 0 28: *rspec-metadata-pg
-rspec-pg 1 28: *rspec-metadata-pg
-rspec-pg 2 28: *rspec-metadata-pg
-rspec-pg 3 28: *rspec-metadata-pg
-rspec-pg 4 28: *rspec-metadata-pg
-rspec-pg 5 28: *rspec-metadata-pg
-rspec-pg 6 28: *rspec-metadata-pg
-rspec-pg 7 28: *rspec-metadata-pg
-rspec-pg 8 28: *rspec-metadata-pg
-rspec-pg 9 28: *rspec-metadata-pg
-rspec-pg 10 28: *rspec-metadata-pg
-rspec-pg 11 28: *rspec-metadata-pg
-rspec-pg 12 28: *rspec-metadata-pg
-rspec-pg 13 28: *rspec-metadata-pg
-rspec-pg 14 28: *rspec-metadata-pg
-rspec-pg 15 28: *rspec-metadata-pg
-rspec-pg 16 28: *rspec-metadata-pg
-rspec-pg 17 28: *rspec-metadata-pg
-rspec-pg 18 28: *rspec-metadata-pg
-rspec-pg 19 28: *rspec-metadata-pg
-rspec-pg 20 28: *rspec-metadata-pg
-rspec-pg 21 28: *rspec-metadata-pg
-rspec-pg 22 28: *rspec-metadata-pg
-rspec-pg 23 28: *rspec-metadata-pg
-rspec-pg 24 28: *rspec-metadata-pg
-rspec-pg 25 28: *rspec-metadata-pg
-rspec-pg 26 28: *rspec-metadata-pg
-rspec-pg 27 28: *rspec-metadata-pg
-
-rspec-mysql 0 28: *rspec-metadata-mysql
-rspec-mysql 1 28: *rspec-metadata-mysql
-rspec-mysql 2 28: *rspec-metadata-mysql
-rspec-mysql 3 28: *rspec-metadata-mysql
-rspec-mysql 4 28: *rspec-metadata-mysql
-rspec-mysql 5 28: *rspec-metadata-mysql
-rspec-mysql 6 28: *rspec-metadata-mysql
-rspec-mysql 7 28: *rspec-metadata-mysql
-rspec-mysql 8 28: *rspec-metadata-mysql
-rspec-mysql 9 28: *rspec-metadata-mysql
-rspec-mysql 10 28: *rspec-metadata-mysql
-rspec-mysql 11 28: *rspec-metadata-mysql
-rspec-mysql 12 28: *rspec-metadata-mysql
-rspec-mysql 13 28: *rspec-metadata-mysql
-rspec-mysql 14 28: *rspec-metadata-mysql
-rspec-mysql 15 28: *rspec-metadata-mysql
-rspec-mysql 16 28: *rspec-metadata-mysql
-rspec-mysql 17 28: *rspec-metadata-mysql
-rspec-mysql 18 28: *rspec-metadata-mysql
-rspec-mysql 19 28: *rspec-metadata-mysql
-rspec-mysql 20 28: *rspec-metadata-mysql
-rspec-mysql 21 28: *rspec-metadata-mysql
-rspec-mysql 22 28: *rspec-metadata-mysql
-rspec-mysql 23 28: *rspec-metadata-mysql
-rspec-mysql 24 28: *rspec-metadata-mysql
-rspec-mysql 25 28: *rspec-metadata-mysql
-rspec-mysql 26 28: *rspec-metadata-mysql
-rspec-mysql 27 28: *rspec-metadata-mysql
-
-spinach-pg 0 2: *spinach-metadata-pg
-spinach-pg 1 2: *spinach-metadata-pg
-
-spinach-mysql 0 2: *spinach-metadata-mysql
-spinach-mysql 1 2: *spinach-metadata-mysql
-
-rspec-pg-rails5 0 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 1 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 2 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 3 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 4 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 5 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 6 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 7 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 8 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 9 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 10 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 11 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 12 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 13 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 14 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 15 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 16 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 17 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 18 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 19 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 20 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 21 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 22 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 23 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 24 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 25 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 26 28: *rspec-metadata-pg-rails5
-rspec-pg-rails5 27 28: *rspec-metadata-pg-rails5
-
-rspec-mysql-rails5 0 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 1 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 2 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 3 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 4 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 5 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 6 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 7 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 8 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 9 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 10 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 11 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 12 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 13 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 14 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 15 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 16 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 17 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 18 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 19 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 20 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 21 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 22 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 23 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 24 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 25 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 26 28: *rspec-metadata-mysql-rails5
-rspec-mysql-rails5 27 28: *rspec-metadata-mysql-rails5
-
-spinach-pg-rails5 0 2: *spinach-metadata-pg-rails5
-spinach-pg-rails5 1 2: *spinach-metadata-pg-rails5
-
-spinach-mysql-rails5 0 2: *spinach-metadata-mysql-rails5
-spinach-mysql-rails5 1 2: *spinach-metadata-mysql-rails5
+rspec-pg 0 30: *rspec-metadata-pg
+rspec-pg 1 30: *rspec-metadata-pg
+rspec-pg 2 30: *rspec-metadata-pg
+rspec-pg 3 30: *rspec-metadata-pg
+rspec-pg 4 30: *rspec-metadata-pg
+rspec-pg 5 30: *rspec-metadata-pg
+rspec-pg 6 30: *rspec-metadata-pg
+rspec-pg 7 30: *rspec-metadata-pg
+rspec-pg 8 30: *rspec-metadata-pg
+rspec-pg 9 30: *rspec-metadata-pg
+rspec-pg 10 30: *rspec-metadata-pg
+rspec-pg 11 30: *rspec-metadata-pg
+rspec-pg 12 30: *rspec-metadata-pg
+rspec-pg 13 30: *rspec-metadata-pg
+rspec-pg 14 30: *rspec-metadata-pg
+rspec-pg 15 30: *rspec-metadata-pg
+rspec-pg 16 30: *rspec-metadata-pg
+rspec-pg 17 30: *rspec-metadata-pg
+rspec-pg 18 30: *rspec-metadata-pg
+rspec-pg 19 30: *rspec-metadata-pg
+rspec-pg 20 30: *rspec-metadata-pg
+rspec-pg 21 30: *rspec-metadata-pg
+rspec-pg 22 30: *rspec-metadata-pg
+rspec-pg 23 30: *rspec-metadata-pg
+rspec-pg 24 30: *rspec-metadata-pg
+rspec-pg 25 30: *rspec-metadata-pg
+rspec-pg 26 30: *rspec-metadata-pg
+rspec-pg 27 30: *rspec-metadata-pg
+rspec-pg 28 30: *rspec-metadata-pg
+rspec-pg 29 30: *rspec-metadata-pg
+
+rspec-mysql 0 30: *rspec-metadata-mysql
+rspec-mysql 1 30: *rspec-metadata-mysql
+rspec-mysql 2 30: *rspec-metadata-mysql
+rspec-mysql 3 30: *rspec-metadata-mysql
+rspec-mysql 4 30: *rspec-metadata-mysql
+rspec-mysql 5 30: *rspec-metadata-mysql
+rspec-mysql 6 30: *rspec-metadata-mysql
+rspec-mysql 7 30: *rspec-metadata-mysql
+rspec-mysql 8 30: *rspec-metadata-mysql
+rspec-mysql 9 30: *rspec-metadata-mysql
+rspec-mysql 10 30: *rspec-metadata-mysql
+rspec-mysql 11 30: *rspec-metadata-mysql
+rspec-mysql 12 30: *rspec-metadata-mysql
+rspec-mysql 13 30: *rspec-metadata-mysql
+rspec-mysql 14 30: *rspec-metadata-mysql
+rspec-mysql 15 30: *rspec-metadata-mysql
+rspec-mysql 16 30: *rspec-metadata-mysql
+rspec-mysql 17 30: *rspec-metadata-mysql
+rspec-mysql 18 30: *rspec-metadata-mysql
+rspec-mysql 19 30: *rspec-metadata-mysql
+rspec-mysql 20 30: *rspec-metadata-mysql
+rspec-mysql 21 30: *rspec-metadata-mysql
+rspec-mysql 22 30: *rspec-metadata-mysql
+rspec-mysql 23 30: *rspec-metadata-mysql
+rspec-mysql 24 30: *rspec-metadata-mysql
+rspec-mysql 25 30: *rspec-metadata-mysql
+rspec-mysql 26 30: *rspec-metadata-mysql
+rspec-mysql 27 30: *rspec-metadata-mysql
+rspec-mysql 28 30: *rspec-metadata-mysql
+rspec-mysql 29 30: *rspec-metadata-mysql
+
+rspec-pg-rails5 0 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 1 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 2 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 3 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 4 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 5 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 6 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 7 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 8 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 9 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 10 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 11 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 12 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 13 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 14 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 15 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 16 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 17 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 18 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 19 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 20 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 21 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 22 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 23 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 24 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 25 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 26 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 27 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 28 30: *rspec-metadata-pg-rails5
+rspec-pg-rails5 29 30: *rspec-metadata-pg-rails5
+
+rspec-mysql-rails5 0 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 1 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 2 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 3 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 4 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 5 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 6 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 7 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 8 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 9 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 10 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 11 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 12 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 13 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 14 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 15 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 16 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 17 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 18 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 19 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 20 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 21 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 22 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 23 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 24 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 25 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 26 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 27 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 28 30: *rspec-metadata-mysql-rails5
+rspec-mysql-rails5 29 30: *rspec-metadata-mysql-rails5
static-analysis:
<<: *dedicated-no-docs-no-db-pull-cache-job
diff --git a/.gitlab/merge_request_templates/Database Changes.md b/.gitlab/merge_request_templates/Database Changes.md
index 2bb1f374e98..1c4f30d9320 100644
--- a/.gitlab/merge_request_templates/Database Changes.md
+++ b/.gitlab/merge_request_templates/Database Changes.md
@@ -37,12 +37,14 @@ When removing columns, tables, indexes or other structures:
- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/doc_styleguide.html)
- [ ] API support added
- [ ] Tests added for this feature/bug
-- Review
- - [ ] Has been reviewed by Backend
- - [ ] Has been reviewed by Database
+- Conform by the [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html)
+ - [ ] Has been reviewed by a Backend maintainer
+ - [ ] Has been reviewed by a Database specialist
- [ ] Conform by the [merge request performance guides](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html)
- [ ] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/CONTRIBUTING.md#style-guides)
-- [ ] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
+- [ ] If you have multiple commits, please combine them into a few logically organized commits by [squashing them](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
- [ ] Internationalization required/considered
- [ ] If paid feature, have we considered GitLab.com plan and how it works for groups and is there a design for promoting it to users who aren't on the correct plan
- [ ] End-to-end tests pass (`package-and-qa` manual pipeline job)
+
+/label ~database
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4f5d19ce2ce..d82f21fe795 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -728,6 +728,3 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[polling-etag]: https://docs.gitlab.com/ce/development/polling.html
[testing]: doc/development/testing_guide/index.md
[us-english]: https://en.wikipedia.org/wiki/American_English
-
-[^1]: Please note that specs other than JavaScript specs are considered backend
- code.
diff --git a/Gemfile b/Gemfile
index 78af9ee4d05..a6cd0ca980a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -160,7 +160,7 @@ gem 'state_machines-activerecord', '~> 0.5.1'
gem 'acts-as-taggable-on', '~> 5.0'
# Background jobs
-gem 'sidekiq', '~> 5.0'
+gem 'sidekiq', '~> 5.1'
gem 'sidekiq-cron', '~> 0.6.0'
gem 'redis-namespace', '~> 1.5.2'
gem 'sidekiq-limit_fetch', '~> 3.4', require: false
@@ -325,8 +325,6 @@ group :development, :test do
gem 'factory_bot_rails', '~> 4.8.2'
gem 'rspec-rails', '~> 3.6.0'
gem 'rspec-retry', '~> 0.4.5'
- gem 'spinach-rails', '~> 0.2.1'
- gem 'spinach-rerun-reporter', '~> 0.0.2'
gem 'rspec_profiling', '~> 0.0.5'
gem 'rspec-set', '~> 0.1.3'
gem 'rspec-parameterized', require: false
@@ -343,7 +341,6 @@ group :development, :test do
gem 'spring', '~> 2.0.0'
gem 'spring-commands-rspec', '~> 1.0.4'
- gem 'spring-commands-spinach', '~> 1.1.0'
gem 'gitlab-styles', '~> 2.3', require: false
# Pin these dependencies, otherwise a new rule could break the CI pipelines
diff --git a/Gemfile.lock b/Gemfile.lock
index 6028ce32d2f..18c25cc34b6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -131,7 +131,6 @@ GEM
coderay (1.1.1)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
- colorize (0.7.7)
commonmarker (0.17.8)
ruby-enum (~> 0.5)
concord (0.1.5)
@@ -288,7 +287,6 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
- gherkin-ruby (0.3.2)
gitaly-proto (0.99.0)
google-protobuf (~> 3.1)
grpc (~> 1.10)
@@ -846,11 +844,11 @@ GEM
rack
shoulda-matchers (3.1.2)
activesupport (>= 4.0.0)
- sidekiq (5.0.5)
+ sidekiq (5.1.3)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
- redis (>= 3.3.4, < 5)
+ redis (>= 3.3.5, < 5)
sidekiq-cron (0.6.0)
rufus-scheduler (>= 3.3.0)
sidekiq (>= 4.2.1)
@@ -869,22 +867,10 @@ GEM
simplecov-html (0.10.0)
slack-notifier (1.5.1)
slop (3.6.0)
- spinach (0.8.10)
- colorize
- gherkin-ruby (>= 0.3.2)
- json
- spinach-rails (0.2.1)
- capybara (>= 2.0.0)
- railties (>= 3)
- spinach (>= 0.4)
- spinach-rerun-reporter (0.0.2)
- spinach (~> 0.8)
spring (2.0.1)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
- spring-commands-spinach (1.1.0)
- spring (>= 0.9.1)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
@@ -1177,17 +1163,14 @@ DEPENDENCIES
settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6)
shoulda-matchers (~> 3.1.2)
- sidekiq (~> 5.0)
+ sidekiq (~> 5.1)
sidekiq-cron (~> 0.6.0)
sidekiq-limit_fetch (~> 3.4)
simple_po_parser (~> 1.1.2)
simplecov (~> 0.14.0)
slack-notifier (~> 1.5.1)
- spinach-rails (~> 0.2.1)
- spinach-rerun-reporter (~> 0.0.2)
spring (~> 2.0.0)
spring-commands-rspec (~> 1.0.4)
- spring-commands-spinach (~> 1.1.0)
sprockets (~> 3.7.0)
sshkey (~> 1.9.0)
stackprof (~> 0.2.10)
diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock
index fc6dfd040c2..af7305619eb 100644
--- a/Gemfile.rails5.lock
+++ b/Gemfile.rails5.lock
@@ -132,7 +132,6 @@ GEM
coderay (1.1.2)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
- colorize (0.8.1)
commonmarker (0.17.9)
ruby-enum (~> 0.5)
concord (0.1.5)
@@ -289,7 +288,6 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
- gherkin-ruby (0.3.2)
gitaly-proto (0.99.0)
google-protobuf (~> 3.1)
grpc (~> 1.10)
@@ -871,22 +869,10 @@ GEM
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
slack-notifier (1.5.1)
- spinach (0.8.10)
- colorize
- gherkin-ruby (>= 0.3.2)
- json
- spinach-rails (0.2.1)
- capybara (>= 2.0.0)
- railties (>= 3)
- spinach (>= 0.4)
- spinach-rerun-reporter (0.0.2)
- spinach (~> 0.8)
spring (2.0.2)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
- spring-commands-spinach (1.1.0)
- spring (>= 0.9.1)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
@@ -1187,11 +1173,8 @@ DEPENDENCIES
simple_po_parser (~> 1.1.2)
simplecov (~> 0.14.0)
slack-notifier (~> 1.5.1)
- spinach-rails (~> 0.2.1)
- spinach-rerun-reporter (~> 0.0.2)
spring (~> 2.0.0)
spring-commands-rspec (~> 1.0.4)
- spring-commands-spinach (~> 1.1.0)
sprockets (~> 3.7.0)
sshkey (~> 1.9.0)
stackprof (~> 0.2.10)
diff --git a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue
new file mode 100644
index 00000000000..df21e2f8771
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue
@@ -0,0 +1,77 @@
+<script>
+import _ from 'underscore';
+import GlModal from '~/vue_shared/components/gl_modal.vue';
+import { s__, sprintf } from '~/locale';
+
+export default {
+ components: {
+ GlModal,
+ },
+ props: {
+ deleteWikiUrl: {
+ type: String,
+ required: true,
+ default: '',
+ },
+ pageTitle: {
+ type: String,
+ required: true,
+ default: '',
+ },
+ csrfToken: {
+ type: String,
+ required: true,
+ default: '',
+ },
+ },
+ computed: {
+ message() {
+ return s__('WikiPageConfirmDelete|Are you sure you want to delete this page?');
+ },
+ title() {
+ return sprintf(
+ s__('WikiPageConfirmDelete|Delete page %{pageTitle}?'),
+ {
+ pageTitle: _.escape(this.pageTitle),
+ },
+ false,
+ );
+ },
+ },
+ methods: {
+ onSubmit() {
+ this.$refs.form.submit();
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ id="delete-wiki-modal"
+ :header-title-text="title"
+ footer-primary-button-variant="danger"
+ :footer-primary-button-text="s__('WikiPageConfirmDelete|Delete page')"
+ @submit="onSubmit"
+ >
+ {{ message }}
+ <form
+ ref="form"
+ :action="deleteWikiUrl"
+ method="post"
+ class="form-horizontal js-requires-input"
+ >
+ <input
+ ref="method"
+ type="hidden"
+ name="_method"
+ value="delete"
+ />
+ <input
+ type="hidden"
+ name="authenticity_token"
+ :value="csrfToken"
+ />
+ </form>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/pages/projects/wikis/index.js b/app/assets/javascripts/pages/projects/wikis/index.js
index ec01c66ffda..0295653cb29 100644
--- a/app/assets/javascripts/pages/projects/wikis/index.js
+++ b/app/assets/javascripts/pages/projects/wikis/index.js
@@ -1,12 +1,40 @@
import $ from 'jquery';
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import csrf from '~/lib/utils/csrf';
import Wikis from './wikis';
import ShortcutsWiki from '../../../shortcuts_wiki';
import ZenMode from '../../../zen_mode';
import GLForm from '../../../gl_form';
+import deleteWikiModal from './components/delete_wiki_modal.vue';
document.addEventListener('DOMContentLoaded', () => {
new Wikis(); // eslint-disable-line no-new
new ShortcutsWiki(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new
new GLForm($('.wiki-form'), true); // eslint-disable-line no-new
+
+ const deleteWikiButton = document.getElementById('delete-wiki-button');
+
+ if (deleteWikiButton) {
+ Vue.use(Translate);
+
+ const { deleteWikiUrl, pageTitle } = deleteWikiButton.dataset;
+ const deleteWikiModalEl = document.getElementById('delete-wiki-modal');
+ const deleteModal = new Vue({ // eslint-disable-line
+ el: deleteWikiModalEl,
+ data: {
+ deleteWikiUrl: '',
+ },
+ render(createElement) {
+ return createElement(deleteWikiModal, {
+ props: {
+ pageTitle,
+ deleteWikiUrl,
+ csrfToken: csrf.token,
+ },
+ });
+ },
+ });
+ }
});
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue
deleted file mode 100644
index f0298f732ea..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-<script>
- export default {
- name: 'MRWidgetMaintainerEdit',
- props: {
- maintainerEditAllowed: {
- type: Boolean,
- default: false,
- required: false,
- },
- },
- };
-</script>
-
-<template>
- <section class="mr-info-list mr-links">
- <p v-if="maintainerEditAllowed">
- {{ s__("mrWidget|Allows edits from maintainers") }}
- </p>
- </section>
-</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue
index bf8628d18a6..926a3172412 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue
@@ -10,6 +10,6 @@ In EE, the configuration extends this object to add a functioning squash-before-
button.
*/
-export default {
- template: '',
-};
+<script>
+ export default {};
+</script>
diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
index 7f5f28091da..15097fa2a3f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js
+++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
@@ -15,7 +15,6 @@ export { default as WidgetHeader } from './components/mr_widget_header.vue';
export { default as WidgetMergeHelp } from './components/mr_widget_merge_help.vue';
export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue';
export { default as Deployment } from './components/deployment.vue';
-export { default as WidgetMaintainerEdit } from './components/mr_widget_maintainer_edit.vue';
export { default as WidgetRelatedLinks } from './components/mr_widget_related_links.vue';
export { default as MergedState } from './components/states/mr_widget_merged.vue';
export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue';
@@ -41,8 +40,8 @@ export { default as MRWidgetService } from './services/mr_widget_service';
export { default as eventHub } from './event_hub';
export { default as getStateKey } from './stores/get_state_key';
export { default as stateMaps } from './stores/state_maps';
-export { default as SquashBeforeMerge } from './components/states/mr_widget_squash_before_merge';
+export { default as SquashBeforeMerge } from './components/states/mr_widget_squash_before_merge.vue';
export { default as notify } from '../lib/utils/notify';
export { default as SourceBranchRemovalStatus } from './components/source_branch_removal_status.vue';
-export { default as mrWidgetOptions } from './mr_widget_options';
+export { default as mrWidgetOptions } from './mr_widget_options.vue';
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 345f9ac1b4b..f69fe03fcb3 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -1,12 +1,13 @@
+<script>
+
import Project from '~/pages/projects/project';
import SmartInterval from '~/smart_interval';
-import Flash from '../flash';
+import createFlash from '../flash';
import {
WidgetHeader,
WidgetMergeHelp,
WidgetPipeline,
Deployment,
- WidgetMaintainerEdit,
WidgetRelatedLinks,
MergedState,
ClosedState,
@@ -40,10 +41,39 @@ import { setFavicon } from '../lib/utils/common_utils';
export default {
el: '#js-vue-mr-widget',
name: 'MRWidget',
+ components: {
+ 'mr-widget-header': WidgetHeader,
+ 'mr-widget-merge-help': WidgetMergeHelp,
+ 'mr-widget-pipeline': WidgetPipeline,
+ Deployment,
+ 'mr-widget-related-links': WidgetRelatedLinks,
+ 'mr-widget-merged': MergedState,
+ 'mr-widget-closed': ClosedState,
+ 'mr-widget-merging': MergingState,
+ 'mr-widget-failed-to-merge': FailedToMerge,
+ 'mr-widget-wip': WorkInProgressState,
+ 'mr-widget-archived': ArchivedState,
+ 'mr-widget-conflicts': ConflictsState,
+ 'mr-widget-nothing-to-merge': NothingToMergeState,
+ 'mr-widget-not-allowed': NotAllowedState,
+ 'mr-widget-missing-branch': MissingBranchState,
+ 'mr-widget-ready-to-merge': ReadyToMergeState,
+ 'sha-mismatch': ShaMismatchState,
+ 'mr-widget-squash-before-merge': SquashBeforeMerge,
+ 'mr-widget-checking': CheckingState,
+ 'mr-widget-unresolved-discussions': UnresolvedDiscussionsState,
+ 'mr-widget-pipeline-blocked': PipelineBlockedState,
+ 'mr-widget-pipeline-failed': PipelineFailedState,
+ 'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState,
+ 'mr-widget-auto-merge-failed': AutoMergeFailed,
+ 'mr-widget-rebase': RebaseState,
+ SourceBranchRemovalStatus,
+ },
props: {
mrData: {
type: Object,
required: false,
+ default: null,
},
},
data() {
@@ -72,6 +102,13 @@ export default {
(!this.mr.isNothingToMergeState && !this.mr.isMergedState);
},
},
+ created() {
+ this.initPolling();
+ this.bindEventHubListeners();
+ },
+ mounted() {
+ this.handleMounted();
+ },
methods: {
createService(store) {
const endpoints = {
@@ -99,7 +136,7 @@ export default {
cb.call(null, data);
}
})
- .catch(() => new Flash('Something went wrong. Please try again.'));
+ .catch(() => createFlash('Something went wrong. Please try again.'));
},
initPolling() {
this.pollingInterval = new SmartInterval({
@@ -134,7 +171,7 @@ export default {
}
})
.catch(() => {
- new Flash('Something went wrong while fetching the environments for this merge request. Please try again.'); // eslint-disable-line
+ createFlash('Something went wrong while fetching the environments for this merge request. Please try again.'); // eslint-disable-line
});
},
fetchActionsContent() {
@@ -147,7 +184,7 @@ export default {
Project.initRefSwitcher();
}
})
- .catch(() => new Flash('Something went wrong. Please try again.'));
+ .catch(() => createFlash('Something went wrong. Please try again.'));
},
handleNotification(data) {
if (data.ci_status === this.mr.ciStatus) return;
@@ -202,76 +239,53 @@ export default {
this.initDeploymentsPolling();
},
},
- created() {
- this.initPolling();
- this.bindEventHubListeners();
- },
- mounted() {
- this.handleMounted();
- },
- components: {
- 'mr-widget-header': WidgetHeader,
- 'mr-widget-merge-help': WidgetMergeHelp,
- 'mr-widget-pipeline': WidgetPipeline,
- Deployment,
- 'mr-widget-maintainer-edit': WidgetMaintainerEdit,
- 'mr-widget-related-links': WidgetRelatedLinks,
- 'mr-widget-merged': MergedState,
- 'mr-widget-closed': ClosedState,
- 'mr-widget-merging': MergingState,
- 'mr-widget-failed-to-merge': FailedToMerge,
- 'mr-widget-wip': WorkInProgressState,
- 'mr-widget-archived': ArchivedState,
- 'mr-widget-conflicts': ConflictsState,
- 'mr-widget-nothing-to-merge': NothingToMergeState,
- 'mr-widget-not-allowed': NotAllowedState,
- 'mr-widget-missing-branch': MissingBranchState,
- 'mr-widget-ready-to-merge': ReadyToMergeState,
- 'mr-widget-sha-mismatch': ShaMismatchState,
- 'mr-widget-squash-before-merge': SquashBeforeMerge,
- 'mr-widget-checking': CheckingState,
- 'mr-widget-unresolved-discussions': UnresolvedDiscussionsState,
- 'mr-widget-pipeline-blocked': PipelineBlockedState,
- 'mr-widget-pipeline-failed': PipelineFailedState,
- 'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState,
- 'mr-widget-auto-merge-failed': AutoMergeFailed,
- 'mr-widget-rebase': RebaseState,
- SourceBranchRemovalStatus,
- },
- template: `
- <div class="mr-state-widget prepend-top-default">
- <mr-widget-header :mr="mr" />
- <mr-widget-pipeline
- v-if="shouldRenderPipelines"
- :pipeline="mr.pipeline"
- :ci-status="mr.ciStatus"
- :has-ci="mr.hasCI"
- />
- <deployment
- v-for="deployment in mr.deployments"
- :key="deployment.id"
- :deployment="deployment"
+};
+</script>
+<template>
+ <div class="mr-state-widget prepend-top-default">
+ <mr-widget-header
+ :mr="mr"
+ />
+ <mr-widget-pipeline
+ v-if="shouldRenderPipelines"
+ :pipeline="mr.pipeline"
+ :ci-status="mr.ciStatus"
+ :has-ci="mr.hasCI"
+ />
+ <deployment
+ v-for="deployment in mr.deployments"
+ :key="deployment.id"
+ :deployment="deployment"
+ />
+ <div class="mr-widget-section">
+ <component
+ :is="componentName"
+ :mr="mr"
+ :service="service"
+ />
+
+ <section
+ v-if="mr.maintainerEditAllowed"
+ class="mr-info-list mr-links"
+ >
+ {{ s__("mrWidget|Allows edits from maintainers") }}
+ </section>
+
+ <mr-widget-related-links
+ v-if="shouldRenderRelatedLinks"
+ :state="mr.state"
+ :related-links="mr.relatedLinks"
+ />
+
+ <source-branch-removal-status
+ v-if="shouldRenderSourceBranchRemovalStatus"
/>
- <div class="mr-widget-section">
- <component
- :is="componentName"
- :mr="mr"
- :service="service" />
- <mr-widget-maintainer-edit
- :maintainerEditAllowed="mr.maintainerEditAllowed" />
- <mr-widget-related-links
- v-if="shouldRenderRelatedLinks"
- :state="mr.state"
- :related-links="mr.relatedLinks" />
- <source-branch-removal-status
- v-if="shouldRenderSourceBranchRemovalStatus"
- />
- </div>
- <div
- class="mr-widget-footer"
- v-if="shouldRenderMergeHelp">
- <mr-widget-merge-help />
- </div>
</div>
- `,
-};
+ <div
+ class="mr-widget-footer"
+ v-if="shouldRenderMergeHelp"
+ >
+ <mr-widget-merge-help />
+ </div>
+ </div>
+</template>
diff --git a/app/controllers/concerns/send_file_upload.rb b/app/controllers/concerns/send_file_upload.rb
index 55011c89886..237c93daee8 100644
--- a/app/controllers/concerns/send_file_upload.rb
+++ b/app/controllers/concerns/send_file_upload.rb
@@ -2,6 +2,10 @@ module SendFileUpload
def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, disposition: 'attachment')
if attachment
redirect_params[:query] = { "response-content-disposition" => "#{disposition};filename=#{attachment.inspect}" }
+ # By default, Rails will send uploads with an extension of .js with a
+ # content-type of text/javascript, which will trigger Rails'
+ # cross-origin JavaScript protection.
+ send_params[:content_type] = 'text/plain' if File.extname(attachment) == '.js'
send_params.merge!(filename: attachment, disposition: disposition)
end
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index bc13b8ad7ba..4d4c2af2415 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -8,19 +8,6 @@ class Projects::NotesController < Projects::ApplicationController
before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
- #
- # This is a fix to make spinach feature tests passing:
- # Controller actions are returned from AbstractController::Base and methods of parent classes are
- # excluded in order to return only specific controller related methods.
- # That is ok for the app (no :create method in ancestors)
- # but fails for tests because there is a :create method on FactoryBot (one of the ancestors)
- #
- # see https://github.com/rails/rails/blob/v4.2.7/actionpack/lib/abstract_controller/base.rb#L78
- #
- def create
- super
- end
-
def delete_attachment
note.remove_attachment!
note.update_attribute(:attachment, nil)
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 0b1b46944aa..f7417a6a5aa 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -181,4 +181,8 @@ class Projects::PipelinesController < Projects::ApplicationController
# Also see https://gitlab.com/gitlab-org/gitlab-ce/issues/42343
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42339')
end
+
+ def authorize_update_pipeline!
+ return access_denied! unless can?(current_user, :update_pipeline, @pipeline)
+ end
end
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 0b90834d415..1f49764e7cc 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -37,12 +37,16 @@ module Ci
delegate :id, to: :project, prefix: true
delegate :full_path, to: :project, prefix: true
- validates :source, exclusion: { in: %w(unknown), unless: :importing? }, on: :create
validates :sha, presence: { unless: :importing? }
validates :ref, presence: { unless: :importing? }
validates :status, presence: { unless: :importing? }
validate :valid_commit_sha, unless: :importing?
+ # Replace validator below with
+ # `validates :source, presence: { unless: :importing? }, on: :create`
+ # when removing Gitlab.rails5? code.
+ validate :valid_source, unless: :importing?, on: :create
+
after_create :keep_around_commits, unless: :importing?
enum source: {
@@ -601,5 +605,11 @@ module Ci
project.repository.keep_around(self.sha)
project.repository.keep_around(self.before_sha)
end
+
+ def valid_source
+ if source.nil? || source == "unknown"
+ errors.add(:source, "invalid source")
+ end
+ end
end
end
diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb
index 808a81cbbf9..8b65758f3e8 100644
--- a/app/policies/ci/build_policy.rb
+++ b/app/policies/ci/build_policy.rb
@@ -14,11 +14,20 @@ module Ci
@subject.triggered_by?(@user)
end
+ condition(:branch_allows_maintainer_push) do
+ @subject.project.branch_allows_maintainer_push?(@user, @subject.ref)
+ end
+
rule { protected_ref }.policy do
prevent :update_build
prevent :erase_build
end
rule { can?(:admin_build) | (can?(:update_build) & owner_of_job) }.enable :erase_build
+
+ rule { can?(:public_access) & branch_allows_maintainer_push }.policy do
+ enable :update_build
+ enable :update_commit_status
+ end
end
end
diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb
index 6363c382ff8..540e4235299 100644
--- a/app/policies/ci/pipeline_policy.rb
+++ b/app/policies/ci/pipeline_policy.rb
@@ -4,8 +4,16 @@ module Ci
condition(:protected_ref) { ref_protected?(@user, @subject.project, @subject.tag?, @subject.ref) }
+ condition(:branch_allows_maintainer_push) do
+ @subject.project.branch_allows_maintainer_push?(@user, @subject.ref)
+ end
+
rule { protected_ref }.prevent :update_pipeline
+ rule { can?(:public_access) & branch_allows_maintainer_push }.policy do
+ enable :update_pipeline
+ end
+
def ref_protected?(user, project, tag, ref)
access = ::Gitlab::UserAccess.new(user, project: project)
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 5759b1a376f..99a0d7118f2 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -76,7 +76,7 @@ class ProjectPolicy < BasePolicy
condition(:request_access_enabled, scope: :subject, score: 0) { project.request_access_enabled }
desc "Has merge requests allowing pushes to user"
- condition(:has_merge_requests_allowing_pushes, scope: :subject) do
+ condition(:has_merge_requests_allowing_pushes) do
project.merge_requests_allowing_push_to_user(user).any?
end
@@ -354,9 +354,7 @@ class ProjectPolicy < BasePolicy
# to run pipelines for the branches they have access to.
rule { can?(:public_access) & has_merge_requests_allowing_pushes }.policy do
enable :create_build
- enable :update_build
enable :create_pipeline
- enable :update_pipeline
end
rule do
diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml
index 9d3d4072027..35c7dc2984a 100644
--- a/app/views/projects/wikis/edit.html.haml
+++ b/app/views/projects/wikis/edit.html.haml
@@ -28,9 +28,16 @@
= link_to project_wiki_history_path(@project, @page), class: "btn" do
= s_("Wiki|Page history")
- if can?(current_user, :admin_wiki, @project)
- = link_to project_wiki_path(@project, @page), data: { confirm: s_("WikiPageConfirmDelete|Are you sure you want to delete this page?")}, method: :delete, class: "btn btn-danger" do
- = _("Delete")
+ %button.btn.btn-danger{ data: { toggle: 'modal',
+ target: '#delete-wiki-modal',
+ delete_wiki_url: project_wiki_path(@project, @page),
+ page_title: @page.title.capitalize },
+ id: 'delete-wiki-button',
+ type: 'button' }
+ = _('Delete')
= render 'form'
= render 'sidebar'
+
+#delete-wiki-modal.modal.fade
diff --git a/bin/secpick b/bin/secpick
index 76ae231e913..5029fe57cfe 100755
--- a/bin/secpick
+++ b/bin/secpick
@@ -5,7 +5,6 @@ require 'rainbow/refinement'
using Rainbow
BRANCH_PREFIX = 'security'.freeze
-STABLE_BRANCH_SUFFIX = 'stable'.freeze
REMOTE = 'dev'.freeze
options = { version: nil, branch: nil, sha: nil }
@@ -37,9 +36,9 @@ abort("Missing options. Use #{$0} --help to see the list of options available".r
abort("Wrong version format #{options[:version].bold}".red) unless options[:version] =~ /\A\d*\-\d*\Z/
branch = [BRANCH_PREFIX, options[:branch], options[:version]].join('-').freeze
-stable_branch = "#{options[:version]}-#{STABLE_BRANCH_SUFFIX}".freeze
+stable_branch = "#{BRANCH_PREFIX}-#{options[:version]}".freeze
-command = "git checkout #{stable_branch} && git pull #{REMOTE} #{stable_branch} && git checkout -B #{branch} && git cherry-pick #{options[:sha]} && git push #{REMOTE} #{branch}"
+command = "git fetch #{REMOTE} #{stable_branch} && git checkout #{stable_branch} && git pull #{REMOTE} #{stable_branch} && git checkout -B #{branch} && git cherry-pick #{options[:sha]} && git push #{REMOTE} #{branch}"
_stdin, stdout, stderr = Open3.popen3(command)
diff --git a/bin/spinach b/bin/spinach
deleted file mode 100755
index eda81c9ed8a..00000000000
--- a/bin/spinach
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env ruby
-
-# Remove this block when removing rails5? code.
-gemfile = %w[1 true].include?(ENV["RAILS5"]) ? "Gemfile.rails5" : "Gemfile"
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../#{gemfile}", __dir__)
-
-begin
- load File.expand_path('../spring', __FILE__)
-rescue LoadError => e
- raise unless e.message.include?('spring')
-end
-require 'bundler/setup'
-load Gem.bin_path('spinach', 'spinach')
diff --git a/changelogs/unreleased/46010-add-index-to-runner-type.yml b/changelogs/unreleased/46010-add-index-to-runner-type.yml
new file mode 100644
index 00000000000..fb8340e37b2
--- /dev/null
+++ b/changelogs/unreleased/46010-add-index-to-runner-type.yml
@@ -0,0 +1,5 @@
+---
+title: Add index on runner_type for ci_runners
+merge_request: 18897
+author:
+type: performance
diff --git a/changelogs/unreleased/46286-fix-ingress-rbac-default-value.yml b/changelogs/unreleased/46286-fix-ingress-rbac-default-value.yml
new file mode 100644
index 00000000000..e9cd8977394
--- /dev/null
+++ b/changelogs/unreleased/46286-fix-ingress-rbac-default-value.yml
@@ -0,0 +1,5 @@
+---
+title: Disables RBAC on nginx-ingress
+merge_request: 18947
+author:
+type: fixed
diff --git a/changelogs/unreleased/46345-kubernetes-popover-illustration-skewed.yml b/changelogs/unreleased/46345-kubernetes-popover-illustration-skewed.yml
new file mode 100644
index 00000000000..a0e6b39fef6
--- /dev/null
+++ b/changelogs/unreleased/46345-kubernetes-popover-illustration-skewed.yml
@@ -0,0 +1,5 @@
+---
+title: Correct skewed Kubernetes popover illustration
+merge_request: 18949
+author:
+type: fixed
diff --git a/changelogs/unreleased/blackst0ne-remove-spinach.yml b/changelogs/unreleased/blackst0ne-remove-spinach.yml
new file mode 100644
index 00000000000..104da257bad
--- /dev/null
+++ b/changelogs/unreleased/blackst0ne-remove-spinach.yml
@@ -0,0 +1,5 @@
+---
+title: Remove Spinach
+merge_request: 18869
+author: '@blackst0ne'
+type: other
diff --git a/changelogs/unreleased/jprovazn-null-byte.yml b/changelogs/unreleased/jprovazn-null-byte.yml
new file mode 100644
index 00000000000..4c4760ac412
--- /dev/null
+++ b/changelogs/unreleased/jprovazn-null-byte.yml
@@ -0,0 +1,5 @@
+---
+title: Fix filename matching when processing file or blob search results
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/jprovazn-pipeline-policy.yml b/changelogs/unreleased/jprovazn-pipeline-policy.yml
new file mode 100644
index 00000000000..2997c6c8667
--- /dev/null
+++ b/changelogs/unreleased/jprovazn-pipeline-policy.yml
@@ -0,0 +1,6 @@
+---
+title: Allow maintainers to retry pipelines on forked projects (if allowed in merge
+ request)
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/refactor-move-squash-before-merge-vue-component.yml b/changelogs/unreleased/refactor-move-squash-before-merge-vue-component.yml
new file mode 100644
index 00000000000..b8b2762a21d
--- /dev/null
+++ b/changelogs/unreleased/refactor-move-squash-before-merge-vue-component.yml
@@ -0,0 +1,5 @@
+---
+title: Move SquashBeforeMerge vue component
+merge_request: 18813
+author: George Tsiolis
+type: performance
diff --git a/changelogs/unreleased/sh-fix-blocked-user-account-ldap.yml b/changelogs/unreleased/sh-fix-blocked-user-account-ldap.yml
new file mode 100644
index 00000000000..f7abe763ea8
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-blocked-user-account-ldap.yml
@@ -0,0 +1,5 @@
+---
+title: Fix system hook not firing for blocked users when LDAP sign-in is used
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-cross-site-origin-uploads-js.yml b/changelogs/unreleased/sh-fix-cross-site-origin-uploads-js.yml
new file mode 100644
index 00000000000..3c51aaae896
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-cross-site-origin-uploads-js.yml
@@ -0,0 +1,5 @@
+---
+title: Fix cross-origin errors when attempting to download JavaScript attachments
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/update-wiki-modal.yml b/changelogs/unreleased/update-wiki-modal.yml
new file mode 100644
index 00000000000..00f2fc4f181
--- /dev/null
+++ b/changelogs/unreleased/update-wiki-modal.yml
@@ -0,0 +1,5 @@
+---
+title: New design for wiki page deletion confirmation
+merge_request: 18712
+author: Constance Okoghenun
+type: added
diff --git a/config/initializers/deprecations.rb b/config/initializers/deprecations.rb
index 2476ea9e38a..c8d7f742bb1 100644
--- a/config/initializers/deprecations.rb
+++ b/config/initializers/deprecations.rb
@@ -1,5 +1,9 @@
-deprecator = ActiveSupport::Deprecation.new('11.0', 'GitLab')
-
if Gitlab.dev_env_or_com?
+ deprecator = ActiveSupport::Deprecation.new('11.0', 'GitLab')
+
+ deprecator.behavior = -> (message, callstack) {
+ Rails.logger.warn("#{message}: #{callstack[1..20].join}")
+ }
+
ActiveSupport::Deprecation.deprecate_methods(Gitlab::GitalyClient::StorageSettings, :legacy_disk_path, deprecator: deprecator)
end
diff --git a/db/migrate/20180511090724_add_index_on_ci_runners_runner_type.rb b/db/migrate/20180511090724_add_index_on_ci_runners_runner_type.rb
new file mode 100644
index 00000000000..580f56007c7
--- /dev/null
+++ b/db/migrate/20180511090724_add_index_on_ci_runners_runner_type.rb
@@ -0,0 +1,15 @@
+class AddIndexOnCiRunnersRunnerType < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_runners, :runner_type
+ end
+
+ def down
+ remove_index :ci_runners, :runner_type
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 95adccf0d5c..4abca1789a0 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20180508135515) do
+ActiveRecord::Schema.define(version: 20180511090724) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -503,6 +503,7 @@ ActiveRecord::Schema.define(version: 20180508135515) do
add_index "ci_runners", ["contacted_at"], name: "index_ci_runners_on_contacted_at", using: :btree
add_index "ci_runners", ["is_shared"], name: "index_ci_runners_on_is_shared", using: :btree
add_index "ci_runners", ["locked"], name: "index_ci_runners_on_locked", using: :btree
+ add_index "ci_runners", ["runner_type"], name: "index_ci_runners_on_runner_type", using: :btree
add_index "ci_runners", ["token"], name: "index_ci_runners_on_token", using: :btree
create_table "ci_stages", force: :cascade do |t|
diff --git a/doc/README.md b/doc/README.md
index c929ba7a59e..ff8dd3fab8a 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -241,7 +241,7 @@ GitLab.com is hosted, managed, and administered by GitLab, Inc., with
and teams: Free, Bronze, Silver, and Gold.
GitLab.com subscriptions grants access
-to the same features available in GitLab self-hosted, **expect
+to the same features available in GitLab self-hosted, **except
[administration](administration/index.md) tools and settings**:
- GitLab.com Free includes the same features available in Core
diff --git a/doc/api/jobs.md b/doc/api/jobs.md
index db4fe2f6880..e4e48edd9a7 100644
--- a/doc/api/jobs.md
+++ b/doc/api/jobs.md
@@ -82,7 +82,7 @@ Example of response
"artifacts_file": null,
"finished_at": "2015-12-24T17:54:24.921Z",
"id": 6,
- "name": "spinach:other",
+ "name": "rspec:other",
"pipeline": {
"id": 6,
"ref": "master",
@@ -196,7 +196,7 @@ Example of response
"artifacts_file": null,
"finished_at": "2015-12-24T17:54:24.921Z",
"id": 6,
- "name": "spinach:other",
+ "name": "rspec:other",
"pipeline": {
"id": 6,
"ref": "master",
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 7165b8062a7..d03b7fa23ca 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -29,6 +29,10 @@ There are a few rules to get your merge request accepted:
to ask one of the [Merge request coaches][team].
1. The reviewer will assign the merge request to a maintainer once the
reviewer is satisfied with the state of the merge request.
+1. Keep in mind that maintainers are also going to perform a final code review.
+ The ideal scenario is that the reviewer has already addressed any concerns
+ the maintainer would have found, and the maintainer only has to perform the
+ merge, but be prepared for further review comments.
For more guidance, see [CONTRIBUTING.md](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md).
@@ -207,3 +211,4 @@ Largely based on the [thoughtbot code review guide].
[projects]: https://about.gitlab.com/handbook/engineering/projects/
[team]: https://about.gitlab.com/team/
[build handbook]: https://about.gitlab.com/handbook/build/handbook/build#how-to-work-with-build
+[^1]: Please note that specs other than JavaScript specs are considered backend code.
diff --git a/doc/development/database_debugging.md b/doc/development/database_debugging.md
index 32f392f1303..9c31265e417 100644
--- a/doc/development/database_debugging.md
+++ b/doc/development/database_debugging.md
@@ -11,7 +11,7 @@ Available `RAILS_ENV`
- `production` (generally not for your main GDK db, but you may need this for e.g. omnibus)
- `development` (this is your main GDK db)
- - `test` (used for tests like rspec and spinach)
+ - `test` (used for tests like rspec)
## Nuke everything and start over
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index fdfa1f10402..31addcaf675 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -65,12 +65,11 @@ To make sure that indices still fit. You could find great details in:
## Run tests
In order to run the test you can use the following commands:
-- `rake spinach` to run the spinach suite
- `rake spec` to run the rspec suite
- `rake karma` to run the karma test suite
- `rake gitlab:test` to run all the tests
-Note: Both `rake spinach` and `rake spec` takes significant time to pass.
+Note: `rake spec` takes significant time to pass.
Instead of running full test suite locally you can save a lot of time by running
a single test or directory related to your changes. After you submit merge request
CI will run full test suite for you. Green CI status in the merge request means
@@ -82,12 +81,10 @@ files it can find, also the ones in `/tmp`
To run a single test file you can use:
- `bin/rspec spec/controllers/commit_controller_spec.rb` for a rspec test
-- `bin/spinach features/project/issues/milestones.feature` for a spinach test
To run several tests inside one directory:
- `bin/rspec spec/requests/api/` for the rspec tests if you want to test API only
-- `bin/spinach features/profile/` for the spinach tests if you want to test only profile pages
### Speed-up tests, rake tasks, and migrations
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 61fa5459b91..9d3f2935127 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -12,8 +12,7 @@ Here are some things to keep in mind regarding test performance:
- `FactoryBot.build(...)` and `.build_stubbed` are faster than `.create`.
- Don't `create` an object when `build`, `build_stubbed`, `attributes_for`,
`spy`, or `double` will do. Database persistence is slow!
-- Don't mark a feature as requiring JavaScript (through `@javascript` in
- Spinach or `:js` in RSpec) unless it's _actually_ required for the test
+- Don't mark a feature as requiring JavaScript (through `:js` in RSpec) unless it's _actually_ required for the test
to be valid. Headless browser testing is slow!
[parallelization]: ci.md#test-suite-parallelization-on-the-ci
diff --git a/doc/development/testing_guide/ci.md b/doc/development/testing_guide/ci.md
index e90de55068d..0d8e150e090 100644
--- a/doc/development/testing_guide/ci.md
+++ b/doc/development/testing_guide/ci.md
@@ -24,8 +24,7 @@ Our current CI parallelization setup is as follows:
uploaded to S3.
After that, the next pipeline will use the up-to-date
-`knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file. The same strategy
-is used for Spinach tests as well.
+`knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file.
### Monitoring
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 0d0d511582b..3b2b9c8c947 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -280,26 +280,6 @@ describe "Admin::AbuseReports", :js do
end
```
-### Spinach errors due to missing JavaScript
-
-NOTE: **Note:** Since we are discouraging the use of Spinach when writing new
-feature tests, you shouldn't ever need to use this. This information is kept
-available for legacy purposes only.
-
-In Spinach, the JavaScript driver is enabled differently. In the `*.feature`
-file for the failing spec, add the `@javascript` flag above the Scenario:
-
-```
-@javascript
-Scenario: Developer can approve merge request
- Given I am a "Shop" developer
- And I visit project "Shop" merge requests page
- And merge request 'Bug NS-04' must be approved
- And I click link "Bug NS-04"
- When I click link "Approve"
- Then I should see approved merge request "Bug NS-04"
-```
-
[jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html
[jasmine-jquery]: https://github.com/velesin/jasmine-jquery
[karma]: http://karma-runner.github.io/
diff --git a/doc/development/testing_guide/index.md b/doc/development/testing_guide/index.md
index 74d09eb91ff..0cd63a54b55 100644
--- a/doc/development/testing_guide/index.md
+++ b/doc/development/testing_guide/index.md
@@ -72,21 +72,6 @@ Everything you should know about how to run end-to-end tests using
---
-## Spinach (feature) tests
-
-GitLab [moved from Cucumber to Spinach](https://github.com/gitlabhq/gitlabhq/pull/1426)
-for its feature/integration tests in September 2012.
-
-As of March 2016, we are [trying to avoid adding new Spinach
-tests](https://gitlab.com/gitlab-org/gitlab-ce/issues/14121) going forward,
-opting for [RSpec feature](#features-integration) specs.
-
-Adding new Spinach scenarios is acceptable _only if_ the new scenario requires
-no more than one new `step` definition. If more than that is required, the
-test should be re-implemented using RSpec instead.
-
----
-
[Return to Development documentation](../README.md)
[^1]: /ci/yaml/README.html#dependencies
diff --git a/doc/development/testing_guide/testing_levels.md b/doc/development/testing_guide/testing_levels.md
index 51794f7f4df..07ced36f0c1 100644
--- a/doc/development/testing_guide/testing_levels.md
+++ b/doc/development/testing_guide/testing_levels.md
@@ -81,7 +81,6 @@ possible).
| Tests path | Testing engine | Notes |
| ---------- | -------------- | ----- |
| `spec/features/` | [Capybara] + [RSpec] | If your spec has the `:js` metadata, the browser driver will be [Poltergeist], otherwise it's using [RackTest]. |
-| `features/` | Spinach | Spinach tests are deprecated, [you shouldn't add new Spinach tests](#spinach-feature-tests). |
### Consider **not** writing a system test!
diff --git a/doc/user/project/merge_requests/maintainer_access.md b/doc/user/project/merge_requests/maintainer_access.md
index c9763a3fe02..89f71e16a50 100644
--- a/doc/user/project/merge_requests/maintainer_access.md
+++ b/doc/user/project/merge_requests/maintainer_access.md
@@ -16,3 +16,5 @@ source project, and only lasts while the merge request is open.
Enable this functionality while creating a merge request:
![Enable maintainer edits](./img/allow_maintainer_push.png)
+
+[ce-17395]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17395
diff --git a/features/steps/group/members.rb b/features/steps/group/members.rb
deleted file mode 100644
index 97bcca7730b..00000000000
--- a/features/steps/group/members.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-class Spinach::Features::GroupMembers < Spinach::FeatureSteps
- include WaitForRequests
- include SharedAuthentication
- include SharedPaths
- include SharedGroup
- include SharedUser
-
- step 'I should see user "John Doe" in team list' do
- expect(group_members_list).to have_content("John Doe")
- end
-
- step 'I should not see user "Mary Jane" in team list' do
- expect(group_members_list).not_to have_content("Mary Jane")
- end
-
- step 'I click on the "Remove User From Group" button for "John Doe"' do
- find(:css, '.project-members-page li', text: "John Doe").find(:css, 'a.btn-remove').click
- # poltergeist always confirms popups.
- end
-
- step 'I click on the "Remove User From Group" button for "Mary Jane"' do
- find(:css, 'li', text: "Mary Jane").find(:css, 'a.btn-remove').click
- # poltergeist always confirms popups.
- end
-
- step 'I should not see the "Remove User From Group" button for "John Doe"' do
- expect(find(:css, '.project-members-page li', text: "John Doe")).not_to have_selector(:css, 'a.btn-remove')
- # poltergeist always confirms popups.
- end
-
- step 'I should not see the "Remove User From Group" button for "Mary Jane"' do
- expect(find(:css, 'li', text: "Mary Jane")).not_to have_selector(:css, 'a.btn-remove')
- # poltergeist always confirms popups.
- end
-
- step 'I change the "Mary Jane" role to "Developer"' do
- member = mary_jane_member
-
- page.within "#group_member_#{member.id}" do
- click_button member.human_access
-
- page.within '.dropdown-menu' do
- click_link 'Developer'
- end
-
- wait_for_requests
- end
- end
-
- step 'I should see "Mary Jane" as "Developer"' do
- member = mary_jane_member
-
- page.within "#group_member_#{member.id}" do
- expect(page).to have_content "Developer"
- end
- end
-
- private
-
- def mary_jane_member
- user = User.find_by(name: "Mary Jane")
- owned_group.members.find_by(user_id: user.id)
- end
-
- def group_members_list
- find(".panel .content-list")
- end
-end
diff --git a/features/steps/profile/notifications.rb b/features/steps/profile/notifications.rb
deleted file mode 100644
index f8eb0f01de8..00000000000
--- a/features/steps/profile/notifications.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class Spinach::Features::ProfileNotifications < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedProject
-
- step 'I visit profile notifications page' do
- visit profile_notifications_path
- end
-
- step 'I should see global notifications settings' do
- expect(page).to have_content "Notifications"
- end
-
- step 'I select Mention setting from dropdown' do
- first(:link, "On mention").click
- end
-
- step 'I should see Notification saved message' do
- expect(page).to have_content 'On mention'
- end
-end
diff --git a/features/steps/project/commits/branches.rb b/features/steps/project/commits/branches.rb
deleted file mode 100644
index 3ecd4c8b672..00000000000
--- a/features/steps/project/commits/branches.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class Spinach::Features::ProjectCommitsBranches < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedProject
- include SharedPaths
-
- step 'I click link "All"' do
- click_link "All"
- end
-
- step 'I click link "Protected"' do
- click_link "Protected"
- end
-
- step 'I click new branch link' do
- click_link "New branch"
- end
-
- step 'I submit new branch form with invalid name' do
- fill_in 'branch_name', with: '1.0 stable'
- page.find("body").click # defocus the branch_name input
- select_branch('master')
- click_button 'Create branch'
- end
-
- def select_branch(branch_name)
- find('.git-revision-dropdown-toggle').click
-
- page.within '#new-branch-form .dropdown-menu' do
- click_link branch_name
- end
- end
-end
diff --git a/features/steps/project/commits/comments.rb b/features/steps/project/commits/comments.rb
deleted file mode 100644
index 3d4d8ad6368..00000000000
--- a/features/steps/project/commits/comments.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class Spinach::Features::ProjectCommitsComments < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedNote
- include SharedPaths
- include SharedProject
-end
diff --git a/features/steps/project/commits/diff_comments.rb b/features/steps/project/commits/diff_comments.rb
deleted file mode 100644
index b9d8cf2c5a5..00000000000
--- a/features/steps/project/commits/diff_comments.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class Spinach::Features::ProjectCommitsDiffComments < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedDiffNote
- include SharedPaths
- include SharedProject
-end
diff --git a/features/steps/project/create.rb b/features/steps/project/create.rb
deleted file mode 100644
index 60fa232672e..00000000000
--- a/features/steps/project/create.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class Spinach::Features::ProjectCreate < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedUser
-
- step 'fill project form with valid data' do
- fill_in 'project_path', with: 'Empty'
- page.within '#content-body' do
- click_button "Create project"
- end
- end
-
- step 'I should see project page' do
- expect(page).to have_content "Empty"
- expect(current_path).to eq project_path(Project.last)
- end
-
- step 'I should see empty project instructions' do
- expect(page).to have_content "git init"
- expect(page).to have_content "git remote"
- expect(page).to have_content Project.last.url_to_repo
- end
-end
diff --git a/features/steps/project/issues/filter_labels.rb b/features/steps/project/issues/filter_labels.rb
deleted file mode 100644
index b467af53c98..00000000000
--- a/features/steps/project/issues/filter_labels.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-class Spinach::Features::ProjectIssuesFilterLabels < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedProject
- include SharedPaths
- include Select2Helper
-
- step 'I should see "Bugfix1" in issues list' do
- page.within ".issues-list" do
- expect(page).to have_content "Bugfix1"
- end
- end
-
- step 'I should see "Bugfix2" in issues list' do
- page.within ".issues-list" do
- expect(page).to have_content "Bugfix2"
- end
- end
-
- step 'I should not see "Bugfix2" in issues list' do
- page.within ".issues-list" do
- expect(page).not_to have_content "Bugfix2"
- end
- end
-
- step 'I should not see "Feature1" in issues list' do
- page.within ".issues-list" do
- expect(page).not_to have_content "Feature1"
- end
- end
-
- step 'I click "dropdown close button"' do
- page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
- sleep 2
- end
-
- step 'I click link "feature"' do
- page.within ".labels-filter" do
- click_link "feature"
- end
- end
-
- step 'project "Shop" has issue "Bugfix1" with labels: "bug", "feature"' do
- project = Project.find_by(name: "Shop")
- issue = create(:issue, title: "Bugfix1", project: project)
- issue.labels << project.labels.find_by(title: 'bug')
- issue.labels << project.labels.find_by(title: 'feature')
- end
-
- step 'project "Shop" has issue "Bugfix2" with labels: "bug", "enhancement"' do
- project = Project.find_by(name: "Shop")
- issue = create(:issue, title: "Bugfix2", project: project)
- issue.labels << project.labels.find_by(title: 'bug')
- issue.labels << project.labels.find_by(title: 'enhancement')
- end
-
- step 'project "Shop" has issue "Feature1" with labels: "feature"' do
- project = Project.find_by(name: "Shop")
- issue = create(:issue, title: "Feature1", project: project)
- issue.labels << project.labels.find_by(title: 'feature')
- end
-end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
deleted file mode 100644
index baa78c23203..00000000000
--- a/features/steps/project/issues/issues.rb
+++ /dev/null
@@ -1,175 +0,0 @@
-class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedIssuable
- include SharedProject
- include SharedNote
- include SharedPaths
- include SharedMarkdown
- include SharedUser
-
- step 'I should not see "Release 0.3" in issues' do
- expect(page).not_to have_content "Release 0.3"
- end
-
- step 'I click link "Closed"' do
- find('.issues-state-filters [data-state="closed"] span', text: 'Closed').click
- end
-
- step 'I should see "Release 0.3" in issues' do
- expect(page).to have_content "Release 0.3"
- end
-
- step 'I should not see "Release 0.4" in issues' do
- expect(page).not_to have_content "Release 0.4"
- end
-
- step 'I click link "All"' do
- find('.issues-state-filters [data-state="all"] span', text: 'All').click
- # Waits for load
- expect(find('.issues-state-filters > .active')).to have_content 'All'
- end
-
- step 'I should see issue "Tweet control"' do
- expect(page).to have_content "Tweet control"
- end
-
- step 'I click "author" dropdown' do
- page.find('.js-author-search').click
- sleep 1
- end
-
- step 'I see current user as the first user' do
- expect(page).to have_selector('.dropdown-content', visible: true)
- users = page.all('.dropdown-menu-author .dropdown-content li a')
- expect(users[0].text).to eq 'Any Author'
- expect(users[1].text).to eq "#{current_user.name} #{current_user.to_reference}"
- end
-
- step 'I click link "500 error on profile"' do
- click_link "500 error on profile"
- end
-
- step 'I should see label \'bug\' with issue' do
- page.within '.issuable-show-labels' do
- expect(page).to have_content 'bug'
- end
- end
-
- step 'I fill in issue search with "Re"' do
- filter_issue "Re"
- end
-
- step 'I fill in issue search with "Bu"' do
- filter_issue "Bu"
- end
-
- step 'I fill in issue search with ".3"' do
- filter_issue ".3"
- end
-
- step 'I fill in issue search with "Something"' do
- filter_issue "Something"
- end
-
- step 'I fill in issue search with ""' do
- filter_issue ""
- end
-
- step 'project "Shop" has milestone "v2.2"' do
- milestone = create(:milestone, title: "v2.2", project: project)
-
- 3.times { create(:issue, project: project, milestone: milestone) }
- end
-
- step 'project "Shop" has milestone "v3.0"' do
- milestone = create(:milestone, title: "v3.0", project: project)
-
- 3.times { create(:issue, project: project, milestone: milestone) }
- end
-
- When 'I select milestone "v3.0"' do
- select "v3.0", from: "milestone_id"
- end
-
- step 'I should see selected milestone with title "v3.0"' do
- issues_milestone_selector = "#issue_milestone_id_chzn > a"
- expect(find(issues_milestone_selector)).to have_content("v3.0")
- end
-
- When 'I select first assignee from "Shop" project' do
- first_assignee = project.users.first
- select first_assignee.name, from: "assignee_id"
- end
-
- step 'I should see first assignee from "Shop" as selected assignee' do
- issues_assignee_selector = "#issue_assignee_id_chzn > a"
-
- assignee_name = project.users.first.name
- expect(find(issues_assignee_selector)).to have_content(assignee_name)
- end
-
- step 'The list should be sorted by "Least popular"' do
- page.within '.issues-list' do
- page.within 'li.issue:nth-child(1)' do
- expect(page).to have_content 'Tweet control'
- expect(page).to have_content '1 2'
- end
-
- page.within 'li.issue:nth-child(2)' do
- expect(page).to have_content 'Release 0.4'
- expect(page).to have_content '2 1'
- end
-
- page.within 'li.issue:nth-child(3)' do
- expect(page).to have_content 'Bugfix'
- expect(page).not_to have_content '0 0'
- end
- end
- end
-
- When 'I visit empty project page' do
- project = Project.find_by(name: 'Empty Project')
- visit project_path(project)
- end
-
- When "I visit project \"Community\" issues page" do
- project = Project.find_by(name: 'Community')
- visit project_issues_path(project)
- end
-
- step 'project \'Shop\' has issue \'Bugfix1\' with description: \'Description for issue1\'' do
- create(:issue, title: 'Bugfix1', description: 'Description for issue1', project: project)
- end
-
- step 'project \'Shop\' has issue \'Feature1\' with description: \'Feature submitted for issue1\'' do
- create(:issue, title: 'Feature1', description: 'Feature submitted for issue1', project: project)
- end
-
- step 'I fill in issue search with \'Description for issue1\'' do
- filter_issue 'Description for issue'
- end
-
- step 'I fill in issue search with \'issue1\'' do
- filter_issue 'issue1'
- end
-
- step 'I fill in issue search with \'Rock and roll\'' do
- filter_issue 'Rock and roll'
- end
-
- step 'I should see \'Bugfix1\' in issues' do
- expect(page).to have_content 'Bugfix1'
- end
-
- step 'I should see \'Feature1\' in issues' do
- expect(page).to have_content 'Feature1'
- end
-
- step 'I should not see \'Bugfix1\' in issues' do
- expect(page).not_to have_content 'Bugfix1'
- end
-
- def filter_issue(text)
- fill_in 'issuable_search', with: text
- end
-end
diff --git a/features/steps/project/issues/milestones.rb b/features/steps/project/issues/milestones.rb
deleted file mode 100644
index 30927306a4f..00000000000
--- a/features/steps/project/issues/milestones.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedProject
- include SharedPaths
- include SharedMarkdown
-
- step 'project "Shop" has milestone "v2.2"' do
- project = Project.find_by(name: "Shop")
- milestone = create(:milestone,
- title: "v2.2",
- project: project,
- description: "# Description header"
- )
- 3.times { create(:issue, project: project, milestone: milestone) }
- end
-
- When 'I click link "All Issues"' do
- click_link 'All Issues'
- end
-end
diff --git a/features/steps/project/issues/references.rb b/features/steps/project/issues/references.rb
deleted file mode 100644
index 69e8b5cbde5..00000000000
--- a/features/steps/project/issues/references.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class Spinach::Features::ProjectIssuesReferences < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedIssuable
- include SharedNote
- include SharedProject
- include SharedUser
-end
diff --git a/features/steps/project/merge_requests/references.rb b/features/steps/project/merge_requests/references.rb
deleted file mode 100644
index ab2ae6847a2..00000000000
--- a/features/steps/project/merge_requests/references.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class Spinach::Features::ProjectMergeRequestsReferences < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedIssuable
- include SharedNote
- include SharedProject
- include SharedUser
-end
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
deleted file mode 100644
index afaad4b255e..00000000000
--- a/features/steps/project/source/browse_files.rb
+++ /dev/null
@@ -1,435 +0,0 @@
-# coding: utf-8
-class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedProject
- include SharedPaths
- include RepoHelpers
- include WaitForRequests
-
- step "I don't have write access" do
- @project = create(:project, :repository, name: "Other Project", path: "other-project")
- @project.add_reporter(@user)
- visit project_tree_path(@project, root_ref)
- end
-
- step 'I should see files from repository' do
- expect(page).to have_content "VERSION"
- expect(page).to have_content ".gitignore"
- expect(page).to have_content "LICENSE"
- end
-
- step 'I should see files from repository for "6d39438"' do
- expect(current_path).to eq project_tree_path(@project, "6d39438")
- expect(page).to have_content ".gitignore"
- expect(page).to have_content "LICENSE"
- end
-
- step 'I see the ".gitignore"' do
- expect(page).to have_content '.gitignore'
- end
-
- step 'I don\'t see the ".gitignore"' do
- expect(page).not_to have_content '.gitignore'
- end
-
- step 'I click on ".gitignore" file in repo' do
- click_link ".gitignore"
- end
-
- step 'I should see its content' do
- wait_for_requests
- expect(page).to have_content old_gitignore_content
- end
-
- step 'I should see its new content' do
- wait_for_requests
- expect(page).to have_content new_gitignore_content
- end
-
- step 'I click link "Raw"' do
- click_link 'Open raw'
- end
-
- step 'I should see raw file content' do
- expect(source).to eq '' # Body is filled in by gitlab-workhorse
- end
-
- step 'I click button "Edit"' do
- find('.js-edit-blob').click
- end
-
- step 'I cannot see the edit button' do
- expect(page).not_to have_link 'edit'
- end
-
- step 'I click button "Fork"' do
- click_link 'Fork'
- end
-
- step 'I edit code' do
- expect(page).to have_selector('.file-editor')
- set_new_content
- end
-
- step 'I fill the new file name' do
- fill_in :file_name, with: new_file_name
- end
-
- step 'I fill the new branch name' do
- fill_in :branch_name, with: 'new_branch_name', visible: true
- end
-
- step 'I fill the new file name with a new directory' do
- fill_in :file_name, with: new_file_name_with_directory
- end
-
- step 'I fill the commit message' do
- fill_in :commit_message, with: 'New commit message', visible: true
- end
-
- step 'I click link "Diff"' do
- click_link 'Preview changes'
- end
-
- step 'I click on "Commit changes"' do
- click_button 'Commit changes'
- end
-
- step 'I click on "Changes" tab' do
- click_link 'Changes'
- end
-
- step 'I click on "Create directory"' do
- click_button 'Create directory'
- end
-
- step 'I click on "Delete"' do
- click_on 'Delete'
- end
-
- step 'I click on "Delete file"' do
- click_button 'Delete file'
- end
-
- step 'I click on "Replace"' do
- click_on "Replace"
- end
-
- step 'I click on "Replace file"' do
- click_button 'Replace file'
- end
-
- step 'I see diff' do
- expect(page).to have_css '.line_holder.new'
- end
-
- step 'I click on "New file" link in repo' do
- find('.add-to-tree').click
- click_link 'New file'
- expect(page).to have_selector('.file-editor')
- end
-
- step 'I click on "Upload file" link in repo' do
- find('.add-to-tree').click
- click_link 'Upload file'
- end
-
- step 'I click on "New directory" link in repo' do
- find('.add-to-tree').click
- click_link 'New directory'
- end
-
- step 'I fill the new directory name' do
- fill_in :dir_name, with: new_dir_name
- end
-
- step 'I fill an existing directory name' do
- fill_in :dir_name, with: 'files'
- end
-
- step 'I can see new file page' do
- expect(page).to have_content "New File"
- expect(page).to have_content "Commit message"
- end
-
- step 'I click on "Upload file"' do
- click_button 'Upload file'
- end
-
- step 'I can see the new commit message' do
- expect(page).to have_content "New commit message"
- end
-
- step 'I upload a new text file' do
- drop_in_dropzone test_text_file
- end
-
- step 'I fill the upload file commit message' do
- page.within('#modal-upload-blob') do
- fill_in :commit_message, with: 'New commit message'
- end
- end
-
- step 'I replace it with a text file' do
- drop_in_dropzone test_text_file
- end
-
- step 'I fill the replace file commit message' do
- page.within('#modal-upload-blob') do
- fill_in :commit_message, with: 'Replacement file commit message'
- end
- end
-
- step 'I can see the replacement commit message' do
- expect(page).to have_content "Replacement file commit message"
- end
-
- step 'I can see the new text file' do
- expect(page).to have_content "Lorem ipsum dolor sit amet"
- expect(page).to have_content "Sed ut perspiciatis unde omnis"
- end
-
- step 'I click on files directory' do
- click_link 'files'
- end
-
- step 'I click on History link' do
- click_link 'History'
- end
-
- step 'I see Browse dir link' do
- expect(page).to have_link 'Browse Directory'
- expect(page).not_to have_link 'Browse Code'
- end
-
- step 'I click on readme file' do
- page.within '.tree-table' do
- click_link 'README.md'
- end
- end
-
- step 'I see Browse file link' do
- expect(page).to have_link 'Browse File'
- expect(page).not_to have_link 'Browse Files'
- end
-
- step 'I see Browse code link' do
- expect(page).to have_link 'Browse Files'
- expect(page).not_to have_link 'Browse Directory'
- end
-
- step 'I click on Permalink' do
- click_link 'Permalink'
- end
-
- step 'I am redirected to the files URL' do
- expect(current_path).to eq project_tree_path(@project, 'master')
- end
-
- step 'I am redirected to the ".gitignore"' do
- expect(current_path).to eq(project_blob_path(@project, 'master/.gitignore'))
- end
-
- step 'I am redirected to the permalink URL' do
- expect(current_path).to(
- eq(project_blob_path(@project,
- @project.repository.commit.sha +
- '/.gitignore'))
- )
- end
-
- step 'I am redirected to the new file' do
- expect(current_path).to eq(
- project_blob_path(@project, 'master/' + new_file_name))
- end
-
- step 'I am redirected to the new file with directory' do
- expect(current_path).to eq(
- project_blob_path(@project, 'master/' + new_file_name_with_directory))
- end
-
- step 'I am redirected to the new merge request page' do
- expect(current_path).to eq(project_new_merge_request_path(@project))
- end
-
- step "I am redirected to the fork's new merge request page" do
- fork = @user.fork_of(@project)
- expect(current_path).to eq(project_new_merge_request_path(fork))
- end
-
- step 'I am redirected to the root directory' do
- expect(current_path).to eq(
- project_tree_path(@project, 'master'))
- end
-
- step "I don't see the permalink link" do
- expect(page).not_to have_link('permalink')
- end
-
- step 'I see "Unable to create directory"' do
- expect(page).to have_content('A directory with this name already exists')
- end
-
- step 'I see "Path can contain only..."' do
- expect(page).to have_content('Path can contain only')
- end
-
- step 'I see a commit error message' do
- expect(page).to have_content('Your changes could not be committed')
- end
-
- step "I switch ref to 'test'" do
- first('.js-project-refs-dropdown').click
-
- page.within '.project-refs-form' do
- click_link "'test'"
- end
- end
-
- step "I switch ref to fix" do
- first('.js-project-refs-dropdown').click
-
- page.within '.project-refs-form' do
- click_link 'fix'
- end
- end
-
- step "I see the ref 'test' has been selected" do
- expect(page).to have_selector '.dropdown-toggle-text', text: "'test'"
- end
-
- step "I visit the 'test' tree" do
- visit project_tree_path(@project, "'test'")
- end
-
- step "I visit the fix tree" do
- visit project_tree_path(@project, "fix/.testdir")
- end
-
- step 'I see the commit data' do
- expect(page).to have_css('.tree-commit-link', visible: true)
- expect(page).not_to have_content('Loading commit data...')
- end
-
- step 'I see the commit data for a directory with a leading dot' do
- expect(page).to have_css('.tree-commit-link', visible: true)
- expect(page).not_to have_content('Loading commit data...')
- end
-
- step 'I click on "files/lfs/lfs_object.iso" file in repo' do
- allow_any_instance_of(Project).to receive(:lfs_enabled?).and_return(true)
- visit project_tree_path(@project, "lfs")
- click_link 'files'
- click_link "lfs"
- click_link "lfs_object.iso"
- end
-
- step 'I should see download link and object size' do
- expect(page).to have_content 'Download (1.5 MB)'
- end
-
- step 'I should not see lfs pointer details' do
- expect(page).not_to have_content 'version https://git-lfs.github.com/spec/v1'
- expect(page).not_to have_content 'oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897'
- expect(page).not_to have_content 'size 1575078'
- end
-
- step 'I should see buttons for allowed commands' do
- page.within '.content' do
- expect(page).to have_link 'Download'
- expect(page).to have_content 'History'
- expect(page).to have_content 'Permalink'
- expect(page).not_to have_content 'Edit'
- expect(page).not_to have_content 'Blame'
- expect(page).to have_content 'Delete'
- expect(page).to have_content 'Replace'
- end
- end
-
- step 'I should see a Fork/Cancel combo' do
- expect(page).to have_link 'Fork'
- expect(page).to have_button 'Cancel'
- end
-
- step 'I should see a notice about a new fork having been created' do
- expect(page).to have_content "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request."
- end
-
- # SVG files
- step 'I upload a new SVG file' do
- drop_in_dropzone test_svg_file
- end
-
- step 'I visit the SVG file' do
- visit project_blob_path(@project, 'new_branch_name/logo_sample.svg')
- end
-
- step 'I can see the new rendered SVG image' do
- expect(page).to have_css('.file-content img')
- end
-
- private
-
- def set_new_content
- find('#editor')
- execute_script("ace.edit('editor').setValue('#{new_gitignore_content}')")
- end
-
- # Content of the gitignore file on the seed repository.
- def old_gitignore_content
- '*.rbc'
- end
-
- # Constant value that differs from the content
- # of the gitignore of the seed repository.
- def new_gitignore_content
- old_gitignore_content + 'a'
- end
-
- # Constant value that is a valid filename and
- # not a filename present at root of the seed repository.
- def new_file_name
- 'not_a_file.md'
- end
-
- # Constant value that is a valid filename with directory and
- # not a filename present at root of the seed repository.
- def new_file_name_with_directory
- 'foo/bar/baz.txt'
- end
-
- # Constant value that is a valid directory and
- # not a directory present at root of the seed repository.
- def new_dir_name
- 'new_dir/subdir'
- end
-
- def drop_in_dropzone(file_path)
- # Generate a fake input selector
- page.execute_script <<-JS
- var fakeFileInput = window.$('<input/>').attr(
- {id: 'fakeFileInput', type: 'file'}
- ).appendTo('body');
- JS
- # Attach the file to the fake input selector with Capybara
- attach_file("fakeFileInput", file_path)
- # Add the file to a fileList array and trigger the fake drop event
- page.execute_script <<-JS
- var fileList = [$('#fakeFileInput')[0].files[0]];
- var e = jQuery.Event('drop', { dataTransfer : { files : fileList } });
- $('.dropzone')[0].dropzone.listeners[0].events.drop(e);
- JS
- end
-
- def test_text_file
- File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt')
- end
-
- def test_image_file
- File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
- end
-
- def test_svg_file
- File.join(Rails.root, 'spec', 'fixtures', 'logo_sample.svg')
- end
-end
diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb
deleted file mode 100644
index 104d024fee2..00000000000
--- a/features/steps/shared/active_tab.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-module SharedActiveTab
- include Spinach::DSL
- include WaitForRequests
-
- after do
- wait_for_requests if javascript_test?
- end
-
- def ensure_active_main_tab(content)
- expect(find('.sidebar-top-level-items > li.active')).to have_content(content)
- end
-
- def ensure_active_sub_tab(content)
- expect(find('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)')).to have_content(content)
- end
-
- def ensure_active_sub_nav(content)
- expect(find('.layout-nav .controls li.active')).to have_content(content)
- end
-
- step 'no other main tabs should be active' do
- expect(page).to have_selector('.sidebar-top-level-items > li.active', count: 1)
- end
-
- step 'no other sub tabs should be active' do
- expect(page).to have_selector('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)', count: 1)
- end
-
- step 'no other sub navs should be active' do
- expect(page).to have_selector('.layout-nav .controls li.active', count: 1)
- end
-end
diff --git a/features/steps/shared/admin.rb b/features/steps/shared/admin.rb
deleted file mode 100644
index ac0a1764147..00000000000
--- a/features/steps/shared/admin.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module SharedAdmin
- include Spinach::DSL
-
- step 'there are projects in system' do
- 2.times { create(:project, :repository) }
- end
-
- step 'system has users' do
- 2.times { create(:user) }
- end
-end
diff --git a/features/steps/shared/authentication.rb b/features/steps/shared/authentication.rb
deleted file mode 100644
index df1428d8266..00000000000
--- a/features/steps/shared/authentication.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require Rails.root.join('features', 'support', 'login_helpers')
-
-module SharedAuthentication
- include Spinach::DSL
- include LoginHelpers
-
- step 'I sign in as a user' do
- sign_out(@user) if @user
-
- @user = create(:user)
- sign_in(@user)
- end
-
- step 'I sign in via the UI' do
- gitlab_sign_in(create(:user))
- end
-
- step 'I should be redirected to sign in page' do
- expect(current_path).to eq new_user_session_path
- end
-
- step "I logout directly" do
- gitlab_sign_out
- end
-
- def current_user
- @user || User.reorder(nil).first
- end
-
- private
-
- def gitlab_sign_in(user)
- visit new_user_session_path
-
- fill_in "user_login", with: user.email
- fill_in "user_password", with: "12345678"
- check 'user_remember_me'
- click_button "Sign in"
-
- @user = user
- end
-
- def gitlab_sign_out
- return unless @user
-
- if Capybara.current_driver == Capybara.javascript_driver
- find('.header-user-dropdown-toggle').click
- click_link 'Sign out'
- expect(page).to have_button('Sign in')
- else
- sign_out(@user)
- end
-
- @user = nil
- end
-end
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
deleted file mode 100644
index 22f397947b0..00000000000
--- a/features/steps/shared/diff_note.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-module SharedDiffNote
- include Spinach::DSL
- include RepoHelpers
- include WaitForRequests
-
- after do
- wait_for_requests if javascript_test?
- end
-
- step 'I delete a diff comment' do
- find('.note').hover
- find(".js-note-delete").click
- end
-
- step 'I haven\'t written any diff comment text' do
- page.within(diff_file_selector) do
- fill_in "note[note]", with: ""
- end
- end
-
- step 'The diff comment preview tab should say there is nothing to do' do
- page.within(diff_file_selector) do
- find('.js-md-preview-button').click
- expect(find('.js-md-preview')).to have_content('Nothing to preview.')
- end
- end
-
- step 'I see side-by-side diff button' do
- expect(page).to have_content "Side-by-side"
- end
-
- def diff_file_selector
- '.diff-file:nth-of-type(1)'
- end
-
- def click_diff_line(code)
- find(".line_holder[id='#{code}'] button").click
- end
-
- def click_parallel_diff_line(code, line_type)
- find(".line_holder.parallel td[id='#{code}']").find(:xpath, 'preceding-sibling::*[1][self::td]').hover
- find(".line_holder.parallel button[data-line-code='#{code}']").click
- end
-end
diff --git a/features/steps/shared/group.rb b/features/steps/shared/group.rb
deleted file mode 100644
index 0126ce39c5a..00000000000
--- a/features/steps/shared/group.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-module SharedGroup
- include Spinach::DSL
-
- step 'current user is developer of group "Owned"' do
- is_member_of(current_user.name, "Owned", Gitlab::Access::DEVELOPER)
- end
-
- step '"John Doe" is guest of group "Guest"' do
- is_member_of("John Doe", "Guest", Gitlab::Access::GUEST)
- end
-
- step '"Mary Jane" is owner of group "Owned"' do
- is_member_of("Mary Jane", "Owned", Gitlab::Access::OWNER)
- end
-
- step '"Mary Jane" is guest of group "Owned"' do
- is_member_of("Mary Jane", "Owned", Gitlab::Access::GUEST)
- end
-
- step '"Mary Jane" is guest of group "Guest"' do
- is_member_of("Mary Jane", "Guest", Gitlab::Access::GUEST)
- end
-
- step 'I should see group "TestGroup"' do
- expect(page).to have_content "TestGroup"
- end
-
- step 'I should not see group "TestGroup"' do
- expect(page).not_to have_content "TestGroup"
- end
-
- protected
-
- def is_member_of(username, groupname, role)
- user = User.find_by(name: username) || create(:user, name: username)
- group = Group.find_by(name: groupname) || create(:group, name: groupname)
- group.add_user(user, role)
- project ||= create(:project, :repository, namespace: group)
- create(:closed_issue_event, project: project)
- project.add_master(user)
- end
-
- def owned_group
- @owned_group ||= Group.find_by(name: "Owned")
- end
-end
diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb
deleted file mode 100644
index cc6fd48935f..00000000000
--- a/features/steps/shared/issuable.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-module SharedIssuable
- include Spinach::DSL
-
- def edit_issuable
- find('.js-issuable-edit', visible: true).click
- end
-
- step 'I leave a comment referencing issue "Community issue"' do
- leave_reference_comment(
- issuable: Issue.find_by(title: 'Community issue'),
- from_project_name: 'Enterprise'
- )
- end
-
- step 'I click link "Edit" for the merge request' do
- edit_issuable
- end
-
- step 'I sort the list by "Least popular"' do
- find('button.dropdown-toggle').click
-
- page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
- click_link 'Least popular'
- end
- end
-
- step 'I click link "Next" in the sidebar' do
- page.within '.issuable-sidebar' do
- click_link 'Next'
- end
- end
-
- def create_issuable_for_project(project_name:, title:, type: :issue)
- project = Project.find_by(name: project_name)
-
- attrs = {
- title: title,
- author: project.users.first,
- description: '# Description header'
- }
-
- case type
- when :issue
- attrs[:project] = project
- when :merge_request
- attrs.merge!(
- source_project: project,
- target_project: project,
- source_branch: 'fix',
- target_branch: 'master'
- )
- end
-
- create(type, attrs)
- end
-
- def leave_reference_comment(issuable:, from_project_name:)
- project = Project.find_by(name: from_project_name)
-
- page.within('.js-main-target-form') do
- fill_in 'note[note]', with: "##{issuable.to_reference(project)}"
- click_button 'Comment'
- end
- end
-
- def visible_note(issuable:, from_project_name:, user_name:)
- project = Project.find_by(name: from_project_name)
-
- expect(page).to have_content(user_name)
- expect(page).to have_content("mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}")
- end
-
- def expect_sidebar_content(content)
- page.within '.issuable-sidebar' do
- expect(page).to have_content content
- end
- end
-end
diff --git a/features/steps/shared/markdown.rb b/features/steps/shared/markdown.rb
deleted file mode 100644
index 65118f07ca2..00000000000
--- a/features/steps/shared/markdown.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module SharedMarkdown
- include Spinach::DSL
-
- step 'I should not see the Markdown preview' do
- expect(find('.gfm-form .js-md-preview')).not_to be_visible
- end
-
- step 'I haven\'t written any description text' do
- find('.gfm-form').fill_in 'Description', with: ''
- end
-end
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
deleted file mode 100644
index 4a6dee3c7b8..00000000000
--- a/features/steps/shared/note.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module SharedNote
- include Spinach::DSL
- include WaitForRequests
-
- after do
- wait_for_requests if javascript_test?
- end
-
- step 'I haven\'t written any comment text' do
- page.within(".js-main-target-form") do
- fill_in "note[note]", with: ""
- end
- end
-
- step 'The comment preview tab should say there is nothing to do' do
- page.within(".js-main-target-form") do
- find('.js-md-preview-button').click
- expect(find('.js-md-preview')).to have_content('Nothing to preview.')
- end
- end
-end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
deleted file mode 100644
index 8f2f5ca26a9..00000000000
--- a/features/steps/shared/paths.rb
+++ /dev/null
@@ -1,413 +0,0 @@
-module SharedPaths
- include Spinach::DSL
- include RepoHelpers
- include DashboardHelper
- include WaitForRequests
-
- step 'I visit new project page' do
- visit new_project_path
- end
-
- step 'I visit login page' do
- visit new_user_session_path
- end
-
- # ----------------------------------------
- # User
- # ----------------------------------------
-
- step 'I visit user "John Doe" page' do
- visit user_path("john_doe")
- end
-
- # ----------------------------------------
- # Group
- # ----------------------------------------
-
- step 'I visit group "Owned" page' do
- visit group_path(Group.find_by(name: "Owned"))
- end
-
- step 'I visit group "Owned" activity page' do
- visit activity_group_path(Group.find_by(name: "Owned"))
- end
-
- step 'I visit group "Owned" issues page' do
- visit issues_group_path(Group.find_by(name: "Owned"))
- end
-
- step 'I visit group "Owned" merge requests page' do
- visit merge_requests_group_path(Group.find_by(name: "Owned"))
- end
-
- step 'I visit group "Owned" milestones page' do
- visit group_milestones_path(Group.find_by(name: "Owned"))
- end
-
- step 'I visit group "Owned" members page' do
- visit group_group_members_path(Group.find_by(name: "Owned"))
- end
-
- step 'I visit group "Owned" projects page' do
- visit projects_group_path(Group.find_by(name: "Owned"))
- end
-
- step 'I visit group "Guest" page' do
- visit group_path(Group.find_by(name: "Guest"))
- end
-
- step 'I visit group "Guest" issues page' do
- visit issues_group_path(Group.find_by(name: "Guest"))
- end
-
- step 'I visit group "Guest" merge requests page' do
- visit merge_requests_group_path(Group.find_by(name: "Guest"))
- end
-
- step 'I visit group "Guest" members page' do
- visit group_group_members_path(Group.find_by(name: "Guest"))
- end
-
- step 'I visit group "Guest" settings page' do
- visit edit_group_path(Group.find_by(name: "Guest"))
- end
-
- # ----------------------------------------
- # Dashboard
- # ----------------------------------------
-
- step 'I visit dashboard page' do
- visit dashboard_projects_path
- end
-
- step 'I visit dashboard activity page' do
- visit activity_dashboard_path
- end
-
- step 'I visit dashboard projects page' do
- visit projects_dashboard_path
- end
-
- step 'I visit dashboard issues page' do
- visit assigned_issues_dashboard_path
- end
-
- step 'I visit dashboard search page' do
- visit search_path
- end
-
- step 'I visit dashboard help page' do
- visit help_path
- end
-
- step 'I visit dashboard groups page' do
- visit dashboard_groups_path
- end
-
- step 'I should be redirected to the dashboard groups page' do
- expect(current_path).to eq dashboard_groups_path
- end
-
- step 'I visit dashboard starred projects page' do
- visit starred_dashboard_projects_path
- end
-
- # ----------------------------------------
- # Profile
- # ----------------------------------------
-
- step 'I visit profile page' do
- visit profile_path
- end
-
- step 'I visit profile applications page' do
- visit applications_profile_path
- end
-
- step 'I visit profile password page' do
- visit edit_profile_password_path
- end
-
- step 'I visit profile account page' do
- visit profile_account_path
- end
-
- step 'I visit profile SSH keys page' do
- visit profile_keys_path
- end
-
- step 'I visit profile preferences page' do
- visit profile_preferences_path
- end
-
- step 'I visit Authentication log page' do
- visit audit_log_profile_path
- end
-
- # ----------------------------------------
- # Admin
- # ----------------------------------------
-
- step 'I visit admin page' do
- visit admin_root_path
- end
-
- step 'I visit abuse reports page' do
- visit admin_abuse_reports_path
- end
-
- step 'I visit admin projects page' do
- visit admin_projects_path
- end
-
- step 'I visit admin users page' do
- visit admin_users_path
- end
-
- step 'I visit admin logs page' do
- visit admin_logs_path
- end
-
- step 'I visit admin messages page' do
- visit admin_broadcast_messages_path
- end
-
- step 'I visit admin hooks page' do
- visit admin_hooks_path
- end
-
- step 'I visit admin Resque page' do
- visit admin_background_jobs_path
- end
-
- step 'I visit admin teams page' do
- visit admin_teams_path
- end
-
- step 'I visit spam logs page' do
- visit admin_spam_logs_path
- end
-
- # ----------------------------------------
- # Generic Project
- # ----------------------------------------
-
- step "I visit my project's settings page" do
- visit edit_project_path(@project)
- end
-
- step 'I visit a binary file in the repo' do
- visit project_blob_path(@project,
- File.join(root_ref, 'files/images/logo-black.png'))
- end
-
- step "I visit my project's commits page" do
- visit project_commits_path(@project, root_ref, { limit: 5 })
- end
-
- step "I visit my project's commits page for a specific path" do
- visit project_commits_path(@project, root_ref + "/files/ruby/regex.rb", { limit: 5 })
- end
-
- step 'I visit my project\'s commits stats page' do
- visit stats_project_repository_path(@project)
- end
-
- step "I visit my project's graph page" do
- # Stub Graph max_size to speed up test (10 commits vs. 650)
- Network::Graph.stub(max_count: 10)
-
- visit project_network_path(@project, root_ref)
- end
-
- step "I visit my project's issues page" do
- visit project_issues_path(@project)
- end
-
- step "I visit my project's merge requests page" do
- visit project_merge_requests_path(@project)
- end
-
- step "I visit my project's members page" do
- visit project_project_members_path(@project)
- end
-
- step "I visit my project's wiki page" do
- visit project_wiki_path(@project, :home)
- end
-
- step 'I visit project hooks page' do
- visit project_settings_integrations_path(@project)
- end
-
- step 'I visit project find file page' do
- visit project_find_file_path(@project, root_ref)
- end
-
- # ----------------------------------------
- # "Shop" Project
- # ----------------------------------------
-
- step 'I visit project "Shop" page' do
- visit project_path(project)
- end
-
- step 'I visit edit project "Shop" page' do
- visit edit_project_path(project)
- end
-
- step 'I visit compare refs page' do
- visit project_compare_index_path(@project)
- end
-
- step 'I visit project commits page' do
- visit project_commits_path(@project, root_ref, { limit: 5 })
- end
-
- step 'I visit project commits page for stable branch' do
- visit project_commits_path(@project, 'stable', { limit: 5 })
- end
-
- step 'I visit blob file from repo' do
- visit project_blob_path(@project, File.join(sample_commit.id, sample_blob.path))
- end
-
- step 'I visit ".gitignore" file in repo' do
- visit project_blob_path(@project, File.join(root_ref, '.gitignore'))
- end
-
- step 'I am on the new file page' do
- expect(current_path).to eq(project_create_blob_path(@project, root_ref))
- end
-
- step 'I am on the ".gitignore" edit file page' do
- expect(current_path).to eq(
- project_edit_blob_path(@project, File.join(root_ref, '.gitignore')))
- end
-
- step 'I visit project source page for "6d39438"' do
- visit project_tree_path(@project, "6d39438")
- end
-
- step 'I visit project source page for' \
- ' "6d394385cf567f80a8fd85055db1ab4c5295806f"' do
- visit project_tree_path(@project,
- '6d394385cf567f80a8fd85055db1ab4c5295806f')
- end
-
- step 'I visit project tags page' do
- visit project_tags_path(@project)
- end
-
- step 'I visit issue page "Release 0.4"' do
- issue = Issue.find_by(title: "Release 0.4")
- visit project_issue_path(issue.project, issue)
- end
-
- step 'I visit project "Forum" labels page' do
- project = Project.find_by(name: 'Forum')
- visit project_labels_path(project)
- end
-
- step 'I visit project "Shop" new label page' do
- project = Project.find_by(name: 'Shop')
- visit new_project_label_path(project)
- end
-
- step 'I visit project "Forum" new label page' do
- project = Project.find_by(name: 'Forum')
- visit new_project_label_path(project)
- end
-
- step 'I visit merge request page "Bug NS-04"' do
- visit merge_request_path("Bug NS-04")
- wait_for_requests
- end
-
- step 'I visit merge request page "Bug NS-07"' do
- visit merge_request_path("Bug NS-07")
- wait_for_requests
- end
-
- step 'I visit merge request page "Bug NS-08"' do
- visit merge_request_path("Bug NS-08")
- wait_for_requests
- end
-
- step 'I visit merge request page "Bug CO-01"' do
- mr = MergeRequest.find_by(title: "Bug CO-01")
- visit project_merge_request_path(mr.target_project, mr)
- wait_for_requests
- end
-
- step 'I visit forked project "Shop" merge requests page' do
- visit project_merge_requests_path(project)
- end
-
- step 'I visit project "Shop" team page' do
- visit project_project_members_path(project)
- end
-
- step 'I visit project wiki page' do
- visit project_wiki_path(@project, :home)
- end
-
- # ----------------------------------------
- # Visibility Projects
- # ----------------------------------------
-
- step 'I visit project "Community" source page' do
- project = Project.find_by(name: 'Community')
- visit project_tree_path(project, root_ref)
- end
-
- step 'I visit project "Internal" page' do
- project = Project.find_by(name: "Internal")
- visit project_path(project)
- end
-
- step 'I visit project "Enterprise" page' do
- project = Project.find_by(name: "Enterprise")
- visit project_path(project)
- end
-
- # ----------------------------------------
- # Empty Projects
- # ----------------------------------------
-
- step "I should not see command line instructions" do
- expect(page).not_to have_css('.empty_wrapper')
- end
-
- # ----------------------------------------
- # Public Projects
- # ----------------------------------------
- step 'I visit the public groups area' do
- visit explore_groups_path
- end
-
- # ----------------------------------------
- # Snippets
- # ----------------------------------------
-
- step 'I visit project "Shop" snippets page' do
- visit project_snippets_path(project)
- end
-
- step 'I visit snippets page' do
- visit explore_snippets_path
- end
-
- def root_ref
- @project.repository.root_ref
- end
-
- def project
- Project.find_by!(name: 'Shop')
- end
-
- def merge_request_path(title)
- mr = MergeRequest.find_by(title: title)
- project_merge_request_path(mr.target_project, mr)
- end
-end
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
deleted file mode 100644
index d0277257320..00000000000
--- a/features/steps/shared/project.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-module SharedProject
- include Spinach::DSL
-
- # Create a project without caring about what it's called
- step "I own a project" do
- @project = create(:project, :repository, namespace: @user.namespace)
- @project.add_master(@user)
- end
-
- step "I own a project in some group namespace" do
- @group = create(:group, name: 'some group')
- @project = create(:project, namespace: @group)
- @project.add_master(@user)
- end
-
- def current_project
- @project ||= Project.first
- end
-
- # ----------------------------------------
- # Visibility of archived project
- # ----------------------------------------
-
- step 'I should not see project "Archive"' do
- project = Project.find_by(name: "Archive")
- expect(page).not_to have_content project.full_name
- end
-
- step 'I should see project "Archive"' do
- project = Project.find_by(name: "Archive")
- expect(page).to have_content project.full_name
- end
-
- # ----------------------------------------
- # Visibility level
- # ----------------------------------------
-
- step 'I should see project "Enterprise"' do
- expect(page).to have_content "Enterprise"
- end
-
- step 'I should not see project "Enterprise"' do
- expect(page).not_to have_content "Enterprise"
- end
-
- step 'internal project "Internal"' do
- create(:project, :internal, :repository, name: 'Internal')
- end
-
- step 'I should see project "Internal"' do
- page.within '.js-projects-list-holder' do
- expect(page).to have_content "Internal"
- end
- end
-
- step 'I should not see project "Internal"' do
- page.within '.js-projects-list-holder' do
- expect(page).not_to have_content "Internal"
- end
- end
-
- step 'I should see project "Community"' do
- expect(page).to have_content "Community"
- end
-
- step 'I should not see project "Community"' do
- expect(page).not_to have_content "Community"
- end
-
- step '"John Doe" owns private project "Enterprise"' do
- user_owns_project(
- user_name: 'John Doe',
- project_name: 'Enterprise'
- )
- end
-
- step '"John Doe" owns internal project "Internal"' do
- user_owns_project(
- user_name: 'John Doe',
- project_name: 'Internal',
- visibility: :internal
- )
- end
-
- step 'public empty project "Empty Public Project"' do
- create :project_empty_repo, :public, name: "Empty Public Project"
- end
-
- step 'project "Shop" has labels: "bug", "feature", "enhancement"' do
- project = Project.find_by(name: "Shop")
- create(:label, project: project, title: 'bug')
- create(:label, project: project, title: 'feature')
- create(:label, project: project, title: 'enhancement')
- end
-
- def user_owns_project(user_name:, project_name:, visibility: :private)
- user = user_exists(user_name, username: user_name.gsub(/\s/, '').underscore)
- project = Project.find_by(name: project_name)
- project ||= create(:project, visibility, name: project_name, namespace: user.namespace)
- project.add_master(user)
- end
-end
diff --git a/features/steps/shared/project_tab.rb b/features/steps/shared/project_tab.rb
deleted file mode 100644
index 5a516ee33bc..00000000000
--- a/features/steps/shared/project_tab.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-require_relative 'active_tab'
-
-module SharedProjectTab
- include Spinach::DSL
- include SharedActiveTab
-
- step 'the active main tab should be Project' do
- ensure_active_main_tab('Overview')
- end
-
- step 'the active main tab should be Repository' do
- ensure_active_main_tab('Repository')
- end
-
- step 'the active main tab should be Issues' do
- ensure_active_main_tab('Issues')
- end
-
- step 'the active sub tab should be Members' do
- ensure_active_sub_tab('Members')
- end
-
- step 'the active main tab should be Merge Requests' do
- ensure_active_main_tab('Merge Requests')
- end
-
- step 'the active main tab should be Snippets' do
- ensure_active_main_tab('Snippets')
- end
-
- step 'the active main tab should be Wiki' do
- ensure_active_main_tab('Wiki')
- end
-
- step 'the active main tab should be Members' do
- ensure_active_main_tab('Members')
- end
-
- step 'the active main tab should be Settings' do
- ensure_active_main_tab('Settings')
- end
-
- step 'the active sub tab should be Graph' do
- ensure_active_sub_tab('Graph')
- end
-
- step 'the active sub tab should be Files' do
- ensure_active_sub_tab('Files')
- end
-
- step 'the active sub tab should be Commits' do
- ensure_active_sub_tab('Commits')
- end
-
- step 'the active sub tab should be Home' do
- ensure_active_sub_tab('Details')
- end
-
- step 'the active sub tab should be Activity' do
- ensure_active_sub_tab('Activity')
- end
-
- step 'the active sub tab should be Charts' do
- ensure_active_sub_tab('Charts')
- end
-end
diff --git a/features/steps/shared/shortcuts.rb b/features/steps/shared/shortcuts.rb
deleted file mode 100644
index a75a8474d26..00000000000
--- a/features/steps/shared/shortcuts.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module SharedShortcuts
- include Spinach::DSL
-
- step 'I press "g" and "p"' do
- find('body').native.send_key('g')
- find('body').native.send_key('p')
- end
-
- step 'I press "g" and "i"' do
- find('body').native.send_key('g')
- find('body').native.send_key('i')
- end
-
- step 'I press "g" and "m"' do
- find('body').native.send_key('g')
- find('body').native.send_key('m')
- end
-end
diff --git a/features/steps/shared/sidebar_active_tab.rb b/features/steps/shared/sidebar_active_tab.rb
deleted file mode 100644
index 07fff16e867..00000000000
--- a/features/steps/shared/sidebar_active_tab.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module SharedSidebarActiveTab
- include Spinach::DSL
-
- step 'no other main tabs should be active' do
- expect(page).to have_selector('.nav-sidebar li.active', count: 1)
- end
-
- def ensure_active_main_tab(content)
- expect(find('.nav-sidebar li.active')).to have_content(content)
- end
-
- step 'the active main tab should be Home' do
- ensure_active_main_tab('Projects')
- end
-
- step 'the active main tab should be Groups' do
- ensure_active_main_tab('Groups')
- end
-
- step 'the active main tab should be Projects' do
- ensure_active_main_tab('Projects')
- end
-
- step 'the active main tab should be Issues' do
- ensure_active_main_tab('Issues')
- end
-
- step 'the active main tab should be Merge Requests' do
- ensure_active_main_tab('Merge Requests')
- end
-end
diff --git a/features/steps/shared/user.rb b/features/steps/shared/user.rb
deleted file mode 100644
index 9cadc91769d..00000000000
--- a/features/steps/shared/user.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-module SharedUser
- include Spinach::DSL
-
- step 'User "John Doe" exists' do
- user_exists("John Doe", { username: "john_doe" })
- end
-
- step 'User "Mary Jane" exists' do
- user_exists("Mary Jane", { username: "mary_jane" })
- end
-
- step 'gitlab user "Mike"' do
- create(:user, name: "Mike")
- end
-
- protected
-
- def user_exists(name, options = {})
- User.find_by(name: name) || create(:user, { name: name, admin: false }.merge(options))
- end
-
- step 'I have no ssh keys' do
- @user.keys.delete_all
- end
-
- step 'I click on "Personal projects" tab' do
- page.within '.nav-links' do
- click_link 'Personal projects'
- end
-
- expect(page).to have_css('.tab-content #projects.active')
- end
-
- step 'I click on "Contributed projects" tab' do
- page.within '.nav-links' do
- click_link 'Contributed projects'
- end
-
- expect(page).to have_css('.tab-content #contributed.active')
- end
-end
diff --git a/features/support/capybara.rb b/features/support/capybara.rb
deleted file mode 100644
index 8879c9ab650..00000000000
--- a/features/support/capybara.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-require 'capybara-screenshot/spinach'
-
-# Give CI some extra time
-timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 60 : 30
-
-Capybara.register_driver :chrome do |app|
- capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
- # This enables access to logs with `page.driver.manage.get_log(:browser)`
- loggingPrefs: {
- browser: "ALL",
- client: "ALL",
- driver: "ALL",
- server: "ALL"
- }
- )
-
- options = Selenium::WebDriver::Chrome::Options.new
- options.add_argument("window-size=1240,1400")
-
- # Chrome won't work properly in a Docker container in sandbox mode
- options.add_argument("no-sandbox")
-
- # Run headless by default unless CHROME_HEADLESS specified
- options.add_argument("headless") unless ENV['CHROME_HEADLESS'] =~ /^(false|no|0)$/i
-
- # Disable /dev/shm use in CI. See https://gitlab.com/gitlab-org/gitlab-ee/issues/4252
- options.add_argument("disable-dev-shm-usage") if ENV['CI'] || ENV['CI_SERVER']
-
- Capybara::Selenium::Driver.new(
- app,
- browser: :chrome,
- desired_capabilities: capabilities,
- options: options
- )
-end
-
-Capybara.javascript_driver = :chrome
-Capybara.default_max_wait_time = timeout
-Capybara.ignore_hidden_elements = false
-
-# Keep only the screenshots generated from the last failing test suite
-Capybara::Screenshot.prune_strategy = :keep_last_run
-# From https://github.com/mattheworiordan/capybara-screenshot/issues/84#issuecomment-41219326
-Capybara::Screenshot.register_driver(:chrome) do |driver, path|
- driver.browser.save_screenshot(path)
-end
-
-Spinach.hooks.before_run do
- TestEnv.eager_load_driver_server
-end
diff --git a/features/support/db_cleaner.rb b/features/support/db_cleaner.rb
deleted file mode 100644
index 31c922d23c3..00000000000
--- a/features/support/db_cleaner.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require 'database_cleaner'
-
-DatabaseCleaner[:active_record].strategy = :deletion
-
-Spinach.hooks.before_scenario do
- DatabaseCleaner.start
-end
-
-Spinach.hooks.after_scenario do
- DatabaseCleaner.clean
-end
diff --git a/features/support/env.rb b/features/support/env.rb
deleted file mode 100644
index 8fa2fcb6e3e..00000000000
--- a/features/support/env.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-require './spec/simplecov_env'
-SimpleCovEnv.start!
-
-ENV['RAILS_ENV'] = 'test'
-require './config/environment'
-require 'rspec/expectations'
-
-if ENV['CI']
- require 'knapsack'
- Knapsack::Adapters::SpinachAdapter.bind
-end
-
-WebMock.enable!
-
-%w(select2_helper test_env repo_helpers wait_for_requests project_forks_helper).each do |f|
- require Rails.root.join('spec', 'support', 'helpers', f)
-end
-
-%w(sidekiq webmock).each do |f|
- require Rails.root.join('spec', 'support', f)
-end
-
-Dir["#{Rails.root}/features/steps/shared/*.rb"].each { |file| require file }
-
-Spinach.hooks.before_run do
- include RSpec::Mocks::ExampleMethods
- include ActiveJob::TestHelper
- include FactoryBot::Syntax::Methods
- include GitlabRoutingHelper
-
- RSpec::Mocks.setup
- TestEnv.init(mailer: false)
-
- # skip pre-receive hook check so we can use
- # web editor and merge
- TestEnv.disable_pre_receive
-end
-
-Spinach.hooks.after_scenario do |scenario_data, step_definitions|
- if scenario_data.tags.include?('javascript')
- include WaitForRequests
- block_and_wait_for_requests_complete
- end
-end
-
-module StdoutReporterWithScenarioLocation
- # Override the standard reporter to show filename and line number next to each
- # scenario for easy, focused re-runs
- def before_scenario_run(scenario, step_definitions = nil)
- @max_step_name_length = scenario.steps.map(&:name).map(&:length).max if scenario.steps.any? # rubocop:disable Gitlab/ModuleWithInstanceVariables
- name = scenario.name
-
- # This number has no significance, it's just to line things up
- max_length = @max_step_name_length + 19 # rubocop:disable Gitlab/ModuleWithInstanceVariables
- out.puts "\n #{'Scenario:'.green} #{name.light_green.ljust(max_length)}" \
- " # #{scenario.feature.filename}:#{scenario.line}"
- end
-end
-
-Spinach::Reporter::Stdout.prepend(StdoutReporterWithScenarioLocation)
diff --git a/features/support/gitaly.rb b/features/support/gitaly.rb
deleted file mode 100644
index 3cd5f4ce497..00000000000
--- a/features/support/gitaly.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-Spinach.hooks.before_scenario do
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true)
-end
diff --git a/features/support/login_helpers.rb b/features/support/login_helpers.rb
deleted file mode 100644
index 540ff25a4f2..00000000000
--- a/features/support/login_helpers.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module LoginHelpers
- # After inclusion, IntegrationHelpers calls these two methods that aren't
- # supported by Spinach, so we perform the end results ourselves
- class << self
- def setup(*args)
- Spinach.hooks.before_scenario do
- Warden.test_mode!
- end
- end
-
- def teardown(*args)
- Spinach.hooks.after_scenario do
- Warden.test_reset!
- end
- end
- end
-
- include Devise::Test::IntegrationHelpers
-end
diff --git a/features/support/rerun.rb b/features/support/rerun.rb
deleted file mode 100644
index 60b78f9d050..00000000000
--- a/features/support/rerun.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# The spinach-rerun-reporter doesn't define the on_undefined_step
-# See it here: https://github.com/javierav/spinach-rerun-reporter/blob/master/lib/spinach/reporter/rerun.rb
-require 'spinach-rerun-reporter'
-
-module Spinach
- class Reporter
- class Rerun
- def on_undefined_step(step_data, failure, step_definitions = nil)
- super step_data, failure, step_definitions
-
- # save feature file and scenario line
- @rerun << "#{current_feature.filename}:#{current_scenario.line}"
- end
- end
- end
-end
diff --git a/lib/gitlab/auth/blocked_user_tracker.rb b/lib/gitlab/auth/blocked_user_tracker.rb
index dae03a179e4..7609a7b04f6 100644
--- a/lib/gitlab/auth/blocked_user_tracker.rb
+++ b/lib/gitlab/auth/blocked_user_tracker.rb
@@ -17,7 +17,9 @@ module Gitlab
# message passed along by Warden.
return unless message == User::BLOCKED_MESSAGE
- login = env.dig(ACTIVE_RECORD_REQUEST_PARAMS, 'user', 'login')
+ # Check for either LDAP or regular GitLab account logins
+ login = env.dig(ACTIVE_RECORD_REQUEST_PARAMS, 'username') ||
+ env.dig(ACTIVE_RECORD_REQUEST_PARAMS, 'user', 'login')
return unless login.present?
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index 390efda326a..2e9b6e302f5 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -59,7 +59,7 @@ module Gitlab
startline = 0
result.each_line.each_with_index do |line, index|
- prefix ||= line.match(/^(?<ref>[^:]*):(?<filename>.*)\x00(?<startline>\d+)\x00/)&.tap do |matches|
+ prefix ||= line.match(/^(?<ref>[^:]*):(?<filename>[^\x00]*)\x00(?<startline>\d+)\x00/)&.tap do |matches|
ref = matches[:ref]
filename = matches[:filename]
startline = matches[:startline]
diff --git a/lib/gitlab/untrusted_regexp.rb b/lib/gitlab/untrusted_regexp.rb
index 7ce2e9d636e..75ba0799058 100644
--- a/lib/gitlab/untrusted_regexp.rb
+++ b/lib/gitlab/untrusted_regexp.rb
@@ -11,7 +11,11 @@ module Gitlab
class UntrustedRegexp
delegate :===, to: :regexp
- def initialize(pattern)
+ def initialize(pattern, multiline: false)
+ if multiline
+ pattern = "(?m)#{pattern}"
+ end
+
@regexp = RE2::Regexp.new(pattern, log_errors: false)
raise RegexpError.new(regexp.error) unless regexp.ok?
@@ -31,6 +35,19 @@ module Gitlab
RE2.Replace(text, regexp, rewrite)
end
+ # Handles regular expressions with the preferred RE2 library where possible
+ # via UntustedRegex. Falls back to Ruby's built-in regular expression library
+ # when the syntax would be invalid in RE2.
+ #
+ # One difference between these is `(?m)` multi-line mode. Ruby regex enables
+ # this by default, but also handles `^` and `$` differently.
+ # See: https://www.regular-expressions.info/modifiers.html
+ def self.with_fallback(pattern, multiline: false)
+ UntrustedRegexp.new(pattern, multiline: multiline)
+ rescue RegexpError
+ Regexp.new(pattern)
+ end
+
private
attr_reader :regexp
diff --git a/lib/tasks/gitlab/test.rake b/lib/tasks/gitlab/test.rake
index 523b0fa055b..2222807fe13 100644
--- a/lib/tasks/gitlab/test.rake
+++ b/lib/tasks/gitlab/test.rake
@@ -4,7 +4,6 @@ namespace :gitlab do
cmds = [
%w(rake brakeman),
%w(rake rubocop),
- %w(rake spinach),
%w(rake spec),
%w(rake karma)
]
diff --git a/lib/tasks/spinach.rake b/lib/tasks/spinach.rake
deleted file mode 100644
index 19ff13f06c0..00000000000
--- a/lib/tasks/spinach.rake
+++ /dev/null
@@ -1,60 +0,0 @@
-Rake::Task["spinach"].clear if Rake::Task.task_defined?('spinach')
-
-namespace :spinach do
- namespace :project do
- desc "GitLab | Spinach | Run project commits, issues and merge requests spinach features"
- task :half do
- run_spinach_tests('@project_commits,@project_issues,@project_merge_requests')
- end
-
- desc "GitLab | Spinach | Run remaining project spinach features"
- task :rest do
- run_spinach_tests('~@admin,~@dashboard,~@profile,~@public,~@snippets,~@project_commits,~@project_issues,~@project_merge_requests')
- end
- end
-
- desc "GitLab | Spinach | Run project spinach features"
- task :project do
- run_spinach_tests('~@admin,~@dashboard,~@profile,~@public,~@snippets')
- end
-
- desc "GitLab | Spinach | Run other spinach features"
- task :other do
- run_spinach_tests('@admin,@dashboard,@profile,@public,@snippets')
- end
-
- desc "GitLab | Spinach | Run other spinach features"
- task :builds do
- run_spinach_tests('@builds')
- end
-end
-
-desc "GitLab | Run spinach"
-task :spinach do
- run_spinach_tests(nil)
-end
-
-def run_system_command(cmd)
- system({ 'RAILS_ENV' => 'test', 'force' => 'yes' }, *cmd)
-end
-
-def run_spinach_command(args)
- run_system_command(%w(spinach -r rerun) + args)
-end
-
-def run_spinach_tests(tags)
- success = run_spinach_command(%W(--tags #{tags}))
- 3.times do |_|
- break if success
- break unless File.exist?('tmp/spinach-rerun.txt')
-
- tests = File.foreach('tmp/spinach-rerun.txt').map(&:chomp)
- puts ''
- puts "Spinach tests for #{tags}: Retrying tests... #{tests}".color(:red)
- puts ''
- sleep(3)
- success = run_spinach_command(tests)
- end
-
- raise("spinach tests for #{tags} failed!") unless success
-end
diff --git a/package.json b/package.json
index 6d5932dcec6..59b4988b264 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
"webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js"
},
"dependencies": {
- "@gitlab-org/gitlab-svgs": "^1.20.0",
+ "@gitlab-org/gitlab-svgs": "^1.22.0",
"autosize": "^4.0.0",
"axios": "^0.17.1",
"babel-core": "^6.26.3",
diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb
index f4c99ea4064..58bb91a0c80 100644
--- a/spec/controllers/concerns/send_file_upload_spec.rb
+++ b/spec/controllers/concerns/send_file_upload_spec.rb
@@ -51,6 +51,21 @@ describe SendFileUpload do
end
end
+ context 'with attachment' do
+ subject { controller.send_upload(uploader, attachment: 'test.js') }
+
+ it 'sends a file with content-type of text/plain' do
+ expected_params = {
+ content_type: 'text/plain',
+ filename: 'test.js',
+ disposition: 'attachment'
+ }
+ expect(controller).to receive(:send_file).with(uploader.path, expected_params)
+
+ subject
+ end
+ end
+
context 'when remote file is used' do
before do
stub_uploads_object_storage(uploader: uploader_class)
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb
index 98566f907f9..0430762c1ff 100644
--- a/spec/factories/clusters/clusters.rb
+++ b/spec/factories/clusters/clusters.rb
@@ -4,8 +4,8 @@ FactoryBot.define do
name 'test-cluster'
trait :project do
- after(:create) do |cluster, evaluator|
- cluster.projects << create(:project)
+ before(:create) do |cluster, evaluator|
+ cluster.projects << create(:project, :repository)
end
end
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index fe334b531f0..a8a627d8806 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -182,6 +182,7 @@ feature 'Gcp Cluster', :js do
it 'user sees a login page' do
expect(page).to have_css('.signin-with-google')
+ expect(page).to have_link('Google account')
end
end
diff --git a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb
index ab9420fc38f..2c67cec6b67 100644
--- a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'User deletes wiki page' do
+feature 'User deletes wiki page', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:wiki_page) { create(:wiki_page, wiki: project.wiki) }
@@ -13,6 +13,7 @@ feature 'User deletes wiki page' do
it 'deletes a page' do
click_on('Edit')
click_on('Delete')
+ find('.js-modal-primary-action').click
expect(page).to have_content('Page was successfully deleted')
end
diff --git a/spec/javascripts/helpers/vue_mount_component_helper.js b/spec/javascripts/helpers/vue_mount_component_helper.js
index effacbcff4e..a34a1add4e0 100644
--- a/spec/javascripts/helpers/vue_mount_component_helper.js
+++ b/spec/javascripts/helpers/vue_mount_component_helper.js
@@ -1,14 +1,30 @@
+import Vue from 'vue';
+
+const mountComponent = (Component, props = {}, el = null) => new Component({
+ propsData: props,
+}).$mount(el);
+
export const createComponentWithStore = (Component, store, propsData = {}) => new Component({
store,
propsData,
});
+export const createComponentWithMixin = (mixins = [], state = {}, props = {}, template = '<div></div>') => {
+ const Component = Vue.extend({
+ template,
+ mixins,
+ data() {
+ return props;
+ },
+ });
+
+ return mountComponent(Component, props);
+};
+
export const mountComponentWithStore = (Component, { el, props, store }) =>
new Component({
store,
propsData: props || { },
}).$mount(el);
-export default (Component, props = {}, el = null) => new Component({
- propsData: props,
-}).$mount(el);
+export default mountComponent;
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js
deleted file mode 100644
index cee22d5342a..00000000000
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import Vue from 'vue';
-import maintainerEditComponent from '~/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-
-describe('RWidgetMaintainerEdit', () => {
- let Component;
- let vm;
-
- beforeEach(() => {
- Component = Vue.extend(maintainerEditComponent);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('when a maintainer is allowed to edit', () => {
- beforeEach(() => {
- vm = mountComponent(Component, {
- maintainerEditAllowed: true,
- });
- });
-
- it('it renders the message', () => {
- expect(vm.$el.textContent.trim()).toEqual('Allows edits from maintainers');
- });
- });
-
- describe('when a maintainer is not allowed to edit', () => {
- beforeEach(() => {
- vm = mountComponent(Component, {
- maintainerEditAllowed: false,
- });
- });
-
- it('hides the message', () => {
- expect(vm.$el.textContent.trim()).toEqual('');
- });
- });
-});
diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
index e55c7649d40..30918428da2 100644
--- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import mrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options';
+import mrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
import eventHub from '~/vue_merge_request_widget/event_hub';
import notify from '~/lib/utils/notify';
import { stateKey } from '~/vue_merge_request_widget/stores/state_maps';
diff --git a/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb b/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb
index 726a3c1c83a..43b68e69131 100644
--- a/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb
+++ b/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb
@@ -17,12 +17,8 @@ describe Gitlab::Auth::BlockedUserTracker do
end
context 'failed login due to blocked user' do
- let(:env) do
- {
- 'warden.options' => { message: User::BLOCKED_MESSAGE },
- described_class::ACTIVE_RECORD_REQUEST_PARAMS => { 'user' => { 'login' => user.username } }
- }
- end
+ let(:base_env) { { 'warden.options' => { message: User::BLOCKED_MESSAGE } } }
+ let(:env) { base_env.merge(request_env) }
subject { described_class.log_if_user_blocked(env) }
@@ -30,23 +26,37 @@ describe Gitlab::Auth::BlockedUserTracker do
expect_any_instance_of(SystemHooksService).to receive(:execute_hooks_for).with(user, :failed_login)
end
- it 'logs a blocked user' do
- user.block!
+ context 'via GitLab login' do
+ let(:request_env) { { described_class::ACTIVE_RECORD_REQUEST_PARAMS => { 'user' => { 'login' => user.username } } } }
- expect(subject).to be_truthy
- end
+ it 'logs a blocked user' do
+ user.block!
+
+ expect(subject).to be_truthy
+ end
- it 'logs a blocked user by e-mail' do
- user.block!
- env[described_class::ACTIVE_RECORD_REQUEST_PARAMS]['user']['login'] = user.email
+ it 'logs a blocked user by e-mail' do
+ user.block!
+ env[described_class::ACTIVE_RECORD_REQUEST_PARAMS]['user']['login'] = user.email
- expect(subject).to be_truthy
+ expect(subject).to be_truthy
+ end
end
- it 'logs a LDAP blocked user' do
- user.ldap_block!
+ context 'via LDAP login' do
+ let(:request_env) { { described_class::ACTIVE_RECORD_REQUEST_PARAMS => { 'username' => user.username } } }
+
+ it 'logs a blocked user' do
+ user.block!
+
+ expect(subject).to be_truthy
+ end
+
+ it 'logs a LDAP blocked user' do
+ user.ldap_block!
- expect(subject).to be_truthy
+ expect(subject).to be_truthy
+ end
end
end
end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index a34b7d9905a..e3f705d2299 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -106,6 +106,18 @@ describe Gitlab::ProjectSearchResults do
end
end
+ context 'when the matching content contains multiple null bytes' do
+ let(:search_result) { "master:testdata/foo.txt\x001\x00blah\x001\x00foo" }
+
+ it 'returns a valid FoundBlob' do
+ expect(subject.filename).to eq('testdata/foo.txt')
+ expect(subject.basename).to eq('testdata/foo')
+ expect(subject.ref).to eq('master')
+ expect(subject.startline).to eq(1)
+ expect(subject.data).to eq("blah\x001\x00foo")
+ end
+ end
+
context 'when the search result ends with an empty line' do
let(:results) { project.repository.search_files_by_content('Role models', 'master') }
diff --git a/spec/lib/gitlab/untrusted_regexp_spec.rb b/spec/lib/gitlab/untrusted_regexp_spec.rb
index bed58d407ef..0ee7fa1e570 100644
--- a/spec/lib/gitlab/untrusted_regexp_spec.rb
+++ b/spec/lib/gitlab/untrusted_regexp_spec.rb
@@ -39,6 +39,14 @@ describe Gitlab::UntrustedRegexp do
expect(result).to be_falsy
end
+
+ it 'can handle regular expressions in multiline mode' do
+ regexp = described_class.new('^\d', multiline: true)
+
+ result = regexp === "Header\n\n1. Content"
+
+ expect(result).to be_truthy
+ end
end
describe '#scan' do
diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb
index 41cf2ef7225..9ca156deaa0 100644
--- a/spec/policies/ci/build_policy_spec.rb
+++ b/spec/policies/ci/build_policy_spec.rb
@@ -94,6 +94,19 @@ describe Ci::BuildPolicy do
end
end
end
+
+ context 'when maintainer is allowed to push to pipeline branch' do
+ let(:project) { create(:project, :public) }
+ let(:owner) { user }
+
+ it 'enables update_build if user is maintainer' do
+ allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false)
+ allow_any_instance_of(Project).to receive(:branch_allows_maintainer_push?).and_return(true)
+
+ expect(policy).to be_allowed :update_build
+ expect(policy).to be_allowed :update_commit_status
+ end
+ end
end
describe 'rules for protected ref' do
diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb
index 48a8064c5fc..a5e509cfa0f 100644
--- a/spec/policies/ci/pipeline_policy_spec.rb
+++ b/spec/policies/ci/pipeline_policy_spec.rb
@@ -62,5 +62,17 @@ describe Ci::PipelinePolicy, :models do
end
end
end
+
+ context 'when maintainer is allowed to push to pipeline branch' do
+ let(:project) { create(:project, :public) }
+ let(:owner) { user }
+
+ it 'enables update_pipeline if user is maintainer' do
+ allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false)
+ allow_any_instance_of(Project).to receive(:branch_allows_maintainer_push?).and_return(true)
+
+ expect(policy).to be_allowed :update_pipeline
+ end
+ end
end
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 8b9c4ac0b4b..6609f5f7afd 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -404,7 +404,7 @@ describe ProjectPolicy do
)
end
let(:maintainer_abilities) do
- %w(create_build update_build create_pipeline update_pipeline)
+ %w(create_build create_pipeline)
end
subject { described_class.new(user, project) }
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index e88e86c2998..b741308e2c5 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -114,7 +114,9 @@ describe PipelineSerializer do
Gitlab::GitalyClient.reset_counts
end
- shared_examples 'no N+1 queries' do
+ context 'with the same ref' do
+ let(:ref) { 'feature' }
+
it 'verifies number of queries', :request_store do
recorded = ActiveRecord::QueryRecorder.new { subject }
@@ -123,12 +125,6 @@ describe PipelineSerializer do
end
end
- context 'with the same ref' do
- let(:ref) { 'feature' }
-
- it_behaves_like 'no N+1 queries'
- end
-
context 'with different refs' do
def ref
@sequence ||= 0
@@ -136,7 +132,16 @@ describe PipelineSerializer do
"feature-#{@sequence}"
end
- it_behaves_like 'no N+1 queries'
+ it 'verifies number of queries', :request_store do
+ recorded = ActiveRecord::QueryRecorder.new { subject }
+
+ # For each ref there is a permission check if maintainer can update
+ # pipeline. With the same ref this check is cached but if refs are
+ # different then there is an extra query per ref
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/46368
+ expect(recorded.count).to be_within(1).of(51)
+ expect(recorded.cached_count).to eq(0)
+ end
end
def create_pipeline(status)
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index f1acfc48468..a73bd7a0268 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Ci::RetryPipelineService, '#execute' do
+ include ProjectForksHelper
+
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
@@ -266,6 +268,33 @@ describe Ci::RetryPipelineService, '#execute' do
end
end
+ context 'when maintainer is allowed to push to forked project' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+ let(:forked_project) { fork_project(project) }
+ let(:pipeline) { create(:ci_pipeline, project: forked_project, ref: 'fixes') }
+
+ before do
+ project.add_master(user)
+ create(:merge_request,
+ source_project: forked_project,
+ target_project: project,
+ source_branch: 'fixes',
+ allow_maintainer_to_push: true)
+ create_build('rspec 1', :failed, 1)
+ end
+
+ it 'allows to retry failed pipeline' do
+ allow_any_instance_of(Project).to receive(:fetch_branch_allows_maintainer_push?).and_return(true)
+ allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false)
+
+ service.execute(pipeline)
+
+ expect(build('rspec 1')).to be_pending
+ expect(pipeline.reload).to be_running
+ end
+ end
+
def statuses
pipeline.reload.statuses
end
diff --git a/spec/services/clusters/create_service_spec.rb b/spec/services/clusters/create_service_spec.rb
index 1c2f9c5cf43..1685dc748bd 100644
--- a/spec/services/clusters/create_service_spec.rb
+++ b/spec/services/clusters/create_service_spec.rb
@@ -8,80 +8,22 @@ describe Clusters::CreateService do
subject { described_class.new(project, user, params).execute(access_token) }
context 'when provider is gcp' do
- shared_context 'valid params' do
- let(:params) do
- {
- name: 'test-cluster',
- provider_type: :gcp,
- provider_gcp_attributes: {
- gcp_project_id: 'gcp-project',
- zone: 'us-central1-a',
- num_nodes: 1,
- machine_type: 'machine_type-a'
- }
- }
- end
- end
-
- shared_context 'invalid params' do
- let(:params) do
- {
- name: 'test-cluster',
- provider_type: :gcp,
- provider_gcp_attributes: {
- gcp_project_id: '!!!!!!!',
- zone: 'us-central1-a',
- num_nodes: 1,
- machine_type: 'machine_type-a'
- }
- }
- end
- end
-
- shared_examples 'create cluster' do
- it 'creates a cluster object and performs a worker' do
- expect(ClusterProvisionWorker).to receive(:perform_async)
-
- expect { subject }
- .to change { Clusters::Cluster.count }.by(1)
- .and change { Clusters::Providers::Gcp.count }.by(1)
-
- expect(subject.name).to eq('test-cluster')
- expect(subject.user).to eq(user)
- expect(subject.project).to eq(project)
- expect(subject.provider.gcp_project_id).to eq('gcp-project')
- expect(subject.provider.zone).to eq('us-central1-a')
- expect(subject.provider.num_nodes).to eq(1)
- expect(subject.provider.machine_type).to eq('machine_type-a')
- expect(subject.provider.access_token).to eq(access_token)
- expect(subject.platform).to be_nil
- end
- end
-
- shared_examples 'error' do
- it 'returns an error' do
- expect(ClusterProvisionWorker).not_to receive(:perform_async)
- expect { subject }.to change { Clusters::Cluster.count }.by(0)
- expect(subject.errors[:"provider_gcp.gcp_project_id"]).to be_present
- end
- end
-
context 'when project has no clusters' do
context 'when correct params' do
- include_context 'valid params'
+ include_context 'valid cluster create params'
- include_examples 'create cluster'
+ include_examples 'create cluster service success'
end
context 'when invalid params' do
- include_context 'invalid params'
+ include_context 'invalid cluster create params'
- include_examples 'error'
+ include_examples 'create cluster service error'
end
end
context 'when project has a cluster' do
- include_context 'valid params'
+ include_context 'valid cluster create params'
let!(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, projects: [project]) }
it 'does not create a cluster' do
diff --git a/spec/support/services/clusters/create_service_shared.rb b/spec/support/services/clusters/create_service_shared.rb
new file mode 100644
index 00000000000..43a2fd05498
--- /dev/null
+++ b/spec/support/services/clusters/create_service_shared.rb
@@ -0,0 +1,57 @@
+shared_context 'valid cluster create params' do
+ let(:params) do
+ {
+ name: 'test-cluster',
+ provider_type: :gcp,
+ provider_gcp_attributes: {
+ gcp_project_id: 'gcp-project',
+ zone: 'us-central1-a',
+ num_nodes: 1,
+ machine_type: 'machine_type-a'
+ }
+ }
+ end
+end
+
+shared_context 'invalid cluster create params' do
+ let(:params) do
+ {
+ name: 'test-cluster',
+ provider_type: :gcp,
+ provider_gcp_attributes: {
+ gcp_project_id: '!!!!!!!',
+ zone: 'us-central1-a',
+ num_nodes: 1,
+ machine_type: 'machine_type-a'
+ }
+ }
+ end
+end
+
+shared_examples 'create cluster service success' do
+ it 'creates a cluster object and performs a worker' do
+ expect(ClusterProvisionWorker).to receive(:perform_async)
+
+ expect { subject }
+ .to change { Clusters::Cluster.count }.by(1)
+ .and change { Clusters::Providers::Gcp.count }.by(1)
+
+ expect(subject.name).to eq('test-cluster')
+ expect(subject.user).to eq(user)
+ expect(subject.project).to eq(project)
+ expect(subject.provider.gcp_project_id).to eq('gcp-project')
+ expect(subject.provider.zone).to eq('us-central1-a')
+ expect(subject.provider.num_nodes).to eq(1)
+ expect(subject.provider.machine_type).to eq('machine_type-a')
+ expect(subject.provider.access_token).to eq(access_token)
+ expect(subject.platform).to be_nil
+ end
+end
+
+shared_examples 'create cluster service error' do
+ it 'returns an error' do
+ expect(ClusterProvisionWorker).not_to receive(:perform_async)
+ expect { subject }.to change { Clusters::Cluster.count }.by(0)
+ expect(subject.errors[:"provider_gcp.gcp_project_id"]).to be_present
+ end
+end
diff --git a/vendor/ingress/values.yaml b/vendor/ingress/values.yaml
index a6b499953bf..d0c1673cefc 100644
--- a/vendor/ingress/values.yaml
+++ b/vendor/ingress/values.yaml
@@ -7,3 +7,8 @@ controller:
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "10254"
+
+rbac:
+ create: false
+ createRole: false
+ createClusterRole: false
diff --git a/yarn.lock b/yarn.lock
index b48a16c6ff1..f34bc81067d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -54,9 +54,9 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
-"@gitlab-org/gitlab-svgs@^1.20.0":
- version "1.20.0"
- resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.20.0.tgz#4c3fa3a91e0693114654b0066fb1ef04c0602047"
+"@gitlab-org/gitlab-svgs@^1.22.0":
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.22.0.tgz#9f2daefebcda911cba8341313c8c464c8087fe44"
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"