summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md16
-rw-r--r--CONTRIBUTING.md36
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/copy_as_gfm.js.es6355
-rw-r--r--app/assets/javascripts/labels_select.js6
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js.es656
-rw-r--r--app/assets/javascripts/shortcuts_issuable.js54
-rw-r--r--app/assets/stylesheets/framework/avatar.scss2
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss3
-rw-r--r--app/assets/stylesheets/framework/filters.scss9
-rw-r--r--app/assets/stylesheets/framework/lists.scss3
-rw-r--r--app/assets/stylesheets/highlight/dark.scss13
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss12
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss12
-rw-r--r--app/assets/stylesheets/highlight/solarized_light.scss15
-rw-r--r--app/assets/stylesheets/highlight/white.scss16
-rw-r--r--app/assets/stylesheets/pages/tree.scss4
-rw-r--r--app/controllers/projects/git_http_client_controller.rb12
-rw-r--r--app/controllers/projects/git_http_controller.rb6
-rw-r--r--app/models/concerns/taskable.rb8
-rw-r--r--app/models/member.rb20
-rw-r--r--app/models/project_group_link.rb3
-rw-r--r--app/services/projects/update_service.rb2
-rw-r--r--app/services/user_project_access_changed_service.rb2
-rw-r--r--app/views/projects/_merge_request_merge_settings.html.haml2
-rw-r--r--app/views/projects/branches/_branch.html.haml2
-rw-r--r--app/views/projects/branches/index.html.haml2
-rw-r--r--app/views/projects/buttons/_download.html.haml2
-rw-r--r--app/views/projects/ci/pipelines/_pipeline.html.haml8
-rw-r--r--app/views/projects/commit/_commit_box.html.haml3
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml4
-rw-r--r--app/views/projects/edit.html.haml15
-rw-r--r--app/views/projects/tree/_tree_content.html.haml4
-rw-r--r--app/views/projects/wikis/git_access.html.haml7
-rw-r--r--app/workers/authorized_projects_worker.rb7
-rw-r--r--changelogs/unreleased/26068_tasklist_issue.yml4
-rw-r--r--changelogs/unreleased/26186-diff-view-plus-and-minus-signs-as-part-of-line-number.yml4
-rw-r--r--changelogs/unreleased/26785-fix-droplab-in-ie-11-v1.yml4
-rw-r--r--changelogs/unreleased/27013-regression-in-commit-title-bar.yml4
-rw-r--r--changelogs/unreleased/27021-line-numbers-now-in-copy-pasta-data.yml4
-rw-r--r--changelogs/unreleased/27066-textarea-border.yml4
-rw-r--r--changelogs/unreleased/27178-update-builds-link-in-project-settings.yml4
-rw-r--r--changelogs/unreleased/add_project_update_hook.yml4
-rw-r--r--changelogs/unreleased/copy-as-md.yml4
-rw-r--r--changelogs/unreleased/display-project-id.yml4
-rw-r--r--changelogs/unreleased/fix-26518.yml4
-rw-r--r--changelogs/unreleased/fix-ci-requests-concurrency-for-newer-runners.yml3
-rw-r--r--changelogs/unreleased/issue-filter-click-to-search.yml4
-rw-r--r--changelogs/unreleased/label-select-toggle.yml4
-rw-r--r--changelogs/unreleased/merge-dropdown-this-context.yml4
-rw-r--r--changelogs/unreleased/refresh-authorizations-fork-join.yml4
-rw-r--r--config/database.yml.mysql8
-rw-r--r--config/initializers/sidekiq.rb9
-rw-r--r--db/fixtures/development/01_admin.rb2
-rw-r--r--db/fixtures/development/04_project.rb2
-rw-r--r--db/fixtures/development/05_users.rb2
-rw-r--r--db/fixtures/development/06_teams.rb2
-rw-r--r--db/fixtures/development/07_milestones.rb2
-rw-r--r--db/fixtures/development/09_issues.rb2
-rw-r--r--db/fixtures/development/10_merge_requests.rb2
-rw-r--r--db/fixtures/development/11_keys.rb22
-rw-r--r--db/fixtures/development/12_snippets.rb2
-rw-r--r--db/fixtures/development/13_comments.rb2
-rw-r--r--db/fixtures/development/14_pipelines.rb2
-rw-r--r--db/fixtures/development/15_award_emoji.rb2
-rw-r--r--db/fixtures/development/16_protected_branches.rb2
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb2
-rw-r--r--doc/README.md3
-rw-r--r--doc/administration/auth/ldap.md11
-rw-r--r--doc/administration/repository_checks.md10
-rw-r--r--doc/administration/repository_storage_paths.md102
-rw-r--r--doc/administration/repository_storages.md101
-rw-r--r--doc/ci/yaml/README.md2
-rw-r--r--doc/gitlab-basics/add-image.md50
-rw-r--r--doc/install/database_mysql.md205
-rw-r--r--doc/system_hooks/system_hooks.md19
-rw-r--r--doc/update/8.15-to-8.16.md2
-rw-r--r--doc/user/profile/account/two_factor_authentication.md118
-rw-r--r--features/steps/project/merge_requests/revert.rb7
-rw-r--r--features/support/env.rb3
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb5
-rw-r--r--lib/banzai/filter/issue_reference_filter.rb2
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb6
-rw-r--r--lib/banzai/filter/video_link_filter.rb3
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb6
-rw-r--r--lib/gitlab/ci/trace_reader.rb1
-rw-r--r--lib/gitlab/job_waiter.rb27
-rw-r--r--lib/gitlab/sidekiq_status.rb66
-rw-r--r--lib/gitlab/sidekiq_status/client_middleware.rb10
-rw-r--r--lib/gitlab/sidekiq_status/server_middleware.rb13
-rw-r--r--spec/controllers/admin/groups_controller_spec.rb2
-rw-r--r--spec/controllers/admin/projects_controller_spec.rb2
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb2
-rw-r--r--spec/controllers/blob_controller_spec.rb2
-rw-r--r--spec/controllers/ci/projects_controller_spec.rb2
-rw-r--r--spec/controllers/dashboard/todos_controller_spec.rb2
-rw-r--r--spec/controllers/groups/milestones_controller_spec.rb2
-rw-r--r--spec/controllers/groups_controller_spec.rb2
-rw-r--r--spec/controllers/import/bitbucket_controller_spec.rb4
-rw-r--r--spec/controllers/import/fogbugz_controller_spec.rb4
-rw-r--r--spec/controllers/import/gitlab_controller_spec.rb4
-rw-r--r--spec/controllers/import/google_code_controller_spec.rb4
-rw-r--r--spec/controllers/notification_settings_controller_spec.rb2
-rw-r--r--spec/controllers/projects/avatars_controller_spec.rb2
-rw-r--r--spec/controllers/projects/blame_controller_spec.rb2
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb2
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb2
-rw-r--r--spec/controllers/projects/commit_controller_spec.rb2
-rw-r--r--spec/controllers/projects/commits_controller_spec.rb2
-rw-r--r--spec/controllers/projects/compare_controller_spec.rb2
-rw-r--r--spec/controllers/projects/cycle_analytics_controller_spec.rb2
-rw-r--r--spec/controllers/projects/discussions_controller_spec.rb6
-rw-r--r--spec/controllers/projects/find_file_controller_spec.rb2
-rw-r--r--spec/controllers/projects/forks_controller_spec.rb2
-rw-r--r--spec/controllers/projects/graphs_controller_spec.rb2
-rw-r--r--spec/controllers/projects/group_links_controller_spec.rb2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb6
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb2
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb4
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb4
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb2
-rw-r--r--spec/controllers/projects/refs_controller_spec.rb2
-rw-r--r--spec/controllers/projects/releases_controller_spec.rb2
-rw-r--r--spec/controllers/projects/repositories_controller_spec.rb2
-rw-r--r--spec/controllers/projects/services_controller_spec.rb2
-rw-r--r--spec/controllers/projects/settings/integrations_controller_spec.rb2
-rw-r--r--spec/controllers/projects/tags_controller_spec.rb2
-rw-r--r--spec/controllers/projects/templates_controller_spec.rb2
-rw-r--r--spec/controllers/projects/tree_controller_spec.rb2
-rw-r--r--spec/controllers/projects/uploads_controller_spec.rb2
-rw-r--r--spec/controllers/projects_controller_spec.rb35
-rw-r--r--spec/controllers/uploads_controller_spec.rb2
-rw-r--r--spec/controllers/users_controller_spec.rb4
-rw-r--r--spec/factories/deploy_keys_projects.rb2
-rw-r--r--spec/factories/events.rb2
-rw-r--r--spec/factories/file_uploader.rb2
-rw-r--r--spec/factories/issues.rb2
-rw-r--r--spec/factories/labels.rb2
-rw-r--r--spec/factories/merge_requests.rb2
-rw-r--r--spec/factories/milestones.rb2
-rw-r--r--spec/factories/notes.rb14
-rw-r--r--spec/factories/project_group_links.rb2
-rw-r--r--spec/factories/project_members.rb2
-rw-r--r--spec/factories/project_snippets.rb2
-rw-r--r--spec/factories/releases.rb2
-rw-r--r--spec/factories/sent_notifications.rb2
-rw-r--r--spec/factories/services.rb2
-rw-r--r--spec/factories/todos.rb2
-rw-r--r--spec/features/copy_as_gfm_spec.rb432
-rw-r--r--spec/features/issues/form_spec.rb16
-rw-r--r--spec/finders/branches_finder_spec.rb2
-rw-r--r--spec/finders/contributed_projects_finder_spec.rb4
-rw-r--r--spec/finders/group_projects_finder_spec.rb10
-rw-r--r--spec/finders/joined_groups_finder_spec.rb2
-rw-r--r--spec/finders/merge_requests_finder_spec.rb6
-rw-r--r--spec/finders/notes_finder_spec.rb4
-rw-r--r--spec/finders/personal_projects_finder_spec.rb6
-rw-r--r--spec/finders/pipelines_finder_spec.rb2
-rw-r--r--spec/finders/projects_finder_spec.rb8
-rw-r--r--spec/finders/tags_finder_spec.rb2
-rw-r--r--spec/helpers/application_helper_spec.rb4
-rw-r--r--spec/helpers/blob_helper_spec.rb2
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb18
-rw-r--r--spec/helpers/graph_helper_spec.rb2
-rw-r--r--spec/helpers/issues_helper_spec.rb2
-rw-r--r--spec/helpers/members_helper_spec.rb2
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb10
-rw-r--r--spec/helpers/milestones_helper_spec.rb14
-rw-r--r--spec/helpers/preferences_helper_spec.rb2
-rw-r--r--spec/helpers/projects_helper_spec.rb4
-rw-r--r--spec/helpers/search_helper_spec.rb6
-rw-r--r--spec/helpers/submodule_helper_spec.rb4
-rw-r--r--spec/helpers/tree_helper_spec.rb2
-rw-r--r--spec/helpers/visibility_level_helper_spec.rb8
-rw-r--r--spec/javascripts/shortcuts_issuable_spec.js21
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb14
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/gollum_tags_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb8
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/video_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/user_parser_spec.rb6
-rw-r--r--spec/lib/constraints/project_url_constrainer_spec.rb2
-rw-r--r--spec/lib/event_filter_spec.rb2
-rw-r--r--spec/lib/extracts_path_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/build/metadata_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/build/status_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/coverage/metadata_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/blame_spec.rb2
-rw-r--r--spec/lib/gitlab/chat_commands/command_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/force_push_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/trace_reader_spec.rb16
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb8
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb2
-rw-r--r--spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb10
-rw-r--r--spec/lib/gitlab/data_builder/note_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/pipeline_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/push_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/highlight_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/line_mapper_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/parallel_diff_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/position_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/position_tracer_spec.rb2
-rw-r--r--spec/lib/gitlab/email/handler/create_issue_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/email/handler/create_note_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/email/message/repository_push_spec.rb2
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/gfm/uploads_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/git/hook_spec.rb2
-rw-r--r--spec/lib/gitlab/git/rev_list_spec.rb2
-rw-r--r--spec/lib/gitlab/git_access_spec.rb18
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/branch_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/comment_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/issue_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/label_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/pull_request_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/release_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/graphs/commits_spec.rb2
-rw-r--r--spec/lib/gitlab/highlight_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/import_export_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/members_mapper_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/repo_bundler_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb2
-rw-r--r--spec/lib/gitlab/job_waiter_spec.rb30
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb12
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb22
-rw-r--r--spec/lib/gitlab/search_results_spec.rb2
-rw-r--r--spec/lib/gitlab/sidekiq_status/client_middleware_spec.rb12
-rw-r--r--spec/lib/gitlab/sidekiq_status/server_middleware_spec.rb14
-rw-r--r--spec/lib/gitlab/sidekiq_status_spec.rb50
-rw-r--r--spec/lib/gitlab/template/issue_template_spec.rb2
-rw-r--r--spec/lib/gitlab/template/merge_request_template_spec.rb2
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb2
-rw-r--r--spec/lib/light_url_builder_spec.rb2
-rw-r--r--spec/lib/repository_cache_spec.rb2
-rw-r--r--spec/models/issue_spec.rb2
-rw-r--r--spec/models/note_spec.rb2
-rw-r--r--spec/requests/git_http_spec.rb22
-rw-r--r--spec/services/system_hooks_service_spec.rb2
-rw-r--r--spec/services/user_project_access_changed_service_spec.rb12
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/sidekiq.rb5
-rw-r--r--spec/support/taskable_shared_examples.rb19
-rw-r--r--spec/workers/authorized_projects_worker_spec.rb12
256 files changed, 2213 insertions, 616 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f5e241e83d..9712b32232e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 8.16.2 (2017-01-25)
+
+- allow issue filter bar to be operated with mouse only. !8681
+- Fix CI requests concurrency for newer runners that prevents from picking pending builds (from 1.9.0-rc5). !8760
+- Add some basic fixes for IE11/Edge.
+- Remove blue border from comment box hover.
+- Fixed bug where links in merge dropdown wouldn't work.
+
## 8.16.1 (2017-01-23)
- Ensure export files are removed after a namespace is deleted.
@@ -403,6 +411,14 @@ entry.
- Whitelist next project names: help, ci, admin, search. !8227
- Adds back CSS for progress-bars. !8237
+## 8.14.8 (2017-01-25)
+
+- Accept environment variables from the `pre-receive` script. !7967
+- Milestoneish SQL performance partially improved and memoized. !8146
+- Fix N+1 queries on milestone show pages. !8185
+- Speed up group milestone index by passing group_id to IssuesFinder. !8363
+- Ensure issuable state changes only fire webhooks once.
+
## 8.14.6 (2017-01-10)
- Update the gitlab-markup gem to the version 1.5.1. !8509
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b68c4a67826..d404f1b91df 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -80,11 +80,9 @@ the remaining issues on the GitHub issue tracker.
## I want to contribute!
If you want to contribute to GitLab, but are not sure where to start,
-look for [issues with the label `up-for-grabs`][up-for-grabs]. These issues
-will be of reasonable size and challenge, for anyone to start contributing to
-GitLab.
-
-This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
+look for [issues with the label `Accepting Merge Requests` and weight < 5][accepting-mrs-weight].
+These issues will be of reasonable size and challenge, for anyone to start
+contributing to GitLab.
## Implement design & UI elements
@@ -214,16 +212,19 @@ associated with in the description of the issue.
## Merge requests
We welcome merge requests with fixes and improvements to GitLab code, tests,
-and/or documentation. The features we would really like a merge request for are
-listed with the label [`Accepting Merge Requests` on our issue tracker for CE][accepting-mrs-ce]
-and [EE][accepting-mrs-ee] but other improvements are also welcome. Please note
-that if an issue is marked for the current milestone either before or while you
-are working on it, a team member may take over the merge request in order to
-ensure the work is finished before the release date.
+and/or documentation. The issues that are specifically suitable for
+community contributions are listed with the label
+[`Accepting Merge Requests` on our issue tracker for CE][accepting-mrs-ce]
+and [EE][accepting-mrs-ee], but you are free to contribute to any other issue
+you want.
+
+Please note that if an issue is marked for the current milestone either before
+or while you are working on it, a team member may take over the merge request
+in order to ensure the work is finished before the release date.
If you want to add a new feature that is not labeled it is best to first create
a feedback issue (if there isn't one already) and leave a comment asking for it
-to be marked as `Accepting merge requests`. Please include screenshots or
+to be marked as `Accepting Merge Requests`. Please include screenshots or
wireframes if the feature will also change the UI.
Merge requests should be opened at [GitLab.com][gitlab-mr-tracker].
@@ -285,14 +286,6 @@ request is as follows:
1. For tests that use Capybara or PhantomJS, see this [article on how
to write reliable asynchronous tests](https://robots.thoughtbot.com/write-reliable-asynchronous-integration-tests-with-capybara).
-The **official merge window** is in the beginning of the month from the 1st to
-the 7th day of the month. This is the best time to submit an MR and get
-feedback fast. Before this time the GitLab Inc. team is still dealing with work
-that is created by the monthly release such as regressions requiring patch
-releases. After the 7th it is already getting closer to the release date of the
-next version. This means there is less time to fix the issues created by
-merging large new features.
-
Please keep the change in a single MR **as small as possible**. If you want to
contribute a large feature think very hard what the minimum viable change is.
Can you split the functionality? Can you only submit the backend/API code? Can
@@ -450,8 +443,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[core team]: https://about.gitlab.com/core-team/
[getting-help]: https://about.gitlab.com/getting-help/
[codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq
-[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs
-[medium-up-for-grabs]: https://medium.com/@kentcdodds/first-timers-only-78281ea47455
+[accepting-mrs-weight]: https://gitlab.com/gitlab-org/gitlab-ce/issues?assignee_id=0&label_name[]=Accepting%20Merge%20Requests&sort=weight_asc
[ce-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/issues
[ee-tracker]: https://gitlab.com/gitlab-org/gitlab-ee/issues
[google-group]: https://groups.google.com/forum/#!forum/gitlabhq
diff --git a/Gemfile b/Gemfile
index 4e9cf91c429..dc8f23d07c6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -322,7 +322,7 @@ group :test do
gem 'email_spec', '~> 1.6.0'
gem 'json-schema', '~> 2.6.2'
gem 'webmock', '~> 1.21.0'
- gem 'test_after_commit', '~> 0.4.2'
+ gem 'test_after_commit', '~> 1.1'
gem 'sham_rack', '~> 1.3.6'
gem 'timecop', '~> 0.8.0'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index c9115982838..133e47e1ea4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -760,7 +760,7 @@ GEM
teaspoon-jasmine (2.2.0)
teaspoon (>= 1.0.0)
temple (0.7.7)
- test_after_commit (0.4.2)
+ test_after_commit (1.1.0)
activerecord (>= 3.2)
thin (1.7.0)
daemons (~> 1.0, >= 1.0.9)
@@ -997,7 +997,7 @@ DEPENDENCIES
sys-filesystem (~> 1.1.6)
teaspoon (~> 1.1.0)
teaspoon-jasmine (~> 2.2.0)
- test_after_commit (~> 0.4.2)
+ test_after_commit (~> 1.1)
thin (~> 1.7.0)
timecop (~> 0.8.0)
truncato (~> 0.7.8)
diff --git a/app/assets/javascripts/copy_as_gfm.js.es6 b/app/assets/javascripts/copy_as_gfm.js.es6
new file mode 100644
index 00000000000..b94125a4210
--- /dev/null
+++ b/app/assets/javascripts/copy_as_gfm.js.es6
@@ -0,0 +1,355 @@
+/* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */
+/* jshint esversion: 6 */
+
+/*= require lib/utils/common_utils */
+
+(() => {
+ const gfmRules = {
+ // The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert
+ // GitLab Flavored Markdown (GFM) to HTML.
+ // These handlers consequently convert that same HTML to GFM to be copied to the clipboard.
+ // Every filter in lib/banzai/pipeline/gfm_pipeline.rb that generates HTML
+ // from GFM should have a handler here, in reverse order.
+ // The GFM-to-HTML-to-GFM cycle is tested in spec/features/copy_as_gfm_spec.rb.
+ InlineDiffFilter: {
+ 'span.idiff.addition'(el, text) {
+ return `{+${text}+}`;
+ },
+ 'span.idiff.deletion'(el, text) {
+ return `{-${text}-}`;
+ },
+ },
+ TaskListFilter: {
+ 'input[type=checkbox].task-list-item-checkbox'(el, text) {
+ return `[${el.checked ? 'x' : ' '}]`;
+ },
+ },
+ ReferenceFilter: {
+ 'a.gfm:not([data-link=true])'(el, text) {
+ return el.dataset.original || text;
+ },
+ },
+ AutolinkFilter: {
+ 'a'(el, text) {
+ // Fallback on the regular MarkdownFilter's `a` handler.
+ if (text !== el.getAttribute('href')) return false;
+
+ return text;
+ },
+ },
+ TableOfContentsFilter: {
+ 'ul.section-nav'(el, text) {
+ return '[[_TOC_]]';
+ },
+ },
+ EmojiFilter: {
+ 'img.emoji'(el, text) {
+ return el.getAttribute('alt');
+ },
+ },
+ ImageLinkFilter: {
+ 'a.no-attachment-icon'(el, text) {
+ return text;
+ },
+ },
+ VideoLinkFilter: {
+ '.video-container'(el, text) {
+ const videoEl = el.querySelector('video');
+ if (!videoEl) return false;
+
+ return CopyAsGFM.nodeToGFM(videoEl);
+ },
+ 'video'(el, text) {
+ return `![${el.dataset.title}](${el.getAttribute('src')})`;
+ },
+ },
+ MathFilter: {
+ 'pre.code.math[data-math-style=display]'(el, text) {
+ return `\`\`\`math\n${text.trim()}\n\`\`\``;
+ },
+ 'code.code.math[data-math-style=inline]'(el, text) {
+ return `$\`${text}\`$`;
+ },
+ 'span.katex-display span.katex-mathml'(el, text) {
+ const mathAnnotation = el.querySelector('annotation[encoding="application/x-tex"]');
+ if (!mathAnnotation) return false;
+
+ return `\`\`\`math\n${CopyAsGFM.nodeToGFM(mathAnnotation)}\n\`\`\``;
+ },
+ 'span.katex-mathml'(el, text) {
+ const mathAnnotation = el.querySelector('annotation[encoding="application/x-tex"]');
+ if (!mathAnnotation) return false;
+
+ return `$\`${CopyAsGFM.nodeToGFM(mathAnnotation)}\`$`;
+ },
+ 'span.katex-html'(el, text) {
+ // We don't want to include the content of this element in the copied text.
+ return '';
+ },
+ 'annotation[encoding="application/x-tex"]'(el, text) {
+ return text.trim();
+ },
+ },
+ SanitizationFilter: {
+ 'dl'(el, text) {
+ let lines = text.trim().split('\n');
+ // Add two spaces to the front of subsequent list items lines,
+ // or leave the line entirely blank.
+ lines = lines.map((l) => {
+ const line = l.trim();
+ if (line.length === 0) return '';
+
+ return ` ${line}`;
+ });
+
+ return `<dl>\n${lines.join('\n')}\n</dl>`;
+ },
+ 'sub, dt, dd, kbd, q, samp, var, ruby, rt, rp, abbr'(el, text) {
+ const tag = el.nodeName.toLowerCase();
+ return `<${tag}>${text}</${tag}>`;
+ },
+ },
+ SyntaxHighlightFilter: {
+ 'pre.code.highlight'(el, t) {
+ const text = t.trim();
+
+ let lang = el.getAttribute('lang');
+ if (lang === 'plaintext') {
+ lang = '';
+ }
+
+ // Prefixes lines with 4 spaces if the code contains triple backticks
+ if (lang === '' && text.match(/^```/gm)) {
+ return text.split('\n').map((l) => {
+ const line = l.trim();
+ if (line.length === 0) return '';
+
+ return ` ${line}`;
+ }).join('\n');
+ }
+
+ return `\`\`\`${lang}\n${text}\n\`\`\``;
+ },
+ 'pre > code'(el, text) {
+ // Don't wrap code blocks in ``
+ return text;
+ },
+ },
+ MarkdownFilter: {
+ 'br'(el, text) {
+ // Two spaces at the end of a line are turned into a BR
+ return ' ';
+ },
+ 'code'(el, text) {
+ let backtickCount = 1;
+ const backtickMatch = text.match(/`+/);
+ if (backtickMatch) {
+ backtickCount = backtickMatch[0].length + 1;
+ }
+
+ const backticks = Array(backtickCount + 1).join('`');
+ const spaceOrNoSpace = backtickCount > 1 ? ' ' : '';
+
+ return backticks + spaceOrNoSpace + text + spaceOrNoSpace + backticks;
+ },
+ 'blockquote'(el, text) {
+ return text.trim().split('\n').map(s => `> ${s}`.trim()).join('\n');
+ },
+ 'img'(el, text) {
+ return `![${el.getAttribute('alt')}](${el.getAttribute('src')})`;
+ },
+ 'a.anchor'(el, text) {
+ // Don't render a Markdown link for the anchor link inside a heading
+ return text;
+ },
+ 'a'(el, text) {
+ return `[${text}](${el.getAttribute('href')})`;
+ },
+ 'li'(el, text) {
+ const lines = text.trim().split('\n');
+ const firstLine = `- ${lines.shift()}`;
+ // Add four spaces to the front of subsequent list items lines,
+ // or leave the line entirely blank.
+ const nextLines = lines.map((s) => {
+ if (s.trim().length === 0) return '';
+
+ return ` ${s}`;
+ });
+
+ return `${firstLine}\n${nextLines.join('\n')}`;
+ },
+ 'ul'(el, text) {
+ return text;
+ },
+ 'ol'(el, text) {
+ // LIs get a `- ` prefix by default, which we replace by `1. ` for ordered lists.
+ return text.replace(/^- /mg, '1. ');
+ },
+ 'h1'(el, text) {
+ return `# ${text.trim()}`;
+ },
+ 'h2'(el, text) {
+ return `## ${text.trim()}`;
+ },
+ 'h3'(el, text) {
+ return `### ${text.trim()}`;
+ },
+ 'h4'(el, text) {
+ return `#### ${text.trim()}`;
+ },
+ 'h5'(el, text) {
+ return `##### ${text.trim()}`;
+ },
+ 'h6'(el, text) {
+ return `###### ${text.trim()}`;
+ },
+ 'strong'(el, text) {
+ return `**${text}**`;
+ },
+ 'em'(el, text) {
+ return `_${text}_`;
+ },
+ 'del'(el, text) {
+ return `~~${text}~~`;
+ },
+ 'sup'(el, text) {
+ return `^${text}`;
+ },
+ 'hr'(el, text) {
+ return '-----';
+ },
+ 'table'(el, text) {
+ const theadEl = el.querySelector('thead');
+ const tbodyEl = el.querySelector('tbody');
+ if (!theadEl || !tbodyEl) return false;
+
+ const theadText = CopyAsGFM.nodeToGFM(theadEl);
+ const tbodyText = CopyAsGFM.nodeToGFM(tbodyEl);
+
+ return theadText + tbodyText;
+ },
+ 'thead'(el, text) {
+ const cells = _.map(el.querySelectorAll('th'), (cell) => {
+ let chars = CopyAsGFM.nodeToGFM(cell).trim().length + 2;
+
+ let before = '';
+ let after = '';
+ switch (cell.style.textAlign) {
+ case 'center':
+ before = ':';
+ after = ':';
+ chars -= 2;
+ break;
+ case 'right':
+ after = ':';
+ chars -= 1;
+ break;
+ default:
+ break;
+ }
+
+ chars = Math.max(chars, 3);
+
+ const middle = Array(chars + 1).join('-');
+
+ return before + middle + after;
+ });
+
+ return `${text}|${cells.join('|')}|`;
+ },
+ 'tr'(el, text) {
+ const cells = _.map(el.querySelectorAll('td, th'), cell => CopyAsGFM.nodeToGFM(cell).trim());
+ return `| ${cells.join(' | ')} |`;
+ },
+ },
+ };
+
+ class CopyAsGFM {
+ constructor() {
+ $(document).on('copy', '.md, .wiki', this.handleCopy);
+ $(document).on('paste', '.js-gfm-input', this.handlePaste);
+ }
+
+ handleCopy(e) {
+ const clipboardData = e.originalEvent.clipboardData;
+ if (!clipboardData) return;
+
+ const documentFragment = window.gl.utils.getSelectedFragment();
+ if (!documentFragment) return;
+
+ // If the documentFragment contains more than just Markdown, don't copy as GFM.
+ if (documentFragment.querySelector('.md, .wiki')) return;
+
+ e.preventDefault();
+ clipboardData.setData('text/plain', documentFragment.textContent);
+
+ const gfm = CopyAsGFM.nodeToGFM(documentFragment);
+ clipboardData.setData('text/x-gfm', gfm);
+ }
+
+ handlePaste(e) {
+ const clipboardData = e.originalEvent.clipboardData;
+ if (!clipboardData) return;
+
+ const gfm = clipboardData.getData('text/x-gfm');
+ if (!gfm) return;
+
+ e.preventDefault();
+
+ window.gl.utils.insertText(e.target, gfm);
+ }
+
+ static nodeToGFM(node) {
+ if (node.nodeType === Node.TEXT_NODE) {
+ return node.textContent;
+ }
+
+ const text = this.innerGFM(node);
+
+ if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
+ return text;
+ }
+
+ for (const filter in gfmRules) {
+ const rules = gfmRules[filter];
+
+ for (const selector in rules) {
+ const func = rules[selector];
+
+ if (!window.gl.utils.nodeMatchesSelector(node, selector)) continue;
+
+ const result = func(node, text);
+ if (result === false) continue;
+
+ return result;
+ }
+ }
+
+ return text;
+ }
+
+ static innerGFM(parentNode) {
+ const nodes = parentNode.childNodes;
+
+ const clonedParentNode = parentNode.cloneNode(true);
+ const clonedNodes = Array.prototype.slice.call(clonedParentNode.childNodes, 0);
+
+ for (let i = 0; i < nodes.length; i += 1) {
+ const node = nodes[i];
+ const clonedNode = clonedNodes[i];
+
+ const text = this.nodeToGFM(node);
+
+ // `clonedNode.replaceWith(text)` is not yet widely supported
+ clonedNode.parentNode.replaceChild(document.createTextNode(text), clonedNode);
+ }
+
+ return clonedParentNode.innerText || clonedParentNode.textContent;
+ }
+ }
+
+ window.gl = window.gl || {};
+ window.gl.CopyAsGFM = CopyAsGFM;
+
+ new CopyAsGFM();
+})();
diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js
index fd1e229e30a..70dc0d06b7b 100644
--- a/app/assets/javascripts/labels_select.js
+++ b/app/assets/javascripts/labels_select.js
@@ -336,7 +336,11 @@
.removeClass('is-active');
}
- if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
+ if ($dropdown.hasClass('js-issuable-form-dropdown')) {
+ return;
+ }
+
+ if ($dropdown.hasClass('js-filter-bulk-update')) {
_this.enableBulkLabelDropdown();
_this.setDropdownData($dropdown, isMarking, this.id(label));
return;
diff --git a/app/assets/javascripts/lib/utils/common_utils.js.es6 b/app/assets/javascripts/lib/utils/common_utils.js.es6
index 7452879d9a3..51993bb3420 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js.es6
+++ b/app/assets/javascripts/lib/utils/common_utils.js.es6
@@ -160,6 +160,62 @@
return decodeURIComponent(results[2].replace(/\+/g, ' '));
};
+ w.gl.utils.getSelectedFragment = () => {
+ const selection = window.getSelection();
+ const documentFragment = selection.getRangeAt(0).cloneContents();
+ if (documentFragment.textContent.length === 0) return null;
+
+ return documentFragment;
+ };
+
+ w.gl.utils.insertText = (target, text) => {
+ // Firefox doesn't support `document.execCommand('insertText', false, text)` on textareas
+
+ const selectionStart = target.selectionStart;
+ const selectionEnd = target.selectionEnd;
+ const value = target.value;
+
+ const textBefore = value.substring(0, selectionStart);
+ const textAfter = value.substring(selectionEnd, value.length);
+ const newText = textBefore + text + textAfter;
+
+ target.value = newText;
+ target.selectionStart = target.selectionEnd = selectionStart + text.length;
+
+ // Trigger autosave
+ $(target).trigger('input');
+
+ // Trigger autosize
+ var event = document.createEvent('Event');
+ event.initEvent('autosize:update', true, false);
+ target.dispatchEvent(event);
+ };
+
+ w.gl.utils.nodeMatchesSelector = (node, selector) => {
+ const matches = Element.prototype.matches ||
+ Element.prototype.matchesSelector ||
+ Element.prototype.mozMatchesSelector ||
+ Element.prototype.msMatchesSelector ||
+ Element.prototype.oMatchesSelector ||
+ Element.prototype.webkitMatchesSelector;
+
+ if (matches) {
+ return matches.call(node, selector);
+ }
+
+ // IE11 doesn't support `node.matches(selector)`
+
+ let parentNode = node.parentNode;
+ if (!parentNode) {
+ parentNode = document.createElement('div');
+ node = node.cloneNode(true);
+ parentNode.appendChild(node);
+ }
+
+ const matchingNodes = parentNode.querySelectorAll(selector);
+ return Array.prototype.indexOf.call(matchingNodes, node) !== -1;
+ };
+
/**
this will take in the headers from an API response and normalize them
this way we don't run into production issues when nginx gives us lowercased header keys
diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js
index 6f919de3da7..4ef516af8c8 100644
--- a/app/assets/javascripts/shortcuts_issuable.js
+++ b/app/assets/javascripts/shortcuts_issuable.js
@@ -39,29 +39,39 @@
}
ShortcutsIssuable.prototype.replyWithSelectedText = function() {
- var quote, replyField, selected, separator;
- if (window.getSelection) {
- selected = window.getSelection().toString();
- replyField = $('.js-main-target-form #note_note');
- if (selected.trim() === "") {
- return;
- }
- // Put a '>' character before each non-empty line in the selection
- quote = _.map(selected.split("\n"), function(val) {
- if (val.trim() !== '') {
- return "> " + val + "\n";
- }
- });
- // If replyField already has some content, add a newline before our quote
- separator = replyField.val().trim() !== "" && "\n" || '';
- replyField.val(function(_, current) {
- return current + separator + quote.join('') + "\n";
- });
- // Trigger autosave for the added text
- replyField.trigger('input');
- // Focus the input field
- return replyField.focus();
+ var quote, replyField, documentFragment, selected, separator;
+
+ documentFragment = window.gl.utils.getSelectedFragment();
+ if (!documentFragment) return;
+
+ // If the documentFragment contains more than just Markdown, don't copy as GFM.
+ if (documentFragment.querySelector('.md, .wiki')) return;
+
+ selected = window.gl.CopyAsGFM.nodeToGFM(documentFragment);
+
+ replyField = $('.js-main-target-form #note_note');
+ if (selected.trim() === "") {
+ return;
}
+ quote = _.map(selected.split("\n"), function(val) {
+ return ("> " + val).trim() + "\n";
+ });
+ // If replyField already has some content, add a newline before our quote
+ separator = replyField.val().trim() !== "" && "\n\n" || '';
+ replyField.val(function(_, current) {
+ return current + separator + quote.join('') + "\n";
+ });
+
+ // Trigger autosave
+ replyField.trigger('input');
+
+ // Trigger autosize
+ var event = document.createEvent('Event');
+ event.initEvent('autosize:update', true, false);
+ replyField.get(0).dispatchEvent(event);
+
+ // Focus the input field
+ return replyField.focus();
};
ShortcutsIssuable.prototype.editIssue = function() {
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index 8392b98f0a7..1d59700543c 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -37,6 +37,8 @@
display: inline-block;
margin-left: 4px;
margin-bottom: 2px;
+ flex-shrink: 0;
+ -webkit-flex-shrink: 0;
&.s16 { margin-right: 4px; }
&.s24 { margin-right: 4px; }
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 755eddefa42..6bfb9a6d1cb 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -125,7 +125,8 @@
top: 100%;
left: 0;
z-index: 9;
- width: 240px;
+ max-width: 280px;
+ min-width: 240px;
margin-top: 2px;
margin-bottom: 0;
font-size: 14px;
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 4b05ec691a8..e3da467a27c 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -132,6 +132,11 @@
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
+
+ &> span {
+ white-space: normal;
+ word-break: break-all;
+ }
}
}
@@ -141,10 +146,6 @@
}
}
-.hint-dropdown {
- width: 250px;
-}
-
.filter-dropdown-loading {
padding: 8px 16px;
}
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index 1c6698ad0c6..426596027de 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -155,7 +155,8 @@ ul.content-list {
}
> .btn,
- > .btn-group {
+ > .btn-group,
+ > .dropdown.inline {
margin-right: $gl-padding-top;
display: inline-block;
margin-top: 3px;
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index cb923166b25..6f2e746d4b0 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -13,6 +13,8 @@ $dark-main-bg: #1d1f21;
$dark-main-color: #1d1f21;
$dark-line-color: #c5c8c6;
$dark-line-num-color: rgba(255, 255, 255, 0.3);
+$dark-line-num-color-new: #627165;
+$dark-line-num-color-old: #806565;
$dark-diff-not-empty-bg: #557;
$dark-highlight-bg: #ffe792;
$dark-highlight-color: $black;
@@ -89,7 +91,6 @@ $dark-il: #de935f;
.diff-line-num,
.diff-line-num a {
- color: $dark-main-color;
color: $dark-line-num-color;
}
@@ -121,11 +122,21 @@ $dark-il: #de935f;
.diff-line-num.new,
.line_content.new {
@include diff_background($dark-new-bg, $dark-new-idiff, $dark-border);
+
+ &::before,
+ a {
+ color: $dark-line-num-color-new;
+ }
}
.diff-line-num.old,
.line_content.old {
@include diff_background($dark-old-bg, $dark-old-idiff, $dark-border);
+
+ &::before,
+ a {
+ color: $dark-line-num-color-old;
+ }
}
.line_content.match {
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index d8510baad8a..2144a5f7466 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -7,6 +7,8 @@ $monokai-bg: #272822;
$monokai-border: #555;
$monokai-text-color: #f8f8f2;
$monokai-line-num-color: rgba(255, 255, 255, 0.3);
+$monokai-line-num-color-new: #707565;
+$monokai-line-num-color-old: #7e736f;
$monokai-line-empty-bg: #49483e;
$monokai-line-empty-border: darken($monokai-line-empty-bg, 15%);
$monokai-diff-border: #808080;
@@ -120,11 +122,21 @@ $monokai-gi: #a6e22e;
.diff-line-num.new,
.line_content.new {
@include diff_background($monokai-new-bg, $monokai-new-idiff, $monokai-diff-border);
+
+ &::before,
+ a {
+ color: $monokai-line-num-color-new;
+ }
}
.diff-line-num.old,
.line_content.old {
@include diff_background($monokai-old-bg, $monokai-old-idiff, $monokai-diff-border);
+
+ &::before,
+ a {
+ color: $monokai-line-num-color-old;
+ }
}
.line_content.match {
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index 874aecb5e16..2cb1d18f12f 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -13,6 +13,8 @@ $solarized-dark-pre-color: #93a1a1;
$solarized-dark-pre-border: #113b46;
$solarized-dark-line-bg: #002b36;
$solarized-dark-line-color: rgba(255, 255, 255, 0.3);
+$solarized-dark-line-color-new: #5a766c;
+$solarized-dark-line-color-old: #7a6c71;
$solarized-dark-highlight: #094554;
$solarized-dark-hll-bg: #174652;
$solarized-dark-c: #586e75;
@@ -124,11 +126,21 @@ $solarized-dark-il: #2aa198;
.diff-line-num.new,
.line_content.new {
@include diff_background($solarized-dark-new-bg, $solarized-dark-new-idiff, $solarized-dark-border);
+
+ &::before,
+ a {
+ color: $solarized-dark-line-color-new;
+ }
}
.diff-line-num.old,
.line_content.old {
@include diff_background($solarized-dark-old-bg, $solarized-dark-old-idiff, $solarized-dark-border);
+
+ &::before,
+ a {
+ color: $solarized-dark-line-color-old;
+ }
}
.line_content.match {
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 499a1c108b8..b72c4326730 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -13,6 +13,9 @@ $solarized-light-pre-bg: #002b36;
$solarized-light-pre-bg: #fdf6e3;
$solarized-light-pre-color: #586e75;
$solarized-light-line-bg: #fdf6e3;
+$solarized-light-line-color: rgba(0, 0, 0, 0.3);
+$solarized-light-line-color-new: #a1a080;
+$solarized-light-line-color-old: #ad9186;
$solarized-light-highlight: #eee8d5;
$solarized-light-hll-bg: #ddd8c5;
$solarized-light-c: #93a1a1;
@@ -98,7 +101,7 @@ $solarized-light-il: #2aa198;
.diff-line-num,
.diff-line-num a {
- color: $black-transparent;
+ color: $solarized-light-line-color;
}
// Code itself
@@ -130,11 +133,21 @@ $solarized-light-il: #2aa198;
.line_content.new {
@include diff_background($solarized-light-new-bg,
$solarized-light-new-idiff, $solarized-light-border);
+
+ &::before,
+ a {
+ color: $solarized-light-line-color-new;
+ }
}
.diff-line-num.old,
.line_content.old {
@include diff_background($solarized-light-old-bg, $solarized-light-old-idiff, $solarized-light-border);
+
+ &::before,
+ a {
+ color: $solarized-light-line-color-old;
+ }
}
.line_content.match {
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index b425c78e0d5..398fbfd3b18 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -108,11 +108,19 @@ $white-gc-bg: #eaf2f5;
&.old {
background-color: $line-number-old;
border-color: $line-removed-dark;
+
+ a {
+ color: scale-color($line-number-old,$red: -30%, $green: -30%, $blue: -30%);
+ }
}
&.new {
background-color: $line-number-new;
border-color: $line-added-dark;
+
+ a {
+ color: scale-color($line-number-new,$red: -30%, $green: -30%, $blue: -30%);
+ }
}
&.hll:not(.empty-cell) {
@@ -125,6 +133,10 @@ $white-gc-bg: #eaf2f5;
&.old {
background-color: $line-removed;
+ &::before {
+ color: scale-color($line-number-old,$red: -30%, $green: -30%, $blue: -30%);
+ }
+
span.idiff {
background-color: $line-removed-dark;
}
@@ -133,6 +145,10 @@ $white-gc-bg: #eaf2f5;
&.new {
background-color: $line-added;
+ &::before {
+ color: scale-color($line-number-new,$red: -30%, $green: -30%, $blue: -30%);
+ }
+
span.idiff {
background-color: $line-added-dark;
}
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index 4cce1c363eb..948921efc0b 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -32,6 +32,10 @@
.last-commit {
@include str-truncated(506px);
+ .fa-angle-right {
+ margin-left: 5px;
+ }
+
@media (min-width: $screen-md-min) and (max-width: $screen-md-max) {
@include str-truncated(450px);
}
diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb
index 8714349e27f..70845617d3c 100644
--- a/app/controllers/projects/git_http_client_controller.rb
+++ b/app/controllers/projects/git_http_client_controller.rb
@@ -109,12 +109,14 @@ class Projects::GitHttpClientController < Projects::ApplicationController
end
def repository
+ wiki? ? project.wiki.repository : project.repository
+ end
+
+ def wiki?
+ return @wiki if defined?(@wiki)
+
_, suffix = project_id_with_suffix
- if suffix == '.wiki.git'
- project.wiki.repository
- else
- project.repository
- end
+ @wiki = suffix == '.wiki.git'
end
def render_not_found
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
index 9184dcccac5..278098fcc58 100644
--- a/app/controllers/projects/git_http_controller.rb
+++ b/app/controllers/projects/git_http_controller.rb
@@ -84,7 +84,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
end
def access
- @access ||= Gitlab::GitAccess.new(user, project, 'http', authentication_abilities: authentication_abilities)
+ @access ||= access_klass.new(user, project, 'http', authentication_abilities: authentication_abilities)
end
def access_check
@@ -102,4 +102,8 @@ class Projects::GitHttpController < Projects::GitHttpClientController
access_check.allowed?
end
+
+ def access_klass
+ @access_klass ||= wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
+ end
end
diff --git a/app/models/concerns/taskable.rb b/app/models/concerns/taskable.rb
index 68385dc47eb..25e2d8ea24e 100644
--- a/app/models/concerns/taskable.rb
+++ b/app/models/concerns/taskable.rb
@@ -11,10 +11,10 @@ module Taskable
INCOMPLETE = 'incomplete'.freeze
ITEM_PATTERN = /
^
- \s*(?:[-+*]|(?:\d+\.))? # optional list prefix
- \s* # optional whitespace prefix
- (\[\s\]|\[[xX]\]) # checkbox
- (\s.+) # followed by whitespace and some text.
+ \s*(?:[-+*]|(?:\d+\.)) # list prefix required - task item has to be always in a list
+ \s+ # whitespace prefix has to be always presented for a list item
+ (\[\s\]|\[[xX]\]) # checkbox
+ (\s.+) # followed by whitespace and some text.
/x
def self.get_tasks(content)
diff --git a/app/models/member.rb b/app/models/member.rb
index c585e0b450e..26a6054e00d 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -68,9 +68,9 @@ class Member < ActiveRecord::Base
after_create :send_request, if: :request?, unless: :importing?
after_create :create_notification_setting, unless: [:pending?, :importing?]
after_create :post_create_hook, unless: [:pending?, :importing?]
- after_create :refresh_member_authorized_projects, if: :importing?
after_update :post_update_hook, unless: [:pending?, :importing?]
after_destroy :post_destroy_hook, unless: :pending?
+ after_commit :refresh_member_authorized_projects
delegate :name, :username, :email, to: :user, prefix: true
@@ -147,8 +147,6 @@ class Member < ActiveRecord::Base
member.save
end
- UserProjectAccessChangedService.new(user.id).execute if user.is_a?(User)
-
member
end
@@ -275,23 +273,27 @@ class Member < ActiveRecord::Base
end
def post_create_hook
- UserProjectAccessChangedService.new(user.id).execute
system_hook_service.execute_hooks_for(self, :create)
end
def post_update_hook
- UserProjectAccessChangedService.new(user.id).execute if access_level_changed?
+ # override in sub class
end
def post_destroy_hook
- refresh_member_authorized_projects
system_hook_service.execute_hooks_for(self, :destroy)
end
+ # Refreshes authorizations of the current member.
+ #
+ # This method schedules a job using Sidekiq and as such **must not** be called
+ # in a transaction. Doing so can lead to the job running before the
+ # transaction has been committed, resulting in the job either throwing an
+ # error or not doing any meaningful work.
def refresh_member_authorized_projects
- # If user/source is being destroyed, project access are gonna be destroyed eventually
- # because of DB foreign keys, so we shouldn't bother with refreshing after each
- # member is destroyed through association
+ # If user/source is being destroyed, project access are going to be
+ # destroyed eventually because of DB foreign keys, so we shouldn't bother
+ # with refreshing after each member is destroyed through association
return if destroyed_by_association.present?
UserProjectAccessChangedService.new(user_id).execute
diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb
index 6149c35cc61..5cb6b0c527d 100644
--- a/app/models/project_group_link.rb
+++ b/app/models/project_group_link.rb
@@ -16,8 +16,7 @@ class ProjectGroupLink < ActiveRecord::Base
validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true
validate :different_group
- after_create :refresh_group_members_authorized_projects
- after_destroy :refresh_group_members_authorized_projects
+ after_commit :refresh_group_members_authorized_projects
def self.access_options
Gitlab::Access.options
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 842e23eb6b6..55d9cb13ae4 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -22,6 +22,8 @@ module Projects
if project.update_attributes(params.except(:default_branch))
if project.previous_changes.include?('path')
project.rename_repo
+ else
+ system_hook_service.execute_hooks_for(project, :update)
end
success
diff --git a/app/services/user_project_access_changed_service.rb b/app/services/user_project_access_changed_service.rb
index 2469b4f0d7c..d7a6804ee88 100644
--- a/app/services/user_project_access_changed_service.rb
+++ b/app/services/user_project_access_changed_service.rb
@@ -4,6 +4,6 @@ class UserProjectAccessChangedService
end
def execute
- AuthorizedProjectsWorker.bulk_perform_async(@user_ids.map { |id| [id] })
+ AuthorizedProjectsWorker.bulk_perform_and_wait(@user_ids.map { |id| [id] })
end
end
diff --git a/app/views/projects/_merge_request_merge_settings.html.haml b/app/views/projects/_merge_request_merge_settings.html.haml
index afe2fd7fd7b..1a1327fb53c 100644
--- a/app/views/projects/_merge_request_merge_settings.html.haml
+++ b/app/views/projects/_merge_request_merge_settings.html.haml
@@ -8,7 +8,7 @@
%br
%span.descr
Builds need to be configured to enable this feature.
- = link_to icon('question-circle'), help_page_path('user/project/merge_requests/merge_when_build_succeeds', anchor: 'only-allow-merge-requests-to-be-merged-if-the-build-succeeds')
+ = link_to icon('question-circle'), help_page_path('user/project/merge_requests/merge_when_pipeline_succeeds', anchor: 'only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds')
.checkbox
= form.label :only_allow_merge_if_all_discussions_are_resolved do
= form.check_box :only_allow_merge_if_all_discussions_are_resolved
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 04efc2e996c..19ffe73a08d 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -18,7 +18,7 @@
- if @project.protected_branch? branch.name
%span.label.label-success
protected
- .controls.hidden-xs
+ .controls.hidden-xs<
- if merge_project && create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-default' do
Merge Request
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 5f8f56150f9..bd1f2d96f56 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -12,7 +12,7 @@
= form_tag(filter_branches_path, method: :get) do
= search_field_tag :search, params[:search], { placeholder: 'Filter by branch name', id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
- .dropdown.inline
+ .dropdown.inline>
%button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
%span.light
= projects_sort_options_hash[@sort]
diff --git a/app/views/projects/buttons/_download.html.haml b/app/views/projects/buttons/_download.html.haml
index 324a7f8cd3f..762ff34a9ec 100644
--- a/app/views/projects/buttons/_download.html.haml
+++ b/app/views/projects/buttons/_download.html.haml
@@ -1,5 +1,5 @@
- if !project.empty_repo? && can?(current_user, :download_code, project)
- .project-action-button.dropdown.inline
+ .project-action-button.dropdown.inline>
%button.btn{ 'data-toggle' => 'dropdown' }
= icon('download')
= icon("caret-down")
diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml
index dfdaeb04869..818a70f38f1 100644
--- a/app/views/projects/ci/pipelines/_pipeline.html.haml
+++ b/app/views/projects/ci/pipelines/_pipeline.html.haml
@@ -78,7 +78,7 @@
.btn-group.inline
- if actions.any?
.btn-group
- %button.dropdown-toggle.btn.btn-default.has-tooltip.js-pipeline-dropdown-manual-actions{ type: 'button', title: 'Manual build', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label': 'Manual build' }
+ %button.dropdown-toggle.btn.btn-default.has-tooltip.js-pipeline-dropdown-manual-actions{ type: 'button', title: 'Manual build', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Manual build' }
= custom_icon('icon_play')
= icon('caret-down', 'aria-hidden' => 'true')
%ul.dropdown-menu.dropdown-menu-align-right
@@ -89,7 +89,7 @@
%span= build.name
- if artifacts.present?
.btn-group
- %button.dropdown-toggle.btn.btn-default.build-artifacts.has-tooltip.js-pipeline-dropdown-download{ type: 'button', title: 'Artifacts', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label': 'Artifacts' }
+ %button.dropdown-toggle.btn.btn-default.build-artifacts.has-tooltip.js-pipeline-dropdown-download{ type: 'button', title: 'Artifacts', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Artifacts' }
= icon("download")
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right
@@ -102,8 +102,8 @@
- if can?(current_user, :update_pipeline, pipeline.project)
.cancel-retry-btns.inline
- if pipeline.retryable?
- = link_to retry_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn has-tooltip', title: 'Retry', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label': 'Retry' , method: :post do
+ = link_to retry_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn has-tooltip', title: 'Retry', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Retry' , method: :post do
= icon("repeat")
- if pipeline.cancelable?
- = link_to cancel_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn btn-remove has-tooltip', title: 'Cancel', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label': 'Cancel' , method: :post do
+ = link_to cancel_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn btn-remove has-tooltip', title: 'Cancel', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Cancel' , method: :post do
= icon("remove")
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 08eb0c57f66..6dba42d5226 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -1,8 +1,7 @@
.page-content-header
.header-main-content
- %strong
+ %strong Commit #{@commit.short_id}
= clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard")
- = @commit.short_id
%span.hidden-xs authored
#{time_ago_with_tooltip(@commit.authored_date)}
%span by
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index b087485aa17..f361204ecac 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -14,7 +14,7 @@
- left_line_code = diff_file.line_code(left)
- left_position = diff_file.position(left)
%td.old_line.diff-line-num{ id: left_line_code, class: left.type, data: { linenumber: left.old_pos } }
- %a{ href: "##{left_line_code}" }= raw(left.old_pos)
+ %a{ href: "##{left_line_code}", data: { linenumber: left.old_pos } }
%td.line_content.parallel.noteable_line{ class: left.type, data: diff_view_line_data(left_line_code, left_position, 'old') }= diff_line_content(left.text)
- else
%td.old_line.diff-line-num.empty-cell
@@ -27,7 +27,7 @@
- right_line_code = diff_file.line_code(right)
- right_position = diff_file.position(right)
%td.new_line.diff-line-num{ id: right_line_code, class: right.type, data: { linenumber: right.new_pos } }
- %a{ href: "##{right_line_code}" }= raw(right.new_pos)
+ %a{ href: "##{right_line_code}", data: { linenumber: right.new_pos } }
%td.line_content.parallel.noteable_line{ class: right.type, data: diff_view_line_data(right_line_code, right_position, 'new') }= diff_line_content(right.text)
- else
%td.old_line.diff-line-num.empty-cell
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 1d7fdf68cb3..114865935d6 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -7,10 +7,17 @@
.project-edit-errors
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f|
%fieldset.append-bottom-0
- .form-group
- = f.label :name, class: 'label-light' do
- Project name
- = f.text_field :name, class: "form-control", id: "project_name_edit"
+ .row
+ .form-group.col-md-9
+ = f.label :name, class: 'label-light' do
+ Project name
+ = f.text_field :name, class: "form-control", id: "project_name_edit"
+
+ .form-group.col-md-3
+ = f.label :id, class: 'label-light' do
+ Project ID
+ = f.text_field :id, class: 'form-control', readonly: true
+
.form-group
= f.label :description, class: 'label-light' do
Project description
diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml
index 2c08221565b..6855c463c6d 100644
--- a/app/views/projects/tree/_tree_content.html.haml
+++ b/app/views/projects/tree/_tree_content.html.haml
@@ -7,10 +7,12 @@
%th.hidden-xs
.pull-left Last commit
.last-commit.hidden-sm.pull-left
+ %i.fa.fa-angle-right
%small.light
- = clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard")
= link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
+ = clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard")
= time_ago_with_tooltip(@commit.committed_date)
+ \-
= @commit.full_title
%small.commit-history-link-spacer &#124;
= link_to 'History', namespace_project_commits_path(@project.namespace, @project, @id), class: 'commit-history-link'
diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml
index e25d6a48573..fb0efd85dcd 100644
--- a/app/views/projects/wikis/git_access.html.haml
+++ b/app/views/projects/wikis/git_access.html.haml
@@ -17,6 +17,13 @@
%pre.dark
:preserve
gem install gollum
+ %p
+ It is recommended to install
+ %code github-markdown
+ so that GFM features render locally:
+ %pre.dark
+ :preserve
+ gem install github-markdown
%h3 Clone your wiki
%pre.dark
diff --git a/app/workers/authorized_projects_worker.rb b/app/workers/authorized_projects_worker.rb
index 2badd0680fb..6abbb5a5250 100644
--- a/app/workers/authorized_projects_worker.rb
+++ b/app/workers/authorized_projects_worker.rb
@@ -2,6 +2,13 @@ class AuthorizedProjectsWorker
include Sidekiq::Worker
include DedicatedSidekiqQueue
+ # Schedules multiple jobs and waits for them to be completed.
+ def self.bulk_perform_and_wait(args_list)
+ job_ids = bulk_perform_async(args_list)
+
+ Gitlab::JobWaiter.new(job_ids).wait
+ end
+
def self.bulk_perform_async(args_list)
Sidekiq::Client.push_bulk('class' => self, 'args' => args_list)
end
diff --git a/changelogs/unreleased/26068_tasklist_issue.yml b/changelogs/unreleased/26068_tasklist_issue.yml
new file mode 100644
index 00000000000..c938351b8a7
--- /dev/null
+++ b/changelogs/unreleased/26068_tasklist_issue.yml
@@ -0,0 +1,4 @@
+---
+title: Don’t count tasks that are not defined as list items correctly
+merge_request: 8526
+author:
diff --git a/changelogs/unreleased/26186-diff-view-plus-and-minus-signs-as-part-of-line-number.yml b/changelogs/unreleased/26186-diff-view-plus-and-minus-signs-as-part-of-line-number.yml
new file mode 100644
index 00000000000..565672917b2
--- /dev/null
+++ b/changelogs/unreleased/26186-diff-view-plus-and-minus-signs-as-part-of-line-number.yml
@@ -0,0 +1,4 @@
+---
+title: Color + and - signs in diffs to increase code legibility
+merge_request:
+author:
diff --git a/changelogs/unreleased/26785-fix-droplab-in-ie-11-v1.yml b/changelogs/unreleased/26785-fix-droplab-in-ie-11-v1.yml
deleted file mode 100644
index 76e9b19b828..00000000000
--- a/changelogs/unreleased/26785-fix-droplab-in-ie-11-v1.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add some basic fixes for IE11/Edge
-merge_request:
-author:
diff --git a/changelogs/unreleased/27013-regression-in-commit-title-bar.yml b/changelogs/unreleased/27013-regression-in-commit-title-bar.yml
new file mode 100644
index 00000000000..7cb5e4b273d
--- /dev/null
+++ b/changelogs/unreleased/27013-regression-in-commit-title-bar.yml
@@ -0,0 +1,4 @@
+---
+title: Fix commit title bar and repository view copy clipboard button order on last commit in repository view
+merge_request:
+author:
diff --git a/changelogs/unreleased/27021-line-numbers-now-in-copy-pasta-data.yml b/changelogs/unreleased/27021-line-numbers-now-in-copy-pasta-data.yml
new file mode 100644
index 00000000000..b5584749098
--- /dev/null
+++ b/changelogs/unreleased/27021-line-numbers-now-in-copy-pasta-data.yml
@@ -0,0 +1,4 @@
+---
+title: Prevent copying of line numbers in parallel diff view
+merge_request: 8706
+author:
diff --git a/changelogs/unreleased/27066-textarea-border.yml b/changelogs/unreleased/27066-textarea-border.yml
deleted file mode 100644
index e45cb3aced5..00000000000
--- a/changelogs/unreleased/27066-textarea-border.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove blue border from comment box hover
-merge_request:
-author:
diff --git a/changelogs/unreleased/27178-update-builds-link-in-project-settings.yml b/changelogs/unreleased/27178-update-builds-link-in-project-settings.yml
new file mode 100644
index 00000000000..52406bba464
--- /dev/null
+++ b/changelogs/unreleased/27178-update-builds-link-in-project-settings.yml
@@ -0,0 +1,4 @@
+---
+title: Updated builds info link on the project settings page
+merge_request:
+author: Ryan Harris
diff --git a/changelogs/unreleased/add_project_update_hook.yml b/changelogs/unreleased/add_project_update_hook.yml
new file mode 100644
index 00000000000..915c9538843
--- /dev/null
+++ b/changelogs/unreleased/add_project_update_hook.yml
@@ -0,0 +1,4 @@
+---
+title: Add system hook for when a project is updated (other than rename/transfer)
+merge_request: 5711
+author: Tommy Beadle
diff --git a/changelogs/unreleased/copy-as-md.yml b/changelogs/unreleased/copy-as-md.yml
new file mode 100644
index 00000000000..637e9dc36e2
--- /dev/null
+++ b/changelogs/unreleased/copy-as-md.yml
@@ -0,0 +1,4 @@
+---
+title: Copying a rendered issue/comment will paste into GFM textareas as actual GFM
+merge_request:
+author:
diff --git a/changelogs/unreleased/display-project-id.yml b/changelogs/unreleased/display-project-id.yml
new file mode 100644
index 00000000000..8705ed28400
--- /dev/null
+++ b/changelogs/unreleased/display-project-id.yml
@@ -0,0 +1,4 @@
+---
+title: Display project ID in project settings
+merge_request: 8572
+author: winniehell
diff --git a/changelogs/unreleased/fix-26518.yml b/changelogs/unreleased/fix-26518.yml
new file mode 100644
index 00000000000..961ac2642fb
--- /dev/null
+++ b/changelogs/unreleased/fix-26518.yml
@@ -0,0 +1,4 @@
+---
+title: Fix access to the wiki code via HTTP when repository feature disabled
+merge_request: 8758
+author:
diff --git a/changelogs/unreleased/fix-ci-requests-concurrency-for-newer-runners.yml b/changelogs/unreleased/fix-ci-requests-concurrency-for-newer-runners.yml
deleted file mode 100644
index 075d74b9cb8..00000000000
--- a/changelogs/unreleased/fix-ci-requests-concurrency-for-newer-runners.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-title: 'Fix CI requests concurrency for newer runners that prevents from picking pending builds (from 1.9.0-rc5)'
-merge_request: 8760
diff --git a/changelogs/unreleased/issue-filter-click-to-search.yml b/changelogs/unreleased/issue-filter-click-to-search.yml
deleted file mode 100644
index c024ea48dc7..00000000000
--- a/changelogs/unreleased/issue-filter-click-to-search.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: allow issue filter bar to be operated with mouse only
-merge_request: 8681
-author:
diff --git a/changelogs/unreleased/label-select-toggle.yml b/changelogs/unreleased/label-select-toggle.yml
new file mode 100644
index 00000000000..af5b4246521
--- /dev/null
+++ b/changelogs/unreleased/label-select-toggle.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed label dropdown toggle text not correctly updating
+merge_request:
+author:
diff --git a/changelogs/unreleased/merge-dropdown-this-context.yml b/changelogs/unreleased/merge-dropdown-this-context.yml
deleted file mode 100644
index 5c4890fcaa2..00000000000
--- a/changelogs/unreleased/merge-dropdown-this-context.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed bug where links in merge dropdown wouldn't work
-merge_request:
-author:
diff --git a/changelogs/unreleased/refresh-authorizations-fork-join.yml b/changelogs/unreleased/refresh-authorizations-fork-join.yml
new file mode 100644
index 00000000000..b1349b9447d
--- /dev/null
+++ b/changelogs/unreleased/refresh-authorizations-fork-join.yml
@@ -0,0 +1,4 @@
+---
+title: Fix race conditions for AuthorizedProjectsWorker
+merge_request:
+author:
diff --git a/config/database.yml.mysql b/config/database.yml.mysql
index d9702870249..a33e40e8eb3 100644
--- a/config/database.yml.mysql
+++ b/config/database.yml.mysql
@@ -3,8 +3,8 @@
#
production:
adapter: mysql2
- encoding: utf8mb4
- collation: utf8mb4_general_ci
+ encoding: utf8
+ collation: utf8_general_ci
reconnect: false
database: gitlabhq_production
pool: 10
@@ -18,8 +18,8 @@ production:
#
development:
adapter: mysql2
- encoding: utf8mb4
- collation: utf8mb4_general_ci
+ encoding: utf8
+ collation: utf8_general_ci
reconnect: false
database: gitlabhq_development
pool: 5
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 5a7365bb0f6..fa318384405 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -12,6 +12,11 @@ Sidekiq.configure_server do |config|
chain.add Gitlab::SidekiqMiddleware::ArgumentsLogger if ENV['SIDEKIQ_LOG_ARGUMENTS']
chain.add Gitlab::SidekiqMiddleware::MemoryKiller if ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS']
chain.add Gitlab::SidekiqMiddleware::RequestStoreMiddleware unless ENV['SIDEKIQ_REQUEST_STORE'] == '0'
+ chain.add Gitlab::SidekiqStatus::ServerMiddleware
+ end
+
+ config.client_middleware do |chain|
+ chain.add Gitlab::SidekiqStatus::ClientMiddleware
end
# Sidekiq-cron: load recurring jobs from gitlab.yml
@@ -46,6 +51,10 @@ end
Sidekiq.configure_client do |config|
config.redis = redis_config_hash
+
+ config.client_middleware do |chain|
+ chain.add Gitlab::SidekiqStatus::ClientMiddleware
+ end
end
# The Sidekiq client API always adds the queue to the Sidekiq queue
diff --git a/db/fixtures/development/01_admin.rb b/db/fixtures/development/01_admin.rb
index bba2fc4b186..6f241f6fa4a 100644
--- a/db/fixtures/development/01_admin.rb
+++ b/db/fixtures/development/01_admin.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
User.seed do |s|
s.id = 1
diff --git a/db/fixtures/development/04_project.rb b/db/fixtures/development/04_project.rb
index a984eda5ab5..c2b8f7ba819 100644
--- a/db/fixtures/development/04_project.rb
+++ b/db/fixtures/development/04_project.rb
@@ -1,4 +1,4 @@
-require 'sidekiq/testing'
+require './spec/support/sidekiq'
Sidekiq::Testing.inline! do
Gitlab::Seeder.quiet do
diff --git a/db/fixtures/development/05_users.rb b/db/fixtures/development/05_users.rb
index 03da29c4c68..101ff3a1209 100644
--- a/db/fixtures/development/05_users.rb
+++ b/db/fixtures/development/05_users.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
20.times do |i|
begin
diff --git a/db/fixtures/development/06_teams.rb b/db/fixtures/development/06_teams.rb
index 5c2a03fec3f..86e0a38aae1 100644
--- a/db/fixtures/development/06_teams.rb
+++ b/db/fixtures/development/06_teams.rb
@@ -1,4 +1,4 @@
-require 'sidekiq/testing'
+require './spec/support/sidekiq'
Sidekiq::Testing.inline! do
Gitlab::Seeder.quiet do
diff --git a/db/fixtures/development/07_milestones.rb b/db/fixtures/development/07_milestones.rb
index 540e4e68259..271bfbc97e0 100644
--- a/db/fixtures/development/07_milestones.rb
+++ b/db/fixtures/development/07_milestones.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
Project.all.each do |project|
5.times do |i|
diff --git a/db/fixtures/development/09_issues.rb b/db/fixtures/development/09_issues.rb
index 4fa572fca9b..d93d133d157 100644
--- a/db/fixtures/development/09_issues.rb
+++ b/db/fixtures/development/09_issues.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
Project.all.each do |project|
10.times do
diff --git a/db/fixtures/development/10_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb
index 87fb8e3300d..c04afe97277 100644
--- a/db/fixtures/development/10_merge_requests.rb
+++ b/db/fixtures/development/10_merge_requests.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
# Limit the number of merge requests per project to avoid long seeds
MAX_NUM_MERGE_REQUESTS = 10
diff --git a/db/fixtures/development/11_keys.rb b/db/fixtures/development/11_keys.rb
index 8b4bee384e1..51e22137d6f 100644
--- a/db/fixtures/development/11_keys.rb
+++ b/db/fixtures/development/11_keys.rb
@@ -1,12 +1,18 @@
-Gitlab::Seeder.quiet do
- User.first(10).each do |user|
- key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt#{user.id + 100}6k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
+require './spec/support/sidekiq'
- user.keys.create(
- title: "Sample key #{user.id}",
- key: key
- )
+# Creating keys runs a gitlab-shell worker. Since we may not have the right
+# gitlab-shell path set (yet) we need to disable this for these fixtures.
+Sidekiq::Testing.disable! do
+ Gitlab::Seeder.quiet do
+ User.first(10).each do |user|
+ key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt#{user.id + 100}6k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
- print '.'
+ user.keys.create(
+ title: "Sample key #{user.id}",
+ key: key
+ )
+
+ print '.'
+ end
end
end
diff --git a/db/fixtures/development/12_snippets.rb b/db/fixtures/development/12_snippets.rb
index 74898544a69..4f3bdba043d 100644
--- a/db/fixtures/development/12_snippets.rb
+++ b/db/fixtures/development/12_snippets.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
content =<<eos
class Member < ActiveRecord::Base
diff --git a/db/fixtures/development/13_comments.rb b/db/fixtures/development/13_comments.rb
index 566c0705638..29b8081055d 100644
--- a/db/fixtures/development/13_comments.rb
+++ b/db/fixtures/development/13_comments.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
Issue.all.each do |issue|
project = issue.project
diff --git a/db/fixtures/development/14_pipelines.rb b/db/fixtures/development/14_pipelines.rb
index be95d788850..534847a7107 100644
--- a/db/fixtures/development/14_pipelines.rb
+++ b/db/fixtures/development/14_pipelines.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
class Gitlab::Seeder::Pipelines
STAGES = %w[build test deploy notify]
BUILDS = [
diff --git a/db/fixtures/development/15_award_emoji.rb b/db/fixtures/development/15_award_emoji.rb
index baac32f2d10..ea343c26b69 100644
--- a/db/fixtures/development/15_award_emoji.rb
+++ b/db/fixtures/development/15_award_emoji.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
emoji = Gitlab::AwardEmoji.emojis.keys
diff --git a/db/fixtures/development/16_protected_branches.rb b/db/fixtures/development/16_protected_branches.rb
index 103c7f9445c..39d466fb43f 100644
--- a/db/fixtures/development/16_protected_branches.rb
+++ b/db/fixtures/development/16_protected_branches.rb
@@ -1,3 +1,5 @@
+require './spec/support/sidekiq'
+
Gitlab::Seeder.quiet do
admin_user = User.find(1)
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index 916ee8dbac8..747901dd634 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -1,4 +1,4 @@
-require 'sidekiq/testing'
+require './spec/support/sidekiq'
require './spec/support/test_env'
class Gitlab::Seeder::CycleAnalytics
diff --git a/doc/README.md b/doc/README.md
index 993b30ccdb5..909740211a6 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -44,7 +44,7 @@
- [Operations](administration/operations.md) Keeping GitLab up and running.
- [Raketasks](raketasks/README.md) Backups, maintenance, automatic webhook setup and the importing of projects.
- [Repository checks](administration/repository_checks.md) Periodic Git repository checks.
-- [Repository storages](administration/repository_storages.md) Manage the paths used to store repositories.
+- [Repository storage paths](administration/repository_storage_paths.md) Manage the paths used to store repositories.
- [Security](security/README.md) Learn what you can do to further secure your GitLab instance.
- [System hooks](system_hooks/system_hooks.md) Notifications when users, projects and keys are changed.
- [Update](update/README.md) Update guides to upgrade your installation.
@@ -61,7 +61,6 @@
- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs.
- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability.
- [Container Registry](administration/container_registry.md) Configure Docker Registry with GitLab.
-- [Multiple mountpoints for the repositories storage](administration/repository_storages.md) Define multiple repository storage paths to distribute the storage load.
## Contributor documentation
diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index 04723365277..f6027b2f99e 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -65,11 +65,15 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
#
# Example: 'Paris' or 'Acme, Ltd.'
label: 'LDAP'
-
+
+ # Example: 'ldap.mydomain.com'
host: '_your_ldap_server'
+ # This port is an example, it is sometimes different but it is always an integer and not a string
port: 389
uid: 'sAMAccountName'
method: 'plain' # "tls" or "ssl" or "plain"
+
+ # Examples: 'america\\momo' or 'CN=Gitlab Git,CN=Users,DC=mydomain,DC=com'
bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
password: '_the_password_of_the_bind_user'
@@ -101,7 +105,7 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
# Base where we can search for users
#
- # Ex. ou=People,dc=gitlab,dc=example
+ # Ex. 'ou=People,dc=gitlab,dc=example' or 'DC=mydomain,DC=com'
#
base: ''
@@ -112,6 +116,9 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
#
# Note: GitLab does not support omniauth-ldap's custom filter syntax.
#
+ # Below an example for get only specific users
+ # Example: '(&(objectclass=user)(|(samaccountname=momo)(samaccountname=toto)))'
+ #
user_filter: ''
# LDAP attributes that GitLab will use to create an account for the LDAP user.
diff --git a/doc/administration/repository_checks.md b/doc/administration/repository_checks.md
index bc2b1f20ed3..ee37ea49874 100644
--- a/doc/administration/repository_checks.md
+++ b/doc/administration/repository_checks.md
@@ -13,12 +13,12 @@ checks failed you can see their output on the admin log page under
## Periodic checks
-GitLab periodically runs a repository check on all project repositories and
-wiki repositories in order to detect data corruption problems. A
-project will be checked no more than once per week. If any projects
+When enabled, GitLab periodically runs a repository check on all project
+repositories and wiki repositories in order to detect data corruption problems.
+A project will be checked no more than once per month. If any projects
fail their repository checks all GitLab administrators will receive an email
-notification of the situation. This notification is sent out no more
-than once a day.
+notification of the situation. This notification is sent out once a week on
+Sunday, by default.
## Disabling periodic checks
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
new file mode 100644
index 00000000000..d6aa6101026
--- /dev/null
+++ b/doc/administration/repository_storage_paths.md
@@ -0,0 +1,102 @@
+# Repository storage paths
+
+> [Introduced][ce-4578] in GitLab 8.10.
+
+GitLab allows you to define multiple repository storage paths to distribute the
+storage load between several mount points.
+
+>**Notes:**
+>
+- You must have at least one storage path called `default`.
+- The paths are defined in key-value pairs. The key is an arbitrary name you
+ can pick to name the file path.
+- The target directories and any of its subpaths must not be a symlink.
+
+## Configure GitLab
+
+>**Warning:**
+In order for [backups] to work correctly, the storage path must **not** be a
+mount point and the GitLab user should have correct permissions for the parent
+directory of the path. In Omnibus GitLab this is taken care of automatically,
+but for source installations you should be extra careful.
+>
+The thing is that for compatibility reasons `gitlab.yml` has a different
+structure than Omnibus. In `gitlab.yml` you indicate the path for the
+repositories, for example `/home/git/repositories`, while in Omnibus you
+indicate `git_data_dirs`, which for the example above would be `/home/git`.
+Then, Omnibus will create a `repositories` directory under that path to use with
+`gitlab.yml`.
+>
+This little detail matters because while restoring a backup, the current
+contents of `/home/git/repositories` [are moved to][raketask] `/home/git/repositories.old`,
+so if `/home/git/repositories` is the mount point, then `mv` would be moving
+things between mount points, and bad things could happen. Ideally,
+`/home/git` would be the mount point, so then things would be moving within the
+same mount point. This is guaranteed with Omnibus installations (because they
+don't specify the full repository path but the parent path), but not for source
+installations.
+
+---
+
+Now that you've read that big fat warning above, let's edit the configuration
+files and add the full paths of the alternative repository storage paths. In
+the example below, we add two more mountpoints that are named `nfs` and `cephfs`
+respectively.
+
+**For installations from source**
+
+1. Edit `gitlab.yml` and add the storage paths:
+
+ ```yaml
+ repositories:
+ # Paths where repositories can be stored. Give the canonicalized absolute pathname.
+ # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!!
+ storages: # You must have at least a 'default' storage path.
+ default: /home/git/repositories
+ nfs: /mnt/nfs/repositories
+ cephfs: /mnt/cephfs/repositories
+ ```
+
+1. [Restart GitLab] for the changes to take effect.
+
+>**Note:**
+The [`gitlab_shell: repos_path` entry][repospath] in `gitlab.yml` will be
+deprecated and replaced by `repositories: storages` in the future, so if you
+are upgrading from a version prior to 8.10, make sure to add the configuration
+as described in the step above. After you make the changes and confirm they are
+working, you can remove the `repos_path` line.
+
+---
+
+**For Omnibus installations**
+
+1. Edit `/etc/gitlab/gitlab.rb` by appending the rest of the paths to the
+ default one:
+
+ ```ruby
+ git_data_dirs({
+ "default" => "/var/opt/gitlab/git-data",
+ "nfs" => "/mnt/nfs/git-data",
+ "cephfs" => "/mnt/cephfs/git-data"
+ })
+ ```
+
+ Note that Omnibus stores the repositories in a `repositories` subdirectory
+ of the `git-data` directory.
+
+## Choose where new project repositories will be stored
+
+Once you set the multiple storage paths, you can choose where new projects will
+be stored via the **Application Settings** in the Admin area.
+
+![Choose repository storage path in Admin area](img/repository_storages_admin_ui.png)
+
+Beginning with GitLab 8.13.4, multiple paths can be chosen. New projects will be
+randomly placed on one of the selected paths.
+
+[ce-4578]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4578
+[restart gitlab]: restart_gitlab.md#installations-from-source
+[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
+[backups]: ../raketasks/backup_restore.md
+[raketask]: https://gitlab.com/gitlab-org/gitlab-ce/blob/033e5423a2594e08a7ebcd2379bd2331f4c39032/lib/backup/repository.rb#L54-56
+[repospath]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-9-stable/config/gitlab.yml.example#L457
diff --git a/doc/administration/repository_storages.md b/doc/administration/repository_storages.md
index ab70557b69a..9d41ba77f34 100644
--- a/doc/administration/repository_storages.md
+++ b/doc/administration/repository_storages.md
@@ -1,102 +1,3 @@
# Repository storages
-> [Introduced][ce-4578] in GitLab 8.10.
-
-GitLab allows you to define multiple repository storage paths to distribute the
-storage load between several mount points.
-
->**Notes:**
->
-- You must have at least one storage path called `default`.
-- The paths are defined in key-value pairs. The key is an arbitrary name you
- can pick to name the file path.
-- The target directories and any of its subpaths must not be a symlink.
-
-## Configure GitLab
-
->**Warning:**
-In order for [backups] to work correctly, the storage path must **not** be a
-mount point and the GitLab user should have correct permissions for the parent
-directory of the path. In Omnibus GitLab this is taken care of automatically,
-but for source installations you should be extra careful.
->
-The thing is that for compatibility reasons `gitlab.yml` has a different
-structure than Omnibus. In `gitlab.yml` you indicate the path for the
-repositories, for example `/home/git/repositories`, while in Omnibus you
-indicate `git_data_dirs`, which for the example above would be `/home/git`.
-Then, Omnibus will create a `repositories` directory under that path to use with
-`gitlab.yml`.
->
-This little detail matters because while restoring a backup, the current
-contents of `/home/git/repositories` [are moved to][raketask] `/home/git/repositories.old`,
-so if `/home/git/repositories` is the mount point, then `mv` would be moving
-things between mount points, and bad things could happen. Ideally,
-`/home/git` would be the mount point, so then things would be moving within the
-same mount point. This is guaranteed with Omnibus installations (because they
-don't specify the full repository path but the parent path), but not for source
-installations.
-
----
-
-Now that you've read that big fat warning above, let's edit the configuration
-files and add the full paths of the alternative repository storage paths. In
-the example below, we add two more mountpoints that are named `nfs` and `cephfs`
-respectively.
-
-**For installations from source**
-
-1. Edit `gitlab.yml` and add the storage paths:
-
- ```yaml
- repositories:
- # Paths where repositories can be stored. Give the canonicalized absolute pathname.
- # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!!
- storages: # You must have at least a 'default' storage path.
- default: /home/git/repositories
- nfs: /mnt/nfs/repositories
- cephfs: /mnt/cephfs/repositories
- ```
-
-1. [Restart GitLab] for the changes to take effect.
-
->**Note:**
-The [`gitlab_shell: repos_path` entry][repospath] in `gitlab.yml` will be
-deprecated and replaced by `repositories: storages` in the future, so if you
-are upgrading from a version prior to 8.10, make sure to add the configuration
-as described in the step above. After you make the changes and confirm they are
-working, you can remove the `repos_path` line.
-
----
-
-**For Omnibus installations**
-
-1. Edit `/etc/gitlab/gitlab.rb` by appending the rest of the paths to the
- default one:
-
- ```ruby
- git_data_dirs({
- "default" => "/var/opt/gitlab/git-data",
- "nfs" => "/mnt/nfs/git-data",
- "cephfs" => "/mnt/cephfs/git-data"
- })
- ```
-
- Note that Omnibus stores the repositories in a `repositories` subdirectory
- of the `git-data` directory.
-
-## Choose where new project repositories will be stored
-
-Once you set the multiple storage paths, you can choose where new projects will
-be stored via the **Application Settings** in the Admin area.
-
-![Choose repository storage path in Admin area](img/repository_storages_admin_ui.png)
-
-Beginning with GitLab 8.13.4, multiple paths can be chosen. New projects will be
-randomly placed on one of the selected paths.
-
-[ce-4578]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4578
-[restart gitlab]: restart_gitlab.md#installations-from-source
-[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
-[backups]: ../raketasks/backup_restore.md
-[raketask]: https://gitlab.com/gitlab-org/gitlab-ce/blob/033e5423a2594e08a7ebcd2379bd2331f4c39032/lib/backup/repository.rb#L54-56
-[repospath]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-9-stable/config/gitlab.yml.example#L457
+This document was moved to a [new location](repository_storage_paths.md).
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 75a0897eb15..f11257be5c3 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -86,7 +86,7 @@ used for time of the build. The configuration of this feature is covered in
### before_script
`before_script` is used to define the command that should be run before all
-builds, including deploy builds. This can be an array or a multi-line string.
+builds, including deploy builds, but after the restoration of artifacts. This can be an array or a multi-line string.
### after_script
diff --git a/doc/gitlab-basics/add-image.md b/doc/gitlab-basics/add-image.md
index 476b48a217c..1a44123aa81 100644
--- a/doc/gitlab-basics/add-image.md
+++ b/doc/gitlab-basics/add-image.md
@@ -1,62 +1,56 @@
# How to add an image
-The following are the steps to add images to your repository in
-GitLab:
+Using your standard tool for copying files (e.g. Finder in Mac OS, or Explorer
+in Windows, or...), put the image file into the GitLab project. You can find the
+project as a regular folder in your files.
-Find the image that you’d like to add.
+Go to your [shell](command-line-commands.md), and move into the folder of your
+Gitlab project. This usually means running the following command until you get
+to the desired destination:
-In your computer files, find the GitLab project to which you'd like to add the image
-(you'll find it as a regular file). Click on every file until you find exactly where you'd
-like to add the image. There, paste the image.
-
-Go to your [shell](command-line-commands.md), and add the following commands:
-
-Add this command for every directory that you'd like to open:
```
-cd NAME-OF-FILE-YOU'D-LIKE-TO-OPEN
+cd NAME-OF-FOLDER-YOU'D-LIKE-TO-OPEN
```
-Create a new branch:
-```
-git checkout -b NAME-OF-BRANCH
-```
+Check if your image is actually present in the directory (if you are in Windows,
+use `dir` instead):
-Check if your image was correctly added to the directory:
```
ls
```
You should see the name of the image in the list shown.
-Move up the hierarchy through directories:
-```
-cd ../
-```
+Check the status:
-Check the status and you should see your image’s name in red:
```
git status
```
-Add your changes:
+Your image's name should appear in red, so `git` took notice of it! Now add it
+to the repository:
+
```
git add NAME-OF-YOUR-IMAGE
```
-Check the status and you should see your image’s name in green:
+Check the status again, your image's name should have turned green:
+
```
git status
```
-Add the commit:
+Commit:
+
```
-git commit -m “DESCRIBE COMMIT IN A FEW WORDS”
+git commit -m "DESCRIBE COMMIT IN A FEW WORDS"
```
-Now you can push (send) your changes (in the branch NAME-OF-BRANCH) to GitLab (the git remote named 'origin'):
+Now you can push (send) your changes (in the branch NAME-OF-BRANCH) to GitLab
+(the git remote named 'origin'):
+
```
git push origin NAME-OF-BRANCH
```
-Your image will be added to your branch in your repository in GitLab. Create a [Merge Request](add-merge-request.md)
-to integrate your changes to your project.
+Your image will be added to your branch in your repository in GitLab.
diff --git a/doc/install/database_mysql.md b/doc/install/database_mysql.md
index 322680f0cf4..65bfb0f7d6e 100644
--- a/doc/install/database_mysql.md
+++ b/doc/install/database_mysql.md
@@ -4,7 +4,7 @@
We do not recommend using MySQL due to various issues. For example, case [(in)sensitivity](https://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html) and [problems](https://bugs.mysql.com/bug.php?id=65830) that [suggested](https://bugs.mysql.com/bug.php?id=50909) [fixes](https://bugs.mysql.com/bug.php?id=65830) [have](https://bugs.mysql.com/bug.php?id=63164).
-## MySQL
+## Initial database setup
# Install the database packages
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
@@ -32,8 +32,11 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
# If this fails, check your MySQL config files (e.g. `/etc/mysql/*.cnf`, `/etc/mysql/conf.d/*`) for the setting "innodb = off"
mysql> SET storage_engine=INNODB;
+ # If you have MySQL < 5.7.7 and want to enable utf8mb4 character set support with your GitLab install, you must set the following NOW:
+ mysql> SET GLOBAL innodb_file_per_table=1, innodb_file_format=Barracuda, innodb_large_prefix=1;
+
# Create the GitLab production database
- mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
+ mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_general_ci`;
# Grant the GitLab user necessary permissions on the database
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER, LOCK TABLES, REFERENCES ON `gitlabhq_production`.* TO 'git'@'localhost';
@@ -51,7 +54,203 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
# Quit the database session
mysql> \q
- # You are done installing the database and can go back to the rest of the installation.
+ # You are done installing the database for now and can go back to the rest of the installation.
+
+Please proceed to the rest of the installation before running through the utf8mb4 support section.
+
+
+### MySQL utf8mb4 support
+
+After installation or upgrade, remember to [convert any new tables](#convert) to `utf8mb4`/`utf8mb4_general_ci`.
+
+---
+
+GitLab 8.14 has introduced [a feature](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7420) requiring `utf8mb4` encoding to be supported in your GitLab MySQL Database, which is not the case if you have setup your database before GitLab 8.16.
+
+Follow the below instructions to ensure you use the most up to date requirements for your GitLab MySQL Database.
+
+**We are about to do the following:**
+- Ensure you can enable `utf8mb4` encoding and `utf8mb4_general_ci` collation for your GitLab DB, tables and data.
+- Convert your GitLab tables and data from `utf8`/`utf8_general_ci` to `utf8mb4`/`utf8mb4_general_ci`
+
+### Check for utf8mb4 support
+
+#### Check for InnoDB File-Per-Table Tablespaces
+
+We need to check, enable and maybe convert your existing GitLab DB tables to the [InnoDB File-Per-Table Tablespaces](http://dev.mysql.com/doc/refman/5.7/en/innodb-multiple-tablespaces.html) as a prerequise for supporting **utfb8mb4 with long indexes** required by recent GitLab databases.
+
+ # Login to MySQL
+ mysql -u root -p
+
+ # Type the MySQL root password
+ mysql > use gitlabhq_production;
+
+ # Check your MySQL version is >= 5.5.3 (GitLab requires 5.5.14+)
+ mysql > SHOW VARIABLES LIKE 'version';
+ +---------------+-----------------+
+ | Variable_name | Value |
+ +---------------+-----------------+
+ | version | 5.5.53-0+deb8u1 |
+ +---------------+-----------------+
+
+ # Note where is your MySQL data dir for later:
+ mysql > select @@datadir;
+ +----------------+
+ | @@datadir |
+ +----------------+
+ | /var/lib/mysql |
+ +----------------+
+
+ # Note whether your MySQL server runs with innodb_file_per_table ON or OFF:
+ mysql> SELECT @@innodb_file_per_table;
+ +-------------------------+
+ | @@innodb_file_per_table |
+ +-------------------------+
+ | 1 |
+ +-------------------------+
+
+ # You can now quit the database session
+ mysql> \q
+
+> You need **MySQL 5.5.3 or later** to perform this update.
+
+Whatever the results of your checks above, we now need to check if your GitLab database has been created using [InnoDB File-Per-Table Tablespaces](http://dev.mysql.com/doc/refman/5.7/en/innodb-multiple-tablespaces.html) (i.e. `innodb_file_per_table` was set to **1** at initial setup time).
+
+> Note: This setting is [enabled by default](http://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_file_per_table) since MySQL 5.6.6.
+
+ # Run this command with root privileges, replace the data dir if different:
+ sudo ls -lh /var/lib/mysql/gitlabhq_production/*.ibd | wc -l
+
+ # Run this command with root privileges, replace the data dir if different:
+ sudo ls -lh /var/lib/mysql/gitlabhq_production/*.frm | wc -l
+
+
+- **Case 1: a result > 0 for both commands**
+
+Congrats, your GitLab database uses the right InnoDB tablespace format.
+
+However, you must still ensure that any **future tables** created by GitLab will still use the right format:
+
+- If `SELECT @@innodb_file_per_table` returned **1** previously, your server is running correctly.
+> It's however a requirement to check *now* that this setting is indeed persisted in your [my.cnf](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) file!
+
+- If `SELECT @@innodb_file_per_table` returned **0** previously, your server is not running correctly.
+> [Enable innodb_file_per_table](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) by running in a MySQL session as root the command `SET GLOBAL innodb_file_per_table=1, innodb_file_format=Barracuda;` and persist the two settings in your [my.cnf](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) file
+
+Now, if you have a **different result** returned by the 2 commands above, it means you have a **mix of tables format** uses in your GitLab database. This can happen if your MySQL server had different values for `innodb_file_per_table` in its life and you updated GitLab at different moments with those inconsistent values. So keep reading.
+
+- **Case 2: a result equals to "0" OR not the same result for both commands**
+
+Unfortunately, none or only some of your GitLab database tables use the GitLab requirement of [InnoDB File-Per-Table Tablespaces](http://dev.mysql.com/doc/refman/5.7/en/innodb-multiple-tablespaces.html).
+
+Let's enable what we need on the running server:
+
+ # Login to MySQL
+ mysql -u root -p
+
+ # Type the MySQL root password
+
+ # Enable innodb_file_per_table and set innodb_file_format on the running server:
+ mysql > SET GLOBAL innodb_file_per_table=1, innodb_file_format=Barracuda;
+
+ # You can now quit the database session
+ mysql> \q
+
+> Now, **persist** [innodb_file_per_table](https://dev.mysql.com/doc/refman/5.6/en/tablespace-enabling.html) and [innodb_file_format](https://dev.mysql.com/doc/refman/5.6/en/innodb-file-format-enabling.html) in your `my.cnf` file.
+
+Ensure at this stage that your GitLab instance is indeed **stopped**.
+
+Now, let's convert all the GitLab database tables to the new tablespace format:
+
+ # Login to MySQL
+ mysql -u root -p
+
+ # Type the MySQL root password
+ mysql > use gitlabhq_production;
+
+ # Safety check: you should still have those values set as follow:
+ mysql> SELECT @@innodb_file_per_table, @@innodb_file_format;
+ +-------------------------+----------------------+
+ | @@innodb_file_per_table | @@innodb_file_format |
+ +-------------------------+----------------------+
+ | 1 | Barracuda |
+ +-------------------------+----------------------+
+
+ mysql > SELECT CONCAT('ALTER TABLE `', TABLE_NAME,'` ENGINE=InnoDB;') AS 'Copy & run these SQL statements:' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="gitlabhq_production" AND TABLE_TYPE="BASE TABLE";
+
+ # If previous query returned results, copy & run all shown SQL statements
+
+ # You can now quit the database session
+ mysql> \q
+
+---
+
+#### Check for proper InnoDB File Format, Row Format, Large Prefix and tables conversion
+
+We need to check, enable and probably convert your existing GitLab DB tables to use the [Barracuda InnoDB file format](https://dev.mysql.com/doc/refman/5.6/en/innodb-file-format.html), the [DYNAMIC row format](https://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_dynamic_row_format) and [innodb_large_prefix](http://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_large_prefix) as a second prerequisite for supporting **utfb8mb4 with long indexes** used by recent GitLab databases.
+
+ # Login to MySQL
+ mysql -u root -p
+
+ # Type the MySQL root password
+ mysql > use gitlabhq_production;
+
+ # Set innodb_file_format and innodb_large_prefix on the running server:
+ # Note: These are the default settings only for MySQL 5.7.7 and later.
+
+ mysql > SET GLOBAL innodb_file_format=Barracuda, innodb_large_prefix=1;
+
+ # Your DB must be (still) using utf8/utf8_general_ci as default encoding and collation.
+ # We will NOT change the default encoding and collation on the DB in order to support future GitLab migrations creating tables
+ # that require "long indexes support" on installations using MySQL <= 5.7.9.
+ # However, when such migrations occur, you will have to follow this guide again to convert the newly created tables to the proper encoding/collation.
+
+ # This should return the following:
+ mysql> SELECT @@character_set_database, @@collation_database;
+ +--------------------------+----------------------+
+ | @@character_set_database | @@collation_database |
+ +--------------------------+----------------------+
+ | utf8 | utf8_general_ci |
+ +--------------------------+----------------------+
+
+> Now, ensure that [innodb_file_format](https://dev.mysql.com/doc/refman/5.6/en/tablespace-enabling.html) and [innodb_large_prefix](http://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_large_prefix) are **persisted** in your `my.cnf` file.
+
+#### Tables and data conversion to utf8mb4
+<a name="convert"></a>
+
+Now that you have a persistent MySQL setup, you can safely upgrade tables after setup or upgrade time:
+
+ # Convert tables not using ROW_FORMAT DYNAMIC:
+
+ mysql> SELECT CONCAT('ALTER TABLE `', TABLE_NAME,'` ROW_FORMAT=DYNAMIC;') AS 'Copy & run these SQL statements:' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="gitlabhq_production" AND TABLE_TYPE="BASE TABLE" AND ROW_FORMAT!="Dynamic";
+
+ # !! If previous query returned results, copy & run all shown SQL statements
+
+ # Convert tables/columns not using utf8mb4/utf8mb4_general_ci as encoding/collation:
+
+ mysql > SET foreign_key_checks = 0;
+
+ mysql > SELECT CONCAT('ALTER TABLE `', TABLE_NAME,'` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;') AS 'Copy & run these SQL statements:' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="gitlabhq_production" AND TABLE_COLLATION != "utf8mb4_general_ci" AND TABLE_TYPE="BASE TABLE";
+
+ # !! If previous query returned results, copy & run all shown SQL statements
+
+ # Turn foreign key checks back on
+ mysql > SET foreign_key_checks = 1;
+
+ # You can now quit the database session
+ mysql> \q
+
+Ensure your GitLab database configuration file uses a proper connection encoding and collation:
+
+```sudo -u git -H editor config/database.yml```
+
+ production:
+ adapter: mysql2
+ encoding: utf8mb4
+ collation: utf8mb4_general_ci
+
+[Restart your GitLab instance](../administration/restart_gitlab.md).
+
## MySQL strings limits
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index c44930a4ceb..ec13c2446ef 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -1,6 +1,6 @@
# System hooks
-Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `project_rename`, `project_transfer`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create`, `key_destroy`, `group_create`, `group_destroy`, `user_add_to_group` and `user_remove_from_group`.
+Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `project_rename`, `project_transfer`, `project_update`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create`, `key_destroy`, `group_create`, `group_destroy`, `user_add_to_group` and `user_remove_from_group`.
System hooks can be used, e.g. for logging or changing information in a LDAP server.
@@ -88,6 +88,23 @@ X-Gitlab-Event: System Hook
}
```
+**Project updated:**
+
+```json
+{
+ "created_at": "2012-07-21T07:30:54Z",
+ "updated_at": "2012-07-21T07:38:22Z",
+ "event_name": "project_update",
+ "name": "StoreCloud",
+ "owner_email": "johnsmith@gmail.com",
+ "owner_name": "John Smith",
+ "path": "storecloud",
+ "path_with_namespace": "jsmith/storecloud",
+ "project_id": 74,
+ "project_visibility": "private",
+}
+```
+
**New Team Member:**
```json
diff --git a/doc/update/8.15-to-8.16.md b/doc/update/8.15-to-8.16.md
index 63f3c3fdda9..2695a16ac0b 100644
--- a/doc/update/8.15-to-8.16.md
+++ b/doc/update/8.15-to-8.16.md
@@ -97,6 +97,8 @@ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
```
+**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md).
+
### 6. Update gitlab-workhorse
Install and compile gitlab-workhorse. This requires
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index 0f959b956a5..cc688a7f99c 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -140,75 +140,77 @@ into the password field.
## Recovery options
-If you lose your code generation device (such as your mobile phone) and you need
-to disable two-factor authentication on your account, you have several options.
+To disable two-factor authentication on your account (for example, if you
+have lost your code generation device) you can:
+* [Use a saved recovery code](#use-a-saved-recovery-code)
+* [Generate new recovery codes using SSH](#generate-new-recovery-codes-using-SSH)
+* [Ask a GitLab administrator to disable two-factor authentication on your account](#ask-a-gitlab-administrator-to-disable-two-factor-authentication-on-your-account)
### Use a saved recovery code
-When you enabled two-factor authentication for your account, a series of
-recovery codes were generated. If you saved those codes somewhere safe, you
-may use one to sign in.
+Enabling two-factor authentication for your account generated several recovery
+codes. If you saved these codes, you can use one of them to sign in.
-First, enter your username/email and password on the GitLab sign in page. When
-prompted for a two-factor code, enter one of the recovery codes you saved
-previously.
+To use a recovery code, enter your username/email and password on the GitLab
+sign-in page. When prompted for a two-factor code, enter the recovery code.
-> **Note:** Once a particular recovery code has been used, it cannot be used again.
- You may still use the other saved recovery codes at a later time.
+> **Note:** Once you use a recovery code, you cannot re-use it. You can still
+ use the other recovery codes you saved.
### Generate new recovery codes using SSH
-It's not uncommon for users to forget to save the recovery codes when enabling
-two-factor authentication. If you have an SSH key added to your GitLab account,
-you can generate a new set of recovery codes using SSH.
-
-Run `ssh git@gitlab.example.com 2fa_recovery_codes`. You will be prompted to
-confirm that you wish to generate new codes. If you choose to continue, any
-previously saved codes will be invalidated.
-
-```bash
-$ ssh git@gitlab.example.com 2fa_recovery_codes
-Are you sure you want to generate new two-factor recovery codes?
-Any existing recovery codes you saved will be invalidated. (yes/no)
-yes
-
-Your two-factor authentication recovery codes are:
-
-119135e5a3ebce8e
-11f6v2a498810dcd
-3924c7ab2089c902
-e79a3398bfe4f224
-34bd7b74adbc8861
-f061691d5107df1a
-169bf32a18e63e7f
-b510e7422e81c947
-20dbed24c5e74663
-df9d3b9403b9c9f0
-
-During sign in, use one of the codes above when prompted for
-your two-factor code. Then, visit your Profile Settings and add
-a new device so you do not lose access to your account again.
-```
-
-Next, go to the GitLab sign in page and enter your username/email and password.
-When prompted for a two-factor code, enter one of the recovery codes obtained
-from the command line output.
-
-> **Note:** After signing in, you should immediately visit your **Profile Settings
- -> Account** to set up two-factor authentication with a new device.
-
-### Ask a GitLab administrator to disable two-factor on your account
-
-If the above two methods are not possible, you may ask a GitLab global
-administrator to disable two-factor authentication for your account. Please
-be aware that this will temporarily leave your account in a less secure state.
-You should sign in and re-enable two-factor authentication as soon as possible
-after the administrator disables it.
+Users often forget to save their recovery codes when enabling two-factor
+authentication. If an SSH key is added to your GitLab account, you can generate
+a new set of recovery codes with SSH.
+
+1. Run `ssh git@gitlab.example.com 2fa_recovery_codes`.
+2. You are prompted to confirm that you want to generate new codes. Continuing this process invalidates previously saved codes.
+ ```
+ bash
+ $ ssh git@gitlab.example.com 2fa_recovery_codes
+ Are you sure you want to generate new two-factor recovery codes?
+ Any existing recovery codes you saved will be invalidated. (yes/no)
+
+ yes
+
+ Your two-factor authentication recovery codes are:
+
+ 119135e5a3ebce8e
+ 11f6v2a498810dcd
+ 3924c7ab2089c902
+ e79a3398bfe4f224
+ 34bd7b74adbc8861
+ f061691d5107df1a
+ 169bf32a18e63e7f
+ b510e7422e81c947
+ 20dbed24c5e74663
+ df9d3b9403b9c9f0
+
+ During sign in, use one of the codes above when prompted for your
+ two-factor code. Then, visit your Profile Settings and add a new device
+ so you do not lose access to your account again.
+ ```
+3. Go to the GitLab sign-in page and enter your username/email and password. When prompted for a two-factor code, enter one of the recovery codes obtained
+from the command-line output.
+
+> **Note:** After signing in, visit your **Profile Settings -> Account** immediately to set up two-factor authentication with a new
+ device.
+
+### Ask a GitLab administrator to disable two-factor authentication on your account
+
+If you cannot use a saved recovery code or generate new recovery codes, ask a
+GitLab global administrator to disable two-factor authentication for your
+account. This will temporarily leave your account in a less secure state.
+Sign in and re-enable two-factor authentication as soon as possible.
## Note to GitLab administrators
-You need to take special care to that 2FA keeps working after
-[restoring a GitLab backup](../../../raketasks/backup_restore.md).
+- You need to take special care to that 2FA keeps working after
+[restoring a GitLab backup](../raketasks/backup_restore.md).
+
+- To ensure 2FA authorizes correctly with TOTP server, you may want to ensure
+your GitLab server's time is synchronized via a service like NTP. Otherwise,
+you may have cases where authorization always fails because of time differences.
[Google Authenticator]: https://support.google.com/accounts/answer/1066447?hl=en
[FreeOTP]: https://fedorahosted.org/freeotp/
diff --git a/features/steps/project/merge_requests/revert.rb b/features/steps/project/merge_requests/revert.rb
index 3cc4fe9dafb..31f95b524b3 100644
--- a/features/steps/project/merge_requests/revert.rb
+++ b/features/steps/project/merge_requests/revert.rb
@@ -30,14 +30,13 @@ class Spinach::Features::RevertMergeRequests < Spinach::FeatureSteps
end
step 'I am signed in as a developer of the project' do
+ @user = create(:user) { |u| @project.add_developer(u) }
login_as(@user)
end
step 'There is an open Merge Request' do
- @user = create(:user)
- @project = create(:project, :public, :repository)
- @project_member = create(:project_member, :developer, user: @user, project: @project)
- @merge_request = create(:merge_request, :with_diffs, :simple, source_project: @project)
+ @merge_request = create(:merge_request, :with_diffs, :simple)
+ @project = @merge_request.source_project
end
step 'I should see a revert error' do
diff --git a/features/support/env.rb b/features/support/env.rb
index 8dbe3624410..f394c30d52f 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -4,7 +4,6 @@ SimpleCovEnv.start!
ENV['RAILS_ENV'] = 'test'
require './config/environment'
require 'rspec/expectations'
-require 'sidekiq/testing/inline'
require_relative 'capybara'
require_relative 'db_cleaner'
@@ -15,7 +14,7 @@ if ENV['CI']
Knapsack::Adapters::SpinachAdapter.bind
end
-%w(select2_helper test_env repo_helpers wait_for_ajax).each do |f|
+%w(select2_helper test_env repo_helpers wait_for_ajax sidekiq).each do |f|
require Rails.root.join('spec', 'support', f)
end
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index 6d04f68c8f9..a3d495a5da0 100644
--- a/lib/banzai/filter/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -153,7 +153,7 @@ module Banzai
title = object_link_title(object)
klass = reference_class(object_sym)
- data = data_attributes_for(link_content || match, project, object)
+ data = data_attributes_for(link_content || match, project, object, link: !!link_content)
if matches.names.include?("url") && matches[:url]
url = matches[:url]
@@ -172,9 +172,10 @@ module Banzai
end
end
- def data_attributes_for(text, project, object)
+ def data_attributes_for(text, project, object, link: false)
data_attribute(
original: text,
+ link: link,
project: project.id,
object_sym => object.id
)
diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb
index 4d1bc687696..fd6b9704132 100644
--- a/lib/banzai/filter/issue_reference_filter.rb
+++ b/lib/banzai/filter/issue_reference_filter.rb
@@ -62,7 +62,7 @@ module Banzai
end
end
- def data_attributes_for(text, project, object)
+ def data_attributes_for(text, project, object, link: false)
if object.is_a?(ExternalIssue)
data_attribute(
project: project.id,
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index 026b81ac175..a447e2b8bff 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -20,17 +20,19 @@ module Banzai
code = node.text
css_classes = "code highlight"
lexer = lexer_for(language)
+ lang = lexer.tag
begin
code = format(lex(lexer, code))
- css_classes << " js-syntax-highlight #{lexer.tag}"
+ css_classes << " js-syntax-highlight #{lang}"
rescue
+ lang = nil
# Gracefully handle syntax highlighter bugs/errors to ensure
# users can still access an issue/comment/etc.
end
- highlighted = %(<pre class="#{css_classes}" v-pre="true"><code>#{code}</code></pre>)
+ highlighted = %(<pre class="#{css_classes}" lang="#{lang}" v-pre="true"><code>#{code}</code></pre>)
# Extracted to a method to measure it
replace_parent_pre_element(node, highlighted)
diff --git a/lib/banzai/filter/video_link_filter.rb b/lib/banzai/filter/video_link_filter.rb
index ac7bbcb0d10..b64a1287d4d 100644
--- a/lib/banzai/filter/video_link_filter.rb
+++ b/lib/banzai/filter/video_link_filter.rb
@@ -35,7 +35,8 @@ module Banzai
src: element['src'],
width: '400',
controls: true,
- 'data-setup' => '{}')
+ 'data-setup' => '{}',
+ 'data-title' => element['title'] || element['alt'])
link = doc.document.create_element(
'a',
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
index 5a1f873496c..ac95a79009b 100644
--- a/lib/banzai/pipeline/gfm_pipeline.rb
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -1,6 +1,12 @@
module Banzai
module Pipeline
class GfmPipeline < BasePipeline
+ # These filters convert GitLab Flavored Markdown (GFM) to HTML.
+ # The handlers defined in app/assets/javascripts/copy_as_gfm.js.es6
+ # consequently convert that same HTML to GFM to be copied to the clipboard.
+ # Every filter that generates HTML from GFM should have a handler in
+ # app/assets/javascripts/copy_as_gfm.js.es6, in reverse order.
+ # The GFM-to-HTML-to-GFM cycle is tested in spec/features/copy_as_gfm_spec.rb.
def self.filters
@filters ||= FilterArray[
Filter::SyntaxHighlightFilter,
diff --git a/lib/gitlab/ci/trace_reader.rb b/lib/gitlab/ci/trace_reader.rb
index 37e51536e8f..1d7ddeb3e0f 100644
--- a/lib/gitlab/ci/trace_reader.rb
+++ b/lib/gitlab/ci/trace_reader.rb
@@ -42,6 +42,7 @@ module Gitlab
end
chunks.join.lines.last(max_lines).join
+ .force_encoding(Encoding.default_external)
end
end
end
diff --git a/lib/gitlab/job_waiter.rb b/lib/gitlab/job_waiter.rb
new file mode 100644
index 00000000000..8db91d25a4b
--- /dev/null
+++ b/lib/gitlab/job_waiter.rb
@@ -0,0 +1,27 @@
+module Gitlab
+ # JobWaiter can be used to wait for a number of Sidekiq jobs to complete.
+ class JobWaiter
+ # The sleep interval between checking keys, in seconds.
+ INTERVAL = 0.1
+
+ # jobs - The job IDs to wait for.
+ def initialize(jobs)
+ @jobs = jobs
+ end
+
+ # Waits for all the jobs to be completed.
+ #
+ # timeout - The maximum amount of seconds to block the caller for. This
+ # ensures we don't indefinitely block a caller in case a job takes
+ # long to process, or is never processed.
+ def wait(timeout = 60)
+ start = Time.current
+
+ while (Time.current - start) <= timeout
+ break if SidekiqStatus.all_completed?(@jobs)
+
+ sleep(INTERVAL) # to not overload Redis too much.
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/sidekiq_status.rb b/lib/gitlab/sidekiq_status.rb
new file mode 100644
index 00000000000..aadc401ff8d
--- /dev/null
+++ b/lib/gitlab/sidekiq_status.rb
@@ -0,0 +1,66 @@
+module Gitlab
+ # The SidekiqStatus module and its child classes can be used for checking if a
+ # Sidekiq job has been processed or not.
+ #
+ # To check if a job has been completed, simply pass the job ID to the
+ # `completed?` method:
+ #
+ # job_id = SomeWorker.perform_async(...)
+ #
+ # if Gitlab::SidekiqStatus.completed?(job_id)
+ # ...
+ # end
+ #
+ # For each job ID registered a separate key is stored in Redis, making lookups
+ # much faster than using Sidekiq's built-in job finding/status API. These keys
+ # expire after a certain period of time to prevent storing too many keys in
+ # Redis.
+ module SidekiqStatus
+ STATUS_KEY = 'gitlab-sidekiq-status:%s'.freeze
+
+ # The default time (in seconds) after which a status key is expired
+ # automatically. The default of 30 minutes should be more than sufficient
+ # for most jobs.
+ DEFAULT_EXPIRATION = 30.minutes.to_i
+
+ # Starts tracking of the given job.
+ #
+ # jid - The Sidekiq job ID
+ # expire - The expiration time of the Redis key.
+ def self.set(jid, expire = DEFAULT_EXPIRATION)
+ Sidekiq.redis do |redis|
+ redis.set(key_for(jid), 1, ex: expire)
+ end
+ end
+
+ # Stops the tracking of the given job.
+ #
+ # jid - The Sidekiq job ID to remove.
+ def self.unset(jid)
+ Sidekiq.redis do |redis|
+ redis.del(key_for(jid))
+ end
+ end
+
+ # Returns true if all the given job have been completed.
+ #
+ # jids - The Sidekiq job IDs to check.
+ #
+ # Returns true or false.
+ def self.all_completed?(jids)
+ keys = jids.map { |jid| key_for(jid) }
+
+ responses = Sidekiq.redis do |redis|
+ redis.pipelined do
+ keys.each { |key| redis.exists(key) }
+ end
+ end
+
+ responses.all? { |value| !value }
+ end
+
+ def self.key_for(jid)
+ STATUS_KEY % jid
+ end
+ end
+end
diff --git a/lib/gitlab/sidekiq_status/client_middleware.rb b/lib/gitlab/sidekiq_status/client_middleware.rb
new file mode 100644
index 00000000000..779a9998b22
--- /dev/null
+++ b/lib/gitlab/sidekiq_status/client_middleware.rb
@@ -0,0 +1,10 @@
+module Gitlab
+ module SidekiqStatus
+ class ClientMiddleware
+ def call(_, job, _, _)
+ SidekiqStatus.set(job['jid'])
+ yield
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/sidekiq_status/server_middleware.rb b/lib/gitlab/sidekiq_status/server_middleware.rb
new file mode 100644
index 00000000000..31dfa46ff9d
--- /dev/null
+++ b/lib/gitlab/sidekiq_status/server_middleware.rb
@@ -0,0 +1,13 @@
+module Gitlab
+ module SidekiqStatus
+ class ServerMiddleware
+ def call(worker, job, queue)
+ ret = yield
+
+ SidekiqStatus.unset(job['jid'])
+
+ ret
+ end
+ end
+ end
+end
diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb
index 602de72d23f..84db26a958a 100644
--- a/spec/controllers/admin/groups_controller_spec.rb
+++ b/spec/controllers/admin/groups_controller_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Admin::GroupsController do
let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
+ let(:project) { create(:empty_project, namespace: group) }
let(:admin) { create(:admin) }
before do
diff --git a/spec/controllers/admin/projects_controller_spec.rb b/spec/controllers/admin/projects_controller_spec.rb
index 8eaacef2024..2c35d394b74 100644
--- a/spec/controllers/admin/projects_controller_spec.rb
+++ b/spec/controllers/admin/projects_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Admin::ProjectsController do
- let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
+ let!(:project) { create(:empty_project, :public) }
before do
sign_in(create(:admin))
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index ea2fd90a9b0..7d2f6dd9d0a 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe AutocompleteController do
- let!(:project) { create(:project) }
+ let!(:project) { create(:empty_project) }
let!(:user) { create(:user) }
context 'GET users' do
diff --git a/spec/controllers/blob_controller_spec.rb b/spec/controllers/blob_controller_spec.rb
index 465013231f9..2fcb4a6a528 100644
--- a/spec/controllers/blob_controller_spec.rb
+++ b/spec/controllers/blob_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::BlobController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/ci/projects_controller_spec.rb b/spec/controllers/ci/projects_controller_spec.rb
index 5022a3e2c80..86f01f437a2 100644
--- a/spec/controllers/ci/projects_controller_spec.rb
+++ b/spec/controllers/ci/projects_controller_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Ci::ProjectsController do
let(:visibility) { :public }
- let!(:project) { create(:project, visibility, ci_id: 1) }
+ let!(:project) { create(:empty_project, visibility, ci_id: 1) }
let(:ci_id) { project.ci_id }
describe '#index' do
diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb
index 19fbc2f7748..79ef3a1adad 100644
--- a/spec/controllers/dashboard/todos_controller_spec.rb
+++ b/spec/controllers/dashboard/todos_controller_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Dashboard::TodosController do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:todo_service) { TodoService.new }
describe 'GET #index' do
diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb
index 8c52f615b8b..6e4b5f78e33 100644
--- a/spec/controllers/groups/milestones_controller_spec.rb
+++ b/spec/controllers/groups/milestones_controller_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Groups::MilestonesController do
let(:group) { create(:group) }
- let(:project) { create(:project, group: group) }
+ let(:project) { create(:empty_project, group: group) }
let(:project2) { create(:empty_project, group: group) }
let(:user) { create(:user) }
let(:title) { '肯定不是中文的问题' }
diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb
index 98dfb3e5216..cad82a34fb0 100644
--- a/spec/controllers/groups_controller_spec.rb
+++ b/spec/controllers/groups_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
describe GroupsController do
let(:user) { create(:user) }
let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
+ let(:project) { create(:empty_project, namespace: group) }
let!(:group_member) { create(:group_member, group: group, user: user) }
describe 'GET #index' do
diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb
index ce7c0b334ee..fa4cc0ebbe0 100644
--- a/spec/controllers/import/bitbucket_controller_spec.rb
+++ b/spec/controllers/import/bitbucket_controller_spec.rb
@@ -52,7 +52,7 @@ describe Import::BitbucketController do
end
it "assigns variables" do
- @project = create(:project, import_type: 'bitbucket', creator_id: user.id)
+ @project = create(:empty_project, import_type: 'bitbucket', creator_id: user.id)
allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo])
get :status
@@ -63,7 +63,7 @@ describe Import::BitbucketController do
end
it "does not show already added project" do
- @project = create(:project, import_type: 'bitbucket', creator_id: user.id, import_source: 'asd/vim')
+ @project = create(:empty_project, import_type: 'bitbucket', creator_id: user.id, import_source: 'asd/vim')
allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo])
get :status
diff --git a/spec/controllers/import/fogbugz_controller_spec.rb b/spec/controllers/import/fogbugz_controller_spec.rb
index 5f0f6dea821..fffbc805335 100644
--- a/spec/controllers/import/fogbugz_controller_spec.rb
+++ b/spec/controllers/import/fogbugz_controller_spec.rb
@@ -16,7 +16,7 @@ describe Import::FogbugzController do
end
it 'assigns variables' do
- @project = create(:project, import_type: 'fogbugz', creator_id: user.id)
+ @project = create(:empty_project, import_type: 'fogbugz', creator_id: user.id)
stub_client(repos: [@repo])
get :status
@@ -26,7 +26,7 @@ describe Import::FogbugzController do
end
it 'does not show already added project' do
- @project = create(:project, import_type: 'fogbugz', creator_id: user.id, import_source: 'vim')
+ @project = create(:empty_project, import_type: 'fogbugz', creator_id: user.id, import_source: 'vim')
stub_client(repos: [@repo])
get :status
diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb
index 6f75ebb16c8..3f73ea000ae 100644
--- a/spec/controllers/import/gitlab_controller_spec.rb
+++ b/spec/controllers/import/gitlab_controller_spec.rb
@@ -36,7 +36,7 @@ describe Import::GitlabController do
end
it "assigns variables" do
- @project = create(:project, import_type: 'gitlab', creator_id: user.id)
+ @project = create(:empty_project, import_type: 'gitlab', creator_id: user.id)
stub_client(projects: [@repo])
get :status
@@ -46,7 +46,7 @@ describe Import::GitlabController do
end
it "does not show already added project" do
- @project = create(:project, import_type: 'gitlab', creator_id: user.id, import_source: 'asd/vim')
+ @project = create(:empty_project, import_type: 'gitlab', creator_id: user.id, import_source: 'asd/vim')
stub_client(projects: [@repo])
get :status
diff --git a/spec/controllers/import/google_code_controller_spec.rb b/spec/controllers/import/google_code_controller_spec.rb
index 4241db6e771..c96fb90f70e 100644
--- a/spec/controllers/import/google_code_controller_spec.rb
+++ b/spec/controllers/import/google_code_controller_spec.rb
@@ -27,7 +27,7 @@ describe Import::GoogleCodeController do
end
it "assigns variables" do
- @project = create(:project, import_type: 'google_code', creator_id: user.id)
+ @project = create(:empty_project, import_type: 'google_code', creator_id: user.id)
stub_client(repos: [@repo], incompatible_repos: [])
get :status
@@ -38,7 +38,7 @@ describe Import::GoogleCodeController do
end
it "does not show already added project" do
- @project = create(:project, import_type: 'google_code', creator_id: user.id, import_source: 'vim')
+ @project = create(:empty_project, import_type: 'google_code', creator_id: user.id, import_source: 'vim')
stub_client(repos: [@repo], incompatible_repos: [])
get :status
diff --git a/spec/controllers/notification_settings_controller_spec.rb b/spec/controllers/notification_settings_controller_spec.rb
index 79b819a1377..9e3a31e1a6b 100644
--- a/spec/controllers/notification_settings_controller_spec.rb
+++ b/spec/controllers/notification_settings_controller_spec.rb
@@ -93,7 +93,7 @@ describe NotificationSettingsController do
end
context 'not authorized' do
- let(:private_project) { create(:project, :private) }
+ let(:private_project) { create(:empty_project, :private) }
before { sign_in(user) }
it 'returns 404' do
diff --git a/spec/controllers/projects/avatars_controller_spec.rb b/spec/controllers/projects/avatars_controller_spec.rb
index f5ea097af8b..8b71d6518bb 100644
--- a/spec/controllers/projects/avatars_controller_spec.rb
+++ b/spec/controllers/projects/avatars_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::AvatarsController do
- let(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
+ let(:project) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/blame_controller_spec.rb b/spec/controllers/projects/blame_controller_spec.rb
index 4402ca43c65..addc5e7ec33 100644
--- a/spec/controllers/projects/blame_controller_spec.rb
+++ b/spec/controllers/projects/blame_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::BlameController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index f35c5d992d9..b36d0e69330 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -1,7 +1,7 @@
require 'rails_helper'
describe Projects::BlobController do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index b88586b8678..9de03876755 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::BranchesController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:developer) { create(:user) }
diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb
index 0fa06a38d2a..a95cfc5c6be 100644
--- a/spec/controllers/projects/commit_controller_spec.rb
+++ b/spec/controllers/projects/commit_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::CommitController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:commit) { project.commit("master") }
let(:pipeline) { create(:ci_pipeline, project: project, commit: commit) }
diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb
index 1ac7e03a2db..54b8d1108a5 100644
--- a/spec/controllers/projects/commits_controller_spec.rb
+++ b/spec/controllers/projects/commits_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::CommitsController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb
index b03c4b52de6..e811c76fb31 100644
--- a/spec/controllers/projects/compare_controller_spec.rb
+++ b/spec/controllers/projects/compare_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::CompareController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:ref_from) { "improve%2Fawesome" }
let(:ref_to) { "feature" }
diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb
index a971adf0539..6a6d71a16ee 100644
--- a/spec/controllers/projects/cycle_analytics_controller_spec.rb
+++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::CycleAnalyticsController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/discussions_controller_spec.rb b/spec/controllers/projects/discussions_controller_spec.rb
index ff617fea847..79ab364a6f3 100644
--- a/spec/controllers/projects/discussions_controller_spec.rb
+++ b/spec/controllers/projects/discussions_controller_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
describe Projects::DiscussionsController do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:user) { create(:user) }
+ let(:merge_request) { create(:merge_request) }
+ let(:project) { merge_request.source_project }
let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
let(:discussion) { note.discussion }
diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb
index 038dfeb8466..a4884256c92 100644
--- a/spec/controllers/projects/find_file_controller_spec.rb
+++ b/spec/controllers/projects/find_file_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::FindFileController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb
index 028ea067a97..a867668d97b 100644
--- a/spec/controllers/projects/forks_controller_spec.rb
+++ b/spec/controllers/projects/forks_controller_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Projects::ForksController do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:forked_project) { Projects::ForkService.new(project, user).execute }
let(:group) { create(:group, owner: forked_project.creator) }
diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb
index 74e6603b0cb..bbe8e4bf6b2 100644
--- a/spec/controllers/projects/graphs_controller_spec.rb
+++ b/spec/controllers/projects/graphs_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::GraphsController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb
index 17dc101b7ee..a976a9c27ab 100644
--- a/spec/controllers/projects/group_links_controller_spec.rb
+++ b/spec/controllers/projects/group_links_controller_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Projects::GroupLinksController do
let(:group) { create(:group, :private) }
let(:group2) { create(:group, :private) }
- let(:project) { create(:project, :private, group: group2) }
+ let(:project) { create(:empty_project, :private, group: group2) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index b5987a83df0..5f27f336f72 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -98,7 +98,7 @@ describe Projects::IssuesController do
end
it 'fills in an issue for a merge request' do
- project_with_repository = create(:project)
+ project_with_repository = create(:project, :repository)
project_with_repository.team << [user, :developer]
mr = create(:merge_request_with_diff_notes, source_project: project_with_repository)
@@ -124,7 +124,7 @@ describe Projects::IssuesController do
describe 'PUT #update' do
context 'when moving issue to another private project' do
- let(:another_project) { create(:project, :private) }
+ let(:another_project) { create(:empty_project, :private) }
before do
sign_in(user)
@@ -466,7 +466,7 @@ describe Projects::IssuesController do
context "when the user is owner" do
let(:owner) { create(:user) }
let(:namespace) { create(:namespace, owner: owner) }
- let(:project) { create(:project, namespace: namespace) }
+ let(:project) { create(:empty_project, namespace: namespace) }
before { sign_in(owner) }
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index 6d30d085056..14207bf6b7a 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::MilestonesController do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:milestone) { create(:milestone, project: project) }
let(:issue) { create(:issue, project: project, milestone: milestone) }
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 9f6d4ec6537..dc597202050 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Projects::NotesController do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:note) { create(:note, noteable: issue, project: project) }
@@ -16,6 +16,7 @@ describe Projects::NotesController do
describe 'POST create' do
let(:merge_request) { create(:merge_request) }
+ let(:project) { merge_request.source_project }
let(:request_params) do
{
note: { note: 'some note', noteable_id: merge_request.id, noteable_type: 'MergeRequest' },
@@ -88,6 +89,7 @@ describe Projects::NotesController do
end
describe "resolving and unresolving" do
+ let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 442f81187dc..416eaa0037e 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -143,7 +143,7 @@ describe Projects::ProjectMembersController do
end
context 'and is an owner' do
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
before { project.team << [user, :master] }
@@ -234,7 +234,7 @@ describe Projects::ProjectMembersController do
end
describe 'POST apply_import' do
- let(:another_project) { create(:project, :private) }
+ let(:another_project) { create(:empty_project, :private) }
let(:member) { create(:user) }
before do
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index 04bd9a01f7b..b23d6e257ba 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::RawController do
- let(:public_project) { create(:project, :public) }
+ let(:public_project) { create(:project, :public, :repository) }
describe "#show" do
context 'regular filename' do
diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb
index abd45a74e2d..d8fb4667c67 100644
--- a/spec/controllers/projects/refs_controller_spec.rb
+++ b/spec/controllers/projects/refs_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::RefsController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb
index 9fd5c3b85f6..69fcc26c77e 100644
--- a/spec/controllers/projects/releases_controller_spec.rb
+++ b/spec/controllers/projects/releases_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::ReleasesController do
- let!(:project) { create(:project) }
+ let!(:project) { create(:project, :repository) }
let!(:user) { create(:user) }
let!(:release) { create(:release, project: project) }
let!(:tag) { release.tag }
diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb
index 38e02a46626..04e88879fb8 100644
--- a/spec/controllers/projects/repositories_controller_spec.rb
+++ b/spec/controllers/projects/repositories_controller_spec.rb
@@ -1,7 +1,7 @@
require "spec_helper"
describe Projects::RepositoriesController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
describe "GET archive" do
context 'as a guest' do
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index a6e708c01e4..16365642a34 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::ServicesController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:service) { create(:service, project: project) }
diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb
index e0f9a5b24a6..65f7bb34f4a 100644
--- a/spec/controllers/projects/settings/integrations_controller_spec.rb
+++ b/spec/controllers/projects/settings/integrations_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::Settings::IntegrationsController do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb
index 5e661c2c41d..c36a5fdd66c 100644
--- a/spec/controllers/projects/tags_controller_spec.rb
+++ b/spec/controllers/projects/tags_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::TagsController do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let!(:release) { create(:release, project: project) }
let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') }
diff --git a/spec/controllers/projects/templates_controller_spec.rb b/spec/controllers/projects/templates_controller_spec.rb
index 19a152bcb05..99d0bcfa8d1 100644
--- a/spec/controllers/projects/templates_controller_spec.rb
+++ b/spec/controllers/projects/templates_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::TemplatesController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:file_path_1) { '.gitlab/issue_templates/bug.md' }
diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb
index 1cc050247c6..b81645a3d2d 100644
--- a/spec/controllers/projects/tree_controller_spec.rb
+++ b/spec/controllers/projects/tree_controller_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::TreeController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb
index 71d0e4be834..f1c8891e87a 100644
--- a/spec/controllers/projects/uploads_controller_spec.rb
+++ b/spec/controllers/projects/uploads_controller_spec.rb
@@ -1,7 +1,7 @@
require('spec_helper')
describe Projects::UploadsController do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index d0a63aa9403..9323f723bdb 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -1,11 +1,11 @@
require('spec_helper')
describe ProjectsController do
- let(:project) { create(:project) }
- let(:public_project) { create(:project, :public) }
- let(:user) { create(:user) }
- let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
- let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
+ let(:project) { create(:empty_project) }
+ let(:public_project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
+ let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
describe 'GET index' do
context 'as a user' do
@@ -32,7 +32,7 @@ describe ProjectsController do
before { sign_in(user) }
context "user does not have access to project" do
- let(:private_project) { create(:project, :private) }
+ let(:private_project) { create(:empty_project, :private) }
it "does not initialize notification setting" do
get :show, namespace_id: private_project.namespace.path, id: private_project.path
@@ -146,6 +146,8 @@ describe ProjectsController do
end
context "rendering default project view" do
+ let(:public_project) { create(:project, :public, :repository) }
+
render_views
it "renders the activity view" do
@@ -190,25 +192,11 @@ describe ProjectsController do
expect(assigns(:project)).to eq(public_project)
expect(response).to redirect_to("/#{public_project.path_with_namespace}")
end
-
- # MySQL queries are case insensitive by default, so this spec would fail.
- if Gitlab::Database.postgresql?
- context "when there is also a match with the same casing" do
- let!(:other_project) { create(:project, :public, namespace: public_project.namespace, path: public_project.path.upcase) }
-
- it "loads the exactly matched project" do
- get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase
-
- expect(assigns(:project)).to eq(other_project)
- expect(response).to have_http_status(200)
- end
- end
- end
end
end
context "when the url contains .atom" do
- let(:public_project_with_dot_atom) { build(:project, :public, name: 'my.atom', path: 'my.atom') }
+ let(:public_project_with_dot_atom) { build(:empty_project, :public, name: 'my.atom', path: 'my.atom') }
it 'expects an error creating the project' do
expect(public_project_with_dot_atom).not_to be_valid
@@ -217,7 +205,7 @@ describe ProjectsController do
context 'when the project is pending deletions' do
it 'renders a 404 error' do
- project = create(:project, pending_delete: true)
+ project = create(:empty_project, pending_delete: true)
sign_in(user)
get :show, namespace_id: project.namespace.path, id: project.path
@@ -233,6 +221,7 @@ describe ProjectsController do
let(:admin) { create(:admin) }
it "sets the repository to the right path after a rename" do
+ project = create(:project, :repository)
new_path = 'renamed_path'
project_params = { path: new_path }
controller.instance_variable_set(:@project, project)
@@ -384,6 +373,8 @@ describe ProjectsController do
end
describe "GET refs" do
+ let(:public_project) { create(:project, :public) }
+
it "gets a list of branches and tags" do
get :refs, namespace_id: public_project.namespace.path, id: public_project.path
diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
index 69124ab06bf..570d9fa43f8 100644
--- a/spec/controllers/uploads_controller_spec.rb
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -41,7 +41,7 @@ describe UploadsController do
end
context "when viewing a project avatar" do
- let!(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
+ let!(:project) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
context "when the project is public" do
before do
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 19a8b1fe524..bbe9aaf737f 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -73,7 +73,7 @@ describe UsersController do
end
context 'forked project' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:forked_project) { Projects::ForkService.new(project, user).execute }
before do
@@ -91,7 +91,7 @@ describe UsersController do
end
describe 'GET #calendar_activities' do
- let!(:project) { create(:project) }
+ let!(:project) { create(:empty_project) }
let!(:user) { create(:user) }
before do
diff --git a/spec/factories/deploy_keys_projects.rb b/spec/factories/deploy_keys_projects.rb
index 27cece487bd..75f8982ecd9 100644
--- a/spec/factories/deploy_keys_projects.rb
+++ b/spec/factories/deploy_keys_projects.rb
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :deploy_keys_project do
deploy_key
- project
+ project factory: :empty_project
end
end
diff --git a/spec/factories/events.rb b/spec/factories/events.rb
index 8820d527c61..bfe41f71b57 100644
--- a/spec/factories/events.rb
+++ b/spec/factories/events.rb
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :event do
- project
+ project factory: :empty_project
author factory: :user
factory :closed_issue_event do
diff --git a/spec/factories/file_uploader.rb b/spec/factories/file_uploader.rb
index 1b36e21f2b0..bc74aeecc3b 100644
--- a/spec/factories/file_uploader.rb
+++ b/spec/factories/file_uploader.rb
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :file_uploader do
- project
+ project factory: :empty_project
secret nil
transient do
diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb
index 2b4670be468..7e09f1ba8ea 100644
--- a/spec/factories/issues.rb
+++ b/spec/factories/issues.rb
@@ -6,7 +6,7 @@ FactoryGirl.define do
factory :issue do
title
author
- project
+ project factory: :empty_project
trait :confidential do
confidential true
diff --git a/spec/factories/labels.rb b/spec/factories/labels.rb
index 3e8822faf97..5ba8443c62c 100644
--- a/spec/factories/labels.rb
+++ b/spec/factories/labels.rb
@@ -2,7 +2,7 @@ FactoryGirl.define do
factory :label, class: ProjectLabel do
sequence(:title) { |n| "label#{n}" }
color "#990000"
- project
+ project factory: :empty_project
transient do
priority nil
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 37eb49c94df..22f84150bb3 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -2,7 +2,7 @@ FactoryGirl.define do
factory :merge_request do
title
author
- source_project factory: :project
+ association :source_project, :repository, factory: :project
target_project { source_project }
# $ git log --pretty=oneline feature..master
diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb
index 84da71ed6dc..841ab3c73b8 100644
--- a/spec/factories/milestones.rb
+++ b/spec/factories/milestones.rb
@@ -1,7 +1,7 @@
FactoryGirl.define do
factory :milestone do
title
- project
+ project factory: :empty_project
trait :active do
state "active"
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 476f2a37793..a21da7074f9 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -4,7 +4,7 @@ include ActionDispatch::TestProcess
FactoryGirl.define do
factory :note do
- project
+ project factory: :empty_project
note "Note"
author
on_issue
@@ -16,10 +16,16 @@ FactoryGirl.define do
factory :note_on_personal_snippet, traits: [:on_personal_snippet]
factory :system_note, traits: [:system]
- factory :legacy_diff_note_on_commit, traits: [:on_commit, :legacy_diff_note], class: LegacyDiffNote
- factory :legacy_diff_note_on_merge_request, traits: [:on_merge_request, :legacy_diff_note], class: LegacyDiffNote
+ factory :legacy_diff_note_on_commit, traits: [:on_commit, :legacy_diff_note], class: LegacyDiffNote do
+ association :project, :repository
+ end
+
+ factory :legacy_diff_note_on_merge_request, traits: [:on_merge_request, :legacy_diff_note], class: LegacyDiffNote do
+ association :project, :repository
+ end
factory :diff_note_on_merge_request, traits: [:on_merge_request], class: DiffNote do
+ association :project, :repository
position do
Gitlab::Diff::Position.new(
old_path: "files/ruby/popen.rb",
@@ -37,6 +43,7 @@ FactoryGirl.define do
end
factory :diff_note_on_commit, traits: [:on_commit], class: DiffNote do
+ association :project, :repository
position do
Gitlab::Diff::Position.new(
old_path: "files/ruby/popen.rb",
@@ -49,6 +56,7 @@ FactoryGirl.define do
end
trait :on_commit do
+ association :project, :repository
noteable nil
noteable_type 'Commit'
noteable_id nil
diff --git a/spec/factories/project_group_links.rb b/spec/factories/project_group_links.rb
index e73cc05f9d7..50341d943f5 100644
--- a/spec/factories/project_group_links.rb
+++ b/spec/factories/project_group_links.rb
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :project_group_link do
- project
+ project factory: :empty_project
group
end
end
diff --git a/spec/factories/project_members.rb b/spec/factories/project_members.rb
index c21927640d1..d62799a5a47 100644
--- a/spec/factories/project_members.rb
+++ b/spec/factories/project_members.rb
@@ -1,7 +1,7 @@
FactoryGirl.define do
factory :project_member do
user
- project
+ project factory: :empty_project
master
trait(:guest) { access_level ProjectMember::GUEST }
diff --git a/spec/factories/project_snippets.rb b/spec/factories/project_snippets.rb
index d681a2c8483..e0fe1b36fd3 100644
--- a/spec/factories/project_snippets.rb
+++ b/spec/factories/project_snippets.rb
@@ -1,5 +1,5 @@
FactoryGirl.define do
factory :project_snippet, parent: :snippet, class: :ProjectSnippet do
- project
+ project factory: :empty_project
end
end
diff --git a/spec/factories/releases.rb b/spec/factories/releases.rb
index 74497dc82c0..6a6d6fa171f 100644
--- a/spec/factories/releases.rb
+++ b/spec/factories/releases.rb
@@ -2,6 +2,6 @@ FactoryGirl.define do
factory :release do
tag "v1.1.0"
description "Awesome release"
- project
+ project factory: :empty_project
end
end
diff --git a/spec/factories/sent_notifications.rb b/spec/factories/sent_notifications.rb
index 78eb929c6e7..6287c40afe9 100644
--- a/spec/factories/sent_notifications.rb
+++ b/spec/factories/sent_notifications.rb
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :sent_notification do
- project
+ project factory: :empty_project
recipient factory: :user
noteable factory: :issue
reply_key "0123456789abcdef" * 2
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index 9de78d68280..a14a46c803e 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -1,5 +1,5 @@
FactoryGirl.define do
factory :service do
- project
+ project factory: :empty_project
end
end
diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb
index 85a8c263643..91d6f39a5bf 100644
--- a/spec/factories/todos.rb
+++ b/spec/factories/todos.rb
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :todo do
- project
+ project factory: :empty_project
author
user
target factory: :issue
diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb
new file mode 100644
index 00000000000..f3a5b565122
--- /dev/null
+++ b/spec/features/copy_as_gfm_spec.rb
@@ -0,0 +1,432 @@
+require 'spec_helper'
+
+describe 'Copy as GFM', feature: true, js: true do
+ include GitlabMarkdownHelper
+ include ActionView::Helpers::JavaScriptHelper
+
+ before do
+ @feat = MarkdownFeature.new
+
+ # `markdown` helper expects a `@project` variable
+ @project = @feat.project
+
+ visit namespace_project_issue_path(@project.namespace, @project, @feat.issue)
+ end
+
+ # The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert GitLab Flavored Markdown (GFM) to HTML.
+ # The handlers defined in app/assets/javascripts/copy_as_gfm.js.es6 consequently convert that same HTML to GFM.
+ # To make sure these filters and handlers are properly aligned, this spec tests the GFM-to-HTML-to-GFM cycle
+ # by verifying (`html_to_gfm(gfm_to_html(gfm)) == gfm`) for a number of examples of GFM for every filter, using the `verify` helper.
+
+ # These are all in a single `it` for performance reasons.
+ it 'works', :aggregate_failures do
+ verify(
+ 'nesting',
+
+ '> 1. [x] **[$`2 + 2`$ {-=-}{+=+} 2^2 ~~:thumbsup:~~](http://google.com)**'
+ )
+
+ verify(
+ 'a real world example from the gitlab-ce README',
+
+ <<-GFM.strip_heredoc
+ # GitLab
+
+ [![Build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
+ [![CE coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby)
+ [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
+ [![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42)
+
+ ## Canonical source
+
+ The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/).
+
+ ## Open source software to collaborate on code
+
+ To see how GitLab looks please see the [features page on our website](https://about.gitlab.com/features/).
+
+
+ - Manage Git repositories with fine grained access controls that keep your code secure
+
+ - Perform code reviews and enhance collaboration with merge requests
+
+ - Complete continuous integration (CI) and CD pipelines to builds, test, and deploy your applications
+
+ - Each project can also have an issue tracker, issue board, and a wiki
+
+ - Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises
+
+ - Completely free and open source (MIT Expat license)
+ GFM
+ )
+
+ verify(
+ 'InlineDiffFilter',
+
+ '{-Deleted text-}',
+ '{+Added text+}'
+ )
+
+ verify(
+ 'TaskListFilter',
+
+ '- [ ] Unchecked task',
+ '- [x] Checked task',
+ '1. [ ] Unchecked numbered task',
+ '1. [x] Checked numbered task'
+ )
+
+ verify(
+ 'ReferenceFilter',
+
+ # issue reference
+ @feat.issue.to_reference,
+ # full issue reference
+ @feat.issue.to_reference(full: true),
+ # issue URL
+ namespace_project_issue_url(@project.namespace, @project, @feat.issue),
+ # issue URL with note anchor
+ namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123'),
+ # issue link
+ "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue)})",
+ # issue link with note anchor
+ "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123')})",
+ )
+
+ verify(
+ 'AutolinkFilter',
+
+ 'https://example.com'
+ )
+
+ verify(
+ 'TableOfContentsFilter',
+
+ '[[_TOC_]]'
+ )
+
+ verify(
+ 'EmojiFilter',
+
+ ':thumbsup:'
+ )
+
+ verify(
+ 'ImageLinkFilter',
+
+ '![Image](https://example.com/image.png)'
+ )
+
+ verify(
+ 'VideoLinkFilter',
+
+ '![Video](https://example.com/video.mp4)'
+ )
+
+ verify(
+ 'MathFilter: math as converted from GFM to HTML',
+
+ '$`c = \pm\sqrt{a^2 + b^2}`$',
+
+ # math block
+ <<-GFM.strip_heredoc
+ ```math
+ c = \pm\sqrt{a^2 + b^2}
+ ```
+ GFM
+ )
+
+ aggregate_failures('MathFilter: math as transformed from HTML to KaTeX') do
+ gfm = '$`c = \pm\sqrt{a^2 + b^2}`$'
+
+ html = <<-HTML.strip_heredoc
+ <span class="katex">
+ <span class="katex-mathml">
+ <math>
+ <semantics>
+ <mrow>
+ <mi>c</mi>
+ <mo>=</mo>
+ <mo>±</mo>
+ <msqrt>
+ <mrow>
+ <msup>
+ <mi>a</mi>
+ <mn>2</mn>
+ </msup>
+ <mo>+</mo>
+ <msup>
+ <mi>b</mi>
+ <mn>2</mn>
+ </msup>
+ </mrow>
+ </msqrt>
+ </mrow>
+ <annotation encoding="application/x-tex">c = \\pm\\sqrt{a^2 + b^2}</annotation>
+ </semantics>
+ </math>
+ </span>
+ <span class="katex-html" aria-hidden="true">
+ <span class="strut" style="height: 0.913389em;"></span>
+ <span class="strut bottom" style="height: 1.04em; vertical-align: -0.126611em;"></span>
+ <span class="base textstyle uncramped">
+ <span class="mord mathit">c</span>
+ <span class="mrel">=</span>
+ <span class="mord">±</span>
+ <span class="sqrt mord"><span class="sqrt-sign" style="top: -0.073389em;">
+ <span class="style-wrap reset-textstyle textstyle uncramped">√</span>
+ </span>
+ <span class="vlist">
+ <span class="" style="top: 0em;">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 1em;">​</span>
+ </span>
+ <span class="mord textstyle cramped">
+ <span class="mord">
+ <span class="mord mathit">a</span>
+ <span class="msupsub">
+ <span class="vlist">
+ <span class="" style="top: -0.289em; margin-right: 0.05em;">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 0em;">​</span>
+ </span>
+ <span class="reset-textstyle scriptstyle cramped">
+ <span class="mord mathrm">2</span>
+ </span>
+ </span>
+ <span class="baseline-fix">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 0em;">​</span>
+ </span>
+ ​</span>
+ </span>
+ </span>
+ </span>
+ <span class="mbin">+</span>
+ <span class="mord">
+ <span class="mord mathit">b</span>
+ <span class="msupsub">
+ <span class="vlist">
+ <span class="" style="top: -0.289em; margin-right: 0.05em;">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 0em;">​</span>
+ </span>
+ <span class="reset-textstyle scriptstyle cramped">
+ <span class="mord mathrm">2</span>
+ </span>
+ </span>
+ <span class="baseline-fix">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 0em;">​</span>
+ </span>
+ ​</span>
+ </span>
+ </span>
+ </span>
+ </span>
+ </span>
+ <span class="" style="top: -0.833389em;">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 1em;">​</span>
+ </span>
+ <span class="reset-textstyle textstyle uncramped sqrt-line"></span>
+ </span>
+ <span class="baseline-fix">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 1em;">​</span>
+ </span>
+ ​</span>
+ </span>
+ </span>
+ </span>
+ </span>
+ </span>
+ HTML
+
+ output_gfm = html_to_gfm(html)
+ expect(output_gfm.strip).to eq(gfm.strip)
+ end
+
+ verify(
+ 'SanitizationFilter',
+
+ <<-GFM.strip_heredoc
+ <sub>sub</sub>
+
+ <dl>
+ <dt>dt</dt>
+ <dd>dd</dd>
+ </dl>
+
+ <kbd>kbd</kbd>
+
+ <q>q</q>
+
+ <samp>samp</samp>
+
+ <var>var</var>
+
+ <ruby>ruby</ruby>
+
+ <rt>rt</rt>
+
+ <rp>rp</rp>
+
+ <abbr>abbr</abbr>
+ GFM
+ )
+
+ verify(
+ 'SanitizationFilter',
+
+ <<-GFM.strip_heredoc,
+ ```
+ Plain text
+ ```
+ GFM
+
+ <<-GFM.strip_heredoc,
+ ```ruby
+ def foo
+ bar
+ end
+ ```
+ GFM
+
+ <<-GFM.strip_heredoc
+ Foo
+
+ This is an example of GFM
+
+ ```js
+ Code goes here
+ ```
+ GFM
+ )
+
+ verify(
+ 'MarkdownFilter',
+
+ "Line with two spaces at the end \nto insert a linebreak",
+
+ '`code`',
+ '`` code with ` ticks ``',
+
+ '> Quote',
+
+ # multiline quote
+ <<-GFM.strip_heredoc,
+ > Multiline
+ > Quote
+ >
+ > With multiple paragraphs
+ GFM
+
+ '![Image](https://example.com/image.png)',
+
+ '# Heading with no anchor link',
+
+ '[Link](https://example.com)',
+
+ '- List item',
+
+ # multiline list item
+ <<-GFM.strip_heredoc,
+ - Multiline
+ List item
+ GFM
+
+ # nested lists
+ <<-GFM.strip_heredoc,
+ - Nested
+
+
+ - Lists
+ GFM
+
+ # list with blockquote
+ <<-GFM.strip_heredoc,
+ - List
+
+ > Blockquote
+ GFM
+
+ '1. Numbered list item',
+
+ # multiline numbered list item
+ <<-GFM.strip_heredoc,
+ 1. Multiline
+ Numbered list item
+ GFM
+
+ # nested numbered list
+ <<-GFM.strip_heredoc,
+ 1. Nested
+
+
+ 1. Numbered lists
+ GFM
+
+ '# Heading',
+ '## Heading',
+ '### Heading',
+ '#### Heading',
+ '##### Heading',
+ '###### Heading',
+
+ '**Bold**',
+
+ '_Italics_',
+
+ '~~Strikethrough~~',
+
+ '2^2',
+
+ '-----',
+
+ # table
+ <<-GFM.strip_heredoc,
+ | Centered | Right | Left |
+ |:--------:|------:|------|
+ | Foo | Bar | **Baz** |
+ | Foo | Bar | **Baz** |
+ GFM
+
+ # table with empty heading
+ <<-GFM.strip_heredoc,
+ | | x | y |
+ |---|---|---|
+ | a | 1 | 0 |
+ | b | 0 | 1 |
+ GFM
+ )
+ end
+
+ alias_method :gfm_to_html, :markdown
+
+ def html_to_gfm(html)
+ js = <<-JS.strip_heredoc
+ (function(html) {
+ var node = document.createElement('div');
+ node.innerHTML = html;
+ return window.gl.CopyAsGFM.nodeToGFM(node);
+ })("#{escape_javascript(html)}")
+ JS
+ page.evaluate_script(js)
+ end
+
+ def verify(label, *gfms)
+ aggregate_failures(label) do
+ gfms.each do |gfm|
+ html = gfm_to_html(gfm)
+ output_gfm = html_to_gfm(html)
+ expect(output_gfm.strip).to eq(gfm.strip)
+ end
+ end
+ end
+
+ # Fake a `current_user` helper
+ def current_user
+ @feat.user
+ end
+end
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 8771cc8e157..741ca95f1ca 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -68,6 +68,22 @@ describe 'New/edit issue', feature: true, js: true do
end
end
end
+
+ it 'correctly updates the dropdown toggle when removing a label' do
+ click_button 'Labels'
+
+ page.within '.dropdown-menu-labels' do
+ click_link label.title
+ end
+
+ expect(find('.js-label-select')).to have_content(label.title)
+
+ page.within '.dropdown-menu-labels' do
+ click_link label.title
+ end
+
+ expect(find('.js-label-select')).to have_content('Labels')
+ end
end
context 'edit issue' do
diff --git a/spec/finders/branches_finder_spec.rb b/spec/finders/branches_finder_spec.rb
index db60c01db0d..91f34973ba5 100644
--- a/spec/finders/branches_finder_spec.rb
+++ b/spec/finders/branches_finder_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe BranchesFinder do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
describe '#execute' do
diff --git a/spec/finders/contributed_projects_finder_spec.rb b/spec/finders/contributed_projects_finder_spec.rb
index 65d7f14c721..ad2d456529a 100644
--- a/spec/finders/contributed_projects_finder_spec.rb
+++ b/spec/finders/contributed_projects_finder_spec.rb
@@ -6,8 +6,8 @@ describe ContributedProjectsFinder do
let(:finder) { described_class.new(source_user) }
- let!(:public_project) { create(:project, :public) }
- let!(:private_project) { create(:project, :private) }
+ let!(:public_project) { create(:empty_project, :public) }
+ let!(:private_project) { create(:empty_project, :private) }
before do
private_project.team << [source_user, Gitlab::Access::MASTER]
diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb
index 00eec3f3f4c..ef97b061ca7 100644
--- a/spec/finders/group_projects_finder_spec.rb
+++ b/spec/finders/group_projects_finder_spec.rb
@@ -6,11 +6,11 @@ describe GroupProjectsFinder do
let(:finder) { described_class.new(source_user) }
- let!(:public_project) { create(:project, :public, group: group, path: '1') }
- let!(:private_project) { create(:project, :private, group: group, path: '2') }
- let!(:shared_project_1) { create(:project, :public, path: '3') }
- let!(:shared_project_2) { create(:project, :private, path: '4') }
- let!(:shared_project_3) { create(:project, :internal, path: '5') }
+ let!(:public_project) { create(:empty_project, :public, group: group, path: '1') }
+ let!(:private_project) { create(:empty_project, :private, group: group, path: '2') }
+ let!(:shared_project_1) { create(:empty_project, :public, path: '3') }
+ let!(:shared_project_2) { create(:empty_project, :private, path: '4') }
+ let!(:shared_project_3) { create(:empty_project, :internal, path: '5') }
before do
shared_project_1.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group)
diff --git a/spec/finders/joined_groups_finder_spec.rb b/spec/finders/joined_groups_finder_spec.rb
index 29a47e005a6..4c389746252 100644
--- a/spec/finders/joined_groups_finder_spec.rb
+++ b/spec/finders/joined_groups_finder_spec.rb
@@ -42,7 +42,7 @@ describe JoinedGroupsFinder do
context 'if profile visitor is in one of the private group projects' do
before do
- project = create(:project, :private, group: private_group, name: 'B', path: 'B')
+ project = create(:empty_project, :private, group: private_group, name: 'B', path: 'B')
project.add_user(profile_visitor, Gitlab::Access::DEVELOPER)
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index e4ba1d2f1c2..3dcd7781e5b 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -4,9 +4,9 @@ describe MergeRequestsFinder do
let(:user) { create :user }
let(:user2) { create :user }
- let(:project1) { create(:project) }
- let(:project2) { create(:project, forked_from_project: project1) }
- let(:project3) { create(:project, :archived, forked_from_project: project1) }
+ let(:project1) { create(:empty_project) }
+ let(:project2) { create(:empty_project, forked_from_project: project1) }
+ let(:project3) { create(:empty_project, :archived, forked_from_project: project1) }
let!(:merge_request1) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1) }
let!(:merge_request2) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1, state: 'closed') }
diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb
index 4d21254323c..bac653ea451 100644
--- a/spec/finders/notes_finder_spec.rb
+++ b/spec/finders/notes_finder_spec.rb
@@ -28,7 +28,7 @@ describe NotesFinder do
end
it "excludes notes on commits the author can't download" do
- project = create(:project, :private)
+ project = create(:project, :private, :repository)
note = create(:note_on_commit, project: project)
params = { target_type: 'commit', target_id: note.noteable.id }
@@ -76,7 +76,7 @@ describe NotesFinder do
end
context 'for target' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:note1) { create :note_on_commit, project: project }
let(:note2) { create :note_on_commit, project: project }
let(:commit) { note1.noteable }
diff --git a/spec/finders/personal_projects_finder_spec.rb b/spec/finders/personal_projects_finder_spec.rb
index a4681fe59d8..e0e17af681a 100644
--- a/spec/finders/personal_projects_finder_spec.rb
+++ b/spec/finders/personal_projects_finder_spec.rb
@@ -4,14 +4,14 @@ describe PersonalProjectsFinder do
let(:source_user) { create(:user) }
let(:current_user) { create(:user) }
let(:finder) { described_class.new(source_user) }
- let!(:public_project) { create(:project, :public, namespace: source_user.namespace) }
+ let!(:public_project) { create(:empty_project, :public, namespace: source_user.namespace) }
let!(:private_project) do
- create(:project, :private, namespace: source_user.namespace, path: 'mepmep')
+ create(:empty_project, :private, namespace: source_user.namespace, path: 'mepmep')
end
let!(:internal_project) do
- create(:project, :internal, namespace: source_user.namespace, path: 'C')
+ create(:empty_project, :internal, namespace: source_user.namespace, path: 'C')
end
before do
diff --git a/spec/finders/pipelines_finder_spec.rb b/spec/finders/pipelines_finder_spec.rb
index b0811d134fa..fdc8215aa47 100644
--- a/spec/finders/pipelines_finder_spec.rb
+++ b/spec/finders/pipelines_finder_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe PipelinesFinder do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let!(:tag_pipeline) { create(:ci_pipeline, project: project, ref: 'v1.0.0') }
let!(:branch_pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index 13bda5f7c5a..e44e7434c80 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -6,19 +6,19 @@ describe ProjectsFinder do
let(:group) { create(:group, :public) }
let!(:private_project) do
- create(:project, :private, name: 'A', path: 'A')
+ create(:empty_project, :private, name: 'A', path: 'A')
end
let!(:internal_project) do
- create(:project, :internal, group: group, name: 'B', path: 'B')
+ create(:empty_project, :internal, group: group, name: 'B', path: 'B')
end
let!(:public_project) do
- create(:project, :public, group: group, name: 'C', path: 'C')
+ create(:empty_project, :public, group: group, name: 'C', path: 'C')
end
let!(:shared_project) do
- create(:project, :private, name: 'D', path: 'D')
+ create(:empty_project, :private, name: 'D', path: 'D')
end
let(:finder) { described_class.new }
diff --git a/spec/finders/tags_finder_spec.rb b/spec/finders/tags_finder_spec.rb
index 98b42e264dc..460e278e2d3 100644
--- a/spec/finders/tags_finder_spec.rb
+++ b/spec/finders/tags_finder_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe TagsFinder do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
describe '#execute' do
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 92053e5a7c6..8b201f348f1 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -55,7 +55,7 @@ describe ApplicationHelper do
describe 'project_icon' do
it 'returns an url for the avatar' do
- project = create(:project, avatar: File.open(uploaded_image_temp_path))
+ project = create(:empty_project, avatar: File.open(uploaded_image_temp_path))
avatar_url = "http://#{Gitlab.config.gitlab.host}/uploads/project/avatar/#{project.id}/banana_sample.gif"
expect(helper.project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).
@@ -63,7 +63,7 @@ describe ApplicationHelper do
end
it 'gives uploaded icon when present' do
- project = create(:project)
+ project = create(:empty_project)
allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true)
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index a43a7238c70..fa516f9903e 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -70,7 +70,7 @@ describe BlobHelper do
describe "#edit_blob_link" do
let(:namespace) { create(:namespace, name: 'gitlab' )}
- let(:project) { create(:project, namespace: namespace) }
+ let(:project) { create(:project, :repository, namespace: namespace) }
before do
allow(self).to receive(:current_user).and_return(double)
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 810311e2b1a..b8ec3521edb 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe GitlabMarkdownHelper do
include ApplicationHelper
- let!(:project) { create(:project) }
+ let!(:project) { create(:project, :repository) }
let(:user) { create(:user, username: 'gfm') }
let(:commit) { project.commit }
@@ -55,18 +55,18 @@ describe GitlabMarkdownHelper do
end
describe '#link_to_gfm' do
- let(:commit_path) { namespace_project_commit_path(project.namespace, project, commit) }
- let(:issues) { create_list(:issue, 2, project: project) }
+ let(:link) { '/commits/0a1b2c3d' }
+ let(:issues) { create_list(:issue, 2, project: project) }
it 'handles references nested in links with all the text' do
- actual = helper.link_to_gfm("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", commit_path)
+ actual = helper.link_to_gfm("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", link)
doc = Nokogiri::HTML.parse(actual)
# Make sure we didn't create invalid markup
expect(doc.errors).to be_empty
# Leading commit link
- expect(doc.css('a')[0].attr('href')).to eq commit_path
+ expect(doc.css('a')[0].attr('href')).to eq link
expect(doc.css('a')[0].text).to eq 'This should finally fix '
# First issue link
@@ -75,7 +75,7 @@ describe GitlabMarkdownHelper do
expect(doc.css('a')[1].text).to eq issues[0].to_reference
# Internal commit link
- expect(doc.css('a')[2].attr('href')).to eq commit_path
+ expect(doc.css('a')[2].attr('href')).to eq link
expect(doc.css('a')[2].text).to eq ' and '
# Second issue link
@@ -84,12 +84,12 @@ describe GitlabMarkdownHelper do
expect(doc.css('a')[3].text).to eq issues[1].to_reference
# Trailing commit link
- expect(doc.css('a')[4].attr('href')).to eq commit_path
+ expect(doc.css('a')[4].attr('href')).to eq link
expect(doc.css('a')[4].text).to eq ' for real'
end
it 'forwards HTML options' do
- actual = helper.link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo')
+ actual = helper.link_to_gfm("Fixed in #{commit.id}", link, class: 'foo')
doc = Nokogiri::HTML.parse(actual)
expect(doc.css('a')).to satisfy do |v|
@@ -100,7 +100,7 @@ describe GitlabMarkdownHelper do
it "escapes HTML passed in as the body" do
actual = "This is a <h1>test</h1> - see #{issues[0].to_reference}"
- expect(helper.link_to_gfm(actual, commit_path)).
+ expect(helper.link_to_gfm(actual, link)).
to match('&lt;h1&gt;test&lt;/h1&gt;')
end
diff --git a/spec/helpers/graph_helper_spec.rb b/spec/helpers/graph_helper_spec.rb
index 51c49f0e587..400635abdde 100644
--- a/spec/helpers/graph_helper_spec.rb
+++ b/spec/helpers/graph_helper_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe GraphHelper do
describe '#get_refs' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:commit) { project.commit("master") }
let(:graph) { Network::Graph.new(project, 'master', commit, '') }
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 9c7e0ee2fe0..13fb9c1f1a7 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -1,7 +1,7 @@
require "spec_helper"
describe IssuesHelper do
- let(:project) { create :project }
+ let(:project) { create(:empty_project) }
let(:issue) { create :issue, project: project }
let(:ext_project) { create :redmine_project }
diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb
index 33934cdf8b1..2b455571d52 100644
--- a/spec/helpers/members_helper_spec.rb
+++ b/spec/helpers/members_helper_spec.rb
@@ -46,7 +46,7 @@ describe MembersHelper do
end
describe '#leave_confirmation_message' do
- let(:project) { build_stubbed(:project) }
+ let(:project) { build_stubbed(:empty_project) }
let(:group) { build_stubbed(:group) }
let(:user) { build_stubbed(:user) }
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index 1f221487393..550b4a66a6a 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe MergeRequestsHelper do
describe 'ci_build_details_path' do
- let(:project) { create :project }
+ let(:project) { create(:empty_project) }
let(:merge_request) { MergeRequest.new }
let(:ci_service) { CiService.new }
let(:last_commit) { Ci::Pipeline.new({}) }
@@ -30,7 +30,7 @@ describe MergeRequestsHelper do
it { is_expected.to eq('#1, #2, and #3') }
context 'for JIRA issues' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:issues) do
[
ExternalIssue.new('JIRA-123', project),
@@ -52,8 +52,8 @@ describe MergeRequestsHelper do
end
describe 'within different projects' do
- let(:project) { create(:project) }
- let(:fork_project) { create(:project, forked_from_project: project) }
+ let(:project) { create(:empty_project) }
+ let(:fork_project) { create(:empty_project, forked_from_project: project) }
let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) }
subject { format_mr_branch_names(merge_request) }
let(:source_title) { "#{fork_project.path_with_namespace}:#{merge_request.source_branch}" }
@@ -64,8 +64,8 @@ describe MergeRequestsHelper do
end
describe 'mr_widget_refresh_url' do
+ let(:project) { create(:empty_project) }
let(:merge_request) { create(:merge_request, source_project: project) }
- let(:project) { create(:project) }
it 'returns correct url for MR' do
expected_url = "#{project.path_with_namespace}/merge_requests/#{merge_request.iid}/merge_widget_refresh"
diff --git a/spec/helpers/milestones_helper_spec.rb b/spec/helpers/milestones_helper_spec.rb
index ea744dbb629..14a95479339 100644
--- a/spec/helpers/milestones_helper_spec.rb
+++ b/spec/helpers/milestones_helper_spec.rb
@@ -21,24 +21,22 @@ describe MilestonesHelper do
end
describe '#milestone_counts' do
- let(:project) { FactoryGirl.create(:project) }
+ let(:project) { create(:empty_project) }
let(:counts) { helper.milestone_counts(project.milestones) }
context 'when there are milestones' do
- let!(:milestone_1) { FactoryGirl.create(:active_milestone, project: project) }
- let!(:milestone_2) { FactoryGirl.create(:active_milestone, project: project) }
- let!(:milestone_3) { FactoryGirl.create(:closed_milestone, project: project) }
-
it 'returns the correct counts' do
+ create_list(:active_milestone, 2, project: project)
+ create(:closed_milestone, project: project)
+
expect(counts).to eq(opened: 2, closed: 1, all: 3)
end
end
context 'when there are only milestones of one type' do
- let!(:milestone_1) { FactoryGirl.create(:active_milestone, project: project) }
- let!(:milestone_2) { FactoryGirl.create(:active_milestone, project: project) }
-
it 'returns the correct counts' do
+ create_list(:active_milestone, 2, project: project)
+
expect(counts).to eq(opened: 2, closed: 0, all: 2)
end
end
diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb
index 77841e85223..1f02e06e312 100644
--- a/spec/helpers/preferences_helper_spec.rb
+++ b/spec/helpers/preferences_helper_spec.rb
@@ -110,7 +110,7 @@ describe PreferencesHelper do
end
context 'when repository is not empty' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
it 'returns readme if user has repository access' do
allow(helper).to receive(:can?).with(nil, :download_code, project).and_return(true)
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 8113742923b..8d1570aa6f3 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -10,7 +10,7 @@ describe ProjectsHelper do
end
describe "can_change_visibility_level?" do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:project_member, :reporter, user: create(:user), project: project).user }
let(:fork_project) { Projects::ForkService.new(project, user).execute }
@@ -97,7 +97,7 @@ describe ProjectsHelper do
end
describe '#license_short_name' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
context 'when project.repository has a license_key' do
it 'returns the nickname of the license if present' do
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 4b2ca3514f8..e51720f10ed 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -42,7 +42,7 @@ describe SearchHelper do
end
it "includes the user's projects" do
- project = create(:project, namespace: create(:namespace, owner: user))
+ project = create(:empty_project, namespace: create(:namespace, owner: user))
expect(search_autocomplete_opts(project.name).size).to eq(1)
end
@@ -52,7 +52,9 @@ describe SearchHelper do
end
context "with a current project" do
- before { @project = create(:project) }
+ before do
+ @project = create(:project, :repository)
+ end
it "includes project-specific sections" do
expect(search_autocomplete_opts("Files").size).to eq(1)
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index 37ac6a2699d..4da1569e59f 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -116,7 +116,7 @@ describe SubmoduleHelper do
context 'submodules with relative links' do
let(:group) { create(:group, name: "Master Project", path: "master-project") }
- let(:project) { create(:project, group: group) }
+ let(:project) { create(:empty_project, group: group) }
let(:commit_id) { sample_commit[:id] }
before do
@@ -145,7 +145,7 @@ describe SubmoduleHelper do
context 'personal project' do
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
it 'one level down with personal project' do
result = relative_self_links('../test.git', commit_id)
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index 8d6537ba4b5..9523d0f4aa6 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe TreeHelper do
describe 'flatten_tree' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
@repository = project.repository
diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb
index db3ad1b99e9..8942b00b128 100644
--- a/spec/helpers/visibility_level_helper_spec.rb
+++ b/spec/helpers/visibility_level_helper_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe VisibilityLevelHelper do
- let(:project) { build(:project) }
+ let(:project) { build(:empty_project) }
let(:group) { build(:group) }
let(:personal_snippet) { build(:personal_snippet) }
let(:project_snippet) { build(:project_snippet) }
@@ -60,8 +60,8 @@ describe VisibilityLevelHelper do
describe "skip_level?" do
describe "forks" do
- let(:project) { create(:project, :internal) }
- let(:fork_project) { create(:project, forked_from_project: project) }
+ let(:project) { create(:empty_project, :internal) }
+ let(:fork_project) { create(:empty_project, forked_from_project: project) }
it "skips levels" do
expect(skip_level?(fork_project, Gitlab::VisibilityLevel::PUBLIC)).to be_truthy
@@ -71,7 +71,7 @@ describe VisibilityLevelHelper do
end
describe "non-forked project" do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:empty_project, :internal) }
it "skips levels" do
expect(skip_level?(project, Gitlab::VisibilityLevel::PUBLIC)).to be_falsey
diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js
index 755dba19744..386fc8f514e 100644
--- a/spec/javascripts/shortcuts_issuable_spec.js
+++ b/spec/javascripts/shortcuts_issuable_spec.js
@@ -1,6 +1,7 @@
/* eslint-disable space-before-function-paren, no-return-assign, no-var, quotes */
/* global ShortcutsIssuable */
+/*= require copy_as_gfm */
/*= require shortcuts_issuable */
(function() {
@@ -14,10 +15,12 @@
});
return describe('#replyWithSelectedText', function() {
var stubSelection;
- // Stub window.getSelection to return the provided String.
- stubSelection = function(text) {
- return window.getSelection = function() {
- return text;
+ // Stub window.gl.utils.getSelectedFragment to return a node with the provided HTML.
+ stubSelection = function(html) {
+ window.gl.utils.getSelectedFragment = function() {
+ var node = document.createElement('div');
+ node.innerHTML = html;
+ return node;
};
};
beforeEach(function() {
@@ -32,13 +35,13 @@
});
describe('with any selection', function() {
beforeEach(function() {
- return stubSelection('Selected text.');
+ return stubSelection('<p>Selected text.</p>');
});
it('leaves existing input intact', function() {
$(this.selector).val('This text was already here.');
expect($(this.selector).val()).toBe('This text was already here.');
this.shortcut.replyWithSelectedText();
- return expect($(this.selector).val()).toBe("This text was already here.\n> Selected text.\n\n");
+ return expect($(this.selector).val()).toBe("This text was already here.\n\n> Selected text.\n\n");
});
it('triggers `input`', function() {
var triggered;
@@ -61,16 +64,16 @@
});
describe('with a one-line selection', function() {
return it('quotes the selection', function() {
- stubSelection('This text has been selected.');
+ stubSelection('<p>This text has been selected.</p>');
this.shortcut.replyWithSelectedText();
return expect($(this.selector).val()).toBe("> This text has been selected.\n\n");
});
});
return describe('with a multi-line selection', function() {
return it('quotes the selected lines as a group', function() {
- stubSelection("Selected line one.\n\nSelected line two.\nSelected line three.\n");
+ stubSelection("<p>Selected line one.</p>\n\n<p>Selected line two.</p>\n\n<p>Selected line three.</p>");
this.shortcut.replyWithSelectedText();
- return expect($(this.selector).val()).toBe("> Selected line one.\n> Selected line two.\n> Selected line three.\n\n");
+ return expect($(this.selector).val()).toBe("> Selected line one.\n>\n> Selected line two.\n>\n> Selected line three.\n\n");
});
});
});
diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
index 9703e2315b8..deadc36524c 100644
--- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:commit1) { project.commit("HEAD~2") }
let(:commit2) { project.commit }
@@ -99,7 +99,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
end
context 'cross-project / cross-namespace complete reference' do
- let(:project2) { create(:project, :public) }
+ let(:project2) { create(:project, :public, :repository) }
let(:reference) { "#{project2.path_with_namespace}@#{commit1.id}...#{commit2.id}" }
it 'links to a valid reference' do
@@ -133,8 +133,8 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
context 'cross-project / same-namespace complete reference' do
let(:namespace) { create(:namespace) }
- let(:project) { create(:project, :public, namespace: namespace) }
- let(:project2) { create(:project, :public, path: "same-namespace", namespace: namespace) }
+ let(:project) { create(:project, :public, :repository, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, path: "same-namespace", namespace: namespace) }
let(:reference) { "#{project2.path}@#{commit1.id}...#{commit2.id}" }
it 'links to a valid reference' do
@@ -168,8 +168,8 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
context 'cross-project shorthand reference' do
let(:namespace) { create(:namespace) }
- let(:project) { create(:project, :public, namespace: namespace) }
- let(:project2) { create(:project, :public, path: "same-namespace", namespace: namespace) }
+ let(:project) { create(:project, :public, :repository, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, path: "same-namespace", namespace: namespace) }
let(:reference) { "#{project2.path}@#{commit1.id}...#{commit2.id}" }
it 'links to a valid reference' do
@@ -203,7 +203,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
context 'cross-project URL reference' do
let(:namespace) { create(:namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:range) { CommitRange.new("#{commit1.id}...master", project) }
let(:reference) { urls.namespace_project_compare_url(project2.namespace, project2, from: commit1.id, to: 'master') }
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index 2e6dcc3a434..a19aac61229 100644
--- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::CommitReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit }
it 'requires project context' do
@@ -96,7 +96,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
context 'cross-project / cross-namespace complete reference' do
let(:namespace) { create(:namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
@@ -122,7 +122,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
context 'cross-project / same-namespace complete reference' do
let(:namespace) { create(:namespace) }
let(:project) { create(:empty_project, namespace: namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
@@ -148,7 +148,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
context 'cross-project shorthand reference' do
let(:namespace) { create(:namespace) }
let(:project) { create(:empty_project, namespace: namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
@@ -173,7 +173,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
context 'cross-project URL reference' do
let(:namespace) { create(:namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { urls.namespace_project_commit_url(project2.namespace, project2, commit.id) }
diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
index fe2ce092e6b..082c0d4dd0d 100644
--- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
+++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::GollumTagsFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:user) { double }
let(:project_wiki) { ProjectWiki.new(project, user) }
diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
index 275010c1a2c..3d3d36061f4 100644
--- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -188,7 +188,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
context 'cross-project URL reference' do
let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
let(:merge) { create(:merge_request, source_project: project2, target_project: project2) }
let(:reference) { urls.namespace_project_merge_request_url(project2.namespace, project2, merge) + '/diffs#note_123' }
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 73b5edb99b3..a317c751d32 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: project) }
let(:reference) { milestone.to_reference }
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index df2dd173b57..1957ba739e2 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -25,7 +25,7 @@ describe Banzai::Filter::RelativeLinkFilter, lib: true do
%(<a href="#{path}">#{path}</a>)
end
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:project_path) { project.path_with_namespace }
let(:ref) { 'markdown' }
let(:commit) { project.commit(ref) }
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index d265d29ee86..69e3c52b35a 100644
--- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -6,21 +6,21 @@ describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
context "when no language is specified" do
it "highlights as plaintext" do
result = filter('<pre><code>def fun end</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" v-pre="true"><code>def fun end</code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code>def fun end</code></pre>')
end
end
context "when a valid language is specified" do
it "highlights as that language" do
result = filter('<pre><code class="ruby">def fun end</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby" v-pre="true"><code><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby" lang="ruby" v-pre="true"><code><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></code></pre>')
end
end
context "when an invalid language is specified" do
it "highlights as plaintext" do
result = filter('<pre><code class="gnuplot">This is a test</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" v-pre="true"><code>This is a test</code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code>This is a test</code></pre>')
end
end
@@ -31,7 +31,7 @@ describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
it "highlights as plaintext" do
result = filter('<pre><code class="ruby">This is a test</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight" v-pre="true"><code>This is a test</code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight" lang="" v-pre="true"><code>This is a test</code></pre>')
end
end
end
diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
index 8b76c1d73c9..639cac6406a 100644
--- a/spec/lib/banzai/filter/upload_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb
@@ -29,7 +29,7 @@ describe Banzai::Filter::UploadLinkFilter, lib: true do
%(<div><a href="#{path}">#{path}</a></div>)
end
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
shared_examples :preserve_unchanged do
it 'does not modify any relative URL in anchor' do
diff --git a/spec/lib/banzai/filter/video_link_filter_spec.rb b/spec/lib/banzai/filter/video_link_filter_spec.rb
index 6ab1be9ccb7..00494f545a3 100644
--- a/spec/lib/banzai/filter/video_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/video_link_filter_spec.rb
@@ -13,7 +13,7 @@ describe Banzai::Filter::VideoLinkFilter, lib: true do
%(<img src="#{path}" />)
end
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
context 'when the element src has a video extension' do
UploaderHelper::VIDEO_EXT.each do |ext|
diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb
index fafc2cec546..31ca9d27b0b 100644
--- a/spec/lib/banzai/reference_parser/user_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb
@@ -147,7 +147,7 @@ describe Banzai::ReferenceParser::UserParser, lib: true do
describe '#nodes_user_can_reference' do
context 'when the link has a data-author attribute' do
it 'returns the nodes when the user is a member of the project' do
- other_project = create(:project)
+ other_project = create(:empty_project)
other_project.team << [user, :developer]
link['data-project'] = other_project.id.to_s
@@ -164,7 +164,7 @@ describe Banzai::ReferenceParser::UserParser, lib: true do
end
it 'returns an empty Array when the user could not be found' do
- other_project = create(:project)
+ other_project = create(:empty_project)
link['data-project'] = other_project.id.to_s
link['data-author'] = ''
@@ -173,7 +173,7 @@ describe Banzai::ReferenceParser::UserParser, lib: true do
end
it 'returns an empty Array when the user is not a team member' do
- other_project = create(:project)
+ other_project = create(:empty_project)
link['data-project'] = other_project.id.to_s
link['data-author'] = user.id.to_s
diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb
index 94266f6653b..a5251e9a8c2 100644
--- a/spec/lib/constraints/project_url_constrainer_spec.rb
+++ b/spec/lib/constraints/project_url_constrainer_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe ProjectUrlConstrainer, lib: true do
- let!(:project) { create(:project) }
+ let!(:project) { create(:empty_project) }
let!(:namespace) { project.namespace }
describe '#matches?' do
diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb
index ec2f66b1136..e3066311b7d 100644
--- a/spec/lib/event_filter_spec.rb
+++ b/spec/lib/event_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe EventFilter, lib: true do
describe '#apply_filter' do
let(:source_user) { create(:user) }
- let!(:public_project) { create(:project, :public) }
+ let!(:public_project) { create(:empty_project, :public) }
let!(:push_event) { create(:event, action: Event::PUSHED, project: public_project, target: public_project, author: source_user) }
let!(:merged_event) { create(:event, action: Event::MERGED, project: public_project, target: public_project, author: source_user) }
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 0e85e302f29..29c07655ae8 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -24,7 +24,7 @@ describe ExtractsPath, lib: true do
let(:params) { { path: sample_commit[:line_code_path], ref: ref } }
before do
- @project = create(:project)
+ @project = create(:project, :repository)
end
it "log tree path has no escape sequences" do
diff --git a/spec/lib/gitlab/badge/build/metadata_spec.rb b/spec/lib/gitlab/badge/build/metadata_spec.rb
index d678e522721..9df96ea04eb 100644
--- a/spec/lib/gitlab/badge/build/metadata_spec.rb
+++ b/spec/lib/gitlab/badge/build/metadata_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
require 'lib/gitlab/badge/shared/metadata'
describe Gitlab::Badge::Build::Metadata do
- let(:badge) { double(project: create(:project), ref: 'feature') }
+ let(:badge) { double(project: create(:empty_project), ref: 'feature') }
let(:metadata) { described_class.new(badge) }
it_behaves_like 'badge metadata'
diff --git a/spec/lib/gitlab/badge/build/status_spec.rb b/spec/lib/gitlab/badge/build/status_spec.rb
index 70f03021d36..3c5414701a7 100644
--- a/spec/lib/gitlab/badge/build/status_spec.rb
+++ b/spec/lib/gitlab/badge/build/status_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Badge::Build::Status do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:sha) { project.commit.sha }
let(:branch) { 'master' }
let(:badge) { described_class.new(project, branch) }
diff --git a/spec/lib/gitlab/badge/coverage/metadata_spec.rb b/spec/lib/gitlab/badge/coverage/metadata_spec.rb
index 74eaf7eaf8b..5e93935ea37 100644
--- a/spec/lib/gitlab/badge/coverage/metadata_spec.rb
+++ b/spec/lib/gitlab/badge/coverage/metadata_spec.rb
@@ -3,7 +3,7 @@ require 'lib/gitlab/badge/shared/metadata'
describe Gitlab::Badge::Coverage::Metadata do
let(:badge) do
- double(project: create(:project), ref: 'feature', job: 'test')
+ double(project: create(:empty_project), ref: 'feature', job: 'test')
end
let(:metadata) { described_class.new(badge) }
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 72b1ba36b58..0a2fe5af2c3 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -52,7 +52,7 @@ describe Gitlab::BitbucketImport::Importer, lib: true do
let(:project) do
create(
- :project,
+ :empty_project,
import_source: project_identifier,
import_data: ProjectImportData.new(credentials: data)
)
diff --git a/spec/lib/gitlab/blame_spec.rb b/spec/lib/gitlab/blame_spec.rb
index 89245761b6f..26b1baf75be 100644
--- a/spec/lib/gitlab/blame_spec.rb
+++ b/spec/lib/gitlab/blame_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Blame, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:path) { 'files/ruby/popen.rb' }
let(:commit) { project.commit('master') }
let(:blob) { project.repository.blob_at(commit.id, path) }
diff --git a/spec/lib/gitlab/chat_commands/command_spec.rb b/spec/lib/gitlab/chat_commands/command_spec.rb
index a2d84977f58..1e81eaef18c 100644
--- a/spec/lib/gitlab/chat_commands/command_spec.rb
+++ b/spec/lib/gitlab/chat_commands/command_spec.rb
@@ -11,7 +11,7 @@ describe Gitlab::ChatCommands::Command, service: true do
context 'when no command is available' do
let(:params) { { text: 'issue show 1' } }
- let(:project) { create(:project, has_external_issue_tracker: true) }
+ let(:project) { create(:empty_project, has_external_issue_tracker: true) }
it 'displays 404 messages' do
expect(subject[:response_type]).to be(:ephemeral)
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index 98effecdbbc..cadfbadca10 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Checks::ChangeAccess, lib: true do
describe '#exec' do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user_access) { Gitlab::UserAccess.new(user, project: project) }
let(:changes) do
{
diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb
index f6288011494..7a84bbebd02 100644
--- a/spec/lib/gitlab/checks/force_push_spec.rb
+++ b/spec/lib/gitlab/checks/force_push_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Checks::ChangeAccess, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
context "exit code checking" do
it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do
diff --git a/spec/lib/gitlab/ci/trace_reader_spec.rb b/spec/lib/gitlab/ci/trace_reader_spec.rb
index f06d78694d6..ff5551bf703 100644
--- a/spec/lib/gitlab/ci/trace_reader_spec.rb
+++ b/spec/lib/gitlab/ci/trace_reader_spec.rb
@@ -11,13 +11,25 @@ describe Gitlab::Ci::TraceReader do
last_lines = random_lines
expected = lines.last(last_lines).join
+ result = subject.read(last_lines: last_lines)
- expect(subject.read(last_lines: last_lines)).to eq(expected)
+ expect(result).to eq(expected)
+ expect(result.encoding).to eq(Encoding.default_external)
end
end
it 'returns everything if trying to get too many lines' do
- expect(build_subject.read(last_lines: lines.size * 2)).to eq(lines.join)
+ result = build_subject.read(last_lines: lines.size * 2)
+
+ expect(result).to eq(lines.join)
+ expect(result.encoding).to eq(Encoding.default_external)
+ end
+
+ it 'returns all contents if last_lines is not specified' do
+ result = build_subject.read
+
+ expect(result).to eq(lines.join)
+ expect(result.encoding).to eq(Encoding.default_external)
end
it 'raises an error if not passing an integer for last_lines' do
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 1bbaca0739a..97af1c2523d 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
describe Gitlab::ClosingIssueExtractor, lib: true do
- let(:project) { create(:project) }
- let(:project2) { create(:project) }
+ let(:project) { create(:empty_project) }
+ let(:project2) { create(:empty_project) }
let(:forked_project) { Projects::ForkService.new(project, project.creator).execute }
- let(:issue) { create(:issue, project: project) }
- let(:issue2) { create(:issue, project: project2) }
+ let(:issue) { create(:issue, project: project) }
+ let(:issue2) { create(:issue, project: project2) }
let(:reference) { issue.to_reference }
let(:cross_reference) { issue2.to_reference(project) }
let(:fork_cross_reference) { issue.to_reference(forked_project) }
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 648d342ecf8..fbf679c5215 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Conflict::File, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:rugged) { repository.rugged }
let(:their_commit) { rugged.branches['conflict-start'].target }
diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
index fb6b6c4a8d2..3dd76ba5b8a 100644
--- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::CycleAnalytics::StageSummary, models: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from) { 1.day.ago }
let(:user) { create(:user, :admin) }
subject { described_class.new(project, from: Time.now, current_user: user).data }
@@ -15,7 +15,7 @@ describe Gitlab::CycleAnalytics::StageSummary, models: true do
end
it "doesn't find issues from other projects" do
- Timecop.freeze(5.days.from_now) { create(:issue, project: create(:project)) }
+ Timecop.freeze(5.days.from_now) { create(:issue, project: create(:empty_project)) }
expect(subject.first[:value]).to eq(0)
end
@@ -30,7 +30,7 @@ describe Gitlab::CycleAnalytics::StageSummary, models: true do
end
it "doesn't find commits from other projects" do
- Timecop.freeze(5.days.from_now) { create_commit("Test message", create(:project), user, 'master') }
+ Timecop.freeze(5.days.from_now) { create_commit("Test message", create(:project, :repository), user, 'master') }
expect(subject.second[:value]).to eq(0)
end
@@ -51,7 +51,9 @@ describe Gitlab::CycleAnalytics::StageSummary, models: true do
end
it "doesn't find commits from other projects" do
- Timecop.freeze(5.days.from_now) { create(:deployment, project: create(:project)) }
+ Timecop.freeze(5.days.from_now) do
+ create(:deployment, project: create(:project, :repository))
+ end
expect(subject.third[:value]).to eq(0)
end
diff --git a/spec/lib/gitlab/data_builder/note_spec.rb b/spec/lib/gitlab/data_builder/note_spec.rb
index 9a4dec91e56..04ec34492e1 100644
--- a/spec/lib/gitlab/data_builder/note_spec.rb
+++ b/spec/lib/gitlab/data_builder/note_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::DataBuilder::Note, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:data) { described_class.build(note, user) }
let(:fixed_time) { Time.at(1425600000) } # Avoid time precision errors
diff --git a/spec/lib/gitlab/data_builder/pipeline_spec.rb b/spec/lib/gitlab/data_builder/pipeline_spec.rb
index a68f5943a6a..f13041e498c 100644
--- a/spec/lib/gitlab/data_builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/data_builder/pipeline_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::DataBuilder::Pipeline do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
diff --git a/spec/lib/gitlab/data_builder/push_spec.rb b/spec/lib/gitlab/data_builder/push_spec.rb
index a379f798a16..dbcfb9b7400 100644
--- a/spec/lib/gitlab/data_builder/push_spec.rb
+++ b/spec/lib/gitlab/data_builder/push_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::DataBuilder::Push, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
describe '.build_sample' do
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 38475792d93..050689b7c9a 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::File, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:commit) { project.commit(sample_commit.id) }
let(:diff) { commit.raw_diffs.first }
let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) }
diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb
index 1c2ddeed692..1e21270d928 100644
--- a/spec/lib/gitlab/diff/highlight_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::Highlight, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:commit) { project.commit(sample_commit.id) }
let(:diff) { commit.raw_diffs.first }
let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) }
diff --git a/spec/lib/gitlab/diff/line_mapper_spec.rb b/spec/lib/gitlab/diff/line_mapper_spec.rb
index 4b943fa382d..2c7ecd1907e 100644
--- a/spec/lib/gitlab/diff/line_mapper_spec.rb
+++ b/spec/lib/gitlab/diff/line_mapper_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::LineMapper, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:commit) { project.commit(sample_commit.id) }
let(:diffs) { commit.raw_diffs }
diff --git a/spec/lib/gitlab/diff/parallel_diff_spec.rb b/spec/lib/gitlab/diff/parallel_diff_spec.rb
index af18d3c25a6..fe5fa048413 100644
--- a/spec/lib/gitlab/diff/parallel_diff_spec.rb
+++ b/spec/lib/gitlab/diff/parallel_diff_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::ParallelDiff, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:commit) { project.commit(sample_commit.id) }
let(:diffs) { commit.raw_diffs }
diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb
index 6e8fff6f516..cdf0af6d7ef 100644
--- a/spec/lib/gitlab/diff/position_spec.rb
+++ b/spec/lib/gitlab/diff/position_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::Position, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
describe "position for an added file" do
let(:commit) { project.commit("2ea1f3dec713d940208fb5ce4a38765ecb5d3f73") }
diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb
index c268f84c759..f5822fed37c 100644
--- a/spec/lib/gitlab/diff/position_tracer_spec.rb
+++ b/spec/lib/gitlab/diff/position_tracer_spec.rb
@@ -51,7 +51,7 @@ describe Gitlab::Diff::PositionTracer, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:current_user) { project.owner }
let(:repository) { project.repository }
let(:file_name) { "test-file" }
diff --git a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
index 08897a4c310..4a9c9a7fe34 100644
--- a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
@@ -13,7 +13,7 @@ describe Gitlab::Email::Handler::CreateIssueHandler, lib: true do
let(:email_raw) { fixture_file('emails/valid_new_issue.eml') }
let(:namespace) { create(:namespace, path: 'gitlabhq') }
- let!(:project) { create(:project, :public, namespace: namespace) }
+ let!(:project) { create(:project, :public, :repository, namespace: namespace) }
let!(:user) do
create(
:user,
diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
index cebbeff50cf..17a4ef25210 100644
--- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
@@ -11,7 +11,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
end
let(:email_raw) { fixture_file('emails/valid_reply.eml') }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:user) { create(:user) }
let(:note) { create(:diff_note_on_merge_request, project: project) }
let(:noteable) { note.noteable }
diff --git a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
index a444257754b..0939e6c4514 100644
--- a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::Email::Handler::UnsubscribeHandler, lib: true do
end
let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "#{mail_key}+unsubscribe") }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
let(:noteable) { create(:issue, project: project) }
diff --git a/spec/lib/gitlab/email/message/repository_push_spec.rb b/spec/lib/gitlab/email/message/repository_push_spec.rb
index 5b966bddb6a..7b3291b8315 100644
--- a/spec/lib/gitlab/email/message/repository_push_spec.rb
+++ b/spec/lib/gitlab/email/message/repository_push_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::Email::Message::RepositoryPush do
include RepoHelpers
let!(:group) { create(:group, name: 'my_group') }
- let!(:project) { create(:project, name: 'my_project', namespace: group) }
+ let!(:project) { create(:project, :repository, name: 'my_project', namespace: group) }
let!(:author) { create(:author, name: 'Author') }
let(:message) do
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index f4703dc704f..5d416c9eec3 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::Gfm::ReferenceRewriter do
let(:text) { 'some text' }
- let(:old_project) { create(:project, name: 'old') }
- let(:new_project) { create(:project, name: 'new') }
+ let(:old_project) { create(:empty_project, name: 'old-project') }
+ let(:new_project) { create(:empty_project, name: 'new-project') }
let(:user) { create(:user) }
before { old_project.team << [user, :reporter] }
diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
index 6eca33f9fee..c3016f63ebf 100644
--- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::Gfm::UploadsRewriter do
let(:user) { create(:user) }
- let(:old_project) { create(:project) }
- let(:new_project) { create(:project) }
+ let(:old_project) { create(:empty_project) }
+ let(:new_project) { create(:empty_project) }
let(:rewriter) { described_class.new(text, old_project, user) }
context 'text contains links to uploads' do
diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb
index d1f947b6850..3f279c21865 100644
--- a/spec/lib/gitlab/git/hook_spec.rb
+++ b/spec/lib/gitlab/git/hook_spec.rb
@@ -3,7 +3,7 @@ require 'fileutils'
describe Gitlab::Git::Hook, lib: true do
describe "#trigger" do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
def create_hook(name)
diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb
index 1f9c987be0b..d48629a296d 100644
--- a/spec/lib/gitlab/git/rev_list_spec.rb
+++ b/spec/lib/gitlab/git/rev_list_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Git::RevList, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
context "validations" do
described_class::ALLOWED_VARIABLES.each do |var|
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 44b84afde47..b080be62b34 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::GitAccess, lib: true do
let(:access) { Gitlab::GitAccess.new(actor, project, 'web', authentication_abilities: authentication_abilities) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:actor) { user }
let(:authentication_abilities) do
@@ -88,7 +88,7 @@ describe Gitlab::GitAccess, lib: true do
end
context 'when project is public' do
- let(:public_project) { create(:project, :public) }
+ let(:public_project) { create(:project, :public, :repository) }
let(:guest_access) { Gitlab::GitAccess.new(nil, public_project, 'web', authentication_abilities: []) }
subject { guest_access.check('git-upload-pack', '_any') }
@@ -124,19 +124,19 @@ describe Gitlab::GitAccess, lib: true do
context 'when unauthorized' do
context 'from public project' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
it { expect(subject).to be_allowed }
end
context 'from internal project' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:project, :internal, :repository) }
it { expect(subject).not_to be_allowed }
end
context 'from private project' do
- let(:project) { create(:project, :private) }
+ let(:project) { create(:project, :private, :repository) }
it { expect(subject).not_to be_allowed }
end
@@ -148,7 +148,7 @@ describe Gitlab::GitAccess, lib: true do
let(:authentication_abilities) { build_authentication_abilities }
describe 'owner' do
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:project, :repository, namespace: user.namespace) }
context 'pull code' do
it { expect(subject).to be_allowed }
@@ -364,19 +364,19 @@ describe Gitlab::GitAccess, lib: true do
context 'when unauthorized' do
context 'to public project' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
it { expect(subject).not_to be_allowed }
end
context 'to internal project' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:project, :internal, :repository) }
it { expect(subject).not_to be_allowed }
end
context 'to private project' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :private, :repository) }
it { expect(subject).not_to be_allowed }
end
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index a5d172233cc..4a0cdc6887e 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::GitAccessWiki, lib: true do
let(:access) { Gitlab::GitAccessWiki.new(user, project, 'web', authentication_abilities: authentication_abilities) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:authentication_abilities) do
[
diff --git a/spec/lib/gitlab/github_import/branch_formatter_spec.rb b/spec/lib/gitlab/github_import/branch_formatter_spec.rb
index 462caa5b5fe..36e7d739f7e 100644
--- a/spec/lib/gitlab/github_import/branch_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/branch_formatter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GithubImport::BranchFormatter, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:commit) { create(:commit, project: project) }
let(:repo) { double }
let(:raw) do
diff --git a/spec/lib/gitlab/github_import/comment_formatter_spec.rb b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
index c520a9c53ad..e6e33d3686a 100644
--- a/spec/lib/gitlab/github_import/comment_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GithubImport::CommentFormatter, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2013-04-10T20:09:31Z') }
let(:updated_at) { DateTime.strptime('2014-03-03T18:58:10Z') }
diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb
index e31ed9c1fa0..eec1fabab54 100644
--- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GithubImport::IssueFormatter, lib: true do
- let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) }
+ let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) }
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
diff --git a/spec/lib/gitlab/github_import/label_formatter_spec.rb b/spec/lib/gitlab/github_import/label_formatter_spec.rb
index 8098754d735..10449ef5fcb 100644
--- a/spec/lib/gitlab/github_import/label_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/label_formatter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GithubImport::LabelFormatter, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:raw) { double(name: 'improvements', color: 'e6e6e6') }
subject { described_class.new(project, raw) }
diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
index 2b3256edcb2..90947ff4707 100644
--- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:source_sha) { create(:commit, project: project).id }
let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
let(:repository) { double(id: 1, fork: false) }
diff --git a/spec/lib/gitlab/github_import/release_formatter_spec.rb b/spec/lib/gitlab/github_import/release_formatter_spec.rb
index 793128c6ab9..13b15e669ab 100644
--- a/spec/lib/gitlab/github_import/release_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/release_formatter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GithubImport::ReleaseFormatter, lib: true do
- let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) }
+ let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) }
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb
index 097861fd34d..ccaa88a5c79 100644
--- a/spec/lib/gitlab/google_code_import/importer_spec.rb
+++ b/spec/lib/gitlab/google_code_import/importer_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::GoogleCodeImport::Importer, lib: true do
'user_map' => { 'thilo...' => "@#{mapped_user.username}" }
}
end
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
subject { described_class.new(project) }
diff --git a/spec/lib/gitlab/graphs/commits_spec.rb b/spec/lib/gitlab/graphs/commits_spec.rb
index f5c064303ad..abb5a26060f 100644
--- a/spec/lib/gitlab/graphs/commits_spec.rb
+++ b/spec/lib/gitlab/graphs/commits_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Graphs::Commits, lib: true do
- let!(:project) { create(:project, :public, :empty_repo) }
+ let!(:project) { create(:empty_project, :public) }
let!(:commit1) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: Time.now) }
let!(:commit1_yesterday) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: 1.day.ago)}
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
index fc021416d92..fadfe4d378e 100644
--- a/spec/lib/gitlab/highlight_spec.rb
+++ b/spec/lib/gitlab/highlight_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Highlight, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:commit) { project.commit(sample_commit.id) }
diff --git a/spec/lib/gitlab/import_export/import_export_spec.rb b/spec/lib/gitlab/import_export/import_export_spec.rb
index d6409a29550..53f7d244d88 100644
--- a/spec/lib/gitlab/import_export/import_export_spec.rb
+++ b/spec/lib/gitlab/import_export/import_export_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::ImportExport, services: true do
describe 'export filename' do
- let(:project) { create(:project, :public, path: 'project-path') }
+ let(:project) { create(:empty_project, :public, path: 'project-path') }
it 'contains the project path' do
expect(described_class.export_filename(project: project)).to include(project.path)
diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb
index b069696b5c7..0b7984d6ca9 100644
--- a/spec/lib/gitlab/import_export/members_mapper_spec.rb
+++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::MembersMapper, services: true do
describe 'map members' do
let(:user) { create(:admin, authorized_projects_populated: true) }
- let(:project) { create(:project, :public, name: 'searchable_project') }
+ let(:project) { create(:empty_project, :public, name: 'searchable_project') }
let(:user2) { create(:user, authorized_projects_populated: true) }
let(:exported_user_id) { 99 }
let(:exported_members) do
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index c8bba553558..d480c3821ec 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -151,6 +151,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
project = create(:project,
:public,
+ :repository,
issues: [issue],
snippets: [snippet],
releases: [release],
diff --git a/spec/lib/gitlab/import_export/repo_bundler_spec.rb b/spec/lib/gitlab/import_export/repo_bundler_spec.rb
index 135e99bc953..d39ea60ff7f 100644
--- a/spec/lib/gitlab/import_export/repo_bundler_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_bundler_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::RepoSaver, services: true do
describe 'bundle a project Git repo' do
let(:user) { create(:user) }
- let!(:project) { create(:project, :public, name: 'searchable_project') }
+ let!(:project) { create(:empty_project, :public, name: 'searchable_project') }
let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" }
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
let(:bundler) { described_class.new(project: project, shared: shared) }
diff --git a/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb
index b628da0f3e8..47d5d2fc150 100644
--- a/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::WikiRepoSaver, services: true do
describe 'bundle a wiki Git repo' do
let(:user) { create(:user) }
- let!(:project) { create(:project, :public, name: 'searchable_project') }
+ let!(:project) { create(:empty_project, :public, name: 'searchable_project') }
let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" }
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
let(:wiki_bundler) { described_class.new(project: project, shared: shared) }
diff --git a/spec/lib/gitlab/job_waiter_spec.rb b/spec/lib/gitlab/job_waiter_spec.rb
new file mode 100644
index 00000000000..780f5b1f8d7
--- /dev/null
+++ b/spec/lib/gitlab/job_waiter_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe Gitlab::JobWaiter do
+ describe '#wait' do
+ let(:waiter) { described_class.new(%w(a)) }
+ it 'returns when all jobs have been completed' do
+ expect(Gitlab::SidekiqStatus).to receive(:all_completed?).with(%w(a)).
+ and_return(true)
+
+ expect(waiter).not_to receive(:sleep)
+
+ waiter.wait
+ end
+
+ it 'sleeps between checking the job statuses' do
+ expect(Gitlab::SidekiqStatus).to receive(:all_completed?).
+ with(%w(a)).
+ and_return(false, true)
+
+ expect(waiter).to receive(:sleep).with(described_class::INTERVAL)
+
+ waiter.wait
+ end
+
+ it 'returns when timing out' do
+ expect(waiter).not_to receive(:sleep)
+ waiter.wait(0)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index d94eb52f838..92e3624a8d8 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::ProjectSearchResults, lib: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:query) { 'hello world' }
describe 'initialize with empty ref' do
@@ -22,6 +22,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
end
describe 'blob search' do
+ let(:project) { create(:project, :repository) }
let(:results) { described_class.new(user, project, 'files').objects('blobs') }
it 'finds by name' do
@@ -74,6 +75,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
end
describe 'confidential issues' do
+ let(:project) { create(:empty_project) }
let(:query) { 'issue' }
let(:author) { create(:user) }
let(:assignee) { create(:user) }
@@ -187,7 +189,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
#
shared_examples 'access restricted commits' do
context 'when project is internal' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:project, :internal, :repository) }
it 'does not search if user is not authenticated' do
commits = described_class.new(nil, project, search_phrase).objects('commits')
@@ -204,7 +206,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
context 'when project is private' do
let!(:creator) { create(:user, username: 'private-project-author') }
- let!(:private_project) { create(:project, :private, creator: creator, namespace: creator.namespace) }
+ let!(:private_project) { create(:project, :private, :repository, creator: creator, namespace: creator.namespace) }
let(:team_master) do
user = create(:user, username: 'private-project-master')
private_project.team << [user, :master]
@@ -246,7 +248,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
describe 'commit search' do
context 'by commit message' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:commit) { project.repository.commit('59e29889be61e6e0e5e223bfa9ac2721d31605b8') }
let(:message) { 'Sorry, I did a mistake' }
@@ -269,7 +271,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
end
context 'by commit hash' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:commit) { project.repository.commit('0b4bc9a') }
commit_hashes = { short: '0b4bc9a', full: '0b4bc9a49b562e85de7cc9e834518ea6828729b9' }
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index bf0ab9635fd..6b689c41ef6 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -1,9 +1,11 @@
require 'spec_helper'
describe Gitlab::ReferenceExtractor, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
- before { project.team << [project.creator, :developer] }
+ before do
+ project.team << [project.creator, :developer]
+ end
subject { Gitlab::ReferenceExtractor.new(project, project.creator) }
@@ -78,22 +80,27 @@ describe Gitlab::ReferenceExtractor, lib: true do
end
it 'accesses valid commits' do
+ project = create(:project, :repository) { |p| p.add_developer(p.creator) }
commit = project.commit('master')
- subject.analyze("this references commits #{commit.sha[0..6]} and 012345")
- extracted = subject.commits
+ extractor = described_class.new(project, project.creator)
+ extractor.analyze("this references commits #{commit.sha[0..6]} and 012345")
+ extracted = extractor.commits
+
expect(extracted.size).to eq(1)
expect(extracted[0].sha).to eq(commit.sha)
expect(extracted[0].message).to eq(commit.message)
end
it 'accesses valid commit ranges' do
+ project = create(:project, :repository) { |p| p.add_developer(p.creator) }
commit = project.commit('master')
earlier_commit = project.commit('master~2')
- subject.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}")
+ extractor = described_class.new(project, project.creator)
+ extractor.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}")
+ extracted = extractor.commit_ranges
- extracted = subject.commit_ranges
expect(extracted.size).to eq(1)
expect(extracted.first).to be_kind_of(CommitRange)
expect(extracted.first.commit_from).to eq earlier_commit
@@ -102,7 +109,6 @@ describe Gitlab::ReferenceExtractor, lib: true do
context 'with an external issue tracker' do
let(:project) { create(:jira_project) }
- subject { described_class.new(project, project.creator) }
it 'returns JIRA issues for a JIRA-integrated project' do
subject.analyze('JIRA-123 and FOOBAR-4567')
@@ -112,7 +118,7 @@ describe Gitlab::ReferenceExtractor, lib: true do
end
context 'with a project with an underscore' do
- let(:other_project) { create(:project, path: 'test_project') }
+ let(:other_project) { create(:empty_project, path: 'test_project') }
let(:issue) { create(:issue, project: other_project) }
before do
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index 9614aad3e73..847fb977400 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::SearchResults do
let(:user) { create(:user) }
- let!(:project) { create(:project, name: 'foo') }
+ let!(:project) { create(:empty_project, name: 'foo') }
let!(:issue) { create(:issue, project: project, title: 'foo') }
let!(:merge_request) do
diff --git a/spec/lib/gitlab/sidekiq_status/client_middleware_spec.rb b/spec/lib/gitlab/sidekiq_status/client_middleware_spec.rb
new file mode 100644
index 00000000000..287bf62d9bd
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_status/client_middleware_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqStatus::ClientMiddleware do
+ describe '#call' do
+ it 'tracks the job in Redis' do
+ expect(Gitlab::SidekiqStatus).to receive(:set).with('123')
+
+ described_class.new.
+ call('Foo', { 'jid' => '123' }, double(:queue), double(:pool)) { nil }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_status/server_middleware_spec.rb b/spec/lib/gitlab/sidekiq_status/server_middleware_spec.rb
new file mode 100644
index 00000000000..80728197b8c
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_status/server_middleware_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqStatus::ServerMiddleware do
+ describe '#call' do
+ it 'stops tracking of a job upon completion' do
+ expect(Gitlab::SidekiqStatus).to receive(:unset).with('123')
+
+ ret = described_class.new.
+ call(double(:worker), { 'jid' => '123' }, double(:queue)) { 10 }
+
+ expect(ret).to eq(10)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_status_spec.rb b/spec/lib/gitlab/sidekiq_status_spec.rb
new file mode 100644
index 00000000000..0aa36a3416b
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_status_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqStatus do
+ describe '.set', :redis do
+ it 'stores the job ID' do
+ described_class.set('123')
+
+ key = described_class.key_for('123')
+
+ Sidekiq.redis do |redis|
+ expect(redis.exists(key)).to eq(true)
+ expect(redis.ttl(key) > 0).to eq(true)
+ end
+ end
+ end
+
+ describe '.unset', :redis do
+ it 'removes the job ID' do
+ described_class.set('123')
+ described_class.unset('123')
+
+ key = described_class.key_for('123')
+
+ Sidekiq.redis do |redis|
+ expect(redis.exists(key)).to eq(false)
+ end
+ end
+ end
+
+ describe '.all_completed?', :redis do
+ it 'returns true if all jobs have been completed' do
+ expect(described_class.all_completed?(%w(123))).to eq(true)
+ end
+
+ it 'returns false if a job has not yet been completed' do
+ described_class.set('123')
+
+ expect(described_class.all_completed?(%w(123 456))).to eq(false)
+ end
+ end
+
+ describe '.key_for' do
+ it 'returns the key for a job ID' do
+ key = described_class.key_for('123')
+
+ expect(key).to be_an_instance_of(String)
+ expect(key).to include('123')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb
index d2d334e6413..45cec65a284 100644
--- a/spec/lib/gitlab/template/issue_template_spec.rb
+++ b/spec/lib/gitlab/template/issue_template_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::Template::IssueTemplate do
subject { described_class }
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:file_path_1) { '.gitlab/issue_templates/bug.md' }
let(:file_path_2) { '.gitlab/issue_templates/template_test.md' }
let(:file_path_3) { '.gitlab/issue_templates/feature_proposal.md' }
diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb
index ddf68c4cf78..ae51b79be22 100644
--- a/spec/lib/gitlab/template/merge_request_template_spec.rb
+++ b/spec/lib/gitlab/template/merge_request_template_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::Template::MergeRequestTemplate do
subject { described_class }
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:file_path_1) { '.gitlab/merge_request_templates/bug.md' }
let(:file_path_2) { '.gitlab/merge_request_templates/template_test.md' }
let(:file_path_3) { '.gitlab/merge_request_templates/feature_proposal.md' }
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index a826b24419a..3fe8cf43934 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -99,7 +99,7 @@ describe Gitlab::UrlBuilder, lib: true do
context 'on another object' do
it 'returns a proper URL' do
- project = build_stubbed(:project)
+ project = build_stubbed(:empty_project)
expect { described_class.build(project) }.
to raise_error(NotImplementedError, 'No URL builder defined for Project')
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 4b1cd466677..7dd4d76d1a3 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Workhorse, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
def decode_workhorse_header(array)
diff --git a/spec/lib/light_url_builder_spec.rb b/spec/lib/light_url_builder_spec.rb
index a826b24419a..3fe8cf43934 100644
--- a/spec/lib/light_url_builder_spec.rb
+++ b/spec/lib/light_url_builder_spec.rb
@@ -99,7 +99,7 @@ describe Gitlab::UrlBuilder, lib: true do
context 'on another object' do
it 'returns a proper URL' do
- project = build_stubbed(:project)
+ project = build_stubbed(:empty_project)
expect { described_class.build(project) }.
to raise_error(NotImplementedError, 'No URL builder defined for Project')
diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb
index f227926f39c..5892f3481a4 100644
--- a/spec/lib/repository_cache_spec.rb
+++ b/spec/lib/repository_cache_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe RepositoryCache, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:backend) { double('backend').as_null_object }
let(:cache) { RepositoryCache.new('example', project.id, backend) }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index bfa36d92ac3..61d72925736 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -217,7 +217,7 @@ describe Issue, models: true do
end
it_behaves_like 'an editable mentionable' do
- subject { create(:issue) }
+ subject { create(:issue, project: create(:project, :repository)) }
let(:backref_text) { "issue #{subject.to_reference}" }
let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 1b8ae356f1f..6f9ae655fed 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -138,7 +138,7 @@ describe Note, models: true do
it_behaves_like 'an editable mentionable' do
subject { create :note, noteable: issue, project: issue.project }
- let(:issue) { create :issue }
+ let(:issue) { create(:issue, project: create(:project, :repository)) }
let(:backref_text) { issue.gfm_reference }
let(:set_mentionable_text) { ->(txt) { subject.note = txt } }
end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 5abda28e26f..6a5ad6deb74 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -55,6 +55,28 @@ describe 'Git HTTP requests', lib: true do
expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
end
end
+
+ context 'but the repo is disabled' do
+ let(:project) { create(:project, repository_access_level: ProjectFeature::DISABLED, wiki_access_level: ProjectFeature::ENABLED) }
+ let(:wiki) { ProjectWiki.new(project) }
+ let(:path) { "/#{wiki.repository.path_with_namespace}.git" }
+
+ before do
+ project.team << [user, :developer]
+ end
+
+ it 'allows clones' do
+ download(path, user: user.username, password: user.password) do |response|
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ it 'allows pushes' do
+ upload(path, user: user.username, password: user.password) do |response|
+ expect(response).to have_http_status(200)
+ end
+ end
+ end
end
context "when the project exists" do
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index fef211ded50..db9f1231682 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -12,6 +12,7 @@ describe SystemHooksService, services: true do
it { expect(event_data(user, :create)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) }
it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) }
it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
+ it { expect(event_data(project, :update)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) }
it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) }
@@ -68,6 +69,7 @@ describe SystemHooksService, services: true do
it { expect(event_name(project, :destroy)).to eq "project_destroy" }
it { expect(event_name(project, :rename)).to eq "project_rename" }
it { expect(event_name(project, :transfer)).to eq "project_transfer" }
+ it { expect(event_name(project, :update)).to eq "project_update" }
it { expect(event_name(project_member, :create)).to eq "user_add_to_team" }
it { expect(event_name(project_member, :destroy)).to eq "user_remove_from_team" }
it { expect(event_name(key, :create)).to eq 'key_create' }
diff --git a/spec/services/user_project_access_changed_service_spec.rb b/spec/services/user_project_access_changed_service_spec.rb
new file mode 100644
index 00000000000..b4efe7de431
--- /dev/null
+++ b/spec/services/user_project_access_changed_service_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe UserProjectAccessChangedService do
+ describe '#execute' do
+ it 'schedules the user IDs' do
+ expect(AuthorizedProjectsWorker).to receive(:bulk_perform_and_wait).
+ with([[1], [2]])
+
+ described_class.new([1, 2]).execute
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index f78899134d5..e160c11111b 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -7,7 +7,6 @@ ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'shoulda/matchers'
-require 'sidekiq/testing/inline'
require 'rspec/retry'
if ENV['CI'] && !ENV['NO_KNAPSACK']
diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb
new file mode 100644
index 00000000000..575d3451150
--- /dev/null
+++ b/spec/support/sidekiq.rb
@@ -0,0 +1,5 @@
+require 'sidekiq/testing/inline'
+
+Sidekiq::Testing.server_middleware do |chain|
+ chain.add Gitlab::SidekiqStatus::ServerMiddleware
+end
diff --git a/spec/support/taskable_shared_examples.rb b/spec/support/taskable_shared_examples.rb
index 1b6c33248c9..4056ff06b84 100644
--- a/spec/support/taskable_shared_examples.rb
+++ b/spec/support/taskable_shared_examples.rb
@@ -72,6 +72,25 @@ shared_examples 'a Taskable' do
end
end
+ describe 'with tasks that are not formatted correctly' do
+ before do
+ subject.description = <<-EOT.strip_heredoc
+ [ ] task 1
+ [ ] task 2
+
+ - [ ]task 1
+ -[ ] task 2
+ EOT
+ end
+
+ it 'returns the correct task status' do
+ expect(subject.task_status).to match('0 of')
+ expect(subject.task_status).to match('0 tasks completed')
+ expect(subject.task_status_short).to match('0/')
+ expect(subject.task_status_short).to match('0 task')
+ end
+ end
+
describe 'with a complete task' do
before do
subject.description = <<-EOT.strip_heredoc
diff --git a/spec/workers/authorized_projects_worker_spec.rb b/spec/workers/authorized_projects_worker_spec.rb
index b6591f272f6..97c4bfcd248 100644
--- a/spec/workers/authorized_projects_worker_spec.rb
+++ b/spec/workers/authorized_projects_worker_spec.rb
@@ -3,6 +3,18 @@ require 'spec_helper'
describe AuthorizedProjectsWorker do
let(:worker) { described_class.new }
+ describe '.bulk_perform_and_wait' do
+ it 'schedules the ids and waits for the jobs to complete' do
+ project = create(:project)
+
+ project.owner.project_authorizations.delete_all
+
+ described_class.bulk_perform_and_wait([[project.owner.id]])
+
+ expect(project.owner.project_authorizations.count).to eq(1)
+ end
+ end
+
describe '#perform' do
it "refreshes user's authorized projects" do
user = create(:user)