summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLin Jen-Shin <godfat@godfat.org>2018-05-15 20:16:53 +0800
committerLin Jen-Shin <godfat@godfat.org>2018-05-15 20:16:53 +0800
commit47d4732fb21ffb3c172e65291eaf7633b70431ac (patch)
tree02cf8d7f927ef5c53ad05c20fb241d00b17a375c
parent6fe8c1758195ca81554238bd24966bd85827b7f7 (diff)
parentf4ef6b474c44eb8e7034034dd95152818ae33b4a (diff)
downloadgitlab-ce-42531-open-invite-404.tar.gz
Merge remote-tracking branch 'upstream/master' into 42531-open-invite-40442531-open-invite-404
* upstream/master: (53 commits) Disable greedy mode when matching filename Add index on runner_type for ci_runners Improve the squash step in the 'Database Changes' MR template Enable update_(build|pipeline) for maintainers Correct skewed Kubernetes popover illustration Fix minor typo of main docs page Fix link to MR for Maintainer Access docs Changes Ingress RBAC value to be false as default More verbose logging for deprecated path access Change `expect` to `except` on help page Backport EE-specific untrusted regexp implementation Add `createComponentWithMixin` to create anonymous components with mixin Update secpick Update Gemfile.rails5.lock Remove /features Update secpick Increase rspec jobs up to 30 Fix specs Add changelog entry [ci skip] Revert clean up `db/fixtures/development/14_pipelines.rb` ...
-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"