summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2017-08-01 17:45:20 +0100
committerFilipa Lacerda <filipa@gitlab.com>2017-08-01 17:45:20 +0100
commit335d4a535f737f19ef4959ec4027681d97d1002b (patch)
tree0d80d58b8f66c2770698d842866ac497d56f9756
parent95f9d6d83bcb7a9f45601f828c34301e536fc195 (diff)
parent4c77c30fbfb3734fd893f7cfe540fa595ea6539c (diff)
downloadgitlab-ce-335d4a535f737f19ef4959ec4027681d97d1002b.tar.gz
Merge branch 'master' into issue-discussions-refactor
* master: (76 commits) Add code review guidelines related to Build [CI skip]. Make time span dropdown style on cycle analytics page consistent Add 204. Remove duplicated method. Make sure we didn't commit conflicts Fix bug in blob test Always fetch branches before finding the merge base, otherwise we could find an outdated merge base Fixes dropdown margin in sidebar Docs add blog articles Inline script cleanup globals and easy Add option to use CommitLanguages RPC CI fixes for gitaly-ruby fix Allow logged in users to read user list under public restriction Small refactor in LegacyNamespace and moved back send_update_instructions Rename ensure_dir_exist -> ensure_storage_path_exist Added some extra TODOs for the Legacy Storage refactor Make disk_path keyword argument and optional Rename more path_with_namespace -> full_path or disk_path Rename path_with_namespace -> disk_path when dealing with the filesystem Rename many path_with_namespace -> full_path ...
-rw-r--r--.gitlab-ci.yml3
-rw-r--r--.rubocop.yml452
-rw-r--r--.rubocop_todo.yml225
-rw-r--r--CHANGELOG.md10
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock14
-rw-r--r--PROCESS.md20
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js5
-rw-r--r--app/assets/javascripts/build.js19
-rw-r--r--app/assets/javascripts/dispatcher.js43
-rw-r--r--app/assets/javascripts/graphs/graphs_bundle.js2
-rw-r--r--app/assets/javascripts/graphs/graphs_charts.js63
-rw-r--r--app/assets/javascripts/graphs/graphs_show.js21
-rw-r--r--app/assets/javascripts/pipelines/pipelines_charts.js38
-rw-r--r--app/assets/javascripts/pipelines/pipelines_times.js27
-rw-r--r--app/assets/javascripts/projects/project_new.js43
-rw-r--r--app/assets/javascripts/ref_select_dropdown.js3
-rw-r--r--app/assets/javascripts/two_factor_auth.js13
-rw-r--r--app/assets/javascripts/ui_development_kit.js22
-rw-r--r--app/assets/stylesheets/framework/filters.scss8
-rw-r--r--app/assets/stylesheets/framework/header.scss23
-rw-r--r--app/assets/stylesheets/framework/layout.scss4
-rw-r--r--app/assets/stylesheets/framework/nav.scss20
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss4
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/new_nav.scss22
-rw-r--r--app/assets/stylesheets/new_sidebar.scss12
-rw-r--r--app/assets/stylesheets/pages/builds.scss19
-rw-r--r--app/assets/stylesheets/pages/cycle_analytics.scss22
-rw-r--r--app/assets/stylesheets/pages/issuable.scss8
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss4
-rw-r--r--app/assets/stylesheets/pages/tree.scss22
-rw-r--r--app/assets/stylesheets/performance_bar.scss14
-rw-r--r--app/controllers/projects/graphs_controller.rb18
-rw-r--r--app/helpers/application_helper.rb6
-rw-r--r--app/helpers/gitlab_routing_helper.rb14
-rw-r--r--app/helpers/merge_requests_helper.rb2
-rw-r--r--app/helpers/nav_helper.rb33
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/mailers/notify.rb2
-rw-r--r--app/models/ci/pipeline.rb2
-rw-r--r--app/models/concerns/storage/legacy_namespace.rb102
-rw-r--r--app/models/concerns/storage/legacy_project.rb76
-rw-r--r--app/models/concerns/storage/legacy_project_wiki.rb9
-rw-r--r--app/models/concerns/storage/legacy_repository.rb7
-rw-r--r--app/models/merge_request.rb4
-rw-r--r--app/models/namespace.rb98
-rw-r--r--app/models/notification_setting.rb34
-rw-r--r--app/models/project.rb120
-rw-r--r--app/models/project_services/flowdock_service.rb6
-rw-r--r--app/models/project_services/jira_service.rb2
-rw-r--r--app/models/project_wiki.rb26
-rw-r--r--app/models/repository.rb22
-rw-r--r--app/policies/global_policy.rb2
-rw-r--r--app/services/git_operation_service.rb2
-rw-r--r--app/services/projects/destroy_service.rb6
-rw-r--r--app/services/projects/import_export/export_service.rb2
-rw-r--r--app/services/projects/import_service.rb4
-rw-r--r--app/services/projects/transfer_service.rb4
-rw-r--r--app/services/quick_actions/interpret_service.rb16
-rw-r--r--app/services/system_hooks_service.rb8
-rw-r--r--app/uploaders/file_uploader.rb2
-rw-r--r--app/views/admin/groups/show.html.haml4
-rw-r--r--app/views/help/ui.html.haml25
-rw-r--r--app/views/import/_githubish_status.html.haml2
-rw-r--r--app/views/import/base/create.js.haml2
-rw-r--r--app/views/import/bitbucket/status.html.haml2
-rw-r--r--app/views/import/fogbugz/status.html.haml2
-rw-r--r--app/views/import/gitlab/status.html.haml2
-rw-r--r--app/views/import/google_code/status.html.haml2
-rw-r--r--app/views/layouts/_google_analytics.html.haml1
-rw-r--r--app/views/layouts/_init_auto_complete.html.haml1
-rw-r--r--app/views/layouts/_page.html.haml4
-rw-r--r--app/views/layouts/_piwik.html.haml1
-rw-r--r--app/views/layouts/application.html.haml5
-rw-r--r--app/views/layouts/nav/_new_admin_sidebar.html.haml2
-rw-r--r--app/views/layouts/nav/_new_group_sidebar.html.haml4
-rw-r--r--app/views/layouts/project.html.haml1
-rw-r--r--app/views/layouts/snippets.html.haml1
-rw-r--r--app/views/peek/views/_host.html.haml2
-rw-r--r--app/views/profiles/personal_access_tokens/index.html.haml8
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml163
-rw-r--r--app/views/projects/_activity.html.haml6
-rw-r--r--app/views/projects/blob/_new_dir.html.haml3
-rw-r--r--app/views/projects/blob/_remove.html.haml3
-rw-r--r--app/views/projects/branches/new.html.haml6
-rw-r--r--app/views/projects/commit/_commit_box.html.haml5
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/commits/show.html.haml52
-rw-r--r--app/views/projects/find_file/show.html.haml10
-rw-r--r--app/views/projects/graphs/charts.html.haml64
-rw-r--r--app/views/projects/graphs/show.html.haml28
-rw-r--r--app/views/projects/imports/show.html.haml2
-rw-r--r--app/views/projects/mattermosts/_team_selection.html.haml2
-rw-r--r--app/views/projects/merge_requests/creations/_new_compare.html.haml2
-rw-r--r--app/views/projects/merge_requests/dropdowns/_project.html.haml2
-rw-r--r--app/views/projects/new.html.haml45
-rw-r--r--app/views/projects/pipelines/charts/_pipeline_times.haml25
-rw-r--r--app/views/projects/pipelines/charts/_pipelines.haml36
-rw-r--r--app/views/projects/pipelines/new.html.haml5
-rw-r--r--app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml2
-rw-r--r--app/views/projects/services/slack_slash_commands/_help.html.haml2
-rw-r--r--app/views/projects/tags/new.html.haml5
-rw-r--r--app/views/projects/tree/_tree_content.html.haml8
-rw-r--r--app/views/projects/wikis/_sidebar.html.haml3
-rw-r--r--app/views/projects/wikis/git_access.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/views/u2f/_register.html.haml4
-rw-r--r--app/workers/git_garbage_collect_worker.rb39
-rw-r--r--app/workers/irker_worker.rb4
-rw-r--r--app/workers/repository_import_worker.rb2
-rw-r--r--changelogs/unreleased/29385-add_shrug_command.yml4
-rw-r--r--changelogs/unreleased/33620-remove-events-from-notification_settings.yml4
-rw-r--r--changelogs/unreleased/34492-firefox-job.yml4
-rw-r--r--changelogs/unreleased/34519-extend-api-group-secret-variable.yml4
-rw-r--r--changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml4
-rw-r--r--changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml5
-rw-r--r--changelogs/unreleased/35697-allow-logged-in-user-to-read-user-list.yml4
-rw-r--r--changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml4
-rw-r--r--changelogs/unreleased/fix-group-milestone-link-in-issuable-sidebar.yml4
-rw-r--r--changelogs/unreleased/help-page-breadcrumb-title-fix.yml4
-rw-r--r--changelogs/unreleased/mk-fix-deploy-key-deletion.yml4
-rw-r--r--changelogs/unreleased/mk-fix-wiki-backup.yml4
-rw-r--r--changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml4
-rw-r--r--changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml4
-rw-r--r--config/gitlab.yml.example2
-rw-r--r--config/webpack.config.js10
-rw-r--r--db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb1
-rw-r--r--db/post_migrate/20170728101014_remove_events_from_notification_settings.rb9
-rw-r--r--db/schema.rb23
-rw-r--r--doc/README.md13
-rw-r--r--doc/administration/auth/ldap.md6
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar.pngbin186116 -> 170256 bytes
-rw-r--r--doc/api/README.md3
-rw-r--r--doc/api/group_level_variables.md125
-rw-r--r--doc/api/project_level_variables.md (renamed from doc/api/build_variables.md)12
-rw-r--r--doc/articles/index.md114
-rw-r--r--doc/development/code_review.md3
-rw-r--r--doc/integration/slash_commands.md21
-rw-r--r--doc/user/group/index.md2
-rw-r--r--doc/user/index.md2
-rw-r--r--doc/user/profile/index.md2
-rw-r--r--doc/user/project/index.md107
-rw-r--r--doc/user/project/koding.md2
-rw-r--r--doc/user/project/repository/index.md2
-rw-r--r--features/steps/project/forked_merge_requests.rb12
-rw-r--r--features/steps/project/redirects.rb4
-rw-r--r--features/steps/project/wiki.rb2
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/group_variables.rb96
-rw-r--r--lib/api/runner.rb4
-rw-r--r--lib/backup/repository.rb19
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb4
-rw-r--r--lib/banzai/filter/relative_link_filter.rb2
-rw-r--r--lib/banzai/filter/upload_link_filter.rb2
-rw-r--r--lib/ci/api/builds.rb4
-rw-r--r--lib/github/import.rb2
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb2
-rw-r--r--lib/gitlab/diff/file.rb18
-rw-r--r--lib/gitlab/ee_compat_check.rb2
-rw-r--r--lib/gitlab/email/message/repository_push.rb2
-rw-r--r--lib/gitlab/git/repository.rb27
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb7
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb18
-rw-r--r--lib/gitlab/github_import/importer.rb2
-rw-r--r--lib/gitlab/github_import/wiki_formatter.rb4
-rw-r--r--lib/gitlab/import_export/repo_restorer.rb2
-rw-r--r--lib/gitlab/import_export/uploads_saver.rb1
-rw-r--r--lib/gitlab/ldap/authentication.rb2
-rw-r--r--lib/gitlab/quick_actions/dsl.rb29
-rw-r--r--lib/gitlab/quick_actions/extractor.rb22
-rw-r--r--lib/gitlab/quick_actions/substitution_definition.rb24
-rw-r--r--lib/gitlab/slash_commands/deploy.rb33
-rw-r--r--lib/gitlab/slash_commands/presenters/deploy.rb11
-rwxr-xr-xlib/support/init.d/gitlab6
-rw-r--r--lib/tasks/gitlab/check.rake2
-rw-r--r--lib/tasks/gitlab/gitaly.rake12
-rw-r--r--lib/tasks/gitlab/list_repos.rake2
-rw-r--r--lib/tasks/gitlab/shell.rake2
-rw-r--r--locale/pt_BR/gitlab.po14
-rw-r--r--rubocop/cop/migration/add_column_with_default_to_large_table.rb1
-rwxr-xr-xscripts/gitaly-test-build10
-rwxr-xr-xscripts/gitaly-test-spawn7
-rwxr-xr-xscripts/lint-conflicts.sh5
-rwxr-xr-xscripts/static-analysis3
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb2
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb6
-rw-r--r--spec/controllers/projects/graphs_controller_spec.rb33
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb2
-rw-r--r--spec/controllers/projects/tree_controller_spec.rb6
-rw-r--r--spec/factories/milestones.rb2
-rw-r--r--spec/factories/notification_settings.rb1
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb4
-rw-r--r--spec/features/commits_spec.rb4
-rw-r--r--spec/features/merge_requests/create_new_mr_spec.rb8
-rw-r--r--spec/features/projects/wiki/markdown_preview_spec.rb48
-rw-r--r--spec/features/projects/wiki/user_git_access_wiki_page_spec.rb2
-rw-r--r--spec/helpers/gitlab_routing_helper_spec.rb53
-rw-r--r--spec/helpers/labels_helper_spec.rb4
-rw-r--r--spec/helpers/markup_helper_spec.rb4
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb4
-rw-r--r--spec/helpers/projects_helper_spec.rb4
-rw-r--r--spec/lib/banzai/filter/abstract_reference_filter_spec.rb14
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb12
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb34
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/snippet_reference_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb10
-rw-r--r--spec/lib/extracts_path_spec.rb4
-rw-r--r--spec/lib/gitlab/backup/repository_spec.rb54
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb8
-rw-r--r--spec/lib/gitlab/email/message/repository_push_spec.rb2
-rw-r--r--spec/lib/gitlab/gfm/uploads_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb10
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb39
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb2
-rw-r--r--spec/lib/gitlab/gitaly_client/notification_service_spec.rb2
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_service_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/wiki_formatter_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/fork_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/repo_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/repo_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/quick_actions/dsl_spec.rb16
-rw-r--r--spec/lib/gitlab/quick_actions/extractor_spec.rb37
-rw-r--r--spec/lib/gitlab/quick_actions/substitution_definition_spec.rb42
-rw-r--r--spec/lib/gitlab/slash_commands/command_spec.rb2
-rw-r--r--spec/lib/gitlab/slash_commands/deploy_spec.rb56
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb20
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb18
-rw-r--r--spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb2
-rw-r--r--spec/migrations/migrate_process_commit_worker_jobs_spec.rb2
-rw-r--r--spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb2
-rw-r--r--spec/models/commit_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb2
-rw-r--r--spec/models/notification_setting_spec.rb12
-rw-r--r--spec/models/project_label_spec.rb4
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb12
-rw-r--r--spec/models/project_services/jira_service_spec.rb6
-rw-r--r--spec/models/project_spec.rb84
-rw-r--r--spec/models/project_wiki_spec.rb18
-rw-r--r--spec/models/repository_spec.rb2
-rw-r--r--spec/requests/api/group_variables_spec.rb221
-rw-r--r--spec/requests/api/internal_spec.rb4
-rw-r--r--spec/requests/api/notification_settings_spec.rb4
-rw-r--r--spec/requests/api/users_spec.rb40
-rw-r--r--spec/requests/git_http_spec.rb42
-rw-r--r--spec/requests/lfs_http_spec.rb2
-rw-r--r--spec/requests/request_profiler_spec.rb2
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb36
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb2
-rw-r--r--spec/services/git_push_service_spec.rb2
-rw-r--r--spec/services/notification_service_spec.rb47
-rw-r--r--spec/services/projects/import_service_spec.rb10
-rw-r--r--spec/services/projects/transfer_service_spec.rb24
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb42
-rw-r--r--spec/services/system_note_service_spec.rb4
-rw-r--r--spec/spec_helper.rb4
-rw-r--r--spec/support/notify_shared_examples.rb2
-rw-r--r--spec/support/project_hook_data_shared_example.rb4
-rw-r--r--spec/support/test_env.rb11
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb6
-rw-r--r--spec/tasks/gitlab/gitaly_rake_spec.rb18
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb52
-rw-r--r--spec/workers/namespaceless_project_destroy_worker_spec.rb2
272 files changed, 3154 insertions, 1596 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index adde3400107..27fdf6ca0b5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -96,6 +96,7 @@ stages:
- export KNAPSACK_GENERATE_REPORT=true
- export CACHE_CLASSES=true
- cp ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
+ - scripts/gitaly-test-spawn
- knapsack rspec "--color --format documentation"
artifacts:
expire_in: 31d
@@ -221,6 +222,7 @@ setup-test-env:
- bundle exec rake gettext:po_to_json
- bundle exec rake gitlab:assets:compile
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
+ - scripts/gitaly-test-build # Do not use 'bundle exec' here
artifacts:
expire_in: 7d
paths:
@@ -486,6 +488,7 @@ karma:
BABEL_ENV: "coverage"
CHROME_LOG_FILE: "chrome_debug.log"
script:
+ - scripts/gitaly-test-spawn
- bundle exec rake gettext:po_to_json
- bundle exec rake karma
coverage: '/^Statements *: (\d+\.\d+%)/'
diff --git a/.rubocop.yml b/.rubocop.yml
index f661a29d9d1..3e4275c271d 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -6,6 +6,7 @@ inherit_from: .rubocop_todo.yml
AllCops:
TargetRubyVersion: 2.3
+ TargetRailsVersion: 4.2
# Cop names are not d§splayed in offense messages by default. Change behavior
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names
# option.
@@ -29,34 +30,230 @@ AllCops:
Bundler/OrderedGems:
Enabled: false
-# Style #######################################################################
+# Layout ######################################################################
# Check indentation of private/protected visibility modifiers.
-Style/AccessModifierIndentation:
- Enabled: true
-
-# Check the naming of accessor methods for get_/set_.
-Style/AccessorMethodName:
- Enabled: false
-
-# Use alias_method instead of alias.
-Style/Alias:
- EnforcedStyle: prefer_alias_method
+Layout/AccessModifierIndentation:
Enabled: true
# Align the elements of an array literal if they span more than one line.
-Style/AlignArray:
+Layout/AlignArray:
Enabled: true
# Align the elements of a hash literal if they span more than one line.
-Style/AlignHash:
+Layout/AlignHash:
Enabled: true
# Here we check if the parameters on a multi-line method call or
# definition are aligned.
-Style/AlignParameters:
+Layout/AlignParameters:
+ Enabled: false
+
+# Put end statement of multiline block on its own line.
+Layout/BlockEndNewline:
+ Enabled: true
+
+# Indentation of when in a case/when/[else/]end.
+Layout/CaseIndentation:
+ Enabled: true
+
+# Indentation of comments.
+Layout/CommentIndentation:
+ Enabled: true
+
+# Multi-line method chaining should be done with leading dots.
+Layout/DotPosition:
+ Enabled: true
+ EnforcedStyle: leading
+
+# Align elses and elsifs correctly.
+Layout/ElseAlignment:
+ Enabled: true
+
+# Add an empty line after magic comments to separate them from code.
+Layout/EmptyLineAfterMagicComment:
+ Enabled: false
+
+# Use empty lines between defs.
+Layout/EmptyLineBetweenDefs:
+ Enabled: true
+
+# Don't use several empty lines in a row.
+Layout/EmptyLines:
+ Enabled: true
+
+# Keep blank lines around access modifiers.
+Layout/EmptyLinesAroundAccessModifier:
+ Enabled: true
+
+# Keeps track of empty lines around block bodies.
+Layout/EmptyLinesAroundBlockBody:
+ Enabled: true
+
+# Keeps track of empty lines around class bodies.
+Layout/EmptyLinesAroundClassBody:
+ Enabled: true
+
+# Keeps track of empty lines around exception handling keywords.
+Layout/EmptyLinesAroundExceptionHandlingKeywords:
+ Enabled: false
+
+# Keeps track of empty lines around method bodies.
+Layout/EmptyLinesAroundMethodBody:
+ Enabled: true
+
+# Keeps track of empty lines around module bodies.
+Layout/EmptyLinesAroundModuleBody:
+ Enabled: true
+
+# Use Unix-style line endings.
+Layout/EndOfLine:
+ Enabled: true
+
+# Checks for a line break before the first parameter in a multi-line method
+# parameter definition.
+Layout/FirstMethodParameterLineBreak:
+ Enabled: true
+
+# Keep indentation straight.
+Layout/IndentationConsistency:
+ Enabled: true
+
+# Use 2 spaces for indentation.
+Layout/IndentationWidth:
+ Enabled: true
+
+# Checks the indentation of the first line of the right-hand-side of a
+# multi-line assignment.
+Layout/IndentAssignment:
+ Enabled: true
+
+# This cops checks the indentation of the here document bodies.
+Layout/IndentHeredoc:
+ Enabled: false
+
+# Comments should start with a space.
+Layout/LeadingCommentSpace:
+ Enabled: true
+
+# Checks that the closing brace in an array literal is either on the same line
+# as the last array element, or a new line.
+Layout/MultilineArrayBraceLayout:
+ Enabled: true
+ EnforcedStyle: symmetrical
+
+# Ensures newlines after multiline block do statements.
+Layout/MultilineBlockLayout:
+ Enabled: true
+
+# Checks that the closing brace in a hash literal is either on the same line as
+# the last hash element, or a new line.
+Layout/MultilineHashBraceLayout:
+ Enabled: true
+ EnforcedStyle: symmetrical
+
+# Checks that the closing brace in a method call is either on the same line as
+# the last method argument, or a new line.
+Layout/MultilineMethodCallBraceLayout:
+ Enabled: false
+ EnforcedStyle: symmetrical
+
+# Checks indentation of method calls with the dot operator that span more than
+# one line.
+Layout/MultilineMethodCallIndentation:
+ Enabled: false
+
+# Checks that the closing brace in a method definition is symmetrical with
+# respect to the opening brace and the method parameters.
+Layout/MultilineMethodDefinitionBraceLayout:
+ Enabled: false
+
+# Checks indentation of binary operations that span more than one line.
+Layout/MultilineOperationIndentation:
+ Enabled: true
+ EnforcedStyle: indented
+
+# Use spaces after colons.
+Layout/SpaceAfterColon:
+ Enabled: true
+
+# Use spaces after commas.
+Layout/SpaceAfterComma:
+ Enabled: true
+
+# Do not put a space between a method name and the opening parenthesis in a
+# method definition.
+Layout/SpaceAfterMethodName:
+ Enabled: true
+
+# Tracks redundant space after the ! operator.
+Layout/SpaceAfterNot:
+ Enabled: true
+
+# Use spaces after semicolons.
+Layout/SpaceAfterSemicolon:
+ Enabled: true
+
+# Use space around equals in parameter default
+Layout/SpaceAroundEqualsInParameterDefault:
+ Enabled: true
+
+# Use a space around keywords if appropriate.
+Layout/SpaceAroundKeyword:
+ Enabled: true
+
+# Use a single space around operators.
+Layout/SpaceAroundOperators:
+ Enabled: true
+
+# No spaces before commas.
+Layout/SpaceBeforeComma:
+ Enabled: true
+
+# Checks for missing space between code and a comment on the same line.
+Layout/SpaceBeforeComment:
+ Enabled: true
+
+# No spaces before semicolons.
+Layout/SpaceBeforeSemicolon:
+ Enabled: true
+
+# Checks for spaces inside square brackets.
+Layout/SpaceInsideBrackets:
+ Enabled: true
+
+# Use spaces inside hash literal braces - or don't.
+Layout/SpaceInsideHashLiteralBraces:
+ Enabled: true
+
+# No spaces inside range literals.
+Layout/SpaceInsideRangeLiteral:
+ Enabled: true
+
+# Checks for padding/surrounding spaces inside string interpolation.
+Layout/SpaceInsideStringInterpolation:
+ EnforcedStyle: no_space
+ Enabled: true
+
+# No hard tabs.
+Layout/Tab:
+ Enabled: true
+
+# Checks trailing blank lines and final newline.
+Layout/TrailingBlankLines:
+ Enabled: true
+
+# Style #######################################################################
+
+# Check the naming of accessor methods for get_/set_.
+Style/AccessorMethodName:
Enabled: false
+# Use alias_method instead of alias.
+Style/Alias:
+ EnforcedStyle: prefer_alias_method
+ Enabled: true
+
# Whether `and` and `or` are banned only in conditionals (conditionals)
# or completely (always).
Style/AndOr:
@@ -91,10 +288,6 @@ Style/BlockComments:
Style/BlockDelimiters:
Enabled: true
-# Put end statement of multiline block on its own line.
-Style/BlockEndNewline:
- Enabled: true
-
# This cop checks for braces around the last parameter in a method call
# if the last parameter is a hash.
Style/BracesAroundHashParameters:
@@ -104,10 +297,6 @@ Style/BracesAroundHashParameters:
Style/CaseEquality:
Enabled: false
-# Indentation of when in a case/when/[else/]end.
-Style/CaseIndentation:
- Enabled: true
-
# Checks for uses of character literals.
Style/CharacterLiteral:
Enabled: true
@@ -142,10 +331,6 @@ Style/ColonMethodCall:
Style/CommentAnnotation:
Enabled: false
-# Indentation of comments.
-Style/CommentIndentation:
- Enabled: true
-
# Check for `if` and `case` statements where each branch is used for
# assignment to the same variable when using the return of the
# condition can be used instead.
@@ -164,57 +349,16 @@ Style/DefWithParentheses:
Style/Documentation:
Enabled: false
-# Multi-line method chaining should be done with leading dots.
-Style/DotPosition:
- Enabled: true
- EnforcedStyle: leading
-
# This cop checks for uses of double negation (!!) to convert something
# to a boolean value. As this is both cryptic and usually redundant, it
# should be avoided.
Style/DoubleNegation:
Enabled: false
-# Align elses and elsifs correctly.
-Style/ElseAlignment:
- Enabled: true
-
-# Use empty lines between defs.
-Style/EmptyLineBetweenDefs:
- Enabled: true
-
-# Don't use several empty lines in a row.
-Style/EmptyLines:
- Enabled: true
-
-# Keep blank lines around access modifiers.
-Style/EmptyLinesAroundAccessModifier:
- Enabled: true
-
-# Keeps track of empty lines around block bodies.
-Style/EmptyLinesAroundBlockBody:
- Enabled: true
-
-# Keeps track of empty lines around class bodies.
-Style/EmptyLinesAroundClassBody:
- Enabled: true
-
-# Keeps track of empty lines around method bodies.
-Style/EmptyLinesAroundMethodBody:
- Enabled: true
-
-# Keeps track of empty lines around module bodies.
-Style/EmptyLinesAroundModuleBody:
- Enabled: true
-
# Avoid the use of END blocks.
Style/EndBlock:
Enabled: true
-# Use Unix-style line endings.
-Style/EndOfLine:
- Enabled: true
-
# Favor the use of Fixnum#even? && Fixnum#odd?
Style/EvenOdd:
Enabled: true
@@ -223,11 +367,6 @@ Style/EvenOdd:
Style/FileName:
Enabled: true
-# Checks for a line break before the first parameter in a multi-line method
-# parameter definition.
-Style/FirstMethodParameterLineBreak:
- Enabled: true
-
# Checks for flip flops.
Style/FlipFlop:
Enabled: true
@@ -236,6 +375,10 @@ Style/FlipFlop:
Style/For:
Enabled: true
+# Use a consistent style for format string tokens.
+Style/FormatStringToken:
+ Enabled: false
+
# Checks if there is a magic comment to enforce string literals
Style/FrozenStringLiteralComment:
Enabled: false
@@ -261,31 +404,19 @@ Style/IdenticalConditionalBranches:
Style/IfWithSemicolon:
Enabled: true
-# Checks the indentation of the first line of the right-hand-side of a
-# multi-line assignment.
-Style/IndentAssignment:
- Enabled: true
-
-# Keep indentation straight.
-Style/IndentationConsistency:
- Enabled: true
-
-# Use 2 spaces for indentation.
-Style/IndentationWidth:
- Enabled: true
-
# Use Kernel#loop for infinite loops.
Style/InfiniteLoop:
Enabled: true
+# Use the inverse method instead of `!.method`
+# if an inverse method is defined.
+Style/InverseMethods:
+ Enabled: false
+
# Use lambda.call(...) instead of lambda.(...).
Style/LambdaCall:
Enabled: true
-# Comments should start with a space.
-Style/LeadingCommentSpace:
- Enabled: true
-
# Checks if the method definitions have or don't have parentheses.
Style/MethodDefParentheses:
Enabled: true
@@ -298,55 +429,23 @@ Style/MethodName:
Style/ModuleFunction:
Enabled: false
-# Checks that the closing brace in an array literal is either on the same line
-# as the last array element, or a new line.
-Style/MultilineArrayBraceLayout:
- Enabled: true
- EnforcedStyle: symmetrical
-
# Avoid multi-line chains of blocks.
Style/MultilineBlockChain:
Enabled: true
-# Ensures newlines after multiline block do statements.
-Style/MultilineBlockLayout:
- Enabled: true
-
-# Checks that the closing brace in a hash literal is either on the same line as
-# the last hash element, or a new line.
-Style/MultilineHashBraceLayout:
- Enabled: true
- EnforcedStyle: symmetrical
-
# Do not use then for multi-line if/unless.
Style/MultilineIfThen:
Enabled: true
-# Checks that the closing brace in a method call is either on the same line as
-# the last method argument, or a new line.
-Style/MultilineMethodCallBraceLayout:
- Enabled: false
- EnforcedStyle: symmetrical
-
-# Checks indentation of method calls with the dot operator that span more than
-# one line.
-Style/MultilineMethodCallIndentation:
- Enabled: false
-
-# Checks that the closing brace in a method definition is symmetrical with
-# respect to the opening brace and the method parameters.
-Style/MultilineMethodDefinitionBraceLayout:
- Enabled: false
-
-# Checks indentation of binary operations that span more than one line.
-Style/MultilineOperationIndentation:
- Enabled: true
- EnforcedStyle: indented
-
# Avoid multi-line `? :` (the ternary operator), use if/unless instead.
Style/MultilineTernaryOperator:
Enabled: true
+# Avoid comparing a variable with multiple items in a conditional,
+# use Array#include? instead.
+Style/MultipleComparison:
+ Enabled: false
+
# This cop checks whether some constant value isn't a
# mutable literal (e.g. array or hash).
Style/MutableConstant:
@@ -421,68 +520,6 @@ Style/SignalException:
EnforcedStyle: only_raise
Enabled: true
-# Use spaces after colons.
-Style/SpaceAfterColon:
- Enabled: true
-
-# Use spaces after commas.
-Style/SpaceAfterComma:
- Enabled: true
-
-# Do not put a space between a method name and the opening parenthesis in a
-# method definition.
-Style/SpaceAfterMethodName:
- Enabled: true
-
-# Tracks redundant space after the ! operator.
-Style/SpaceAfterNot:
- Enabled: true
-
-# Use spaces after semicolons.
-Style/SpaceAfterSemicolon:
- Enabled: true
-
-# Use space around equals in parameter default
-Style/SpaceAroundEqualsInParameterDefault:
- Enabled: true
-
-# Use a space around keywords if appropriate.
-Style/SpaceAroundKeyword:
- Enabled: true
-
-# Use a single space around operators.
-Style/SpaceAroundOperators:
- Enabled: true
-
-# No spaces before commas.
-Style/SpaceBeforeComma:
- Enabled: true
-
-# Checks for missing space between code and a comment on the same line.
-Style/SpaceBeforeComment:
- Enabled: true
-
-# No spaces before semicolons.
-Style/SpaceBeforeSemicolon:
- Enabled: true
-
-# Checks for spaces inside square brackets.
-Style/SpaceInsideBrackets:
- Enabled: true
-
-# Use spaces inside hash literal braces - or don't.
-Style/SpaceInsideHashLiteralBraces:
- Enabled: true
-
-# No spaces inside range literals.
-Style/SpaceInsideRangeLiteral:
- Enabled: true
-
-# Checks for padding/surrounding spaces inside string interpolation.
-Style/SpaceInsideStringInterpolation:
- EnforcedStyle: no_space
- Enabled: true
-
# Check for the usage of parentheses around stabby lambda arguments.
Style/StabbyLambdaParentheses:
EnforcedStyle: require_parentheses
@@ -498,13 +535,9 @@ Style/StringMethods:
intern: to_sym
Enabled: true
-# No hard tabs.
-Style/Tab:
- Enabled: true
-
-# Checks trailing blank lines and final newline.
-Style/TrailingBlankLines:
- Enabled: true
+# Use %i or %I for arrays of symbols.
+Style/SymbolArray:
+ Enabled: false
# This cop checks for trailing comma in array and hash literals.
Style/TrailingCommaInLiteral:
@@ -553,6 +586,10 @@ Style/WhileUntilModifier:
Style/WordArray:
Enabled: true
+# Do not use literals as the first operand of a comparison.
+Style/YodaCondition:
+ Enabled: false
+
# Use `proc` instead of `Proc.new`.
Style/Proc:
Enabled: true
@@ -608,6 +645,11 @@ Metrics/PerceivedComplexity:
# Lint ########################################################################
+# Checks for ambiguous block association with method when param passed without
+# parentheses.
+Lint/AmbiguousBlockAssociation:
+ Enabled: false
+
# Checks for ambiguous operators in the first argument of a method invocation
# without parentheses.
Lint/AmbiguousOperator:
@@ -809,6 +851,10 @@ Lint/Void:
# Performance #################################################################
+# Use `caller(n..n)` instead of `caller`.
+Performance/Caller:
+ Enabled: false
+
# Use `casecmp` rather than `downcase ==`.
Performance/Casecmp:
Enabled: true
@@ -883,6 +929,14 @@ Rails/ActionFilter:
Enabled: true
EnforcedStyle: action
+# Check that models subclass ApplicationRecord.
+Rails/ApplicationRecord:
+ Enabled: false
+
+# Enforce using `blank?` and `present?`.
+Rails/Blank:
+ Enabled: false
+
# Checks the correct usage of date aware methods, such as `Date.today`,
# `Date.current`, etc.
Rails/Date:
@@ -939,10 +993,18 @@ Rails/OutputSafety:
Rails/PluralizationGrammar:
Enabled: true
+# Enforce using `blank?` and `present?`.
+Rails/Present:
+ Enabled: false
+
# Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`.
Rails/ReadWriteAttribute:
Enabled: false
+# Do not assign relative date to constants.
+Rails/RelativeDateConstant:
+ Enabled: false
+
# Checks the arguments of ActiveRecord scopes.
Rails/ScopeArgs:
Enabled: true
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 2ec558e274f..9caef3bde08 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,26 +1,89 @@
# This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 0`
-# on 2017-04-07 20:17:35 -0400 using RuboCop version 0.47.1.
+# on 2017-07-10 01:48:30 +0900 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 233
+# Offense count: 181
+# Cop supports --auto-correct.
+# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
+Layout/ExtraSpacing:
+ Enabled: false
+
+# Offense count: 119
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
+# SupportedStyles: special_inside_parentheses, consistent, align_brackets
+Layout/IndentArray:
+ Enabled: false
+
+# Offense count: 208
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
+# SupportedStyles: special_inside_parentheses, consistent, align_braces
+Layout/IndentHash:
+ Enabled: false
+
+# Offense count: 174
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, SupportedStyles.
+# SupportedStyles: space, no_space
+Layout/SpaceBeforeBlockBraces:
+ Enabled: false
+
+# Offense count: 8
+# Cop supports --auto-correct.
+# Configuration parameters: AllowForAlignment.
+Layout/SpaceBeforeFirstArg:
+ Enabled: false
+
+# Offense count: 64
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, SupportedStyles.
+# SupportedStyles: require_no_space, require_space
+Layout/SpaceInLambdaLiteral:
+ Enabled: false
+
+# Offense count: 256
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters.
+# SupportedStyles: space, no_space
+# SupportedStylesForEmptyBraces: space, no_space
+Layout/SpaceInsideBlockBraces:
+ Enabled: false
+
+# Offense count: 135
+# Cop supports --auto-correct.
+Layout/SpaceInsideParens:
+ Enabled: false
+
+# Offense count: 14
+# Cop supports --auto-correct.
+Layout/SpaceInsidePercentLiteralDelimiters:
+ Enabled: false
+
+# Offense count: 89
+# Cop supports --auto-correct.
+Layout/TrailingWhitespace:
+ Enabled: false
+
+# Offense count: 272
RSpec/EmptyLineAfterFinalLet:
Enabled: false
-# Offense count: 167
+# Offense count: 181
RSpec/EmptyLineAfterSubject:
Enabled: false
-# Offense count: 72
+# Offense count: 78
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: implicit, each, example
RSpec/HookArgument:
Enabled: false
-# Offense count: 11
+# Offense count: 9
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: it_behaves_like, it_should_behave_like
RSpec/ItBehavesLike:
@@ -30,19 +93,19 @@ RSpec/ItBehavesLike:
RSpec/IteratedExpectation:
Enabled: false
-# Offense count: 3
+# Offense count: 2
RSpec/OverwritingSetup:
Enabled: false
-# Offense count: 34
+# Offense count: 36
RSpec/RepeatedExample:
Enabled: false
-# Offense count: 43
+# Offense count: 86
RSpec/ScatteredLet:
Enabled: false
-# Offense count: 32
+# Offense count: 20
RSpec/ScatteredSetup:
Enabled: false
@@ -50,7 +113,7 @@ RSpec/ScatteredSetup:
RSpec/SharedContext:
Enabled: false
-# Offense count: 150
+# Offense count: 115
Rails/FilePath:
Enabled: false
@@ -60,90 +123,71 @@ Rails/FilePath:
Rails/ReversibleMigration:
Enabled: false
-# Offense count: 302
+# Offense count: 336
# Configuration parameters: Blacklist.
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/SkipsModelValidations:
Enabled: false
-# Offense count: 7
+# Offense count: 11
# Cop supports --auto-correct.
Security/YAMLLoad:
Enabled: false
-# Offense count: 59
+# Offense count: 58
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: percent_q, bare_percent
Style/BarePercentLiterals:
Enabled: false
-# Offense count: 5
+# Offense count: 6
# Cop supports --auto-correct.
Style/EachWithObject:
Enabled: false
-# Offense count: 28
+# Offense count: 31
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty, nil, both
Style/EmptyElse:
Enabled: false
-# Offense count: 4
+# Offense count: 9
# Cop supports --auto-correct.
Style/EmptyLiteral:
Enabled: false
-# Offense count: 59
+# Offense count: 78
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, expanded
Style/EmptyMethod:
Enabled: false
-# Offense count: 214
+# Offense count: 23
# Cop supports --auto-correct.
-# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
-Style/ExtraSpacing:
- Enabled: false
-
-# Offense count: 9
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: format, sprintf, percent
Style/FormatString:
Enabled: false
-# Offense count: 285
+# Offense count: 301
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Enabled: false
-# Offense count: 16
+# Offense count: 18
Style/IfInsideElse:
Enabled: false
-# Offense count: 186
+# Offense count: 182
# Cop supports --auto-correct.
# Configuration parameters: MaxLineLength.
Style/IfUnlessModifier:
Enabled: false
-# Offense count: 99
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
-# SupportedStyles: special_inside_parentheses, consistent, align_brackets
-Style/IndentArray:
- Enabled: false
-
-# Offense count: 160
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
-# SupportedStyles: special_inside_parentheses, consistent, align_braces
-Style/IndentHash:
- Enabled: false
-
-# Offense count: 50
+# Offense count: 52
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: line_count_dependent, lambda, literal
@@ -155,63 +199,63 @@ Style/Lambda:
Style/LineEndConcatenation:
Enabled: false
-# Offense count: 34
+# Offense count: 40
# Cop supports --auto-correct.
Style/MethodCallWithoutArgsParentheses:
Enabled: false
-# Offense count: 10
+# Offense count: 13
Style/MethodMissing:
Enabled: false
-# Offense count: 3
+# Offense count: 6
# Cop supports --auto-correct.
Style/MultilineIfModifier:
Enabled: false
-# Offense count: 24
+# Offense count: 26
# Cop supports --auto-correct.
Style/NestedParenthesizedCalls:
Enabled: false
-# Offense count: 18
+# Offense count: 20
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
# SupportedStyles: skip_modifier_ifs, always
Style/Next:
Enabled: false
-# Offense count: 37
+# Offense count: 45
# Cop supports --auto-correct.
# Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles.
# SupportedOctalStyles: zero_with_o, zero_only
Style/NumericLiteralPrefix:
Enabled: false
-# Offense count: 88
+# Offense count: 98
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Enabled: false
-# Offense count: 36
+# Offense count: 42
# Cop supports --auto-correct.
Style/ParallelAssignment:
Enabled: false
-# Offense count: 570
+# Offense count: 800
# Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
Enabled: false
-# Offense count: 14
+# Offense count: 15
# Cop supports --auto-correct.
Style/PerlBackrefs:
Enabled: false
-# Offense count: 83
+# Offense count: 105
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
# NamePrefix: is_, has_, have_
# NamePrefixBlacklist: is_, has_, have_
@@ -219,47 +263,47 @@ Style/PerlBackrefs:
Style/PredicateName:
Enabled: false
-# Offense count: 65
+# Offense count: 58
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, exploded
Style/RaiseArgs:
Enabled: false
-# Offense count: 5
+# Offense count: 6
# Cop supports --auto-correct.
Style/RedundantBegin:
Enabled: false
-# Offense count: 32
+# Offense count: 37
# Cop supports --auto-correct.
Style/RedundantFreeze:
Enabled: false
-# Offense count: 15
+# Offense count: 14
# Cop supports --auto-correct.
# Configuration parameters: AllowMultipleReturnValues.
Style/RedundantReturn:
Enabled: false
-# Offense count: 382
+# Offense count: 406
# Cop supports --auto-correct.
Style/RedundantSelf:
Enabled: false
-# Offense count: 111
+# Offense count: 115
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral:
Enabled: false
-# Offense count: 24
+# Offense count: 29
# Cop supports --auto-correct.
Style/RescueModifier:
Enabled: false
-# Offense count: 7
+# Offense count: 8
# Cop supports --auto-correct.
Style/SelfAssignment:
Enabled: false
@@ -270,101 +314,58 @@ Style/SelfAssignment:
Style/SingleLineMethods:
Enabled: false
-# Offense count: 168
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles.
-# SupportedStyles: space, no_space
-Style/SpaceBeforeBlockBraces:
- Enabled: false
-
-# Offense count: 8
-# Cop supports --auto-correct.
-# Configuration parameters: AllowForAlignment.
-Style/SpaceBeforeFirstArg:
- Enabled: false
-
-# Offense count: 46
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles.
-# SupportedStyles: require_no_space, require_space
-Style/SpaceInLambdaLiteral:
- Enabled: false
-
-# Offense count: 229
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters.
-# SupportedStyles: space, no_space
-# SupportedStylesForEmptyBraces: space, no_space
-Style/SpaceInsideBlockBraces:
- Enabled: false
-
-# Offense count: 116
-# Cop supports --auto-correct.
-Style/SpaceInsideParens:
- Enabled: false
-
-# Offense count: 12
-# Cop supports --auto-correct.
-Style/SpaceInsidePercentLiteralDelimiters:
- Enabled: false
-
-# Offense count: 57
+# Offense count: 64
# Cop supports --auto-correct.
# Configuration parameters: SupportedStyles.
# SupportedStyles: use_perl_names, use_english_names
Style/SpecialGlobalVars:
EnforcedStyle: use_perl_names
-# Offense count: 42
+# Offense count: 44
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiteralsInInterpolation:
Enabled: false
-# Offense count: 64
+# Offense count: 84
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method
Style/SymbolProc:
Enabled: false
-# Offense count: 6
+# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
Style/TernaryParentheses:
Enabled: false
-# Offense count: 18
+# Offense count: 17
# Cop supports --auto-correct.
# Configuration parameters: AllowNamedUnderscoreVariables.
Style/TrailingUnderscoreVariable:
Enabled: false
-# Offense count: 78
-# Cop supports --auto-correct.
-Style/TrailingWhitespace:
- Enabled: false
-
-# Offense count: 3
+# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
Style/TrivialAccessors:
Enabled: false
-# Offense count: 6
+# Offense count: 5
# Cop supports --auto-correct.
Style/UnlessElse:
Enabled: false
-# Offense count: 24
+# Offense count: 28
# Cop supports --auto-correct.
Style/UnneededInterpolation:
Enabled: false
-# Offense count: 8
+# Offense count: 11
# Cop supports --auto-correct.
Style/ZeroLengthPredicate:
Enabled: false
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 412cd86bad6..706823ed693 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,16 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 9.4.3 (2017-07-31)
+
+- Fix Prometheus client PID reuse bug. !13130
+- Improve deploy environment chatops slash command. !13150
+- Fix asynchronous javascript paths when GitLab is installed under a relative URL. !13165
+- Fix LDAP authentication to Git repository or container registry.
+- Fixed new navigation breadcrumb title on help pages.
+- Ensure filesystem metrics test files are deleted.
+- Properly affixes nav bar in job view in microsoft edge.
+
## 9.4.2 (2017-07-28)
- Fix job merge request link to a forked source project. !12965
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index d21d277be51..4e8f395fa5e 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.25.0
+0.26.0
diff --git a/Gemfile b/Gemfile
index afea07ee6ff..a9a1cbc144d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -339,8 +339,8 @@ group :development, :test do
gem 'spring-commands-rspec', '~> 1.0.4'
gem 'spring-commands-spinach', '~> 1.1.0'
- gem 'rubocop', '~> 0.47.1', require: false
- gem 'rubocop-rspec', '~> 1.15.0', require: false
+ gem 'rubocop', '~> 0.49.1', require: false
+ gem 'rubocop-rspec', '~> 1.15.1', require: false
gem 'scss_lint', '~> 0.54.0', require: false
gem 'haml_lint', '~> 0.21.0', require: false
gem 'simplecov', '~> 0.14.0', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 627750e2c1d..5a327a14c4a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -323,7 +323,7 @@ GEM
multi_json (~> 1.10)
retriable (~> 1.4)
signet (~> 0.6)
- google-protobuf (3.2.0.2)
+ google-protobuf (3.3.0)
googleauth (0.5.1)
faraday (~> 0.9)
jwt (~> 1.4)
@@ -545,6 +545,7 @@ GEM
rubypants (~> 0.2)
orm_adapter (0.5.0)
os (0.9.6)
+ parallel (1.11.2)
paranoia (2.3.1)
activerecord (>= 4.0, < 5.2)
parser (2.4.0.0)
@@ -730,13 +731,14 @@ GEM
pg
rails
sqlite3
- rubocop (0.47.1)
+ rubocop (0.49.1)
+ parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
- rubocop-rspec (1.15.0)
+ rubocop-rspec (1.15.1)
rubocop (>= 0.42.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
@@ -868,7 +870,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
- unicode-display_width (1.1.3)
+ unicode-display_width (1.3.0)
unicorn (5.1.0)
kgio (~> 2.6)
raindrops (~> 0.7)
@@ -1078,8 +1080,8 @@ DEPENDENCIES
rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5)
- rubocop (~> 0.47.1)
- rubocop-rspec (~> 1.15.0)
+ rubocop (~> 0.49.1)
+ rubocop-rspec (~> 1.15.1)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.16.2)
ruby_parser (~> 3.8)
diff --git a/PROCESS.md b/PROCESS.md
index 3b97a4e8c75..2b3d142bf77 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -128,7 +128,7 @@ information, see
### After the 7th
-Once the stable branch is frozen, only fixes for regressions (bugs introduced in that same release)
+Once the stable branch is frozen, only fixes for [regressions](#regressions)
and security issues will be cherry-picked into the stable branch.
Any merge requests cherry-picked into the stable branch for a previous release will also be picked into the latest stable branch.
These fixes will be shipped in the next RC for that release if it is before the 22nd.
@@ -158,6 +158,24 @@ release should have the correct milestone assigned _and_ have the label
Merge requests without a milestone and this label will
not be merged into any stable branches.
+### Regressions
+
+A regression for a particular monthly release is a bug that exists in that
+release, but wasn't present in the release before. This includes bugs in
+features that were only added in that monthly release. Every regression **must**
+have the milestone of the release it was introduced in - if a regression doesn't
+have a milestone, it might be 'just' a bug!
+
+For instance, if 10.5.0 adds a feature, and that feature doesn't work correctly,
+then this is a regression in 10.5. If 10.5.1 then fixes that, but 10.5.3 somehow
+reintroduces the bug, then this bug is still a regression in 10.5.
+
+Because GitLab.com runs release candidates of new releases, a regression can be
+reported in a release before its 'official' release date on the 22nd of the
+month. When we say 'the most recent monthly release', this can refer to either
+the version currently running on GitLab.com, or the most recent version
+available in the package repositories.
+
## Release retrospective and kickoff
### Retrospective
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index 1c64ccf536f..b5500ac116f 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -8,6 +8,7 @@ import BlobFileDropzone from '../blob/blob_file_dropzone';
$(() => {
const editBlobForm = $('.js-edit-blob-form');
const uploadBlobForm = $('.js-upload-blob-form');
+ const deleteBlobForm = $('.js-delete-blob-form');
if (editBlobForm.length) {
const urlRoot = editBlobForm.data('relative-url-root');
@@ -30,4 +31,8 @@ $(() => {
'.btn-upload-file',
);
}
+
+ if (deleteBlobForm.length) {
+ new NewCommitForm(deleteBlobForm);
+ }
});
diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js
index 1dfa064acfd..b3d3bbcf84f 100644
--- a/app/assets/javascripts/build.js
+++ b/app/assets/javascripts/build.js
@@ -64,7 +64,7 @@ window.Build = (function () {
$(window)
.off('scroll')
.on('scroll', () => {
- const contentHeight = this.$buildTraceOutput.prop('scrollHeight');
+ const contentHeight = this.$buildTraceOutput.height();
if (contentHeight > this.windowSize) {
// means the user did not scroll, the content was updated.
this.windowSize = contentHeight;
@@ -105,16 +105,17 @@ window.Build = (function () {
};
Build.prototype.canScroll = function () {
- return document.body.scrollHeight > window.innerHeight;
+ return $(document).height() > $(window).height();
};
Build.prototype.toggleScroll = function () {
- const currentPosition = document.body.scrollTop;
- const windowHeight = window.innerHeight;
+ const currentPosition = $(document).scrollTop();
+ const scrollHeight = $(document).height();
+ const windowHeight = $(window).height();
if (this.canScroll()) {
if (currentPosition > 0 &&
- (document.body.scrollHeight - currentPosition !== windowHeight)) {
+ (scrollHeight - currentPosition !== windowHeight)) {
// User is in the middle of the log
this.toggleDisableButton(this.$scrollTopBtn, false);
@@ -124,7 +125,7 @@ window.Build = (function () {
this.toggleDisableButton(this.$scrollTopBtn, true);
this.toggleDisableButton(this.$scrollBottomBtn, false);
- } else if (document.body.scrollHeight - currentPosition === windowHeight) {
+ } else if (scrollHeight - currentPosition === windowHeight) {
// User is at the bottom of the build log.
this.toggleDisableButton(this.$scrollTopBtn, false);
@@ -137,7 +138,7 @@ window.Build = (function () {
};
Build.prototype.scrollDown = function () {
- document.body.scrollTop = document.body.scrollHeight;
+ $(document).scrollTop($(document).height());
};
Build.prototype.scrollToBottom = function () {
@@ -147,7 +148,7 @@ window.Build = (function () {
};
Build.prototype.scrollToTop = function () {
- document.body.scrollTop = 0;
+ $(document).scrollTop(0);
this.hasBeenScrolled = true;
this.toggleScroll();
};
@@ -178,7 +179,7 @@ window.Build = (function () {
this.state = log.state;
}
- this.windowSize = this.$buildTraceOutput.prop('scrollHeight');
+ this.windowSize = this.$buildTraceOutput.height();
if (log.append) {
this.$buildTraceOutput.append(log.html);
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 9d706b5ba59..a2664c0301e 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -8,6 +8,8 @@
/* global LabelsSelect */
/* global MilestoneSelect */
/* global Commit */
+/* global CommitsList */
+/* global NewBranchForm */
/* global NotificationsForm */
/* global NotificationsDropdown */
/* global GroupAvatar */
@@ -18,15 +20,20 @@
/* global Search */
/* global Admin */
/* global NamespaceSelects */
+/* global NewCommitForm */
+/* global NewBranchForm */
/* global Project */
/* global ProjectAvatar */
/* global MergeRequest */
/* global Compare */
/* global CompareAutocomplete */
+/* global ProjectFindFile */
/* global ProjectNew */
/* global ProjectShow */
+/* global ProjectImport */
/* global Labels */
/* global Shortcuts */
+/* global ShortcutsFindFile */
/* global Sidebar */
/* global ShortcutsWiki */
@@ -194,7 +201,6 @@ import GpgBadges from './gpg_badges';
break;
case 'explore:groups:index':
new GroupsList();
-
const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) break;
const exploreGroupsLanding = new Landing(
@@ -217,6 +223,10 @@ import GpgBadges from './gpg_badges';
case 'projects:compare:show':
new gl.Diff();
break;
+ case 'projects:branches:new':
+ case 'projects:branches:create':
+ new NewBranchForm($('.js-create-branch-form'), JSON.parse(document.getElementById('availableRefs').innerHTML));
+ break;
case 'projects:branches:index':
gl.AjaxLoadingSpinner.init();
new DeleteModal();
@@ -258,7 +268,7 @@ import GpgBadges from './gpg_badges';
case 'projects:tags:new':
new ZenMode();
new gl.GLForm($('.tag-form'), true);
- new RefSelectDropdown($('.js-branch-select'), window.gl.availableRefs);
+ new RefSelectDropdown($('.js-branch-select'));
break;
case 'projects:snippets:show':
initNotes();
@@ -304,18 +314,23 @@ import GpgBadges from './gpg_badges';
container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
+ $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break;
case 'projects:commit:pipelines':
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
+ $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break;
- case 'projects:commits:show':
+ case 'projects:activity':
+ new gl.Activities();
shortcut_handler = new ShortcutsNavigation();
- GpgBadges.fetch();
break;
- case 'projects:activity':
+ case 'projects:commits:show':
+ CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
+ new gl.Activities();
shortcut_handler = new ShortcutsNavigation();
+ GpgBadges.fetch();
break;
case 'projects:show':
shortcut_handler = new ShortcutsNavigation();
@@ -330,6 +345,12 @@ import GpgBadges from './gpg_badges';
case 'projects:edit':
setupProjectEdit();
break;
+ case 'projects:imports:show':
+ new ProjectImport();
+ break;
+ case 'projects:pipelines:new':
+ new NewBranchForm($('.js-new-pipeline-form'));
+ break;
case 'projects:pipelines:builds':
case 'projects:pipelines:failures':
case 'projects:pipelines:show':
@@ -383,8 +404,19 @@ import GpgBadges from './gpg_badges';
shortcut_handler = new ShortcutsNavigation();
new TreeView();
new BlobViewer();
+ new NewCommitForm($('.js-create-dir-form'));
+ $('#tree-slider').waitForImages(function() {
+ gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
+ });
break;
case 'projects:find_file:show':
+ const findElement = document.querySelector('.js-file-finder');
+ const projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
+ url: findElement.dataset.fileFindUrl,
+ treeUrl: findElement.dataset.findTreeUrl,
+ blobUrlTemplate: findElement.dataset.blobUrlTemplate,
+ });
+ new ShortcutsFindFile(projectFindFile);
shortcut_handler = true;
break;
case 'projects:blob:show':
@@ -540,6 +572,7 @@ import GpgBadges from './gpg_badges';
shortcut_handler = new ShortcutsWiki();
new ZenMode();
new gl.GLForm($('.wiki-form'), true);
+ new Sidebar();
break;
case 'snippets':
shortcut_handler = new ShortcutsNavigation();
diff --git a/app/assets/javascripts/graphs/graphs_bundle.js b/app/assets/javascripts/graphs/graphs_bundle.js
index a433c7ba8f0..534bc535bb6 100644
--- a/app/assets/javascripts/graphs/graphs_bundle.js
+++ b/app/assets/javascripts/graphs/graphs_bundle.js
@@ -1,6 +1,4 @@
import Chart from 'vendor/Chart';
-import ContributorsStatGraph from './stat_graph_contributors';
// export to global scope
window.Chart = Chart;
-window.ContributorsStatGraph = ContributorsStatGraph;
diff --git a/app/assets/javascripts/graphs/graphs_charts.js b/app/assets/javascripts/graphs/graphs_charts.js
new file mode 100644
index 00000000000..279ffef770f
--- /dev/null
+++ b/app/assets/javascripts/graphs/graphs_charts.js
@@ -0,0 +1,63 @@
+import Chart from 'vendor/Chart';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML);
+
+ const responsiveChart = (selector, data) => {
+ const options = {
+ scaleOverlay: true,
+ responsive: true,
+ pointHitDetectionRadius: 2,
+ maintainAspectRatio: false,
+ };
+ // get selector by context
+ const ctx = selector.get(0).getContext('2d');
+ // pointing parent container to make chart.js inherit its width
+ const container = $(selector).parent();
+ const generateChart = () => {
+ selector.attr('width', $(container).width());
+ if (window.innerWidth < 768) {
+ // Scale fonts if window width lower than 768px (iPad portrait)
+ options.scaleFontSize = 8;
+ }
+ return new Chart(ctx).Bar(data, options);
+ };
+ // enabling auto-resizing
+ $(window).resize(generateChart);
+ return generateChart();
+ };
+
+ const chartData = (keys, values) => {
+ const data = {
+ labels: keys,
+ datasets: [{
+ fillColor: 'rgba(220,220,220,0.5)',
+ strokeColor: 'rgba(220,220,220,1)',
+ barStrokeWidth: 1,
+ barValueSpacing: 1,
+ barDatasetSpacing: 1,
+ data: values,
+ }],
+ };
+ return data;
+ };
+
+ const hourData = chartData(projectChartData.hour.keys, projectChartData.hour.values);
+ responsiveChart($('#hour-chart'), hourData);
+
+ const dayData = chartData(projectChartData.weekDays.keys, projectChartData.weekDays.values);
+ responsiveChart($('#weekday-chart'), dayData);
+
+ const monthData = chartData(projectChartData.month.keys, projectChartData.month.values);
+ responsiveChart($('#month-chart'), monthData);
+
+ const data = projectChartData.languages;
+ const ctx = $('#languages-chart').get(0).getContext('2d');
+ const options = {
+ scaleOverlay: true,
+ responsive: true,
+ maintainAspectRatio: false,
+ };
+
+ new Chart(ctx).Pie(data, options);
+});
diff --git a/app/assets/javascripts/graphs/graphs_show.js b/app/assets/javascripts/graphs/graphs_show.js
new file mode 100644
index 00000000000..36bad6db3e1
--- /dev/null
+++ b/app/assets/javascripts/graphs/graphs_show.js
@@ -0,0 +1,21 @@
+import ContributorsStatGraph from './stat_graph_contributors';
+
+document.addEventListener('DOMContentLoaded', () => {
+ $.ajax({
+ type: 'GET',
+ url: document.querySelector('.js-graphs-show').dataset.projectGraphPath,
+ dataType: 'json',
+ success(data) {
+ const graph = new ContributorsStatGraph();
+ graph.init(data);
+
+ $('#brush_change').change(() => {
+ graph.change_date_header();
+ graph.redraw_authors();
+ });
+
+ $('.stat-graph').fadeIn();
+ $('.loading-graph').hide();
+ },
+ });
+});
diff --git a/app/assets/javascripts/pipelines/pipelines_charts.js b/app/assets/javascripts/pipelines/pipelines_charts.js
new file mode 100644
index 00000000000..001faf4be33
--- /dev/null
+++ b/app/assets/javascripts/pipelines/pipelines_charts.js
@@ -0,0 +1,38 @@
+import Chart from 'vendor/Chart';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const chartData = JSON.parse(document.getElementById('pipelinesChartsData').innerHTML);
+ const buildChart = (chartScope) => {
+ const data = {
+ labels: chartScope.labels,
+ datasets: [{
+ fillColor: '#7f8fa4',
+ strokeColor: '#7f8fa4',
+ pointColor: '#7f8fa4',
+ pointStrokeColor: '#EEE',
+ data: chartScope.totalValues,
+ },
+ {
+ fillColor: '#44aa22',
+ strokeColor: '#44aa22',
+ pointColor: '#44aa22',
+ pointStrokeColor: '#fff',
+ data: chartScope.successValues,
+ },
+ ],
+ };
+ const ctx = $(`#${chartScope.scope}Chart`).get(0).getContext('2d');
+ const options = {
+ scaleOverlay: true,
+ responsive: true,
+ maintainAspectRatio: false,
+ };
+ if (window.innerWidth < 768) {
+ // Scale fonts if window width lower than 768px (iPad portrait)
+ options.scaleFontSize = 8;
+ }
+ new Chart(ctx).Line(data, options);
+ };
+
+ chartData.forEach(scope => buildChart(scope));
+});
diff --git a/app/assets/javascripts/pipelines/pipelines_times.js b/app/assets/javascripts/pipelines/pipelines_times.js
new file mode 100644
index 00000000000..b5e7a0e53d9
--- /dev/null
+++ b/app/assets/javascripts/pipelines/pipelines_times.js
@@ -0,0 +1,27 @@
+import Chart from 'vendor/Chart';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const chartData = JSON.parse(document.getElementById('pipelinesTimesChartsData').innerHTML);
+ const data = {
+ labels: chartData.labels,
+ datasets: [{
+ fillColor: 'rgba(220,220,220,0.5)',
+ strokeColor: 'rgba(220,220,220,1)',
+ barStrokeWidth: 1,
+ barValueSpacing: 1,
+ barDatasetSpacing: 1,
+ data: chartData.values,
+ }],
+ };
+ const ctx = $('#build_timesChart').get(0).getContext('2d');
+ const options = {
+ scaleOverlay: true,
+ responsive: true,
+ maintainAspectRatio: false,
+ };
+ if (window.innerWidth < 768) {
+ // Scale fonts if window width lower than 768px (iPad portrait)
+ options.scaleFontSize = 8;
+ }
+ new Chart(ctx).Bar(data, options);
+});
diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js
new file mode 100644
index 00000000000..2091b275c3d
--- /dev/null
+++ b/app/assets/javascripts/projects/project_new.js
@@ -0,0 +1,43 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const importBtnTooltip = 'Please enter a valid project name.';
+ const $importBtnWrapper = $('.import_gitlab_project');
+
+ $('.how_to_import_link').on('click', (e) => {
+ e.preventDefault();
+ $('.how_to_import_link').next('.modal').show();
+ });
+
+ $('.modal-header .close').on('click', () => {
+ $('.modal').hide();
+ });
+
+ $('.btn_import_gitlab_project').on('click', () => {
+ const importHref = $('a.btn_import_gitlab_project').attr('href');
+ $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$('#project_path').val()}`);
+ });
+
+ $('.btn_import_gitlab_project').attr('disabled', !$('#project_path').val().trim().length);
+ $importBtnWrapper.attr('title', importBtnTooltip);
+
+ $('#new_project').on('submit', () => {
+ const $path = $('#project_path');
+ $path.val($path.val().trim());
+ });
+
+ $('#project_path').on('keyup', () => {
+ if ($('#project_path').val().trim().length) {
+ $('.btn_import_gitlab_project').attr('disabled', false);
+ $importBtnWrapper.attr('title', '');
+ $importBtnWrapper.removeClass('has-tooltip');
+ } else {
+ $('.btn_import_gitlab_project').attr('disabled', true);
+ $importBtnWrapper.addClass('has-tooltip');
+ }
+ });
+
+ $('#project_import_url').disable();
+ $('.import_git').on('click', () => {
+ const $projectImportUrl = $('#project_import_url');
+ $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'));
+ });
+});
diff --git a/app/assets/javascripts/ref_select_dropdown.js b/app/assets/javascripts/ref_select_dropdown.js
index 215cd6fbdfd..65e4101352c 100644
--- a/app/assets/javascripts/ref_select_dropdown.js
+++ b/app/assets/javascripts/ref_select_dropdown.js
@@ -1,7 +1,8 @@
class RefSelectDropdown {
constructor($dropdownButton, availableRefs) {
+ const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
$dropdownButton.glDropdown({
- data: availableRefs,
+ data: availableRefsValue,
filterable: true,
filterByText: true,
remote: false,
diff --git a/app/assets/javascripts/two_factor_auth.js b/app/assets/javascripts/two_factor_auth.js
new file mode 100644
index 00000000000..d26f61562a5
--- /dev/null
+++ b/app/assets/javascripts/two_factor_auth.js
@@ -0,0 +1,13 @@
+/* global U2FRegister */
+document.addEventListener('DOMContentLoaded', () => {
+ const twoFactorNode = document.querySelector('.js-two-factor-auth');
+ const skippable = twoFactorNode.dataset.twoFactorSkippable === 'true';
+ if (skippable) {
+ const button = `<a class="btn btn-xs btn-warning pull-right" data-method="patch" href="${twoFactorNode.dataset.two_factor_skip_url}">Configure it later</a>`;
+ const flashAlert = document.querySelector('.flash-alert .container-fluid');
+ if (flashAlert) flashAlert.insertAdjacentHTML('beforeend', button);
+ }
+
+ const u2fRegister = new U2FRegister($('#js-register-u2f'), gon.u2f);
+ u2fRegister.start();
+});
diff --git a/app/assets/javascripts/ui_development_kit.js b/app/assets/javascripts/ui_development_kit.js
new file mode 100644
index 00000000000..f503076715c
--- /dev/null
+++ b/app/assets/javascripts/ui_development_kit.js
@@ -0,0 +1,22 @@
+import Api from './api';
+
+document.addEventListener('DOMContentLoaded', () => {
+ $('#js-project-dropdown').glDropdown({
+ data: (term, callback) => {
+ Api.projects(term, {
+ order_by: 'last_activity_at',
+ }, (data) => {
+ callback(data);
+ });
+ },
+ text: project => (project.name_with_namespace || project.name),
+ selectable: true,
+ fieldName: 'author_id',
+ filterable: true,
+ search: {
+ fields: ['name_with_namespace'],
+ },
+ id: data => data.id,
+ isSelected: data => (data.id === 2),
+ });
+});
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index ab2abaca33a..ec13a86ccf7 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -414,13 +414,16 @@
background-color: $dropdown-hover-color;
color: $white-light;
text-decoration: none;
+ outline: 0;
.avatar {
border-color: $white-light;
}
}
-.filter-dropdown-item {
+.droplab-dropdown .dropdown-menu .filter-dropdown-item {
+ padding: 0;
+
.btn {
border: none;
width: 100%;
@@ -455,14 +458,11 @@
}
.dropdown-user {
- display: -webkit-flex;
display: flex;
}
.dropdown-user-details {
- display: -webkit-flex;
display: flex;
- -webkit-flex-direction: column;
flex-direction: column;
> span {
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 605f4284bb5..1c4238bc564 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -313,6 +313,29 @@ header {
.impersonation i {
color: $red-500;
}
+
+ // TODO: fallback to global style
+ .dropdown-menu,
+ .dropdown-menu-nav {
+ li {
+ padding: 0 1px;
+
+ a {
+ border-radius: 0;
+ padding: 8px 16px;
+
+ &:hover,
+ &:active,
+ &:focus {
+ background-color: $gray-darker;
+ }
+ }
+ }
+ }
+}
+
+.with-performance-bar header.navbar-gitlab {
+ top: $performance-bar-height;
}
.navbar-nav {
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 4a9d41b4fda..67c3287ed74 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -120,3 +120,7 @@ of the body element here, we negate cascading side effects but allow momentum sc
.page-with-sidebar {
-webkit-overflow-scrolling: auto;
}
+
+.with-performance-bar .page-with-sidebar {
+ margin-top: $header-height + $performance-bar-height;
+}
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 35b4d77a5ab..88e7ba117d5 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -347,6 +347,10 @@
}
}
+.with-performance-bar .layout-nav {
+ margin-top: $header-height + $performance-bar-height;
+}
+
.scrolling-tabs-container {
position: relative;
@@ -441,6 +445,22 @@
}
}
+.with-performance-bar .page-with-layout-nav {
+ .right-sidebar {
+ top: ($header-height + 1) * 2 + $performance-bar-height;
+ }
+
+ &.page-with-sub-nav {
+ .right-sidebar {
+ top: ($header-height + 1) * 3 + $performance-bar-height;
+
+ &.affix {
+ top: $header-height + $performance-bar-height;
+ }
+ }
+ }
+}
+
.nav-block {
&.activities {
border-bottom: 1px solid $border-color;
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index 49b2f0e43a4..09b60ad1676 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -89,6 +89,10 @@
}
}
+.with-performance-bar .right-sidebar.affix {
+ top: $header-height + $performance-bar-height;
+}
+
@mixin maintain-sidebar-dimensions {
display: block;
width: $gutter-width;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index cf0a1ad57d0..0df6f24bfe6 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -204,6 +204,7 @@ $divergence-graph-separator-bg: #ccc;
$general-hover-transition-duration: 100ms;
$general-hover-transition-curve: linear;
$highlight-changes-color: rgb(235, 255, 232);
+$performance-bar-height: 35px;
/*
diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss
index 360ffda8d71..1c4a84de7ec 100644
--- a/app/assets/stylesheets/new_nav.scss
+++ b/app/assets/stylesheets/new_nav.scss
@@ -309,6 +309,25 @@ header.navbar-gitlab-new {
outline: 0;
}
}
+
+ // TODO: fallback to global style
+ .dropdown-menu {
+ li {
+ padding: 0 1px;
+
+ a {
+ border-radius: 0;
+ padding: 8px 16px;
+
+ &.is-focused,
+ &:hover,
+ &:active,
+ &:focus {
+ background-color: $gray-darker;
+ }
+ }
+ }
+ }
}
.breadcrumbs-container {
@@ -325,6 +344,7 @@ header.navbar-gitlab-new {
.breadcrumbs-links {
flex: 1;
+ min-width: 0;
align-self: center;
color: $gl-text-color-quaternary;
@@ -343,7 +363,7 @@ header.navbar-gitlab-new {
}
.title {
- white-space: nowrap;
+ display: inline-block;
> a {
&:last-of-type:not(:first-child) {
diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss
index ae43197a1a6..54f3e8d882c 100644
--- a/app/assets/stylesheets/new_sidebar.scss
+++ b/app/assets/stylesheets/new_sidebar.scss
@@ -118,7 +118,7 @@ $new-sidebar-width: 220px;
z-index: 400;
width: $new-sidebar-width;
transition: left $sidebar-transition-duration;
- top: 50px;
+ top: $header-height;
bottom: 0;
left: 0;
overflow: auto;
@@ -163,6 +163,10 @@ $new-sidebar-width: 220px;
}
}
+.with-performance-bar .nav-sidebar {
+ top: $header-height + $performance-bar-height;
+}
+
.sidebar-sub-level-items {
display: none;
padding-bottom: 8px;
@@ -260,7 +264,7 @@ $new-sidebar-width: 220px;
// Make issue boards full-height now that sub-nav is gone
.boards-list {
- height: calc(100vh - 50px);
+ height: calc(100vh - #{$header-height});
@media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
@@ -270,6 +274,10 @@ $new-sidebar-width: 220px;
}
}
+.with-performance-bar .boards-list {
+ height: calc(100vh - #{$header-height} - #{$performance-bar-height});
+}
+
// Change color of all horizontal tabs to match the new indigo color
.nav-links li.active a {
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index b6fc628c02b..28c99d8e57c 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -64,10 +64,10 @@
color: $gl-text-color;
position: sticky;
position: -webkit-sticky;
- top: 50px;
+ top: $header-height;
&.affix {
- top: 50px;
+ top: $header-height;
}
// with sidebar
@@ -86,6 +86,7 @@
position: absolute;
right: 0;
left: 0;
+ top: 0;
}
.truncated-info {
@@ -171,6 +172,16 @@
}
}
+.with-performance-bar .build-page {
+ .top-bar {
+ top: $header-height + $performance-bar-height;
+
+ &.affix {
+ top: $header-height + $performance-bar-height;
+ }
+ }
+}
+
.build-header {
.ci-header-container,
.header-action-buttons {
@@ -300,9 +311,7 @@
}
.dropdown-menu {
- right: $gl-padding;
- left: $gl-padding;
- width: auto;
+ margin-top: -$gl-padding;
}
svg {
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss
index eeb90759f10..87b50c7687e 100644
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ b/app/assets/stylesheets/pages/cycle_analytics.scss
@@ -110,6 +110,10 @@
.js-ca-dropdown {
top: $gl-padding-top;
+
+ .dropdown-menu-align-right {
+ margin-top: 2px;
+ }
}
.content-list {
@@ -442,6 +446,24 @@
margin-bottom: 20px;
}
}
+
+ // TODO: fallback to global style
+ .dropdown-menu {
+ li {
+ padding: 0 1px;
+
+ a {
+ border-radius: 0;
+ padding: 8px 16px;
+
+ &:hover,
+ &:active,
+ &:focus {
+ background-color: $gray-darker;
+ }
+ }
+ }
+ }
}
.cycle-analytics-overview {
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 9391e1d70e6..55cfa645f79 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -445,6 +445,14 @@
}
}
+.with-performance-bar .right-sidebar {
+ top: $header-height + $performance-bar-height;
+
+ .issuable-sidebar {
+ height: calc(100% - #{$header-height} - #{$performance-bar-height});
+ }
+}
+
.detail-page-description {
padding: 16px 0;
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 2db967547dd..4693b2434c7 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -759,6 +759,10 @@
}
}
+.with-performance-bar .merge-request-tabs-holder {
+ top: $header-height + $performance-bar-height;
+}
+
.merge-request-tabs {
display: flex;
margin-bottom: 0;
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index dc88cf3e699..e0f46172769 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -202,6 +202,28 @@
}
}
}
+
+ // TODO: fallback to global style
+ .dropdown-menu:not(.dropdown-menu-selectable) {
+ li {
+ padding: 0 1px;
+
+ &.dropdown-header {
+ padding: 8px 16px;
+ }
+
+ a {
+ border-radius: 0;
+ padding: 8px 16px;
+
+ &:hover,
+ &:active,
+ &:focus {
+ background-color: $gray-darker;
+ }
+ }
+ }
+ }
}
.blob-commit-info {
diff --git a/app/assets/stylesheets/performance_bar.scss b/app/assets/stylesheets/performance_bar.scss
index 2890b6b1e49..6e539e39ca1 100644
--- a/app/assets/stylesheets/performance_bar.scss
+++ b/app/assets/stylesheets/performance_bar.scss
@@ -3,9 +3,16 @@
@import "peek/views/rblineprof";
#peek {
- height: 35px;
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ z-index: 2000;
+ overflow-x: hidden;
+
+ height: $performance-bar-height;
background: $black;
- line-height: 35px;
+ line-height: $performance-bar-height;
color: $perf-bar-text;
&.disabled {
@@ -25,7 +32,8 @@
}
.wrapper {
- width: 1000px;
+ width: 80%;
+ height: $performance-bar-height;
margin: 0 auto;
}
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 57372f9e79d..475d4c86294 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -43,23 +43,7 @@ class Projects::GraphsController < Projects::ApplicationController
end
def get_languages
- @languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages
- total = @languages.map(&:last).sum
-
- @languages = @languages.map do |language|
- name, share = language
- color = Linguist::Language[name].color || "##{Digest::SHA256.hexdigest(name)[0...6]}"
- {
- value: (share.to_f * 100 / total).round(2),
- label: name,
- color: color,
- highlight: color
- }
- end
-
- @languages.sort! do |x, y|
- y[:value] <=> x[:value]
- end
+ @languages = @project.repository.languages
end
def fetch_graph
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 1c165700b19..14dc9bd9d62 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -264,7 +264,11 @@ module ApplicationHelper
end
def page_class
- "issue-boards-page" if current_controller?(:boards)
+ class_names = []
+ class_names << 'issue-boards-page' if current_controller?(:boards)
+ class_names << 'with-performance-bar' if performance_bar_enabled?
+
+ class_names
end
# Returns active css class when condition returns true
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index 0517a699ae0..1f7db9b2eb8 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -48,7 +48,11 @@ module GitlabRoutingHelper
end
def milestone_path(entity, *args)
- project_milestone_path(entity.project, entity, *args)
+ if entity.is_group_milestone?
+ group_milestone_path(entity.group, entity, *args)
+ elsif entity.is_project_milestone?
+ project_milestone_path(entity.project, entity, *args)
+ end
end
def issue_url(entity, *args)
@@ -63,6 +67,14 @@ module GitlabRoutingHelper
project_pipeline_url(pipeline.project, pipeline.id, *args)
end
+ def milestone_url(entity, *args)
+ if entity.is_group_milestone?
+ group_milestone_url(entity.group, entity, *args)
+ elsif entity.is_project_milestone?
+ project_milestone_url(entity.project, entity, *args)
+ end
+ end
+
def pipeline_job_url(pipeline, build, *args)
project_job_url(pipeline.project, build.id, *args)
end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 78cf7b26a31..c31023f2d9a 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -40,7 +40,7 @@ module MergeRequestsHelper
def merge_path_description(merge_request, separator)
if merge_request.for_fork?
- "Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.path_with_namespace}:#{@merge_request.target_branch}"
+ "Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.full_path}:#{@merge_request.target_branch}"
else
"Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}"
end
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index b769462abc2..b1205b8529b 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -1,38 +1,49 @@
module NavHelper
+ def page_with_sidebar_class
+ class_name = page_gutter_class
+ class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar
+
+ class_name
+ end
+
def page_gutter_class
if current_path?('merge_requests#show') ||
current_path?('projects/merge_requests/conflicts#show') ||
current_path?('issues#show') ||
current_path?('milestones#show')
if cookies[:collapsed_gutter] == 'true'
- "page-gutter right-sidebar-collapsed"
+ %w[page-gutter right-sidebar-collapsed]
else
- "page-gutter right-sidebar-expanded"
+ %w[page-gutter right-sidebar-expanded]
end
elsif current_path?('jobs#show')
- "page-gutter build-sidebar right-sidebar-expanded"
+ %w[page-gutter build-sidebar right-sidebar-expanded]
elsif current_path?('wikis#show') ||
current_path?('wikis#edit') ||
current_path?('wikis#update') ||
current_path?('wikis#history') ||
current_path?('wikis#git_access')
- "page-gutter wiki-sidebar right-sidebar-expanded"
+ %w[page-gutter wiki-sidebar right-sidebar-expanded]
+ else
+ []
end
end
def nav_header_class
- class_name = ''
- class_name << " with-horizontal-nav" if defined?(nav) && nav
+ class_names = []
+ class_names << 'with-horizontal-nav' if defined?(nav) && nav
- class_name
+ class_names
end
def layout_nav_class
- class_name = ''
- class_name << " page-with-layout-nav" if defined?(nav) && nav
- class_name << " page-with-sub-nav" if content_for?(:sub_nav)
+ return [] if show_new_nav?
- class_name
+ class_names = []
+ class_names << 'page-with-layout-nav' if defined?(nav) && nav
+ class_names << 'page-with-sub-nav' if content_for?(:sub_nav)
+
+ class_names
end
def nav_control_class
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 9a8d296d514..34ff6107eab 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -398,7 +398,7 @@ module ProjectsHelper
if project
import_path = "/Home/Stacks/import"
- repo = project.path_with_namespace
+ repo = project.full_path
branch ||= project.default_branch
sha ||= project.commit.short_id
@@ -458,7 +458,7 @@ module ProjectsHelper
def readme_cache_key
sha = @project.commit.try(:sha) || 'nil'
- [@project.path_with_namespace, sha, "readme"].join('-')
+ [@project.full_path, sha, "readme"].join('-')
end
def current_ref
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index eaac6fcb548..9efabe3f44e 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -165,7 +165,7 @@ class Notify < BaseMailer
headers['X-GitLab-Project'] = @project.name
headers['X-GitLab-Project-Id'] = @project.id
- headers['X-GitLab-Project-Path'] = @project.path_with_namespace
+ headers['X-GitLab-Project-Path'] = @project.full_path
end
def add_unsubscription_headers_and_links
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index d2abcf30034..ea7331cb27f 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -317,7 +317,7 @@ module Ci
return @config_processor if defined?(@config_processor)
@config_processor ||= begin
- Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
+ Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.full_path)
rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
self.yaml_errors = e.message
nil
diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb
new file mode 100644
index 00000000000..5ab5c80a2f5
--- /dev/null
+++ b/app/models/concerns/storage/legacy_namespace.rb
@@ -0,0 +1,102 @@
+module Storage
+ module LegacyNamespace
+ extend ActiveSupport::Concern
+
+ def move_dir
+ if any_project_has_container_registry_tags?
+ raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry')
+ end
+
+ # Move the namespace directory in all storage paths used by member projects
+ repository_storage_paths.each do |repository_storage_path|
+ # Ensure old directory exists before moving it
+ gitlab_shell.add_namespace(repository_storage_path, full_path_was)
+
+ unless gitlab_shell.mv_namespace(repository_storage_path, full_path_was, full_path)
+ Rails.logger.error "Exception moving path #{repository_storage_path} from #{full_path_was} to #{full_path}"
+
+ # if we cannot move namespace directory we should rollback
+ # db changes in order to prevent out of sync between db and fs
+ raise Gitlab::UpdatePathError.new('namespace directory cannot be moved')
+ end
+ end
+
+ Gitlab::UploadsTransfer.new.rename_namespace(full_path_was, full_path)
+ Gitlab::PagesTransfer.new.rename_namespace(full_path_was, full_path)
+
+ remove_exports!
+
+ # If repositories moved successfully we need to
+ # send update instructions to users.
+ # However we cannot allow rollback since we moved namespace dir
+ # So we basically we mute exceptions in next actions
+ begin
+ send_update_instructions
+ true
+ rescue
+ # Returning false does not rollback after_* transaction but gives
+ # us information about failing some of tasks
+ false
+ end
+ end
+
+ # Hooks
+
+ # Save the storage paths before the projects are destroyed to use them on after destroy
+ def prepare_for_destroy
+ old_repository_storage_paths
+ end
+
+ private
+
+ def old_repository_storage_paths
+ @old_repository_storage_paths ||= repository_storage_paths
+ end
+
+ def repository_storage_paths
+ # We need to get the storage paths for all the projects, even the ones that are
+ # pending delete. Unscoping also get rids of the default order, which causes
+ # problems with SELECT DISTINCT.
+ Project.unscoped do
+ all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path)
+ end
+ end
+
+ def rm_dir
+ # Remove the namespace directory in all storages paths used by member projects
+ old_repository_storage_paths.each do |repository_storage_path|
+ # Move namespace directory into trash.
+ # We will remove it later async
+ new_path = "#{full_path}+#{id}+deleted"
+
+ if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path)
+ Gitlab::AppLogger.info %Q(Namespace directory "#{full_path}" moved to "#{new_path}")
+
+ # Remove namespace directroy async with delay so
+ # GitLab has time to remove all projects first
+ run_after_commit do
+ GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path)
+ end
+ end
+ end
+
+ remove_exports!
+ end
+
+ def remove_exports!
+ Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete))
+ end
+
+ def export_path
+ File.join(Gitlab::ImportExport.storage_path, full_path_was)
+ end
+
+ def full_path_was
+ if parent
+ parent.full_path + '/' + path_was
+ else
+ path_was
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/storage/legacy_project.rb b/app/models/concerns/storage/legacy_project.rb
new file mode 100644
index 00000000000..815db712285
--- /dev/null
+++ b/app/models/concerns/storage/legacy_project.rb
@@ -0,0 +1,76 @@
+module Storage
+ module LegacyProject
+ extend ActiveSupport::Concern
+
+ def disk_path
+ full_path
+ end
+
+ def ensure_storage_path_exist
+ gitlab_shell.add_namespace(repository_storage_path, namespace.full_path)
+ end
+
+ def rename_repo
+ path_was = previous_changes['path'].first
+ old_path_with_namespace = File.join(namespace.full_path, path_was)
+ new_path_with_namespace = File.join(namespace.full_path, path)
+
+ Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}"
+
+ if has_container_registry_tags?
+ Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!"
+
+ # we currently doesn't support renaming repository if it contains images in container registry
+ raise StandardError.new('Project cannot be renamed, because images are present in its container registry')
+ end
+
+ expire_caches_before_rename(old_path_with_namespace)
+
+ if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace)
+ # If repository moved successfully we need to send update instructions to users.
+ # However we cannot allow rollback since we moved repository
+ # So we basically we mute exceptions in next actions
+ begin
+ gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
+ send_move_instructions(old_path_with_namespace)
+ expires_full_path_cache
+
+ @old_path_with_namespace = old_path_with_namespace
+
+ SystemHooksService.new.execute_hooks_for(self, :rename)
+
+ @repository = nil
+ rescue => e
+ Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}"
+ # Returning false does not rollback after_* transaction but gives
+ # us information about failing some of tasks
+ false
+ end
+ else
+ Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
+
+ # if we cannot move namespace directory we should rollback
+ # db changes in order to prevent out of sync between db and fs
+ raise StandardError.new('repository cannot be renamed')
+ end
+
+ Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
+
+ Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path)
+ Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path)
+ end
+
+ def create_repository(force: false)
+ # Forked import is handled asynchronously
+ return if forked? && !force
+
+ if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
+ repository.after_create
+ true
+ else
+ errors.add(:base, 'Failed to create repository via gitlab-shell')
+ false
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/storage/legacy_project_wiki.rb b/app/models/concerns/storage/legacy_project_wiki.rb
new file mode 100644
index 00000000000..ff82cb0ffa9
--- /dev/null
+++ b/app/models/concerns/storage/legacy_project_wiki.rb
@@ -0,0 +1,9 @@
+module Storage
+ module LegacyProjectWiki
+ extend ActiveSupport::Concern
+
+ def disk_path
+ project.disk_path + '.wiki'
+ end
+ end
+end
diff --git a/app/models/concerns/storage/legacy_repository.rb b/app/models/concerns/storage/legacy_repository.rb
new file mode 100644
index 00000000000..593749bf019
--- /dev/null
+++ b/app/models/concerns/storage/legacy_repository.rb
@@ -0,0 +1,7 @@
+module Storage
+ module LegacyRepository
+ extend ActiveSupport::Concern
+
+ delegate :disk_path, to: :project
+ end
+end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 81e0776e79c..8ca850b6d96 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -630,7 +630,7 @@ class MergeRequest < ActiveRecord::Base
def target_project_path
if target_project
- target_project.path_with_namespace
+ target_project.full_path
else
"(removed)"
end
@@ -638,7 +638,7 @@ class MergeRequest < ActiveRecord::Base
def source_project_path
if source_project
- source_project.path_with_namespace
+ source_project.full_path
else
"(removed)"
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 0bb04194bdb..6073fb94a3f 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -8,6 +8,7 @@ class Namespace < ActiveRecord::Base
include Gitlab::VisibilityLevel
include Routable
include AfterCommitQueue
+ include Storage::LegacyNamespace
# Prevent users from creating unreasonably deep level of nesting.
# The number 20 was taken based on maximum nesting level of
@@ -41,10 +42,11 @@ class Namespace < ActiveRecord::Base
delegate :name, to: :owner, allow_nil: true, prefix: true
- after_update :move_dir, if: :path_changed?
after_commit :refresh_access_of_projects_invited_groups, on: :update, if: -> { previous_changes.key?('share_with_group_lock') }
- # Save the storage paths before the projects are destroyed to use them on after destroy
+ # Legacy Storage specific hooks
+
+ after_update :move_dir, if: :path_changed?
before_destroy(prepend: true) { prepare_for_destroy }
after_destroy :rm_dir
@@ -118,43 +120,6 @@ class Namespace < ActiveRecord::Base
owner_name
end
- def move_dir
- if any_project_has_container_registry_tags?
- raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry')
- end
-
- # Move the namespace directory in all storages paths used by member projects
- repository_storage_paths.each do |repository_storage_path|
- # Ensure old directory exists before moving it
- gitlab_shell.add_namespace(repository_storage_path, full_path_was)
-
- unless gitlab_shell.mv_namespace(repository_storage_path, full_path_was, full_path)
- Rails.logger.error "Exception moving path #{repository_storage_path} from #{full_path_was} to #{full_path}"
-
- # if we cannot move namespace directory we should rollback
- # db changes in order to prevent out of sync between db and fs
- raise Gitlab::UpdatePathError.new('namespace directory cannot be moved')
- end
- end
-
- Gitlab::UploadsTransfer.new.rename_namespace(full_path_was, full_path)
- Gitlab::PagesTransfer.new.rename_namespace(full_path_was, full_path)
-
- remove_exports!
-
- # If repositories moved successfully we need to
- # send update instructions to users.
- # However we cannot allow rollback since we moved namespace dir
- # So we basically we mute exceptions in next actions
- begin
- send_update_instructions
- rescue
- # Returning false does not rollback after_* transaction but gives
- # us information about failing some of tasks
- false
- end
- end
-
def any_project_has_container_registry_tags?
all_projects.any?(&:has_container_registry_tags?)
end
@@ -206,14 +171,6 @@ class Namespace < ActiveRecord::Base
parent_id_changed?
end
- def prepare_for_destroy
- old_repository_storage_paths
- end
-
- def old_repository_storage_paths
- @old_repository_storage_paths ||= repository_storage_paths
- end
-
# Includes projects from this namespace and projects from all subgroups
# that belongs to this namespace
def all_projects
@@ -232,37 +189,6 @@ class Namespace < ActiveRecord::Base
private
- def repository_storage_paths
- # We need to get the storage paths for all the projects, even the ones that are
- # pending delete. Unscoping also get rids of the default order, which causes
- # problems with SELECT DISTINCT.
- Project.unscoped do
- all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path)
- end
- end
-
- def rm_dir
- # Remove the namespace directory in all storages paths used by member projects
- old_repository_storage_paths.each do |repository_storage_path|
- # Move namespace directory into trash.
- # We will remove it later async
- new_path = "#{full_path}+#{id}+deleted"
-
- if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path)
- message = "Namespace directory \"#{full_path}\" moved to \"#{new_path}\""
- Gitlab::AppLogger.info message
-
- # Remove namespace directroy async with delay so
- # GitLab has time to remove all projects first
- run_after_commit do
- GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path)
- end
- end
- end
-
- remove_exports!
- end
-
def refresh_access_of_projects_invited_groups
Group
.joins(project_group_links: :project)
@@ -270,22 +196,6 @@ class Namespace < ActiveRecord::Base
.find_each(&:refresh_members_authorized_projects)
end
- def remove_exports!
- Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete))
- end
-
- def export_path
- File.join(Gitlab::ImportExport.storage_path, full_path_was)
- end
-
- def full_path_was
- if parent
- parent.full_path + '/' + path_was
- else
- path_was
- end
- end
-
def nesting_level_allowed
if ancestors.count > Group::NUMBER_OF_ANCESTORS_ALLOWED
errors.add(:parent_id, "has too deep level of nesting")
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index 81844b1e2ca..9b1cac64c44 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -1,4 +1,8 @@
class NotificationSetting < ActiveRecord::Base
+ include IgnorableColumn
+
+ ignore_column :events
+
enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 }
default_value_for :level, NotificationSetting.levels[:global]
@@ -41,9 +45,6 @@ class NotificationSetting < ActiveRecord::Base
:success_pipeline
].freeze
- store :events, coder: JSON
- before_save :convert_events
-
def self.find_or_create_for(source)
setting = find_or_initialize_by(source: source)
@@ -54,42 +55,17 @@ class NotificationSetting < ActiveRecord::Base
setting
end
- # 1. Check if this event has a value stored in its database column.
- # 2. If it does, return that value.
- # 3. If it doesn't (the value is nil), return the value from the serialized
- # JSON hash in `events`.
- (EMAIL_EVENTS - [:failed_pipeline]).each do |event|
- define_method(event) do
- bool = super()
-
- bool.nil? ? !!events[event] : bool
- end
-
- alias_method :"#{event}?", event
- end
-
# Allow people to receive failed pipeline notifications if they already have
# custom notifications enabled, as these are more like mentions than the other
# custom settings.
def failed_pipeline
bool = super
- bool = events[:failed_pipeline] if bool.nil?
bool.nil? || bool
end
alias_method :failed_pipeline?, :failed_pipeline
def event_enabled?(event)
- respond_to?(event) && public_send(event)
- end
-
- def convert_events
- return if events_before_type_cast.nil?
-
- EMAIL_EVENTS.each do |event|
- write_attribute(event, public_send(event))
- end
-
- write_attribute(:events, nil)
+ respond_to?(event) && !!public_send(event)
end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index d827bfaa806..d85782782aa 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -17,6 +17,7 @@ class Project < ActiveRecord::Base
include ProjectFeaturesCompatibility
include SelectForProjectAuthorization
include Routable
+ include Storage::LegacyProject
extend Gitlab::ConfigHelper
@@ -43,9 +44,8 @@ class Project < ActiveRecord::Base
default_value_for :snippets_enabled, gitlab_config_features.snippets
default_value_for :only_allow_merge_if_all_discussions_are_resolved, false
- after_create :ensure_dir_exist
+ after_create :ensure_storage_path_exist
after_create :create_project_feature, unless: :project_feature
- after_save :ensure_dir_exist, if: :namespace_id_changed?
after_save :update_project_statistics, if: :namespace_id_changed?
# set last_activity_at to the same as created_at
@@ -67,6 +67,10 @@ class Project < ActiveRecord::Base
after_validation :check_pending_delete
+ # Legacy Storage specific hooks
+
+ after_save :ensure_storage_path_exist, if: :namespace_id_changed?
+
acts_as_taggable
attr_accessor :new_default_branch
@@ -375,7 +379,7 @@ class Project < ActiveRecord::Base
begin
Projects::HousekeepingService.new(project).execute
rescue Projects::HousekeepingService::LeaseTaken => e
- Rails.logger.info("Could not perform housekeeping for project #{project.path_with_namespace} (#{project.id}): #{e}")
+ Rails.logger.info("Could not perform housekeeping for project #{project.full_path} (#{project.id}): #{e}")
end
end
end
@@ -476,12 +480,12 @@ class Project < ActiveRecord::Base
end
def repository
- @repository ||= Repository.new(path_with_namespace, self)
+ @repository ||= Repository.new(full_path, self, disk_path: disk_path)
end
def container_registry_url
if Gitlab.config.registry.enabled
- "#{Gitlab.config.registry.host_port}/#{path_with_namespace.downcase}"
+ "#{Gitlab.config.registry.host_port}/#{full_path.downcase}"
end
end
@@ -520,16 +524,16 @@ class Project < ActiveRecord::Base
job_id =
if forked?
RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path,
- forked_from_project.path_with_namespace,
+ forked_from_project.full_path,
self.namespace.full_path)
else
RepositoryImportWorker.perform_async(self.id)
end
if job_id
- Rails.logger.info "Import job started for #{path_with_namespace} with job ID #{job_id}"
+ Rails.logger.info "Import job started for #{full_path} with job ID #{job_id}"
else
- Rails.logger.error "Import job failed to start for #{path_with_namespace}"
+ Rails.logger.error "Import job failed to start for #{full_path}"
end
end
@@ -690,7 +694,7 @@ class Project < ActiveRecord::Base
# `from` argument can be a Namespace or Project.
def to_reference(from = nil, full: false)
if full || cross_namespace_reference?(from)
- path_with_namespace
+ full_path
elsif cross_project_reference?(from)
path
end
@@ -714,7 +718,7 @@ class Project < ActiveRecord::Base
author.ensure_incoming_email_token!
Gitlab::IncomingEmail.reply_address(
- "#{path_with_namespace}+#{author.incoming_email_token}")
+ "#{full_path}+#{author.incoming_email_token}")
end
def build_commit_note(commit)
@@ -941,7 +945,7 @@ class Project < ActiveRecord::Base
end
def url_to_repo
- gitlab_shell.url_to_repo(path_with_namespace)
+ gitlab_shell.url_to_repo(full_path)
end
def repo_exists?
@@ -974,56 +978,6 @@ class Project < ActiveRecord::Base
!group
end
- def rename_repo
- path_was = previous_changes['path'].first
- old_path_with_namespace = File.join(namespace.full_path, path_was)
- new_path_with_namespace = File.join(namespace.full_path, path)
-
- Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}"
-
- if has_container_registry_tags?
- Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!"
-
- # we currently doesn't support renaming repository if it contains images in container registry
- raise StandardError.new('Project cannot be renamed, because images are present in its container registry')
- end
-
- expire_caches_before_rename(old_path_with_namespace)
-
- if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace)
- # If repository moved successfully we need to send update instructions to users.
- # However we cannot allow rollback since we moved repository
- # So we basically we mute exceptions in next actions
- begin
- gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
- send_move_instructions(old_path_with_namespace)
- expires_full_path_cache
-
- @old_path_with_namespace = old_path_with_namespace
-
- SystemHooksService.new.execute_hooks_for(self, :rename)
-
- @repository = nil
- rescue => e
- Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}"
- # Returning false does not rollback after_* transaction but gives
- # us information about failing some of tasks
- false
- end
- else
- Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
-
- # if we cannot move namespace directory we should rollback
- # db changes in order to prevent out of sync between db and fs
- raise StandardError.new('repository cannot be renamed')
- end
-
- Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
-
- Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path)
- Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path)
- end
-
# Expires various caches before a project is renamed.
def expire_caches_before_rename(old_path)
repo = Repository.new(old_path, self)
@@ -1048,7 +1002,7 @@ class Project < ActiveRecord::Base
git_http_url: http_url_to_repo,
namespace: namespace.name,
visibility_level: visibility_level,
- path_with_namespace: path_with_namespace,
+ path_with_namespace: full_path,
default_branch: default_branch,
ci_config_path: ci_config_path
}
@@ -1109,19 +1063,6 @@ class Project < ActiveRecord::Base
merge_requests.where(source_project_id: self.id)
end
- def create_repository(force: false)
- # Forked import is handled asynchronously
- return if forked? && !force
-
- if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
- repository.after_create
- true
- else
- errors.add(:base, 'Failed to create repository via gitlab-shell')
- false
- end
- end
-
def ensure_repository
create_repository(force: true) unless repository_exists?
end
@@ -1257,7 +1198,7 @@ class Project < ActiveRecord::Base
end
def pages_path
- File.join(Settings.pages.path, path_with_namespace)
+ File.join(Settings.pages.path, disk_path)
end
def public_pages_path
@@ -1265,9 +1206,21 @@ class Project < ActiveRecord::Base
end
def remove_private_deploy_keys
- deploy_keys.where(public: false).delete_all
+ exclude_keys_linked_to_other_projects = <<-SQL
+ NOT EXISTS (
+ SELECT 1
+ FROM deploy_keys_projects dkp2
+ WHERE dkp2.deploy_key_id = deploy_keys_projects.deploy_key_id
+ AND dkp2.project_id != deploy_keys_projects.project_id
+ )
+ SQL
+
+ deploy_keys.where(public: false)
+ .where(exclude_keys_linked_to_other_projects)
+ .delete_all
end
+ # TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal?
def remove_pages
::Projects::UpdatePagesConfigurationService.new(self).execute
@@ -1315,7 +1268,7 @@ class Project < ActiveRecord::Base
end
def export_path
- File.join(Gitlab::ImportExport.storage_path, path_with_namespace)
+ File.join(Gitlab::ImportExport.storage_path, disk_path)
end
def export_project_path
@@ -1327,16 +1280,12 @@ class Project < ActiveRecord::Base
status.zero?
end
- def ensure_dir_exist
- gitlab_shell.add_namespace(repository_storage_path, namespace.full_path)
- end
-
def predefined_variables
[
{ key: 'CI_PROJECT_ID', value: id.to_s, public: true },
{ key: 'CI_PROJECT_NAME', value: path, public: true },
- { key: 'CI_PROJECT_PATH', value: path_with_namespace, public: true },
- { key: 'CI_PROJECT_PATH_SLUG', value: path_with_namespace.parameterize, public: true },
+ { key: 'CI_PROJECT_PATH', value: full_path, public: true },
+ { key: 'CI_PROJECT_PATH_SLUG', value: full_path.parameterize, public: true },
{ key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path, public: true },
{ key: 'CI_PROJECT_URL', value: web_url, public: true }
]
@@ -1441,6 +1390,7 @@ class Project < ActiveRecord::Base
alias_method :name_with_namespace, :full_name
alias_method :human_name, :full_name
+ # @deprecated cannot remove yet because it has an index with its name in elasticsearch
alias_method :path_with_namespace, :full_path
private
@@ -1495,7 +1445,7 @@ class Project < ActiveRecord::Base
def pending_delete_twin
return false unless path
- Project.pending_delete.find_by_full_path(path_with_namespace)
+ Project.pending_delete.find_by_full_path(full_path)
end
##
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 2db95b9aaa3..4d23a17a545 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -35,9 +35,9 @@ class FlowdockService < Service
data[:after],
token: token,
repo: project.repository.path_to_repo,
- repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
- commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
- diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s"
+ repo_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}",
+ commit_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/%s",
+ diff_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/compare/%s...%s"
)
end
end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 2aa19443198..c2414885368 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -140,7 +140,7 @@ class JiraService < IssueTrackerService
url: resource_url(user_path(author))
},
project: {
- name: project.path_with_namespace,
+ name: project.full_path,
url: resource_url(namespace_project_path(project.namespace, project)) # rubocop:disable Cop/ProjectPathHelper
},
entity: {
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index dfca0031af8..e8929a35836 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -1,5 +1,6 @@
class ProjectWiki
include Gitlab::ShellAdapter
+ include Storage::LegacyProjectWiki
MARKUPS = {
'Markdown' => :markdown,
@@ -26,16 +27,19 @@ class ProjectWiki
@project.path + '.wiki'
end
- def path_with_namespace
- @project.path_with_namespace + ".wiki"
+ def full_path
+ @project.full_path + '.wiki'
end
+ # @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem
+ alias_method :path_with_namespace, :full_path
+
def web_url
Gitlab::Routing.url_helpers.project_wiki_url(@project, :home)
end
def url_to_repo
- gitlab_shell.url_to_repo(path_with_namespace)
+ gitlab_shell.url_to_repo(full_path)
end
def ssh_url_to_repo
@@ -43,11 +47,11 @@ class ProjectWiki
end
def http_url_to_repo
- "#{Gitlab.config.gitlab.url}/#{path_with_namespace}.git"
+ "#{Gitlab.config.gitlab.url}/#{full_path}.git"
end
def wiki_base_path
- [Gitlab.config.gitlab.relative_url_root, "/", @project.path_with_namespace, "/wikis"].join('')
+ [Gitlab.config.gitlab.relative_url_root, '/', @project.full_path, '/wikis'].join('')
end
# Returns the Gollum::Wiki object.
@@ -134,7 +138,7 @@ class ProjectWiki
end
def repository
- @repository ||= Repository.new(path_with_namespace, @project)
+ @repository ||= Repository.new(full_path, @project, disk_path: disk_path)
end
def default_branch
@@ -142,7 +146,7 @@ class ProjectWiki
end
def create_repo!
- if init_repo(path_with_namespace)
+ if init_repo(disk_path)
wiki = Gollum::Wiki.new(path_to_repo)
else
raise CouldNotCreateWikiError
@@ -162,15 +166,15 @@ class ProjectWiki
web_url: web_url,
git_ssh_url: ssh_url_to_repo,
git_http_url: http_url_to_repo,
- path_with_namespace: path_with_namespace,
+ path_with_namespace: full_path,
default_branch: default_branch
}
end
private
- def init_repo(path_with_namespace)
- gitlab_shell.add_repository(project.repository_storage_path, path_with_namespace)
+ def init_repo(disk_path)
+ gitlab_shell.add_repository(project.repository_storage_path, disk_path)
end
def commit_details(action, message = nil, title = nil)
@@ -184,7 +188,7 @@ class ProjectWiki
end
def path_to_repo
- @path_to_repo ||= File.join(project.repository_storage_path, "#{path_with_namespace}.git")
+ @path_to_repo ||= File.join(project.repository_storage_path, "#{disk_path}.git")
end
def update_project_activity
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 50b7a477904..7ea9f1459a0 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -4,7 +4,7 @@ class Repository
include Gitlab::ShellAdapter
include RepositoryMirroring
- attr_accessor :path_with_namespace, :project
+ attr_accessor :full_path, :disk_path, :project
delegate :ref_name_for_sha, to: :raw_repository
@@ -52,13 +52,14 @@ class Repository
end
end
- def initialize(path_with_namespace, project)
- @path_with_namespace = path_with_namespace
+ def initialize(full_path, project, disk_path: nil)
+ @full_path = full_path
+ @disk_path = disk_path || full_path
@project = project
end
def raw_repository
- return nil unless path_with_namespace
+ return nil unless full_path
@raw_repository ||= initialize_raw_repository
end
@@ -66,7 +67,7 @@ class Repository
# Return absolute path to repository
def path_to_repo
@path_to_repo ||= File.expand_path(
- File.join(repository_storage_path, path_with_namespace + ".git")
+ File.join(repository_storage_path, disk_path + '.git')
)
end
@@ -469,7 +470,7 @@ class Repository
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314
def exists?
- return false unless path_with_namespace
+ return false unless full_path
Gitlab::GitalyClient.migrate(:repository_exists) do |enabled|
if enabled
@@ -1005,7 +1006,7 @@ class Repository
end
def fetch_remote(remote, forced: false, no_tags: false)
- gitlab_shell.fetch_remote(repository_storage_path, path_with_namespace, remote, forced: forced, no_tags: no_tags)
+ gitlab_shell.fetch_remote(repository_storage_path, disk_path, remote, forced: forced, no_tags: no_tags)
end
def fetch_ref(source_path, source_ref, target_ref)
@@ -1104,7 +1105,8 @@ class Repository
end
def cache
- @cache ||= RepositoryCache.new(path_with_namespace, @project.id)
+ # TODO: should we use UUIDs here? We could move repositories without clearing this cache
+ @cache ||= RepositoryCache.new(full_path, @project.id)
end
def tags_sorted_by_committed_date
@@ -1127,7 +1129,7 @@ class Repository
end
def repository_event(event, tags = {})
- Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags))
+ Gitlab::Metrics.add_event(event, { path: full_path }.merge(tags))
end
def create_commit(params = {})
@@ -1141,6 +1143,6 @@ class Repository
end
def initialize_raw_repository
- Gitlab::Git::Repository.new(project.repository_storage, path_with_namespace + '.git')
+ Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git')
end
end
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index 1c91425f589..1be7bbe9953 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy
prevent :log_in
end
- rule { admin | ~restricted_public_level }.policy do
+ rule { ~(anonymous & restricted_public_level) }.policy do
enable :read_users_list
end
end
diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb
index 32925e9c1f2..545ca0742e4 100644
--- a/app/services/git_operation_service.rb
+++ b/app/services/git_operation_service.rb
@@ -60,7 +60,7 @@ class GitOperationService
start_branch_name = nil if start_repository.empty_repo?
if start_branch_name && !start_repository.branch_exists?(start_branch_name)
- raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.path_with_namespace}"
+ raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.full_path}"
end
update_branch_with_hooks(branch_name) do
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index f6e8b6655f2..11ad4838471 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -9,7 +9,7 @@ module Projects
def async_execute
project.update_attribute(:pending_delete, true)
job_id = ProjectDestroyWorker.perform_async(project.id, current_user.id, params)
- Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.path_with_namespace} with job ID #{job_id}")
+ Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.full_path} with job ID #{job_id}")
end
def execute
@@ -40,7 +40,7 @@ module Projects
private
def repo_path
- project.path_with_namespace
+ project.disk_path
end
def wiki_path
@@ -127,7 +127,7 @@ module Projects
def flush_caches(project)
project.repository.before_delete
- Repository.new(wiki_path, project).before_delete
+ Repository.new(wiki_path, project, disk_path: repo_path).before_delete
end
end
end
diff --git a/app/services/projects/import_export/export_service.rb b/app/services/projects/import_export/export_service.rb
index 535da706159..fe4e8ea10bf 100644
--- a/app/services/projects/import_export/export_service.rb
+++ b/app/services/projects/import_export/export_service.rb
@@ -2,7 +2,7 @@ module Projects
module ImportExport
class ExportService < BaseService
def execute(_options = {})
- @shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.path_with_namespace, 'work'))
+ @shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.disk_path, 'work'))
save_all
end
diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb
index eea17e24903..50ec3651515 100644
--- a/app/services/projects/import_service.rb
+++ b/app/services/projects/import_service.rb
@@ -11,7 +11,7 @@ module Projects
success
rescue => e
- error("Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}")
+ error("Error importing repository #{project.import_url} into #{project.full_path} - #{e.message}")
end
private
@@ -51,7 +51,7 @@ module Projects
end
def clone_repository
- gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url)
+ gitlab_shell.import_repository(project.repository_storage_path, project.disk_path, project.import_url)
end
def fetch_repository
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 4bb98e5cb4e..5957f612e84 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -34,7 +34,7 @@ module Projects
private
def transfer(project)
- @old_path = project.path_with_namespace
+ @old_path = project.full_path
@old_group = project.group
@new_path = File.join(@new_namespace.try(:full_path) || '', project.path)
@old_namespace = project.namespace
@@ -61,11 +61,13 @@ module Projects
project.send_move_instructions(@old_path)
# Move main repository
+ # TODO: check storage type and NOOP when not using Legacy
unless move_repo_folder(@old_path, @new_path)
raise TransferError.new('Cannot move project')
end
# Move wiki repo also if present
+ # TODO: check storage type and NOOP when not using Legacy
move_repo_folder("#{@old_path}.wiki", "#{@new_path}.wiki")
# Move missing group labels to project
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 5dc1b91d2c0..c22bf7498bb 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -4,6 +4,9 @@ module QuickActions
attr_reader :issuable
+ SHRUG = '¯\\_(ツ)_/¯'.freeze
+ TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
+
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and hash of changes to be applied to a record.
def execute(content, issuable)
@@ -14,6 +17,7 @@ module QuickActions
content, commands = extractor.extract_commands(content, context)
extract_updates(commands, context)
+
[content, @updates]
end
@@ -423,6 +427,18 @@ module QuickActions
@updates[:spend_time] = { duration: :reset, user: current_user }
end
+ desc "Append the comment with #{SHRUG}"
+ params '<Comment>'
+ substitution :shrug do |comment|
+ "#{comment} #{SHRUG}"
+ end
+
+ desc "Append the comment with #{TABLEFLIP}"
+ params '<Comment>'
+ substitution :tableflip do |comment|
+ "#{comment} #{TABLEFLIP}"
+ end
+
# This is a dummy command, so that it appears in the autocomplete commands
desc 'CC'
params '@user'
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index bd58a54592f..cbcd4478af6 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -24,7 +24,7 @@ class SystemHooksService
key: model.key,
id: model.id
)
-
+
if model.user
data[:username] = model.user.username
end
@@ -56,7 +56,7 @@ class SystemHooksService
when GroupMember
data.merge!(group_member_data(model))
end
-
+
data
end
@@ -79,7 +79,7 @@ class SystemHooksService
{
name: model.name,
path: model.path,
- path_with_namespace: model.path_with_namespace,
+ path_with_namespace: model.full_path,
project_id: model.id,
owner_name: owner.name,
owner_email: owner.respond_to?(:email) ? owner.email : "",
@@ -93,7 +93,7 @@ class SystemHooksService
{
project_name: project.name,
project_path: project.path,
- project_path_with_namespace: project.path_with_namespace,
+ project_path_with_namespace: project.full_path,
project_id: project.id,
user_username: model.user.username,
user_name: model.user.name,
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index 652277e3b78..7027ac4b5db 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -30,7 +30,7 @@ class FileUploader < GitlabUploader
#
# Returns a String without a trailing slash
def self.dynamic_path_segment(model)
- File.join(CarrierWave.root, base_dir, model.path_with_namespace)
+ File.join(CarrierWave.root, base_dir, model.full_path)
end
attr_accessor :model
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 843c71af466..2aadc071c75 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -70,7 +70,7 @@
%span.badge
= storage_counter(project.statistics.storage_size)
%span.pull-right.light
- %span.monospace= project.path_with_namespace + ".git"
+ %span.monospace= project.full_path + '.git'
.panel-footer
= paginate @projects, param_name: 'projects_page', theme: 'gitlab'
@@ -88,7 +88,7 @@
%span.badge
= storage_counter(project.statistics.storage_size)
%span.pull-right.light
- %span.monospace= project.path_with_namespace + ".git"
+ %span.monospace= project.full_path + '.git'
.col-md-6
- if can?(current_user, :admin_group_member, @group)
diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
index 48edbb8c16f..f18c3a74120 100644
--- a/app/views/help/ui.html.haml
+++ b/app/views/help/ui.html.haml
@@ -1,5 +1,7 @@
- page_title "UI Development Kit", "Help"
- lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum nisi sapien, non consequat lectus aliquam ultrices. Suspendisse sodales est euismod nunc condimentum, a consectetur diam ornare."
+- content_for :page_specific_javascripts do
+ = webpack_bundle_tag('ui_development_kit')
.gitlab-ui-dev-kit
%h1 GitLab UI development kit
@@ -407,29 +409,6 @@
.dropdown-content
.dropdown-loading
= icon('spinner spin')
- :javascript
- $('#js-project-dropdown').glDropdown({
- data: function (term, callback) {
- Api.projects(term, { order_by: 'last_activity_at' }, function (data) {
- callback(data);
- });
- },
- text: function (project) {
- return project.name_with_namespace || project.name;
- },
- selectable: true,
- fieldName: "author_id",
- filterable: true,
- search: {
- fields: ['name_with_namespace']
- },
- id: function (data) {
- return data.id;
- },
- isSelected: function (data) {
- return data.id === 2;
- }
- })
.example
%div
diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml
index 0e7f0b5ed4f..e9a04e6c122 100644
--- a/app/views/import/_githubish_status.html.haml
+++ b/app/views/import/_githubish_status.html.haml
@@ -25,7 +25,7 @@
%td
= provider_project_link(provider, project.import_source)
%td
- = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ = link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span
diff --git a/app/views/import/base/create.js.haml b/app/views/import/base/create.js.haml
index fde671e25a9..4dc3a4a0acf 100644
--- a/app/views/import/base/create.js.haml
+++ b/app/views/import/base/create.js.haml
@@ -4,7 +4,7 @@
job.attr("id", "project_#{@project.id}")
target_field = job.find(".import-target")
target_field.empty()
- target_field.append('#{link_to @project.path_with_namespace, project_path(@project)}')
+ target_field.append('#{link_to @project.full_path, project_path(@project)}')
$("table.import-jobs tbody").prepend(job)
job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
- else
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index e6058617ac9..9589e0956f4 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -35,7 +35,7 @@
%td
= link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: '_blank', rel: 'noopener noreferrer'
%td
- = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ = link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span
diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml
index 5de5da5e6a2..7b832c6a23a 100644
--- a/app/views/import/fogbugz/status.html.haml
+++ b/app/views/import/fogbugz/status.html.haml
@@ -33,7 +33,7 @@
%td
= project.import_source
%td
- = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ = link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span
diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml
index 7456799ca0e..37734414835 100644
--- a/app/views/import/gitlab/status.html.haml
+++ b/app/views/import/gitlab/status.html.haml
@@ -28,7 +28,7 @@
%td
= link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
%td
- = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ = link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span
diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml
index 60de6bfe816..bc61aeece72 100644
--- a/app/views/import/google_code/status.html.haml
+++ b/app/views/import/google_code/status.html.haml
@@ -38,7 +38,7 @@
%td
= link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank", rel: 'noopener noreferrer'
%td
- = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ = link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span
diff --git a/app/views/layouts/_google_analytics.html.haml b/app/views/layouts/_google_analytics.html.haml
index 81e03c7eff2..98ea96b0b77 100644
--- a/app/views/layouts/_google_analytics.html.haml
+++ b/app/views/layouts/_google_analytics.html.haml
@@ -1,3 +1,4 @@
+-# haml-lint:disable InlineJavaScript
:javascript
var _gaq = _gaq || [];
_gaq.push(['_setAccount', '#{extra_config.google_analytics_id}']);
diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml
index 4bb0dfc73fd..9704c9ec624 100644
--- a/app/views/layouts/_init_auto_complete.html.haml
+++ b/app/views/layouts/_init_auto_complete.html.haml
@@ -2,6 +2,7 @@
- noteable_type = @noteable.class if @noteable.present?
- if project
+ -# haml-lint:disable InlineJavaScript
:javascript
gl.GfmAutoComplete = gl.GfmAutoComplete || {};
gl.GfmAutoComplete.dataSources = {
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 873220cc73d..c4f8cd71395 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -1,4 +1,4 @@
-.page-with-sidebar{ class: "#{('page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar)} #{page_gutter_class}" }
+.page-with-sidebar{ class: page_with_sidebar_class }
- if show_new_nav?
- if defined?(nav) && nav
= render "layouts/nav/#{nav}"
@@ -9,7 +9,7 @@
= render "layouts/nav/#{nav}"
- if content_for?(:sub_nav)
= yield :sub_nav
- .content-wrapper{ class: "#{(layout_nav_class unless show_new_nav?)}" }
+ .content-wrapper{ class: layout_nav_class }
- if show_new_nav?
.mobile-overlay
.alert-wrapper
diff --git a/app/views/layouts/_piwik.html.haml b/app/views/layouts/_piwik.html.haml
index 259b4f7cdfc..a888e8ae187 100644
--- a/app/views/layouts/_piwik.html.haml
+++ b/app/views/layouts/_piwik.html.haml
@@ -1,4 +1,5 @@
<!-- Piwik -->
+-# haml-lint:disable InlineJavaScript
:javascript
var _paq = _paq || [];
_paq.push(['trackPageView']);
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 38b95d11fd4..b53f382fa3d 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -1,8 +1,9 @@
!!! 5
-%html{ lang: I18n.locale, class: "#{page_class}" }
+%html{ lang: I18n.locale, class: page_class }
= render "layouts/head"
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form
+ = render 'peek/bar'
- if show_new_nav?
= render "layouts/header/new"
- else
@@ -10,5 +11,3 @@
= render 'layouts/page', sidebar: sidebar, nav: nav
= yield :scripts_body
-
- = render 'peek/bar'
diff --git a/app/views/layouts/nav/_new_admin_sidebar.html.haml b/app/views/layouts/nav/_new_admin_sidebar.html.haml
index 95443de40c2..8db3e69aed4 100644
--- a/app/views/layouts/nav/_new_admin_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_admin_sidebar.html.haml
@@ -91,8 +91,8 @@
= nav_link(controller: :abuse_reports) do
= link_to admin_abuse_reports_path, title: "Abuse Reports" do
%span
- Abuse Reports
%span.badge.count= number_with_delimiter(AbuseReport.count(:all))
+ Abuse Reports
- if akismet_enabled?
= nav_link(controller: :spam_logs) do
diff --git a/app/views/layouts/nav/_new_group_sidebar.html.haml b/app/views/layouts/nav/_new_group_sidebar.html.haml
index a7897c09e79..4fd9e213ead 100644
--- a/app/views/layouts/nav/_new_group_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_group_sidebar.html.haml
@@ -28,9 +28,9 @@
= nav_link(path: ['groups#issues', 'labels#index', 'milestones#index']) do
= link_to issues_group_path(@group), title: 'Issues' do
%span
- Issues
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.badge.count= number_with_delimiter(issues.count)
+ Issues
%ul.sidebar-sub-level-items
= nav_link(path: 'groups#issues', html_options: { class: 'home' }) do
@@ -51,9 +51,9 @@
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
%span
- Merge Requests
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
%span.badge.count= number_with_delimiter(merge_requests.count)
+ Merge Requests
= nav_link(path: 'group_members#index') do
= link_to group_group_members_path(@group), title: 'Members' do
%span
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 99adb83cd1f..54d56e9b873 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -10,6 +10,7 @@
- content_for :project_javascripts do
- project = @target_project || @project
- if current_user
+ -# haml-lint:disable InlineJavaScript
:javascript
window.uploads_path = "#{project_uploads_path(project)}";
diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml
index 57971205e0e..849075a0ba5 100644
--- a/app/views/layouts/snippets.html.haml
+++ b/app/views/layouts/snippets.html.haml
@@ -2,6 +2,7 @@
- content_for :page_specific_javascripts do
- if @snippet && current_user
+ -# haml-lint:disable InlineJavaScript
:javascript
window.uploads_path = "#{upload_path('personal_snippet', id: @snippet.id)}";
diff --git a/app/views/peek/views/_host.html.haml b/app/views/peek/views/_host.html.haml
new file mode 100644
index 00000000000..40769b5c6f6
--- /dev/null
+++ b/app/views/peek/views/_host.html.haml
@@ -0,0 +1,2 @@
+%span.current-host
+ = truncate(view.hostname)
diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml
index cf750378e25..2216708d354 100644
--- a/app/views/profiles/personal_access_tokens/index.html.haml
+++ b/app/views/profiles/personal_access_tokens/index.html.haml
@@ -1,5 +1,6 @@
- page_title "Personal Access Tokens"
- @content_class = "limit-container-width" unless fluid_layout
+
= render 'profiles/head'
.row.prepend-top-default
@@ -19,7 +20,7 @@
%h5.prepend-top-0
Your New Personal Access Token
.form-group
- = text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control", 'aria-describedby' => "created-personal-access-token-help-block"
+ = text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control js-select-on-focus", 'aria-describedby' => "created-personal-access-token-help-block"
= clipboard_button(text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left")
%span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again.
@@ -28,8 +29,3 @@
= render "shared/personal_access_tokens_form", path: profile_personal_access_tokens_path, impersonation: false, token: @personal_access_token, scopes: @scopes
= render "shared/personal_access_tokens_table", impersonation: false, active_tokens: @active_personal_access_tokens, inactive_tokens: @inactive_personal_access_tokens
-
-:javascript
- $("#created-personal-access-token").click(function() {
- this.select();
- });
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index 037cb30efb9..33e062c1c9c 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -7,97 +7,92 @@
= render 'profiles/head'
-- if inject_u2f_api?
- - content_for :page_specific_javascripts do
+- content_for :page_specific_javascripts do
+ - if inject_u2f_api?
= page_specific_javascript_bundle_tag('u2f')
+ = page_specific_javascript_bundle_tag('two_factor_auth')
-.row.prepend-top-default
- .col-lg-4
- %h4.prepend-top-0
- Register Two-Factor Authentication App
- %p
- Use an app on your mobile device to enable two-factor authentication (2FA).
- .col-lg-8
- - if current_user.two_factor_otp_enabled?
- = icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page."
- - else
+.js-two-factor-auth{ 'data-two-factor-skippable' => "#{two_factor_skippable?}", 'data-two_factor_skip_url' => skip_profile_two_factor_auth_path }
+ .row.prepend-top-default
+ .col-lg-4
+ %h4.prepend-top-0
+ Register Two-Factor Authentication App
%p
- Download the Google Authenticator application from App Store or Google Play Store and scan this code.
- More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}.
- .row.append-bottom-10
- .col-md-4
- = raw @qr_code
- .col-md-8
- .account-well
- %p.prepend-top-0.append-bottom-0
- Can't scan the code?
- %p.prepend-top-0.append-bottom-0
- To add the entry manually, provide the following details to the application on your phone.
- %p.prepend-top-0.append-bottom-0
- Account:
- = @account_string
- %p.prepend-top-0.append-bottom-0
- Key:
- = current_user.otp_secret.scan(/.{4}/).join(' ')
- %p.two-factor-new-manual-content
- Time based: Yes
- = form_tag profile_two_factor_auth_path, method: :post do |f|
- - if @error
- .alert.alert-danger
- = @error
- .form-group
- = label_tag :pin_code, nil, class: "label-light"
- = text_field_tag :pin_code, nil, class: "form-control", required: true
- .prepend-top-default
- = submit_tag 'Register with two-factor app', class: 'btn btn-success'
+ Use an app on your mobile device to enable two-factor authentication (2FA).
+ .col-lg-8
+ - if current_user.two_factor_otp_enabled?
+ = icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page."
+ - else
+ %p
+ Download the Google Authenticator application from App Store or Google Play Store and scan this code.
+ More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}.
+ .row.append-bottom-10
+ .col-md-4
+ = raw @qr_code
+ .col-md-8
+ .account-well
+ %p.prepend-top-0.append-bottom-0
+ Can't scan the code?
+ %p.prepend-top-0.append-bottom-0
+ To add the entry manually, provide the following details to the application on your phone.
+ %p.prepend-top-0.append-bottom-0
+ Account:
+ = @account_string
+ %p.prepend-top-0.append-bottom-0
+ Key:
+ = current_user.otp_secret.scan(/.{4}/).join(' ')
+ %p.two-factor-new-manual-content
+ Time based: Yes
+ = form_tag profile_two_factor_auth_path, method: :post do |f|
+ - if @error
+ .alert.alert-danger
+ = @error
+ .form-group
+ = label_tag :pin_code, nil, class: "label-light"
+ = text_field_tag :pin_code, nil, class: "form-control", required: true
+ .prepend-top-default
+ = submit_tag 'Register with two-factor app', class: 'btn btn-success'
-%hr
+ %hr
-.row.prepend-top-default
-
- .col-lg-4
- %h4.prepend-top-0
- Register Universal Two-Factor (U2F) Device
- %p
- Use a hardware device to add the second factor of authentication.
- %p
- As U2F devices are only supported by a few browsers, we require that you set up a
- two-factor authentication app before a U2F device. That way you'll always be able to
- log in - even when you're using an unsupported browser.
- .col-lg-8
- - if @u2f_registration.errors.present?
- = form_errors(@u2f_registration)
- = render "u2f/register"
+ .row.prepend-top-default
+ .col-lg-4
+ %h4.prepend-top-0
+ Register Universal Two-Factor (U2F) Device
+ %p
+ Use a hardware device to add the second factor of authentication.
+ %p
+ As U2F devices are only supported by a few browsers, we require that you set up a
+ two-factor authentication app before a U2F device. That way you'll always be able to
+ log in - even when you're using an unsupported browser.
+ .col-lg-8
+ - if @u2f_registration.errors.present?
+ = form_errors(@u2f_registration)
+ = render "u2f/register"
- %hr
+ %hr
- %h5 U2F Devices (#{@u2f_registrations.length})
+ %h5 U2F Devices (#{@u2f_registrations.length})
- - if @u2f_registrations.present?
- .table-responsive
- %table.table.table-bordered.u2f-registrations
- %colgroup
- %col{ width: "50%" }
- %col{ width: "30%" }
- %col{ width: "20%" }
- %thead
- %tr
- %th Name
- %th Registered On
- %th
- %tbody
- - @u2f_registrations.each do |registration|
+ - if @u2f_registrations.present?
+ .table-responsive
+ %table.table.table-bordered.u2f-registrations
+ %colgroup
+ %col{ width: "50%" }
+ %col{ width: "30%" }
+ %col{ width: "20%" }
+ %thead
%tr
- %td= registration.name.presence || "<no name set>"
- %td= registration.created_at.to_date.to_s(:medium)
- %td= link_to "Delete", profile_u2f_registration_path(registration), method: :delete, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to delete this device? This action cannot be undone." }
-
- - else
- .settings-message.text-center
- You don't have any U2F devices registered yet.
-
+ %th Name
+ %th Registered On
+ %th
+ %tbody
+ - @u2f_registrations.each do |registration|
+ %tr
+ %td= registration.name.presence || "<no name set>"
+ %td= registration.created_at.to_date.to_s(:medium)
+ %td= link_to "Delete", profile_u2f_registration_path(registration), method: :delete, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to delete this device? This action cannot be undone." }
-- if two_factor_skippable?
- :javascript
- var button = "<a class='btn btn-xs btn-warning pull-right' data-method='patch' href='#{skip_profile_two_factor_auth_path}'>Configure it later</a>";
- $(".flash-alert").append(button);
+ - else
+ .settings-message.text-center
+ You don't have any U2F devices registered yet.
diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml
index ecc966ed453..ad63f5e73ae 100644
--- a/app/views/projects/_activity.html.haml
+++ b/app/views/projects/_activity.html.haml
@@ -8,9 +8,3 @@
.content_list.project-activity{ :"data-href" => activity_project_path(@project) }
= spinner
-
-:javascript
- var activity = new gl.Activities();
- $(document).on('page:restore', function (event) {
- activity.reloadActivities()
- })
diff --git a/app/views/projects/blob/_new_dir.html.haml b/app/views/projects/blob/_new_dir.html.haml
index b2959ef6d31..03ab1bb59e4 100644
--- a/app/views/projects/blob/_new_dir.html.haml
+++ b/app/views/projects/blob/_new_dir.html.haml
@@ -20,6 +20,3 @@
- unless can?(current_user, :push_code, @project)
.inline.prepend-left-10
= commit_in_fork_help
-
-:javascript
- new NewCommitForm($('.js-create-dir-form'))
diff --git a/app/views/projects/blob/_remove.html.haml b/app/views/projects/blob/_remove.html.haml
index 6a4a657fa8c..750bdef3308 100644
--- a/app/views/projects/blob/_remove.html.haml
+++ b/app/views/projects/blob/_remove.html.haml
@@ -13,6 +13,3 @@
.col-sm-offset-2.col-sm-10
= button_tag 'Delete file', class: 'btn btn-remove btn-remove-file'
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
-
-:javascript
- new NewCommitForm($('.js-delete-blob-form'))
diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml
index 03eefcc2b4d..2baaaf6ac5b 100644
--- a/app/views/projects/branches/new.html.haml
+++ b/app/views/projects/branches/new.html.haml
@@ -28,8 +28,4 @@
.form-actions
= button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
-
-:javascript
- var availableRefs = #{@project.repository.ref_names.to_json};
-
- new NewBranchForm($('.js-create-branch-form'), availableRefs)
+%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 419fbe99af8..09bcd187e59 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -1,4 +1,4 @@
-.page-content-header
+.page-content-header.js-commit-box{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) }
.header-main-content
= render partial: 'signature', object: @commit.signature
%strong
@@ -79,6 +79,3 @@
= render 'shared/mini_pipeline_graph', pipeline: last_pipeline, klass: 'js-commit-pipeline-graph'
in
= time_interval_in_words last_pipeline.duration
-
-:javascript
- $(".commit-info.branches").load("#{branches_project_commit_path(@project, @commit.id)}");
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 12b73ecdf13..e7da47032be 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -5,7 +5,7 @@
- notes = commit.notes
- note_count = notes.user.count
-- cache_key = [project.path_with_namespace, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)]
+- cache_key = [project.full_path, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)]
- cache_key.push(commit.status(ref)) if commit.status(ref)
= cache(cache_key, expires_in: 1.day) do
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index bd2d900997e..7ae56086177 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -11,34 +11,32 @@
= content_for :sub_nav do
= render "head"
-%div{ class: container_class }
- .tree-holder
- .nav-block
- .tree-ref-container
- .tree-ref-holder
- = render 'shared/ref_switcher', destination: 'commits'
+.js-project-commits-show{ 'data-commits-limit' => @limit }
+ %div{ class: container_class }
+ .tree-holder
+ .nav-block
+ .tree-ref-container
+ .tree-ref-holder
+ = render 'shared/ref_switcher', destination: 'commits'
+
+ %ul.breadcrumb.repo-breadcrumb
+ = commits_breadcrumbs
+ .tree-controls.hidden-xs.hidden-sm
+ - if @merge_request.present?
+ .control
+ = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
+ - elsif create_mr_button?(@repository.root_ref, @ref)
+ .control
+ = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
- %ul.breadcrumb.repo-breadcrumb
- = commits_breadcrumbs
- .tree-controls.hidden-xs.hidden-sm
- - if @merge_request.present?
.control
- = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
- - elsif create_mr_button?(@repository.root_ref, @ref)
+ = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do
+ = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
.control
- = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
+ = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
+ = icon("rss")
- .control
- = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do
- = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
- .control
- = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
- = icon("rss")
-
- %div{ id: dom_id(@project) }
- %ol#commits-list.list-unstyled.content_list
- = render 'commits', project: @project, ref: @ref
- = spinner
-
-:javascript
- CommitsList.init(#{@limit});
+ %div{ id: dom_id(@project) }
+ %ol#commits-list.list-unstyled.content_list
+ = render 'commits', project: @project, ref: @ref
+ = spinner
diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml
index e3bf48ee47f..021575160ea 100644
--- a/app/views/projects/find_file/show.html.haml
+++ b/app/views/projects/find_file/show.html.haml
@@ -1,7 +1,7 @@
- page_title "Find File", @ref
= render "projects/commits/head"
-.file-finder-holder.tree-holder.clearfix
+.file-finder-holder.tree-holder.clearfix.js-file-finder{ 'data-file-find-url': "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}", 'data-find-tree-url': escape_javascript(project_tree_path(@project, @ref)), 'data-blob-url-template': escape_javascript(project_blob_path(@project, @id || @commit.id)) }
.nav-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'find_file', path: @path
@@ -17,11 +17,3 @@
%table.table.files-slider{ class: "table_#{@hex_path} tree-table table-striped" }
%tbody
= spinner nil, true
-
-:javascript
- var projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
- url: "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}",
- treeUrl: "#{escape_javascript(project_tree_path(@project, @ref))}",
- blobUrlTemplate: "#{escape_javascript(project_blob_path(@project, @id || @commit.id))}"
- });
- new ShortcutsFindFile(projectFindFile);
diff --git a/app/views/projects/graphs/charts.html.haml b/app/views/projects/graphs/charts.html.haml
index 249b9d82ad9..228c8c84792 100644
--- a/app/views/projects/graphs/charts.html.haml
+++ b/app/views/projects/graphs/charts.html.haml
@@ -3,8 +3,9 @@
- if show_new_nav?
- add_to_breadcrumbs("Repository", project_tree_path(@project))
- content_for :page_specific_javascripts do
- = page_specific_javascript_bundle_tag('common_d3')
- = page_specific_javascript_bundle_tag('graphs')
+ = webpack_bundle_tag('common_d3')
+ = webpack_bundle_tag('graphs')
+ = webpack_bundle_tag('graphs_charts')
= render "projects/commits/head"
.repo-charts{ class: container_class }
@@ -75,55 +76,10 @@
Commits per day hour (UTC)
%canvas#hour-chart
-:javascript
- var responsiveChart = function (selector, data) {
- var options = { "scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2, maintainAspectRatio: false };
- // get selector by context
- var ctx = selector.get(0).getContext("2d");
- // pointing parent container to make chart.js inherit its width
- var container = $(selector).parent();
- var generateChart = function() {
- selector.attr('width', $(container).width());
- if (window.innerWidth < 768) {
- // Scale fonts if window width lower than 768px (iPad portrait)
- options.scaleFontSize = 8
- }
- return new Chart(ctx).Bar(data, options);
- };
- // enabling auto-resizing
- $(window).resize(generateChart);
- return generateChart();
- };
-
- var chartData = function (keys, values) {
- var data = {
- labels : keys,
- datasets : [{
- fillColor : "rgba(220,220,220,0.5)",
- strokeColor : "rgba(220,220,220,1)",
- barStrokeWidth: 1,
- barValueSpacing: 1,
- barDatasetSpacing: 1,
- data : values
- }]
- };
- return data;
- };
-
- var hourData = chartData(#{@commits_per_time.keys.to_json}, #{@commits_per_time.values.to_json});
- responsiveChart($('#hour-chart'), hourData);
-
- var dayData = chartData(#{@commits_per_week_days.keys.to_json}, #{@commits_per_week_days.values.to_json});
- responsiveChart($('#weekday-chart'), dayData);
-
- var monthData = chartData(#{@commits_per_month.keys.to_json}, #{@commits_per_month.values.to_json});
- responsiveChart($('#month-chart'), monthData);
-
- var data = #{@languages.to_json};
- var ctx = $("#languages-chart").get(0).getContext("2d");
- var options = {
- scaleOverlay: true,
- responsive: true,
- maintainAspectRatio: false
- }
- var myPieChart = new Chart(ctx).Pie(data, options);
+%script#projectChartData{ type: "application/json" }
+ - projectChartData = {};
+ - projectChartData['hour'] = { 'keys' => @commits_per_time.keys, 'values' => @commits_per_time.values }
+ - projectChartData['weekDays'] = { 'keys' => @commits_per_week_days.keys, 'values' => @commits_per_week_days.values }
+ - projectChartData['month'] = { 'keys' => @commits_per_month.keys, 'values' => @commits_per_month.values }
+ - projectChartData['languages'] = @languages
+ = projectChartData.to_json.html_safe
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 4256a8c4d7e..f41a0d8293b 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -1,15 +1,16 @@
- @no_container = true
- page_title "Contributors"
- content_for :page_specific_javascripts do
- = page_specific_javascript_bundle_tag('common_d3')
- = page_specific_javascript_bundle_tag('graphs')
+ = webpack_bundle_tag('common_d3')
+ = webpack_bundle_tag('graphs')
+ = webpack_bundle_tag('graphs_show')
- if show_new_nav?
- add_to_breadcrumbs("Repository", project_tree_path(@project))
= render 'projects/commits/head'
-%div{ class: container_class }
+.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
.sub-header-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs'
@@ -33,24 +34,3 @@
#contributors-master
#contributors.clearfix
%ol.contributors-list.clearfix
-
-
-
-:javascript
- $.ajax({
- type: "GET",
- url: "#{project_graph_path(@project, current_ref, format: :json)}",
- dataType: "json",
- success: function (data) {
- var graph = new ContributorsStatGraph();
- graph.init(data);
-
- $("#brush_change").change(function(){
- graph.change_date_header();
- graph.redraw_authors();
- });
-
- $(".stat-graph").fadeIn();
- $(".loading-graph").hide();
- }
- });
diff --git a/app/views/projects/imports/show.html.haml b/app/views/projects/imports/show.html.haml
index c52b3860636..8c490773a56 100644
--- a/app/views/projects/imports/show.html.haml
+++ b/app/views/projects/imports/show.html.haml
@@ -10,5 +10,3 @@
- if @project.external_import?
%p.monospace git clone --bare #{@project.safe_import_url}
%p Please wait while we import the repository for you. Refresh at will.
- :javascript
- new ProjectImport();
diff --git a/app/views/projects/mattermosts/_team_selection.html.haml b/app/views/projects/mattermosts/_team_selection.html.haml
index 3bdb5d0adc4..20acd476f73 100644
--- a/app/views/projects/mattermosts/_team_selection.html.haml
+++ b/app/views/projects/mattermosts/_team_selection.html.haml
@@ -33,7 +33,7 @@
Suggestions:
%code= 'gitlab'
%code= @project.path # Path contains no spaces, but dashes
- %code= @project.path_with_namespace
+ %code= @project.full_path
%p
Reserved:
= link_to 'https://docs.mattermost.com/help/messaging/executing-commands.html#built-in-commands', target: '__blank' do
diff --git a/app/views/projects/merge_requests/creations/_new_compare.html.haml b/app/views/projects/merge_requests/creations/_new_compare.html.haml
index 8958b2cf5e1..9d5cebdda53 100644
--- a/app/views/projects/merge_requests/creations/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_compare.html.haml
@@ -41,7 +41,7 @@
- projects = target_projects(@project)
.merge-request-select.dropdown
= f.hidden_field :target_project_id
- = dropdown_toggle f.object.target_project.path_with_namespace, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" }
+ = dropdown_toggle f.object.target_project.full_path, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" }
.dropdown-menu.dropdown-menu-selectable.dropdown-target-project
= dropdown_title("Select target project")
= dropdown_filter("Search projects")
diff --git a/app/views/projects/merge_requests/dropdowns/_project.html.haml b/app/views/projects/merge_requests/dropdowns/_project.html.haml
index 25d5dc92f8a..aaf1ab00eeb 100644
--- a/app/views/projects/merge_requests/dropdowns/_project.html.haml
+++ b/app/views/projects/merge_requests/dropdowns/_project.html.haml
@@ -2,4 +2,4 @@
- projects.each do |project|
%li
%a{ href: "#", class: "#{('is-active' if selected == project.id)}", data: { id: project.id } }
- = project.path_with_namespace
+ = project.full_path
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 87cc23fc649..25109f0f414 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -4,6 +4,8 @@
- page_title 'New Project'
- header_title "Projects", dashboard_projects_path
- visibility_level = params.dig(:project, :visibility_level) || default_project_visibility
+- content_for :page_specific_javascripts do
+ = webpack_bundle_tag 'project_new'
.project-edit-container
.project-edit-errors
@@ -111,46 +113,3 @@
%i.fa.fa-spinner.fa-spin
Creating project &amp; repository.
%p Please wait a moment, this page will automatically refresh when ready.
-
-:javascript
- var importBtnTooltip = "Please enter a valid project name.";
- var $importBtnWrapper = $('.import_gitlab_project');
-
- $('.how_to_import_link').bind('click', function (e) {
- e.preventDefault();
- var import_modal = $(this).next(".modal").show();
- });
-
- $('.modal-header .close').bind('click', function() {
- $(".modal").hide();
- });
-
- $('.btn_import_gitlab_project').bind('click', function() {
- var _href = $("a.btn_import_gitlab_project").attr("href");
- $(".btn_import_gitlab_project").attr("href", _href + '?namespace_id=' + $("#project_namespace_id").val() + '&path=' + $("#project_path").val());
- });
-
- $('.btn_import_gitlab_project').attr('disabled', $('#project_path').val().trim().length === 0);
- $importBtnWrapper.attr('title', importBtnTooltip);
-
- $('#new_project').submit(function(){
- var $path = $('#project_path');
- $path.val($path.val().trim());
- });
-
- $('#project_path').keyup(function(){
- if($(this).val().trim().length !== 0) {
- $('.btn_import_gitlab_project').attr('disabled', false);
- $importBtnWrapper.attr('title','');
- $importBtnWrapper.removeClass('has-tooltip');
- } else {
- $('.btn_import_gitlab_project').attr('disabled',true);
- $importBtnWrapper.addClass('has-tooltip');
- }
- });
-
- $('#project_import_url').disable();
- $('.import_git').click(function( event ) {
- $projectImportUrl = $('#project_import_url');
- $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'));
- });
diff --git a/app/views/projects/pipelines/charts/_pipeline_times.haml b/app/views/projects/pipelines/charts/_pipeline_times.haml
index 1292f580a81..a5dbd1b1532 100644
--- a/app/views/projects/pipelines/charts/_pipeline_times.haml
+++ b/app/views/projects/pipelines/charts/_pipeline_times.haml
@@ -1,27 +1,10 @@
+- content_for :page_specific_javascripts do
+ = webpack_bundle_tag('pipelines_times')
+
%div
%p.light
= _("Commit duration in minutes for last 30 commits")
%canvas#build_timesChart{ height: 200 }
-:javascript
- var data = {
- labels : #{@charts[:pipeline_times].labels.to_json},
- datasets : [
- {
- fillColor : "rgba(220,220,220,0.5)",
- strokeColor : "rgba(220,220,220,1)",
- barStrokeWidth: 1,
- barValueSpacing: 1,
- barDatasetSpacing: 1,
- data : #{@charts[:pipeline_times].pipeline_times.to_json}
- }
- ]
- }
- var ctx = $("#build_timesChart").get(0).getContext("2d");
- var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false };
- if (window.innerWidth < 768) {
- // Scale fonts if window width lower than 768px (iPad portrait)
- options.scaleFontSize = 8
- }
- new Chart(ctx).Bar(data, options);
+%script#pipelinesTimesChartsData{ type: "application/json" }= { :labels => @charts[:pipeline_times].labels, :values => @charts[:pipeline_times].pipeline_times }.to_json.html_safe
diff --git a/app/views/projects/pipelines/charts/_pipelines.haml b/app/views/projects/pipelines/charts/_pipelines.haml
index be884448087..02f1ef4b6da 100644
--- a/app/views/projects/pipelines/charts/_pipelines.haml
+++ b/app/views/projects/pipelines/charts/_pipelines.haml
@@ -1,3 +1,6 @@
+- content_for :page_specific_javascripts do
+ = webpack_bundle_tag('pipelines_charts')
+
%h4= _("Pipelines charts")
%p
&nbsp;
@@ -26,31 +29,8 @@
= _("Jobs for last year")
%canvas#yearChart.padded{ height: 250 }
-- [:week, :month, :year].each do |scope|
- :javascript
- var data = {
- labels : #{@charts[scope].labels.to_json},
- datasets : [
- {
- fillColor : "#7f8fa4",
- strokeColor : "#7f8fa4",
- pointColor : "#7f8fa4",
- pointStrokeColor : "#EEE",
- data : #{@charts[scope].total.to_json}
- },
- {
- fillColor : "#44aa22",
- strokeColor : "#44aa22",
- pointColor : "#44aa22",
- pointStrokeColor : "#fff",
- data : #{@charts[scope].success.to_json}
- }
- ]
- }
- var ctx = $("##{scope}Chart").get(0).getContext("2d");
- var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false };
- if (window.innerWidth < 768) {
- // Scale fonts if window width lower than 768px (iPad portrait)
- options.scaleFontSize = 8
- }
- new Chart(ctx).Line(data, options);
+%script#pipelinesChartsData{ type: "application/json" }
+ - chartData = []
+ - [:week, :month, :year].each do |scope|
+ - chartData.push({ 'scope' => scope, 'labels' => @charts[scope].labels, 'totalValues' => @charts[scope].total, 'successValues' => @charts[scope].success })
+ = chartData.to_json.html_safe
diff --git a/app/views/projects/pipelines/new.html.haml b/app/views/projects/pipelines/new.html.haml
index c966df62856..4ad37d0e882 100644
--- a/app/views/projects/pipelines/new.html.haml
+++ b/app/views/projects/pipelines/new.html.haml
@@ -20,7 +20,4 @@
= f.submit 'Create pipeline', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_pipelines_path(@project), class: 'btn btn-cancel'
-:javascript
- var availableRefs = #{@project.repository.ref_names.to_json};
-
- new NewBranchForm($('.js-new-pipeline-form'), availableRefs)
+%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
diff --git a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
index ef3599460f1..5dbcbf7eba6 100644
--- a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
+++ b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
@@ -39,7 +39,7 @@
Suggestions:
%code= 'gitlab'
%code= @project.path # Path contains no spaces, but dashes
- %code= @project.path_with_namespace
+ %code= @project.full_path
.form-group
= label_tag :request_url, 'Request URL', class: 'col-sm-2 col-xs-12 control-label'
diff --git a/app/views/projects/services/slack_slash_commands/_help.html.haml b/app/views/projects/services/slack_slash_commands/_help.html.haml
index 73b99453a4b..c31c95608c6 100644
--- a/app/views/projects/services/slack_slash_commands/_help.html.haml
+++ b/app/views/projects/services/slack_slash_commands/_help.html.haml
@@ -33,7 +33,7 @@
Suggestions:
%code= 'gitlab'
%code= @project.path # Path contains no spaces, but dashes
- %code= @project.path_with_namespace
+ %code= @project.full_path
.form-group
= label_tag :url, 'URL', class: 'col-sm-2 col-xs-12 control-label'
diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml
index f1bbaf40387..521b4d927bc 100644
--- a/app/views/projects/tags/new.html.haml
+++ b/app/views/projects/tags/new.html.haml
@@ -40,7 +40,4 @@
.form-actions
= button_tag 'Create tag', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel'
-
-:javascript
- window.gl = window.gl || { };
- window.gl.availableRefs = #{@project.repository.ref_names.to_json};
+%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml
index 6560bd5ab3f..820b947804e 100644
--- a/app/views/projects/tree/_tree_content.html.haml
+++ b/app/views/projects/tree/_tree_content.html.haml
@@ -1,4 +1,4 @@
-.tree-content-holder
+.tree-content-holder.js-tree-content{ 'data-logs-path': @logs_path }
.table-holder
%table.table#tree-slider{ class: "table_#{@hex_path} tree-table" }
%thead
@@ -22,9 +22,3 @@
- if can_edit_tree?
= render 'projects/blob/upload', title: _('Upload New File'), placeholder: _('Upload New File'), button_title: _('Upload file'), form_path: project_create_blob_path(@project, @id), method: :post
= render 'projects/blob/new_dir'
-
-:javascript
- // Load last commit log for each file in tree
- $('#tree-slider').waitForImages(function() {
- gl.utils.ajaxGet("#{escape_javascript(@logs_path)}");
- });
diff --git a/app/views/projects/wikis/_sidebar.html.haml b/app/views/projects/wikis/_sidebar.html.haml
index 62873d3aa66..e71ce1f357f 100644
--- a/app/views/projects/wikis/_sidebar.html.haml
+++ b/app/views/projects/wikis/_sidebar.html.haml
@@ -19,6 +19,3 @@
More Pages
= render 'projects/wikis/new'
-
-:javascript
- new Sidebar();
diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml
index e64dd6085fe..e740fb93ea4 100644
--- a/app/views/projects/wikis/git_access.html.haml
+++ b/app/views/projects/wikis/git_access.html.haml
@@ -7,7 +7,7 @@
.git-access-header
Clone repository
- %strong= @project_wiki.path_with_namespace
+ %strong= @project_wiki.full_path
= render "shared/clone_panel", project: @project_wiki
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index b08267357e5..e7510c1d1ec 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -37,7 +37,7 @@
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.hide-collapsed
- if issuable.milestone
- = link_to issuable.milestone.title, project_milestone_path(@project, issuable.milestone), class: "bold has-tooltip", title: milestone_remaining_days(issuable.milestone), data: { container: "body", html: 1 }
+ = link_to issuable.milestone.title, milestone_path(issuable.milestone), class: "bold has-tooltip", title: milestone_remaining_days(issuable.milestone), data: { container: "body", html: 1 }
- else
%span.no-value None
diff --git a/app/views/u2f/_register.html.haml b/app/views/u2f/_register.html.haml
index 00788e77b6b..093b2d82813 100644
--- a/app/views/u2f/_register.html.haml
+++ b/app/views/u2f/_register.html.haml
@@ -37,7 +37,3 @@
.col-md-3
= hidden_field_tag 'u2f_registration[device_response]', nil, class: 'form-control', required: true, id: "js-device-response"
= submit_tag "Register U2F device", class: "btn btn-success"
-
-:javascript
- var u2fRegister = new U2FRegister($("#js-register-u2f"), gon.u2f);
- u2fRegister.start();
diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb
index d369b639ae9..c95497dfaba 100644
--- a/app/workers/git_garbage_collect_worker.rb
+++ b/app/workers/git_garbage_collect_worker.rb
@@ -5,6 +5,12 @@ class GitGarbageCollectWorker
sidekiq_options retry: false
+ GITALY_MIGRATED_TASKS = {
+ gc: :garbage_collect,
+ full_repack: :repack_full,
+ incremental_repack: :repack_incremental
+ }.freeze
+
def perform(project_id, task = :gc, lease_key = nil, lease_uuid = nil)
project = Project.find(project_id)
task = task.to_sym
@@ -15,8 +21,14 @@ class GitGarbageCollectWorker
Gitlab::GitLogger.info(description)
- output, status = Gitlab::Popen.popen(cmd, repo_path)
- Gitlab::GitLogger.error("#{description} failed:\n#{output}") unless status.zero?
+ gitaly_migrate(GITALY_MIGRATED_TASKS[task]) do |is_enabled|
+ if is_enabled
+ gitaly_call(task, project.repository.raw_repository)
+ else
+ output, status = Gitlab::Popen.popen(cmd, repo_path)
+ Gitlab::GitLogger.error("#{description} failed:\n#{output}") unless status.zero?
+ end
+ end
# Refresh the branch cache in case garbage collection caused a ref lookup to fail
flush_ref_caches(project) if task == :gc
@@ -26,6 +38,19 @@ class GitGarbageCollectWorker
private
+ ## `repository` has to be a Gitlab::Git::Repository
+ def gitaly_call(task, repository)
+ client = Gitlab::GitalyClient::RepositoryService.new(repository)
+ case task
+ when :gc
+ client.garbage_collect(bitmaps_enabled?)
+ when :full_repack
+ client.repack_full(bitmaps_enabled?)
+ when :incremental_repack
+ client.repack_incremental
+ end
+ end
+
def command(task)
case task
when :gc
@@ -55,4 +80,14 @@ class GitGarbageCollectWorker
config_value = write_bitmaps ? 'true' : 'false'
%W[git -c repack.writeBitmaps=#{config_value}]
end
+
+ def gitaly_migrate(method, &block)
+ Gitlab::GitalyClient.migrate(method, &block)
+ rescue GRPC::NotFound => e
+ Gitlab::GitLogger.error("#{method} failed:\nRepository not found")
+ raise Gitlab::Git::Repository::NoRepository.new(e)
+ rescue GRPC::BadStatus => e
+ Gitlab::GitLogger.error("#{method} failed:\n#{e}")
+ raise Gitlab::Git::CommandError.new(e)
+ end
end
diff --git a/app/workers/irker_worker.rb b/app/workers/irker_worker.rb
index 22f67fa9e9f..3dd14466994 100644
--- a/app/workers/irker_worker.rb
+++ b/app/workers/irker_worker.rb
@@ -66,7 +66,7 @@ class IrkerWorker
end
def send_new_branch(project, repo_name, committer, branch)
- repo_path = project.path_with_namespace
+ repo_path = project.full_path
newbranch = "#{Gitlab.config.gitlab.url}/#{repo_path}/branches"
newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors
@@ -109,7 +109,7 @@ class IrkerWorker
end
def send_commits_count(data, project, repo, committer, branch)
- url = compare_url data, project.path_with_namespace
+ url = compare_url data, project.full_path
commits = colorize_commits data['total_commits_count']
new_commits = 'new commit'
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index 625476b7e01..6be541abd3e 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -16,7 +16,7 @@ class RepositoryImportWorker
Gitlab::Metrics.add_event(:import_repository,
import_url: @project.import_url,
- path: @project.path_with_namespace)
+ path: @project.full_path)
project.update_columns(import_jid: self.jid, import_error: nil)
diff --git a/changelogs/unreleased/29385-add_shrug_command.yml b/changelogs/unreleased/29385-add_shrug_command.yml
new file mode 100644
index 00000000000..14b8f486d5c
--- /dev/null
+++ b/changelogs/unreleased/29385-add_shrug_command.yml
@@ -0,0 +1,4 @@
+---
+title: Add /shrug and /tableflip commands
+merge_request: 10068
+author: Alex Ives
diff --git a/changelogs/unreleased/33620-remove-events-from-notification_settings.yml b/changelogs/unreleased/33620-remove-events-from-notification_settings.yml
new file mode 100644
index 00000000000..f5f3ef3fb82
--- /dev/null
+++ b/changelogs/unreleased/33620-remove-events-from-notification_settings.yml
@@ -0,0 +1,4 @@
+---
+title: Remove events column from notification settings table
+merge_request:
+author:
diff --git a/changelogs/unreleased/34492-firefox-job.yml b/changelogs/unreleased/34492-firefox-job.yml
new file mode 100644
index 00000000000..881b8f649ea
--- /dev/null
+++ b/changelogs/unreleased/34492-firefox-job.yml
@@ -0,0 +1,4 @@
+---
+title: Use jQuery to control scroll behavior in job log for cross browser consistency
+merge_request:
+author:
diff --git a/changelogs/unreleased/34519-extend-api-group-secret-variable.yml b/changelogs/unreleased/34519-extend-api-group-secret-variable.yml
new file mode 100644
index 00000000000..e0b625c392f
--- /dev/null
+++ b/changelogs/unreleased/34519-extend-api-group-secret-variable.yml
@@ -0,0 +1,4 @@
+---
+title: Extend API for Group Secret Variable
+merge_request: 12936
+author:
diff --git a/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml b/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml
new file mode 100644
index 00000000000..0eb2d069719
--- /dev/null
+++ b/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml
@@ -0,0 +1,4 @@
+---
+title: Bump rubocop to 0.49.1 and rubocop-rspec to 1.15.1
+merge_request:
+author: Takuya Noguchi
diff --git a/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml b/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml
deleted file mode 100644
index 41b506681f9..00000000000
--- a/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix asynchronous javascript paths when GitLab is installed under a relative
- URL
-merge_request: 13165
-author:
diff --git a/changelogs/unreleased/35697-allow-logged-in-user-to-read-user-list.yml b/changelogs/unreleased/35697-allow-logged-in-user-to-read-user-list.yml
new file mode 100644
index 00000000000..54b2e71bef9
--- /dev/null
+++ b/changelogs/unreleased/35697-allow-logged-in-user-to-read-user-list.yml
@@ -0,0 +1,4 @@
+---
+title: Allow any logged in users to read_users_list even if it's restricted
+merge_request: 13201
+author:
diff --git a/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml b/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml
new file mode 100644
index 00000000000..988fdacb5fd
--- /dev/null
+++ b/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed breadcrumbs title aggressively collapsing
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-group-milestone-link-in-issuable-sidebar.yml b/changelogs/unreleased/fix-group-milestone-link-in-issuable-sidebar.yml
new file mode 100644
index 00000000000..1558e575e6d
--- /dev/null
+++ b/changelogs/unreleased/fix-group-milestone-link-in-issuable-sidebar.yml
@@ -0,0 +1,4 @@
+---
+title: Fix links to group milestones from issue and merge request sidebar
+merge_request:
+author:
diff --git a/changelogs/unreleased/help-page-breadcrumb-title-fix.yml b/changelogs/unreleased/help-page-breadcrumb-title-fix.yml
deleted file mode 100644
index 040fe4b9916..00000000000
--- a/changelogs/unreleased/help-page-breadcrumb-title-fix.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed new navigation breadcrumb title on help pages
-merge_request:
-author:
diff --git a/changelogs/unreleased/mk-fix-deploy-key-deletion.yml b/changelogs/unreleased/mk-fix-deploy-key-deletion.yml
new file mode 100644
index 00000000000..9ff2e49b14c
--- /dev/null
+++ b/changelogs/unreleased/mk-fix-deploy-key-deletion.yml
@@ -0,0 +1,4 @@
+---
+title: Fix deletion of deploy keys linked to other projects
+merge_request: 13162
+author:
diff --git a/changelogs/unreleased/mk-fix-wiki-backup.yml b/changelogs/unreleased/mk-fix-wiki-backup.yml
new file mode 100644
index 00000000000..ba9c1e85955
--- /dev/null
+++ b/changelogs/unreleased/mk-fix-wiki-backup.yml
@@ -0,0 +1,4 @@
+---
+title: Fix improperly skipped backups of wikis.
+merge_request: 13096
+author:
diff --git a/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml b/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml
deleted file mode 100644
index 1186dc59dc7..00000000000
--- a/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Ensure filesystem metrics test files are deleted
-merge_request:
-author:
diff --git a/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml b/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml
deleted file mode 100644
index dfff4c23308..00000000000
--- a/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix Prometheus client PID reuse bug
-merge_request: 13130
-author:
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index e9bf2df490f..73a68c6da1b 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -282,7 +282,7 @@ production: &base
#
# Example: '/etc/ca.pem'
#
- ca_cert: ''
+ ca_file: ''
# Specifies the SSL version for OpenSSL to use, if the OpenSSL default
# is not appropriate.
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 1bcbad3a60d..e81ef2abddb 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -39,6 +39,8 @@ var config = {
environments_folder: './environments/folder/environments_folder_bundle.js',
filtered_search: './filtered_search/filtered_search_bundle.js',
graphs: './graphs/graphs_bundle.js',
+ graphs_charts: './graphs/graphs_charts.js',
+ graphs_show: './graphs/graphs_show.js',
group: './group.js',
groups: './groups/index.js',
groups_list: './groups_list.js',
@@ -55,8 +57,11 @@ var config = {
notes: './notes/index.js',
pdf_viewer: './blob/pdf_viewer.js',
pipelines: './pipelines/pipelines_bundle.js',
- pipelines_details: './pipelines/pipeline_details_bundle.js',
+ pipelines_charts: './pipelines/pipelines_charts.js',
+ pipelines_details: './pipelines/pipeline_details_bundle.js',
+ pipelines_times: './pipelines/pipelines_times.js',
profile: './profile/profile_bundle.js',
+ project_new: './projects/project_new.js',
prometheus_metrics: './prometheus_metrics',
protected_branches: './protected_branches',
protected_tags: './protected_tags',
@@ -68,9 +73,12 @@ var config = {
stl_viewer: './blob/stl_viewer.js',
terminal: './terminal/terminal_bundle.js',
u2f: ['vendor/u2f'],
+ ui_development_kit: './ui_development_kit.js',
+ users: './users/index.js',
raven: './raven/index.js',
vue_merge_request_widget: './vue_merge_request_widget/index.js',
test: './test.js',
+ two_factor_auth: './two_factor_auth.js',
performance_bar: './performance_bar.js',
webpack_runtime: './webpack.js',
},
diff --git a/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb b/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb
index c0cb9d78748..bcdae272209 100644
--- a/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb
+++ b/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb
@@ -16,6 +16,7 @@ class MigrateProcessCommitWorkerJobs < ActiveRecord::Migration
end
def repository_path
+ # TODO: review if the change from Legacy storage needs to reflect here as well.
File.join(repository_storage_path, read_attribute(:path_with_namespace) + '.git')
end
diff --git a/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb b/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb
new file mode 100644
index 00000000000..cd533391d8d
--- /dev/null
+++ b/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb
@@ -0,0 +1,9 @@
+class RemoveEventsFromNotificationSettings < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ remove_column :notification_settings, :events, :text
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 0abdb987b77..4ba218e1e0d 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170725145659) do
+ActiveRecord::Schema.define(version: 20170728101014) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -254,32 +254,32 @@ ActiveRecord::Schema.define(version: 20170725145659) do
add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree
add_index "ci_builds", ["user_id"], name: "index_ci_builds_on_user_id", using: :btree
- create_table "ci_pipeline_schedule_variables", force: :cascade do |t|
+ create_table "ci_group_variables", force: :cascade do |t|
t.string "key", null: false
t.text "value"
t.text "encrypted_value"
t.string "encrypted_value_salt"
t.string "encrypted_value_iv"
- t.integer "pipeline_schedule_id", null: false
+ t.integer "group_id", null: false
+ t.boolean "protected", default: false, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
- add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree
+ add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree
- create_table "ci_group_variables", force: :cascade do |t|
+ create_table "ci_pipeline_schedule_variables", force: :cascade do |t|
t.string "key", null: false
t.text "value"
t.text "encrypted_value"
t.string "encrypted_value_salt"
t.string "encrypted_value_iv"
- t.integer "group_id", null: false
- t.boolean "protected", default: false, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.integer "pipeline_schedule_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
- add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree
+ add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree
create_table "ci_pipeline_schedules", force: :cascade do |t|
t.string "description"
@@ -981,7 +981,6 @@ ActiveRecord::Schema.define(version: 20170725145659) do
t.integer "level", default: 0, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.text "events"
t.boolean "new_note"
t.boolean "new_issue"
t.boolean "reopen_issue"
@@ -1624,8 +1623,8 @@ ActiveRecord::Schema.define(version: 20170725145659) do
add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify
add_foreign_key "ci_builds", "ci_stages", column: "stage_id", name: "fk_3a9eaa254d", on_delete: :cascade
add_foreign_key "ci_builds", "projects", name: "fk_befce0568a", on_delete: :cascade
- add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade
add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade
+ add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade
add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade
add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify
add_foreign_key "ci_pipeline_variables", "ci_pipelines", column: "pipeline_id", name: "fk_f29c5f4380", on_delete: :cascade
diff --git a/doc/README.md b/doc/README.md
index cc63ecb7eab..8bb8e147cd1 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -44,16 +44,17 @@ Shortcuts to GitLab's most visited docs:
### Projects and groups
-- [Create a project](gitlab-basics/create-project.md)
-- [Fork a project](gitlab-basics/fork-project.md)
-- [Importing and exporting projects between instances](user/project/settings/import_export.md).
-- [Project access](public_access/public_access.md): Setting up your project's visibility to public, internal, or private.
+- [Projects](user/project/index.md):
+ - [Create a project](gitlab-basics/create-project.md)
+ - [Fork a project](gitlab-basics/fork-project.md)
+ - [Importing and exporting projects between instances](user/project/settings/import_export.md).
+ - [Project access](public_access/public_access.md): Setting up your project's visibility to public, internal, or private.
+ - [GitLab Pages](user/project/pages/index.md): Build, test, and deploy your static website with GitLab Pages.
- [Groups](user/group/index.md): Organize your projects in groups.
- - [GitLab Subgroups](user/group/subgroups/index.md)
+ - [Subgroups](user/group/subgroups/index.md)
- [Search through GitLab](user/search/index.md): Search for issues, merge requests, projects, groups, todos, and issues in Issue Boards.
- [Snippets](user/snippets.md): Snippets allow you to create little bits of code.
- [Wikis](user/project/wiki/index.md): Enhance your repository documentation with built-in wikis.
-- [GitLab Pages](user/project/pages/index.md): Build, test, and deploy your static website with GitLab Pages.
### Repository
diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index a7395e03d1c..425c924cdf2 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -96,7 +96,7 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
#
# Example: '/etc/ca.pem'
#
- ca_cert: ''
+ ca_file: ''
# Specifies the SSL version for OpenSSL to use, if the OpenSSL default
# is not appropriate.
@@ -259,9 +259,9 @@ group you can use the following syntax:
(memberOf:1.2.840.113556.1.4.1941:=CN=My Group,DC=Example,DC=com)
```
-Find more information about this "LDAP_MATCHING_RULE_IN_CHAIN" filter at
+Find more information about this "LDAP_MATCHING_RULE_IN_CHAIN" filter at
https://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx. Support for
-nested members in the user filter should not be confused with
+nested members in the user filter should not be confused with
[group sync nested groups support (EE only)](https://docs.gitlab.com/ee/administration/auth/ldap-ee.html#supported-ldap-group-types-attributes).
Please note that GitLab does not support the custom filter syntax used by
diff --git a/doc/administration/monitoring/performance/img/performance_bar.png b/doc/administration/monitoring/performance/img/performance_bar.png
index d38293d2ed6..b3c6bc474e3 100644
--- a/doc/administration/monitoring/performance/img/performance_bar.png
+++ b/doc/administration/monitoring/performance/img/performance_bar.png
Binary files differ
diff --git a/doc/api/README.md b/doc/api/README.md
index fe29563eaca..1d2226e2ae8 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -11,7 +11,8 @@ following locations:
- [Award Emoji](award_emoji.md)
- [Branches](branches.md)
- [Broadcast Messages](broadcast_messages.md)
-- [Build Variables](build_variables.md)
+- [Project-level Variables](project_level_variables.md)
+- [Group-level Variables](group_level_variables.md)
- [Commits](commits.md)
- [Deployments](deployments.md)
- [Deploy Keys](deploy_keys.md)
diff --git a/doc/api/group_level_variables.md b/doc/api/group_level_variables.md
new file mode 100644
index 00000000000..e19be7b35c4
--- /dev/null
+++ b/doc/api/group_level_variables.md
@@ -0,0 +1,125 @@
+# Group-level Variables API
+
+## List group variables
+
+Get list of a group's variables.
+
+```
+GET /groups/:id/variables
+```
+
+| Attribute | Type | required | Description |
+|-----------|---------|----------|---------------------|
+| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+
+```
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables"
+```
+
+```json
+[
+ {
+ "key": "TEST_VARIABLE_1",
+ "value": "TEST_1"
+ },
+ {
+ "key": "TEST_VARIABLE_2",
+ "value": "TEST_2"
+ }
+]
+```
+
+## Show variable details
+
+Get the details of a group's specific variable.
+
+```
+GET /groups/:id/variables/:key
+```
+
+| Attribute | Type | required | Description |
+|-----------|---------|----------|-----------------------|
+| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `key` | string | yes | The `key` of a variable |
+
+```
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/TEST_VARIABLE_1"
+```
+
+```json
+{
+ "key": "TEST_VARIABLE_1",
+ "value": "TEST_1"
+}
+```
+
+## Create variable
+
+Create a new variable.
+
+```
+POST /groups/:id/variables
+```
+
+| Attribute | Type | required | Description |
+|-------------|---------|----------|-----------------------|
+| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `key` | string | yes | The `key` of a variable; must have no more than 255 characters; only `A-Z`, `a-z`, `0-9`, and `_` are allowed |
+| `value` | string | yes | The `value` of a variable |
+| `protected` | boolean | no | Whether the variable is protected |
+
+```
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
+```
+
+```json
+{
+ "key": "NEW_VARIABLE",
+ "value": "new value",
+ "protected": false
+}
+```
+
+## Update variable
+
+Update a group's variable.
+
+```
+PUT /groups/:id/variables/:key
+```
+
+| Attribute | Type | required | Description |
+|-------------|---------|----------|-------------------------|
+| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `key` | string | yes | The `key` of a variable |
+| `value` | string | yes | The `value` of a variable |
+| `protected` | boolean | no | Whether the variable is protected |
+
+```
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/NEW_VARIABLE" --form "value=updated value"
+```
+
+```json
+{
+ "key": "NEW_VARIABLE",
+ "value": "updated value",
+ "protected": true
+}
+```
+
+## Remove variable
+
+Remove a group's variable.
+
+```
+DELETE /groups/:id/variables/:key
+```
+
+| Attribute | Type | required | Description |
+|-----------|---------|----------|-------------------------|
+| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `key` | string | yes | The `key` of a variable |
+
+```
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/VARIABLE_1"
+```
diff --git a/doc/api/build_variables.md b/doc/api/project_level_variables.md
index d4f00256ed3..82ac0b09027 100644
--- a/doc/api/build_variables.md
+++ b/doc/api/project_level_variables.md
@@ -1,8 +1,8 @@
-# Build Variables API
+# Project-level Variables API
## List project variables
-Get list of a project's build variables.
+Get list of a project's variables.
```
GET /projects/:id/variables
@@ -31,7 +31,7 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/
## Show variable details
-Get the details of a project's specific build variable.
+Get the details of a project's specific variable.
```
GET /projects/:id/variables/:key
@@ -55,7 +55,7 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/
## Create variable
-Create a new build variable.
+Create a new variable.
```
POST /projects/:id/variables
@@ -82,7 +82,7 @@ curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitl
## Update variable
-Update a project's build variable.
+Update a project's variable.
```
PUT /projects/:id/variables/:key
@@ -109,7 +109,7 @@ curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitla
## Remove variable
-Remove a project's build variable.
+Remove a project's variable.
```
DELETE /projects/:id/variables/:key
diff --git a/doc/articles/index.md b/doc/articles/index.md
index a4e41517d83..d7e662d737f 100644
--- a/doc/articles/index.md
+++ b/doc/articles/index.md
@@ -7,40 +7,106 @@ to provide the community with guidance on specific processes to achieve certain
They are written by members of the GitLab Team and by
[Community Writers](https://about.gitlab.com/handbook/product/technical-writing/community-writers/).
+Part of the articles listed below link to the [GitLab Blog](https://about.gitlab.com/blog/),
+where they were originally published.
+
## Authentication
-- **LDAP**
- - [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md)
- - [How to configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/)
+Learn how to explore GitLab's supported [authentications methods](../topics/authentication/index.md):
+
+| Article title | Category | Publishing date |
+| :------------ | :------: | --------------: |
+| **LDAP** |
+| [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md)| Admin guide | 2017/05/03 |
+| [How to configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) | Admin guide | 2017/05/03 |
+
+## Build, test, and deploy with GitLab CI/CD
+
+Build, test, and deploy the software you develop with [GitLab CI/CD](../ci/README.md):
+
+| Article title | Category | Publishing date |
+| :------------ | :------: | --------------: |
+| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017/07/13 |
+| [Dockerizing GitLab Review Apps](https://about.gitlab.com/2017/07/11/dockerizing-review-apps/) | Concepts | 2017/07/11 |
+| [Continuous Integration: From Jenkins to GitLab Using Docker](https://about.gitlab.com/2017/07/27/docker-my-precious/) | Concepts | 2017/07/27 |
+| [Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/) | Tutorial | 2016/12/14 |
+| [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/) | Tutorial | 2016/11/30 |
+| [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/) | Tutorial | 2016/10/12 |
+| [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/) | Tutorial | 2016/08/11 |
+| [Continuous Delivery with GitLab and Convox](https://about.gitlab.com/2016/06/09/continuous-delivery-with-gitlab-and-convox/) | Technical overview | 2016/06/09 |
+| [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/) | Technical overview | 2017/05/15 |
+| [Setting up GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) | Tutorial | 2016/03/10 |
## Git
-- [How to install Git](how_to_install_git/index.md)
+Learn how to use [Git with GitLab](../topics/git/index.md):
+
+| Article title | Category | Publishing date |
+| :------------ | :------: | --------------: |
+| [Why Git is Worth the Learning Curve](https://about.gitlab.com/2017/05/17/learning-curve-is-the-biggest-challenge-developers-face-with-git/) | Concepts | 2017/05/17 |
+| [How to install Git](how_to_install_git/index.md) | Tutorial | 2017/05/15 |
+| [Getting Started with Git LFS](https://about.gitlab.com/2017/01/30/getting-started-with-git-lfs-tutorial/) | Tutorial | 2017/01/30 |
+| [Git Tips & Tricks](https://about.gitlab.com/2016/12/08/git-tips-and-tricks/) | Technical overview | 2016/12/08 |
## GitLab Pages
-- **GitLab Pages from A to Z**
- - [Part 1: Static sites and GitLab Pages domains](../user/project/pages/getting_started_part_one.md)
- - [Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md)
- - [Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md)
- - [Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md)
-- [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/)
-- [GitLab CI: Deployment & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/)
+Learn how to deploy a static website with [GitLab Pages](../user/project/pages/index.md#getting-started):
-## Sofware development
+| Article title | Category | Publishing date |
+| :------------ | :------: | --------------: |
+| **Series: GitLab Pages from A to Z:** |
+| [- Part 1: Static sites and GitLab Pages domains](../user/project/pages/getting_started_part_one.md)| User guide | 2017/02/22 |
+| [- Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md)| User guide | 2017/02/22 |
+| [- Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md)| User guide | 2017/02/22 |
+| [- Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md)| User guide | 2017/02/22 |
+| [Setting up GitLab Pages with CloudFlare Certificates](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/) | Tutorial | 2017/02/07 |
+| [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) | Tutorial | 2016/12/07 |
+| [Publish Code Coverage Report with GitLab Pages](https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/) | Tutorial | 2016/11/03 |
+| [GitLab CI: Deployment & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) | Tutorial | 2016/08/26 |
+| [Posting to your GitLab Pages blog from iOS](https://about.gitlab.com/2016/08/19/posting-to-your-gitlab-pages-blog-from-ios/) | Tutorial | 2016/08/19 |
+| **Series: Static Site Generator:** |
+| [- Part 1: Dynamic vs Static Websites](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/) | Tutorial | 2016/06/03 |
+| [- Part 2: Modern Static Site Generators](https://about.gitlab.com/2016/06/10/ssg-overview-gitlab-pages-part-2/) | Tutorial | 2016/06/10 |
+| [- Part 3: Build any SSG site with GitLab Pages](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) | Tutorial | 2016/06/17 |
+| [Securing your GitLab Pages with TLS and Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/) | Tutorial | 2016/04/11 |
+| [Hosting on GitLab.com with GitLab Pages](https://about.gitlab.com/2016/04/07/gitlab-pages-setup/) | Tutorial | 2016/04/07 |
-- [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/)
-- [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/)
-- [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/)
-- [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/)
-- [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/)
+## Install and maintain GitLab
-## Build, test, and deploy with GitLab CI/CD
+Install, upgrade, integrate, migrate to GitLab:
+
+| Article title | Category | Publishing date |
+| :------------ | :------: | --------------: |
+| [Video Tutorial: Idea to Production on Google Container Engine (GKE)](https://about.gitlab.com/2017/01/23/video-tutorial-idea-to-production-on-google-container-engine-gke/) | Tutorial | 2017/01/23 |
+| [How to Setup a GitLab Instance on Microsoft Azure](https://about.gitlab.com/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/) | Tutorial | 2016/07/13 |
+| [Get started with OpenShift Origin 3 and GitLab](https://about.gitlab.com/2016/06/28/get-started-with-openshift-origin-3-and-gitlab/) | Tutorial | 2016/06/28 |
+| [Getting started with GitLab and DigitalOcean](https://about.gitlab.com/2016/04/27/getting-started-with-gitlab-and-digitalocean/) | Tutorial | 2016/04/27 |
+
+## Software development
+
+Learn how to explore the best of GitLab's software development's capabilities:
+
+| Article title | Category | Publishing date |
+| :------------ | :------: | --------------: |
+| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017/07/13 |
+| [From 2/3 of the Self-Hosted Git Market, to the Next-Generation CI System, to Auto DevOps](https://about.gitlab.com/2017/06/29/whats-next-for-gitlab-ci/)| Concepts | 2017/06/29 |
+| [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/) | Concepts | 2017/05/22 |
+| [Demo: GitLab Service Desk](https://about.gitlab.com/2017/05/09/demo-service-desk/) | Feature highlight | 2017/05/09 |
+| [Demo - Mapping Work Versus Time, With Burndown Charts](https://about.gitlab.com/2017/04/25/mapping-work-to-do-versus-time-with-burndown-charts/) | Feature highlight | 2017/04/25 |
+| [Demo – Cloud Native Development with GitLab](https://about.gitlab.com/2017/04/18/cloud-native-demo/) | Feature highlight | 2017/04/18 |
+| [Demo - Mastering Code Review With GitLab](https://about.gitlab.com/2017/03/17/demo-mastering-code-review-with-gitlab/) | Feature highlight | 2017/03/17 |
+| [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/) | Technical overview | 2016/11/14 |
+| [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) | Technical overview | 2016/10/25 |
+| [Trends in Version Control Land: Microservices](https://about.gitlab.com/2016/08/16/trends-in-version-control-land-microservices/) | Concepts | 2016/08/16 |
+| [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) | Concepts | 2016/08/05 |
+| [Trends in Version Control Land: Innersourcing](https://about.gitlab.com/2016/07/07/trends-version-control-innersourcing/) | Concepts | 2016/07/07 |
+| [Tutorial: It's all connected in GitLab](https://about.gitlab.com/2016/03/08/gitlab-tutorial-its-all-connected/) | Technical overview | 2016/03/08 |
+
+## Technologies
-**Build, test, and deploy** the software you develop with **[GitLab CI/CD](../ci/README.md)**
+| Article title | Category | Publishing date |
+| :------------ | :------: | --------------: |
+| [Why we are not leaving the cloud](https://about.gitlab.com/2017/03/02/why-we-are-not-leaving-the-cloud/) | Concepts | 2017/03/02 |
+| [Why We Chose Vue.js](https://about.gitlab.com/2016/10/20/why-we-chose-vue/) | Concepts | 2016/10/20 |
+| [Markdown Kramdown Tips & Tricks](https://about.gitlab.com/2016/07/19/markdown-kramdown-tips-and-tricks/) | Technical overview | 2016/07/19 |
-- [Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/)
-- [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/)
-- [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/)
-- [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/)
-- [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/)
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index e3f37616757..64a89976300 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -11,6 +11,8 @@ There are a few rules to get your merge request accepted:
**approved by a [frontend maintainer][projects]**.
1. If your merge request includes frontend and backend changes [^1], it must
be **approved by a [frontend and a backend maintainer][projects]**.
+ 1. If your merge request includes a new dependency or a filesystem change, it must
+ be **approved by a [Build team member][team]**. See [how to work with the Build team][build handbook] for more details.
1. To lower the amount of merge requests maintainers need to review, you can
ask or assign any [reviewers][projects] for a first review.
1. If you need some guidance (e.g. it's your first merge request), feel free
@@ -194,3 +196,4 @@ Largely based on the [thoughtbot code review guide].
[projects]: https://about.gitlab.com/handbook/engineering/projects/
[team]: https://about.gitlab.com/team/
+[build handbook]: https://about.gitlab.com/handbook/build/handbook/build#how-to-work-with-build
diff --git a/doc/integration/slash_commands.md b/doc/integration/slash_commands.md
index 5d880ba785c..aa52b5415cf 100644
--- a/doc/integration/slash_commands.md
+++ b/doc/integration/slash_commands.md
@@ -2,7 +2,11 @@
Slash commands in Mattermost and Slack allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
-Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are:
+Commands are scoped to a project, with a trigger term that is specified during configuration.
+
+We suggest you use the project name as the trigger term for simplicity and clarity.
+
+Taking the trigger term as `project-name`, the commands are:
| Command | Effect |
@@ -12,3 +16,18 @@ Commands are scoped to a project, with a trigger term that is specified during c
| `/project-name issue show <id>` | Shows the issue with id `<id>` |
| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment |
+
+## Issue commands
+
+It is possible to create new issue, display issue details and search up to 5 issues.
+
+## Deploy command
+
+In order to deploy to an environment, GitLab will try to find a deployment
+manual action in the pipeline.
+
+If there is only one action for a given environment, it is going to be triggered.
+If there is more than one action defined, GitLab will try to find an action
+which name equals the environment name we want to deploy to.
+
+Command will return an error when no matching action has been found.
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 2691cf7d671..08da721c71d 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -42,7 +42,7 @@ In GitLab, a namespace is a unique name to be used as a user name, a group name,
For example, consider a user called John:
-1. John creates his account on GitLab.com with the username `jonh`;
+1. John creates his account on GitLab.com with the username `john`;
his profile will be accessed under `https://gitlab.example.com/john`
1. John creates a group for his team with the groupname `john-team`;
his group and its projects will be accessed under `https://gitlab.example.com/john-team`
diff --git a/doc/user/index.md b/doc/user/index.md
index 522cf932349..1281cc6e4f0 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -66,7 +66,7 @@ For more use cases please check our [Technical Articles](../articles/index.md).
## Projects
-In GitLab, you can create projects for numerous reasons, such as, host
+In GitLab, you can create [projects](project/index.md) for numerous reasons, such as, host
your code, use it as an issue tracker, collaborate on code, and continuously
build, test, and deploy your app with built-in GitLab CI/CD. Or, you can do
it all at once, from one single project.
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index 0e3747817d2..7d25970fcb1 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -23,7 +23,7 @@ On your profile page, you will see the following information:
- Personal information
- Activity stream: see your activity streamline and the history of your contributions
- Groups: [groups](../group/index.md) you're a member of
-- Contributed projects: projects you contributed to
+- Contributed projects: [projects](../project/index.md) you contributed to
- Personal projects: your personal projects (respecting the project's visibility level)
- Snippets: your personal code [snippets](../snippets.md#personal-snippets)
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
new file mode 100644
index 00000000000..91a19600951
--- /dev/null
+++ b/doc/user/project/index.md
@@ -0,0 +1,107 @@
+# Projects
+
+In GitLab, you can create projects for hosting
+your codebase, use it as an issue tracker, collaborate on code, and continuously
+build, test, and deploy your app with built-in GitLab CI/CD.
+
+Your projects can be [available](../../public_access/public_access.md)
+publicly, internally, or privately, at your choice. GitLab does not limit
+the number of private projects you create.
+
+## Project's features
+
+When you create a project in GitLab, you'll have access to a large number of
+[features](https://about.gitlab.com/features/):
+
+**Issues and merge requests:**
+
+- [Issue tracker](issues/index.md): Discuss implementations with your team within issues
+ - [Issue Boards](issue_board.md): Organize and prioritize your workflow
+ - [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards) (**EES/EEP**): Allow your teams to create their own workflows (Issue Boards) for the same project
+- [Repositories](repository/index.md): Host your code in a fully
+integrated platform
+ - [Protected branches](protected_branches.md): Prevent collaborators
+ from messing with history or pushing code without review
+ - [Protected tags](protected_tags.md): Control over who has
+ permission to create tags, and prevent accidental update or deletion
+- [Merge Requests](merge_requests/index.md): Apply your branching
+strategy and get reviewed by your team
+ - [Merge Request Approvals](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html) (**EES/EEP**): Ask for approval before
+ implementing a change
+ - [Fix merge conflicts from the UI](merge_requests/resolve_conflicts.md):
+ Your Git diff tool right from GitLab's UI
+ - [Review Apps](../../ci/review_apps/index.md): Live preview the results
+ of the changes proposed in a merge request in a per-branch basis
+- [Labels](labels.md): Organize issues and merge requests by labels
+- [Time Tracking](../../workflow/time_tracking.md): Track estimate time
+and time spent on
+ the conclusion of an issue or merge request
+- [Milestones](milestones/index.md): Work towards a target date
+- [Description templates](description_templates.md): Define context-specific
+templates for issue and merge request description fields for your project
+- [Slash commands (quick actions)](quick_actions.md): Textual shortcuts for
+common actions on issues or merge requests
+
+**GitLab CI/CD:**
+
+- [GitLab CI/CD](../../ci/README.md): GitLab's built-in [Continuous Integration, Delivery, and Deployment](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) tool
+ - [Container Registry](container_registry.md): Build and push Docker
+ images out-of-the-box
+ - [Auto Deploy](../../ci/autodeploy/index.md): Configure GitLab CI/CD
+ to automatically set up your app's deployment
+ - [Enable and disable GitLab CI](../../ci/enable_or_disable_ci.md)
+ - [Pipelines](../../ci/pipelines.md#pipelines): Configure and visualize
+ your GitLab CI/CD pipelines from the UI
+ - [Scheduled Pipelines](pipelines/schedules.md): Schedule a pipeline
+ to start at a chosen time
+ - [Pipeline Graphs](../../ci/pipelines.md#pipeline-graphs): View your
+ entire pipeline from the UI
+ - [Job artifacts](pipelines/job_artifacts.md): Define,
+ browse, and download job artifacts
+ - [Pipeline settings](pipelines/settings.md): Set up Git strategy (choose the default way your repository is fetched from GitLab in a job),
+ timeout (defines the maximum amount of time in minutes that a job is able run), custom path for `.gitlab-ci.yml`, test coverage parsing, pipeline's visibility, and much more
+- [GitLab Pages](pages/index.md): Build, test, and deploy your static
+website with GitLab Pages
+
+**Other features:**
+
+- [Cycle Analytics](cycle_analytics.md): Review your development lifecycle
+- [Koding integration](koding.md) (not available on GitLab.com): Integrate
+with Koding to have access to a web terminal right from the GitLab UI
+- [Syntax highlighting](highlighting.md): An alternative to customize
+your code blocks, overriding GitLab's default choice of language
+
+### Project's integrations
+
+[Integrate your project](integrations/index.md) with Jira, Mattermost,
+Kubernetes, Slack, and a lot more.
+
+## New project
+
+Learn how to [create a new project](../../gitlab-basics/create-project.md) in GitLab.
+
+### Fork a project
+
+You can [fork a project](../../gitlab-basics/fork-project.md) in order to:
+
+- Collaborate on code by forking a project and creating a merge request
+from your fork to the upstream project
+- Fork a sample project to work on the top of that
+
+## Import or export a project
+
+- Import a project from:
+ - [GitHub to GitLab](../../workflow/importing/import_projects_from_github.md)
+ - [BitBucket to GitLab](../../workflow/importing/import_projects_from_bitbucket.md)
+ - [Gitea to GitLab](../../workflow/importing/import_projects_from_gitea.md)
+ - [FogBugz to GitLab](../../workflow/importing/import_projects_from_fogbugz.md)
+- [Export a project from GitLab](settings/import_export.md#exporting-a-project-and-its-data)
+- [Importing and exporting projects between GitLab instances](settings/import_export.md)
+
+## Leave a project
+
+**Leave project** will only display on the project's dashboard
+when a project is part of a group (under a
+[group namespace](../group/index.md#namespaces)).
+If you choose to leave a project you will no longer be a project
+member, therefore, unable to contribute.
diff --git a/doc/user/project/koding.md b/doc/user/project/koding.md
index c56a1efe3c2..455e2ee47b4 100644
--- a/doc/user/project/koding.md
+++ b/doc/user/project/koding.md
@@ -1,4 +1,4 @@
-# Koding & GitLab
+# Koding integration
> [Introduced][ce-5909] in GitLab 8.11.
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index bb41eb41795..4b2c435a120 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -2,7 +2,7 @@
A [repository](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository)
is what you use to store your codebase in GitLab and change it with version control.
-A repository is part of a project, which has a lot of other features.
+A repository is part of a [project](../index.md), which has a lot of other features.
## Create a repository
diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb
index c6cabace25b..420ac8a695a 100644
--- a/features/steps/project/forked_merge_requests.rb
+++ b/features/steps/project/forked_merge_requests.rb
@@ -30,8 +30,8 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
expect(@merge_request.source_project).to eq @forked_project
expect(@merge_request.source_branch).to eq "fix"
expect(@merge_request.target_branch).to eq "master"
- expect(page).to have_content @forked_project.path_with_namespace
- expect(page).to have_content @project.path_with_namespace
+ expect(page).to have_content @forked_project.full_path
+ expect(page).to have_content @project.full_path
expect(page).to have_content @merge_request.source_branch
expect(page).to have_content @merge_request.target_branch
@@ -43,10 +43,10 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
expect(page).to have_content('Target branch')
first('.js-source-project').click
- first('.dropdown-source-project a', text: @forked_project.path_with_namespace)
+ first('.dropdown-source-project a', text: @forked_project.full_path)
first('.js-target-project').click
- first('.dropdown-target-project a', text: @project.path_with_namespace)
+ first('.dropdown-target-project a', text: @project.full_path)
first('.js-source-branch').click
wait_for_requests
@@ -81,8 +81,8 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
expect(@merge_request.source_project).to eq @forked_project
expect(@merge_request.source_branch).to eq "fix"
expect(@merge_request.target_branch).to eq "master"
- expect(page).to have_content @forked_project.path_with_namespace
- expect(page).to have_content @project.path_with_namespace
+ expect(page).to have_content @forked_project.full_path
+ expect(page).to have_content @project.full_path
expect(page).to have_content @merge_request.source_branch
expect(page).to have_content @merge_request.target_branch
end
diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb
index b2ceb8dd9a8..cbe6f93f87e 100644
--- a/features/steps/project/redirects.rb
+++ b/features/steps/project/redirects.rb
@@ -47,7 +47,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
step 'I should be redirected to "Community" page' do
project = Project.find_by(name: 'Community')
- expect(current_path).to eq "/#{project.path_with_namespace}"
+ expect(current_path).to eq "/#{project.full_path}"
expect(status_code).to eq 200
end
@@ -61,7 +61,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
step 'I should be redirected to "Enterprise" page' do
project = Project.find_by(name: 'Enterprise')
- expect(current_path).to eq "/#{project.path_with_namespace}"
+ expect(current_path).to eq "/#{project.full_path}"
expect(status_code).to eq 200
end
end
diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb
index 6a478c50e5e..2b8da2a6f19 100644
--- a/features/steps/project/wiki.rb
+++ b/features/steps/project/wiki.rb
@@ -142,7 +142,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
end
step 'I should see non-escaped link in the pages list' do
- expect(page).to have_xpath("//a[@href='/#{project.path_with_namespace}/wikis/one/two/three-test']")
+ expect(page).to have_xpath("//a[@href='/#{project.full_path}/wikis/one/two/three-test']")
end
step 'I edit the Wiki page with a path' do
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 045a0db1842..ae10da2d85f 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -139,6 +139,7 @@ module API
mount ::API::Triggers
mount ::API::Users
mount ::API::Variables
+ mount ::API::GroupVariables
mount ::API::Version
route :any, '*path' do
diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb
new file mode 100644
index 00000000000..f64da4ab77b
--- /dev/null
+++ b/lib/api/group_variables.rb
@@ -0,0 +1,96 @@
+module API
+ class GroupVariables < Grape::API
+ include PaginationParams
+
+ before { authenticate! }
+ before { authorize! :admin_build, user_group }
+
+ params do
+ requires :id, type: String, desc: 'The ID of a group'
+ end
+
+ resource :groups, requirements: { id: %r{[^/]+} } do
+ desc 'Get group-level variables' do
+ success Entities::Variable
+ end
+ params do
+ use :pagination
+ end
+ get ':id/variables' do
+ variables = user_group.variables
+ present paginate(variables), with: Entities::Variable
+ end
+
+ desc 'Get a specific variable from a group' do
+ success Entities::Variable
+ end
+ params do
+ requires :key, type: String, desc: 'The key of the variable'
+ end
+ get ':id/variables/:key' do
+ key = params[:key]
+ variable = user_group.variables.find_by(key: key)
+
+ return not_found!('GroupVariable') unless variable
+
+ present variable, with: Entities::Variable
+ end
+
+ desc 'Create a new variable in a group' do
+ success Entities::Variable
+ end
+ params do
+ requires :key, type: String, desc: 'The key of the variable'
+ requires :value, type: String, desc: 'The value of the variable'
+ optional :protected, type: String, desc: 'Whether the variable is protected'
+ end
+ post ':id/variables' do
+ variable_params = declared_params(include_missing: false)
+
+ variable = user_group.variables.create(variable_params)
+
+ if variable.valid?
+ present variable, with: Entities::Variable
+ else
+ render_validation_error!(variable)
+ end
+ end
+
+ desc 'Update an existing variable from a group' do
+ success Entities::Variable
+ end
+ params do
+ optional :key, type: String, desc: 'The key of the variable'
+ optional :value, type: String, desc: 'The value of the variable'
+ optional :protected, type: String, desc: 'Whether the variable is protected'
+ end
+ put ':id/variables/:key' do
+ variable = user_group.variables.find_by(key: params[:key])
+
+ return not_found!('GroupVariable') unless variable
+
+ variable_params = declared_params(include_missing: false).except(:key)
+
+ if variable.update(variable_params)
+ present variable, with: Entities::Variable
+ else
+ render_validation_error!(variable)
+ end
+ end
+
+ desc 'Delete an existing variable from a group' do
+ success Entities::Variable
+ end
+ params do
+ requires :key, type: String, desc: 'The key of the variable'
+ end
+ delete ':id/variables/:key' do
+ variable = user_group.variables.find_by(key: params[:key])
+ not_found!('GroupVariable') unless variable
+
+ status 204
+ variable.destroy
+ end
+ end
+ end
+end
diff --git a/lib/api/runner.rb b/lib/api/runner.rb
index 405d25ca3c1..88fc62d33df 100644
--- a/lib/api/runner.rb
+++ b/lib/api/runner.rb
@@ -90,7 +90,7 @@ module API
if result.valid?
if result.build
Gitlab::Metrics.add_event(:build_found,
- project: result.build.project.path_with_namespace)
+ project: result.build.project.full_path)
present result.build, with: Entities::JobRequest::Response
else
Gitlab::Metrics.add_event(:build_not_found)
@@ -119,7 +119,7 @@ module API
job.trace.set(params[:trace]) if params[:trace]
Gitlab::Metrics.add_event(:update_build,
- project: job.project.path_with_namespace)
+ project: job.project.full_path)
case params[:state].to_s
when 'success'
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index a1685c77916..88821ae56e0 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -7,7 +7,7 @@ module Backup
prepare
Project.find_each(batch_size: 1000) do |project|
- progress.print " * #{project.path_with_namespace} ... "
+ progress.print " * #{project.full_path} ... "
path_to_project_repo = path_to_repo(project)
path_to_project_bundle = path_to_bundle(project)
@@ -42,7 +42,7 @@ module Backup
path_to_wiki_bundle = path_to_bundle(wiki)
if File.exist?(path_to_wiki_repo)
- progress.print " * #{wiki.path_with_namespace} ... "
+ progress.print " * #{wiki.full_path} ... "
if empty_repo?(wiki)
progress.puts " [SKIPPED]".color(:cyan)
else
@@ -71,11 +71,11 @@ module Backup
end
Project.find_each(batch_size: 1000) do |project|
- progress.print " * #{project.path_with_namespace} ... "
+ progress.print " * #{project.full_path} ... "
path_to_project_repo = path_to_repo(project)
path_to_project_bundle = path_to_bundle(project)
- project.ensure_dir_exist
+ project.ensure_storage_path_exist
cmd = if File.exist?(path_to_project_bundle)
%W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_project_bundle} #{path_to_project_repo})
@@ -104,7 +104,7 @@ module Backup
path_to_wiki_bundle = path_to_bundle(wiki)
if File.exist?(path_to_wiki_bundle)
- progress.print " * #{wiki.path_with_namespace} ... "
+ progress.print " * #{wiki.full_path} ... "
# If a wiki bundle exists, first remove the empty repo
# that was initialized with ProjectWiki.new() and then
@@ -142,11 +142,11 @@ module Backup
end
def path_to_bundle(project)
- File.join(backup_repos_path, project.path_with_namespace + '.bundle')
+ File.join(backup_repos_path, project.disk_path + '.bundle')
end
def path_to_tars(project, dir = nil)
- path = File.join(backup_repos_path, project.path_with_namespace)
+ path = File.join(backup_repos_path, project.disk_path)
if dir
File.join(path, "#{dir}.tar")
@@ -185,13 +185,14 @@ module Backup
def progress_warn(project, cmd, output)
progress.puts "[WARNING] Executing #{cmd}".color(:orange)
- progress.puts "Ignoring error on #{project.path_with_namespace} - #{output}".color(:orange)
+ progress.puts "Ignoring error on #{project.full_path} - #{output}".color(:orange)
end
def empty_repo?(project_or_wiki)
+ project_or_wiki.repository.expire_exists_cache # protect backups from stale cache
project_or_wiki.repository.empty_repo?
rescue => e
- progress.puts "Ignoring repository error and continuing backing up project: #{project_or_wiki.path_with_namespace} - #{e.message}".color(:orange)
+ progress.puts "Ignoring repository error and continuing backing up project: #{project_or_wiki.full_path} - #{e.message}".color(:orange)
false
end
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index 7a262dd025c..685b43605ae 100644
--- a/lib/banzai/filter/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -259,7 +259,7 @@ module Banzai
found = []
projects.each do |project|
- ref = project.path_with_namespace
+ ref = project.full_path
get_or_set_cache(cache, ref) { project }
found << ref
end
@@ -277,7 +277,7 @@ module Banzai
end
def current_project_path
- @current_project_path ||= project.path_with_namespace
+ @current_project_path ||= project.full_path
end
def current_project_namespace_path
diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb
index c2fed57a0d8..758f15c8a67 100644
--- a/lib/banzai/filter/relative_link_filter.rb
+++ b/lib/banzai/filter/relative_link_filter.rb
@@ -51,7 +51,7 @@ module Banzai
uri.path = [
relative_url_root,
- context[:project].path_with_namespace,
+ context[:project].full_path,
uri_type(file_path),
Addressable::URI.escape(ref),
Addressable::URI.escape(file_path)
diff --git a/lib/banzai/filter/upload_link_filter.rb b/lib/banzai/filter/upload_link_filter.rb
index 45bb66dc99f..09844931be5 100644
--- a/lib/banzai/filter/upload_link_filter.rb
+++ b/lib/banzai/filter/upload_link_filter.rb
@@ -28,7 +28,7 @@ module Banzai
end
def build_url(uri)
- File.join(Gitlab.config.gitlab.url, project.path_with_namespace, uri)
+ File.join(Gitlab.config.gitlab.url, project.full_path, uri)
end
def project
diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb
index e2e91ce99cd..79058c02ce5 100644
--- a/lib/ci/api/builds.rb
+++ b/lib/ci/api/builds.rb
@@ -29,7 +29,7 @@ module Ci
if result.valid?
if result.build
Gitlab::Metrics.add_event(:build_found,
- project: result.build.project.path_with_namespace)
+ project: result.build.project.full_path)
present result.build, with: Entities::BuildDetails
else
@@ -64,7 +64,7 @@ module Ci
build.trace.set(params[:trace]) if params[:trace]
Gitlab::Metrics.add_event(:update_build,
- project: build.project.path_with_namespace)
+ project: build.project.full_path)
case params[:state].to_s
when 'success'
diff --git a/lib/github/import.rb b/lib/github/import.rb
index ff5d7db2705..cea4be5460b 100644
--- a/lib/github/import.rb
+++ b/lib/github/import.rb
@@ -93,7 +93,7 @@ module Github
def fetch_wiki_repository
wiki_url = "https://#{options.fetch(:token)}@github.com/#{repo}.wiki.git"
- wiki_path = "#{project.path_with_namespace}.wiki"
+ wiki_path = "#{project.full_path}.wiki"
unless project.wiki.repository_exists?
gitlab_shell.import_repository(project.repository_storage_path, wiki_path, wiki_url)
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index 5a6d9ae99a0..28bbf3b384e 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -61,7 +61,7 @@ module Gitlab
def import_wiki
return if project.wiki.repository_exists?
- path_with_namespace = "#{project.path_with_namespace}.wiki"
+ path_with_namespace = "#{project.full_path}.wiki"
import_url = project.import_url.sub(/\.git\z/, ".git/wiki")
gitlab_shell.import_repository(project.repository_storage_path, path_with_namespace, import_url)
rescue StandardError => e
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index d2863a4da71..6d7de52cb80 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -79,13 +79,6 @@ module Gitlab
@new_content_sha = refs&.head_sha
end
- def new_content_commit
- return @new_content_commit if defined?(@new_content_commit)
-
- sha = new_content_commit
- @new_content_commit = repository.commit(sha) if sha
- end
-
def old_content_sha
return if new_file?
return @old_content_sha if defined?(@old_content_sha)
@@ -94,13 +87,6 @@ module Gitlab
@old_content_sha = refs&.base_sha
end
- def old_content_commit
- return @old_content_commit if defined?(@old_content_commit)
-
- sha = old_content_sha
- @old_content_commit = repository.commit(sha) if sha
- end
-
def new_blob
return @new_blob if defined?(@new_blob)
@@ -123,10 +109,6 @@ module Gitlab
new_content_sha || old_content_sha
end
- def content_commit
- new_content_commit || old_content_commit
- end
-
def blob
new_blob || old_blob
end
diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb
index 85e6db0a689..72d7d4f84d1 100644
--- a/lib/gitlab/ee_compat_check.rb
+++ b/lib/gitlab/ee_compat_check.rb
@@ -181,8 +181,6 @@ module Gitlab
end
def find_merge_base_with_master(branch:)
- return if merge_base_found?
-
# Start with (Math.exp(3).to_i = 20) until (Math.exp(6).to_i = 403)
# In total we go (20 + 54 + 148 + 403 = 625) commits deeper
depth = 20
diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb
index dd1d9dcd555..cd9d3a6483f 100644
--- a/lib/gitlab/email/message/repository_push.rb
+++ b/lib/gitlab/email/message/repository_push.rb
@@ -117,7 +117,7 @@ module Gitlab
def subject
subject_text = '[Git]'
- subject_text << "[#{project.path_with_namespace}]"
+ subject_text << "[#{project.full_path}]"
subject_text << "[#{ref_name}]" if @action == :push
subject_text << ' '
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index a3bc79109f8..88529ba2c47 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -636,6 +636,33 @@ module Gitlab
@attributes.attributes(path)
end
+ def languages(ref = nil)
+ Gitlab::GitalyClient.migrate(:commit_languages) do |is_enabled|
+ if is_enabled
+ gitaly_commit_client.languages(ref)
+ else
+ ref ||= rugged.head.target_id
+ languages = Linguist::Repository.new(rugged, ref).languages
+ total = languages.map(&:last).sum
+
+ languages = languages.map do |language|
+ name, share = language
+ color = Linguist::Language[name].color || "##{Digest::SHA256.hexdigest(name)[0...6]}"
+ {
+ value: (share.to_f * 100 / total).round(2),
+ label: name,
+ color: color,
+ highlight: color
+ }
+ end
+
+ languages.sort do |x, y|
+ y[:value] <=> x[:value]
+ end
+ end
+ end
+ end
+
def gitaly_repository
Gitlab::GitalyClient::Util.repository(@storage, @relative_path)
end
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index c6e52b530b3..a834781b1f1 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -118,6 +118,13 @@ module Gitlab
consume_commits_response(response)
end
+ def languages(ref = nil)
+ request = Gitaly::CommitLanguagesRequest.new(repository: @gitaly_repo, revision: ref || '')
+ response = GitalyClient.call(@repository.storage, :commit_service, :commit_languages, request)
+
+ response.languages.map { |l| { value: l.share.round(2), label: l.name, color: l.color, highlight: l.color } }
+ end
+
private
def commit_diff_request_params(commit, options = {})
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index f5d84ea8762..13e75b256a7 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -4,12 +4,28 @@ module Gitlab
def initialize(repository)
@repository = repository
@gitaly_repo = repository.gitaly_repository
+ @storage = repository.storage
end
def exists?
request = Gitaly::RepositoryExistsRequest.new(repository: @gitaly_repo)
- GitalyClient.call(@repository.storage, :repository_service, :exists, request).exists
+ GitalyClient.call(@storage, :repository_service, :exists, request).exists
+ end
+
+ def garbage_collect(create_bitmap)
+ request = Gitaly::GarbageCollectRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap)
+ GitalyClient.call(@storage, :repository_service, :garbage_collect, request)
+ end
+
+ def repack_full(create_bitmap)
+ request = Gitaly::RepackFullRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap)
+ GitalyClient.call(@storage, :repository_service, :repack_full, request)
+ end
+
+ def repack_incremental
+ request = Gitaly::RepackIncrementalRequest.new(repository: @gitaly_repo)
+ GitalyClient.call(@storage, :repository_service, :repack_incremental, request)
end
end
end
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index a8c0b47e786..266b1a6fece 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -254,7 +254,7 @@ module Gitlab
def import_wiki
unless project.wiki.repository_exists?
wiki = WikiFormatter.new(project)
- gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url)
+ gitlab_shell.import_repository(project.repository_storage_path, wiki.disk_path, wiki.import_url)
end
rescue Gitlab::Shell::Error => e
# GitHub error message when the wiki repo has not been created,
diff --git a/lib/gitlab/github_import/wiki_formatter.rb b/lib/gitlab/github_import/wiki_formatter.rb
index 6c592ff469c..0396122eeb9 100644
--- a/lib/gitlab/github_import/wiki_formatter.rb
+++ b/lib/gitlab/github_import/wiki_formatter.rb
@@ -7,8 +7,8 @@ module Gitlab
@project = project
end
- def path_with_namespace
- "#{project.path_with_namespace}.wiki"
+ def disk_path
+ "#{project.disk_path}.wiki"
end
def import_url
diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb
index c824d3ea9fc..32ca2809b2f 100644
--- a/lib/gitlab/import_export/repo_restorer.rb
+++ b/lib/gitlab/import_export/repo_restorer.rb
@@ -13,7 +13,7 @@ module Gitlab
def restore
return true unless File.exist?(@path_to_bundle)
- gitlab_shell.import_repository(@project.repository_storage_path, @project.path_with_namespace, @path_to_bundle)
+ gitlab_shell.import_repository(@project.repository_storage_path, @project.disk_path, @path_to_bundle)
rescue => e
@shared.error(e)
false
diff --git a/lib/gitlab/import_export/uploads_saver.rb b/lib/gitlab/import_export/uploads_saver.rb
index 62a2553675c..f9ae5079d7c 100644
--- a/lib/gitlab/import_export/uploads_saver.rb
+++ b/lib/gitlab/import_export/uploads_saver.rb
@@ -24,6 +24,7 @@ module Gitlab
end
def uploads_path
+ # TODO: decide what to do with uploads. We will use UUIDs here too?
File.join(Rails.root.join('public/uploads'), @project.path_with_namespace)
end
end
diff --git a/lib/gitlab/ldap/authentication.rb b/lib/gitlab/ldap/authentication.rb
index 4745311402c..ed1de73f8c6 100644
--- a/lib/gitlab/ldap/authentication.rb
+++ b/lib/gitlab/ldap/authentication.rb
@@ -42,7 +42,7 @@ module Gitlab
end
def adapter
- OmniAuth::LDAP::Adaptor.new(config.options.symbolize_keys)
+ OmniAuth::LDAP::Adaptor.new(config.omniauth_options)
end
def config
diff --git a/lib/gitlab/quick_actions/dsl.rb b/lib/gitlab/quick_actions/dsl.rb
index a4a97236ffc..536765305e1 100644
--- a/lib/gitlab/quick_actions/dsl.rb
+++ b/lib/gitlab/quick_actions/dsl.rb
@@ -105,9 +105,32 @@ module Gitlab
# # Awesome code block
# end
def command(*command_names, &block)
+ define_command(CommandDefinition, *command_names, &block)
+ end
+
+ # Registers a new substitution which is recognizable from body of email or
+ # comment.
+ # It accepts aliases and takes a block with the formatted content.
+ #
+ # Example:
+ #
+ # command :my_substitution, :alias_for_my_substitution do |text|
+ # "#{text} MY AWESOME SUBSTITUTION"
+ # end
+ def substitution(*substitution_names, &block)
+ define_command(SubstitutionDefinition, *substitution_names, &block)
+ end
+
+ def definition_by_name(name)
+ command_definitions_by_name[name.to_sym]
+ end
+
+ private
+
+ def define_command(klass, *command_names, &block)
name, *aliases = command_names
- definition = CommandDefinition.new(
+ definition = klass.new(
name,
aliases: aliases,
description: @description,
@@ -130,10 +153,6 @@ module Gitlab
@condition_block = nil
@parse_params_block = nil
end
-
- def definition_by_name(name)
- command_definitions_by_name[name.to_sym]
- end
end
end
end
diff --git a/lib/gitlab/quick_actions/extractor.rb b/lib/gitlab/quick_actions/extractor.rb
index 09576be7156..3ebfa3bd4b8 100644
--- a/lib/gitlab/quick_actions/extractor.rb
+++ b/lib/gitlab/quick_actions/extractor.rb
@@ -46,6 +46,8 @@ module Gitlab
end
end
+ content, commands = perform_substitutions(content, commands)
+
[content.strip, commands]
end
@@ -110,6 +112,26 @@ module Gitlab
}mx
end
+ def perform_substitutions(content, commands)
+ return unless content
+
+ substitution_definitions = self.command_definitions.select do |definition|
+ definition.is_a?(Gitlab::QuickActions::SubstitutionDefinition)
+ end
+
+ substitution_definitions.each do |substitution|
+ match_data = substitution.match(content)
+ if match_data
+ command = [substitution.name.to_s]
+ command << match_data[1] unless match_data[1].empty?
+ commands << command
+ end
+ content = substitution.perform_substitution(self, content)
+ end
+
+ [content, commands]
+ end
+
def command_names(opts)
command_definitions.flat_map do |command|
next if command.noop?
diff --git a/lib/gitlab/quick_actions/substitution_definition.rb b/lib/gitlab/quick_actions/substitution_definition.rb
new file mode 100644
index 00000000000..032c49ed159
--- /dev/null
+++ b/lib/gitlab/quick_actions/substitution_definition.rb
@@ -0,0 +1,24 @@
+module Gitlab
+ module QuickActions
+ class SubstitutionDefinition < CommandDefinition
+ # noop?=>true means these won't get extracted or removed by Gitlab::QuickActions::Extractor#extract_commands
+ # QuickActions::InterpretService#perform_substitutions handles them separately
+ def noop?
+ true
+ end
+
+ def match(content)
+ content.match %r{^/#{all_names.join('|')} ?(.*)$}
+ end
+
+ def perform_substitution(context, content)
+ return unless content
+
+ all_names.each do |a_name|
+ content.gsub!(%r{/#{a_name} ?(.*)$}, execute_block(action_block, context, '\1'))
+ end
+ content
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/slash_commands/deploy.rb b/lib/gitlab/slash_commands/deploy.rb
index e71eb15d604..93e00ab75a1 100644
--- a/lib/gitlab/slash_commands/deploy.rb
+++ b/lib/gitlab/slash_commands/deploy.rb
@@ -21,29 +21,34 @@ module Gitlab
from = match[:from]
to = match[:to]
- actions = find_actions(from, to)
+ action = find_action(from, to)
- if actions.none?
- Gitlab::SlashCommands::Presenters::Deploy.new(nil).no_actions
- elsif actions.one?
- action = play!(from, to, actions.first)
- Gitlab::SlashCommands::Presenters::Deploy.new(action).present(from, to)
+ if action.nil?
+ Gitlab::SlashCommands::Presenters::Deploy
+ .new(action).action_not_found
else
- Gitlab::SlashCommands::Presenters::Deploy.new(actions).too_many_actions
+ deployment = action.play(current_user)
+
+ Gitlab::SlashCommands::Presenters::Deploy
+ .new(deployment).present(from, to)
end
end
private
- def play!(from, to, action)
- action.play(current_user)
- end
-
- def find_actions(from, to)
+ def find_action(from, to)
environment = project.environments.find_by(name: from)
- return [] unless environment
+ return unless environment
- environment.actions_for(to).select(&:starts_environment?)
+ actions = environment.actions_for(to).select do |action|
+ action.starts_environment?
+ end
+
+ if actions.many?
+ actions.find { |action| action.name == to.to_s }
+ else
+ actions.first
+ end
end
end
end
diff --git a/lib/gitlab/slash_commands/presenters/deploy.rb b/lib/gitlab/slash_commands/presenters/deploy.rb
index b8dc77bd37b..ebae0f57f9b 100644
--- a/lib/gitlab/slash_commands/presenters/deploy.rb
+++ b/lib/gitlab/slash_commands/presenters/deploy.rb
@@ -3,17 +3,14 @@ module Gitlab
module Presenters
class Deploy < Presenters::Base
def present(from, to)
- message = "Deployment started from #{from} to #{to}. [Follow its progress](#{resource_url})."
+ message = "Deployment started from #{from} to #{to}. " \
+ "[Follow its progress](#{resource_url})."
in_channel_response(text: message)
end
- def no_actions
- ephemeral_response(text: "No action found to be executed")
- end
-
- def too_many_actions
- ephemeral_response(text: "Too many actions defined")
+ def action_not_found
+ ephemeral_response(text: "Couldn't find a deployment manual action.")
end
end
end
diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab
index c5f93336346..2f2de083dc0 100755
--- a/lib/support/init.d/gitlab
+++ b/lib/support/init.d/gitlab
@@ -291,7 +291,7 @@ start_gitlab() {
fi
if [ "$gitlab_workhorse_status" = "0" ]; then
- echo "The GitLab Workhorse is already running with pid $spid, not restarting"
+ echo "The GitLab Workhorse is already running with pid $hpid, not restarting"
else
# No need to remove a socket, gitlab-workhorse does this itself.
# Because gitlab-workhorse has multiple executables we need to fix
@@ -313,7 +313,7 @@ start_gitlab() {
if [ "$gitlab_pages_enabled" = true ]; then
if [ "$gitlab_pages_status" = "0" ]; then
- echo "The GitLab Pages is already running with pid $spid, not restarting"
+ echo "The GitLab Pages is already running with pid $gppid, not restarting"
else
$app_root/bin/daemon_with_pidfile $gitlab_pages_pid_path \
$gitlab_pages_dir/gitlab-pages $gitlab_pages_options \
@@ -421,7 +421,7 @@ print_status() {
fi
if [ "$gitlab_pages_enabled" = true ]; then
if [ "$gitlab_pages_status" = "0" ]; then
- echo "The GitLab Pages with pid $mpid is running."
+ echo "The GitLab Pages with pid $gppid is running."
else
printf "The GitLab Pages is \033[31mnot running\033[0m.\n"
fi
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 858f1cd7b34..dbb3b827b9a 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -527,7 +527,7 @@ namespace :gitlab do
repo_dirs = user.authorized_projects.map do |p|
File.join(
p.repository_storage_path,
- "#{p.path_with_namespace}.git"
+ "#{p.disk_path}.git"
)
end
diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake
index 9df07ea8d83..680e76af471 100644
--- a/lib/tasks/gitlab/gitaly.rake
+++ b/lib/tasks/gitlab/gitaly.rake
@@ -19,7 +19,10 @@ namespace :gitlab do
Dir.chdir(args.dir) do
create_gitaly_configuration
- Bundler.with_original_env { run_command!([command]) }
+ # In CI we run scripts/gitaly-test-build instead of this command
+ unless ENV['CI'].present?
+ Bundler.with_original_env { run_command!(%w[/usr/bin/env -u BUNDLE_GEMFILE] + [command]) }
+ end
end
end
@@ -30,7 +33,9 @@ namespace :gitlab do
puts "# Gitaly storage configuration generated from #{Gitlab.config.source} on #{Time.current.to_s(:long)}"
puts "# This is in TOML format suitable for use in Gitaly's config.toml file."
- puts gitaly_configuration_toml
+ # Exclude gitaly-ruby configuration because that depends on the gitaly
+ # installation directory.
+ puts gitaly_configuration_toml(gitaly_ruby: false)
end
private
@@ -41,7 +46,7 @@ namespace :gitlab do
# only generate a configuration for the most common and simplest case: when
# we have exactly one Gitaly process and we are sure it is running locally
# because it uses a Unix socket.
- def gitaly_configuration_toml
+ def gitaly_configuration_toml(gitaly_ruby: true)
storages = []
address = nil
@@ -60,6 +65,7 @@ namespace :gitlab do
end
config = { socket_path: address.sub(%r{\Aunix:}, ''), storage: storages }
config[:auth] = { token: 'secret' } if Rails.env.test?
+ config[:'gitaly-ruby'] = { dir: File.join(Dir.pwd, 'ruby') } if gitaly_ruby
TOML.dump(config)
end
diff --git a/lib/tasks/gitlab/list_repos.rake b/lib/tasks/gitlab/list_repos.rake
index ffcc76e5498..b732db9db6e 100644
--- a/lib/tasks/gitlab/list_repos.rake
+++ b/lib/tasks/gitlab/list_repos.rake
@@ -9,7 +9,7 @@ namespace :gitlab do
scope = scope.where('id IN (?) OR namespace_id in (?)', project_ids, namespace_ids)
end
scope.find_each do |project|
- base = File.join(project.repository_storage_path, project.path_with_namespace)
+ base = File.join(project.repository_storage_path, project.disk_path)
puts base + '.git'
puts base + '.wiki.git'
end
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index ee2cdcdea1b..42825f29e32 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -80,7 +80,7 @@ namespace :gitlab do
print '-'
else
if Gitlab::Shell.new.add_repository(project.repository_storage_path,
- project.path_with_namespace)
+ project.disk_path)
print '.'
else
print 'F'
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 78cf6d2dacc..ee00b816b84 100644
--- a/locale/pt_BR/gitlab.po
+++ b/locale/pt_BR/gitlab.po
@@ -413,14 +413,14 @@ msgstr[0] "Fork"
msgstr[1] "Forks"
msgid "ForkedFromProjectPath|Forked from"
-msgstr "Forked de"
+msgstr "Fork criado a partir de"
msgid "From issue creation until deploy to production"
msgstr "Da abertura de tarefas até a implantação para a produção"
msgid "From merge request merge until deploy to production"
msgstr ""
-"Da aceitação da solicitação de incorporação até a implantação em produção"
+"Do merge request até a implantação em produção"
msgid "Go to your fork"
msgstr "Ir para seu fork"
@@ -576,7 +576,7 @@ msgid "NotificationEvent|Successful pipeline"
msgstr "Pipeline bem sucedido"
msgid "NotificationLevel|Custom"
-msgstr "Personalizar"
+msgstr "Personalizado"
msgid "NotificationLevel|Disabled"
msgstr "Desabilitado"
@@ -881,9 +881,9 @@ msgid ""
"the issue to a milestone, or add the issue to a list on your Issue Board. "
"Begin creating issues to see data for this stage."
msgstr ""
-"A etapa de relatos mostra o tempo que leva desde a criação de uma issue até "
-"sua atribuição a um marco, ou sua adição a uma lista no seu Issue Board. "
-"Comece a criar issues para ver dados para esta etapa."
+"A etapa de planejamento mostra o tempo que se leva desde a criação de uma "
+"issue até sua atribuição à um milestone, ou sua adição a uma lista no seu "
+"Issue Board. Comece a criar issues para ver dados para esta etapa."
msgid "The phase of the development lifecycle."
msgstr "A fase do ciclo de vida do desenvolvimento."
@@ -974,7 +974,7 @@ msgid "Time before an issue gets scheduled"
msgstr "Tempo até que uma issue seja agendada"
msgid "Time before an issue starts implementation"
-msgstr "Tempo até que uma issue comece a ser implementado"
+msgstr "Tempo até que uma issue comece a ser implementada"
msgid "Time between merge request creation and merge/close"
msgstr ""
diff --git a/rubocop/cop/migration/add_column_with_default_to_large_table.rb b/rubocop/cop/migration/add_column_with_default_to_large_table.rb
index 87788b0d9c2..fb363f95b56 100644
--- a/rubocop/cop/migration/add_column_with_default_to_large_table.rb
+++ b/rubocop/cop/migration/add_column_with_default_to_large_table.rb
@@ -20,6 +20,7 @@ module RuboCop
'necessary'.freeze
LARGE_TABLES = %i[
+ ci_pipelines
ci_builds
events
issues
diff --git a/scripts/gitaly-test-build b/scripts/gitaly-test-build
new file mode 100755
index 00000000000..44d314009e2
--- /dev/null
+++ b/scripts/gitaly-test-build
@@ -0,0 +1,10 @@
+#!/usr/bin/env ruby
+
+# This script assumes tmp/tests/gitaly already contains the correct
+# Gitaly version. We just have to compile it and run its 'bundle
+# install'. We have this separate script for that because weird things
+# were happening in CI when we have a 'bundle exec' process that later
+# called 'bundle install' using a different Gemfile, as happens with
+# gitlab-ce and gitaly.
+
+abort 'gitaly build failed' unless system('make', chdir: 'tmp/tests/gitaly')
diff --git a/scripts/gitaly-test-spawn b/scripts/gitaly-test-spawn
new file mode 100755
index 00000000000..dd603eec7f6
--- /dev/null
+++ b/scripts/gitaly-test-spawn
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+
+gitaly_dir = 'tmp/tests/gitaly'
+args = %W[#{gitaly_dir}/gitaly #{gitaly_dir}/config.toml]
+
+# Print the PID of the spawned process
+puts spawn(*args, [:out, :err] => 'log/gitaly-test.log')
diff --git a/scripts/lint-conflicts.sh b/scripts/lint-conflicts.sh
new file mode 100755
index 00000000000..f3877600c8c
--- /dev/null
+++ b/scripts/lint-conflicts.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+output=`git ls-files -z | grep -zvE '\.(rb|js|haml)$' | xargs -0n1 grep -HEn '^<<<<<<< '`
+echo $output
+test -z "$output"
diff --git a/scripts/static-analysis b/scripts/static-analysis
index 6d35684b97f..e4f80e8fc6f 100755
--- a/scripts/static-analysis
+++ b/scripts/static-analysis
@@ -11,7 +11,8 @@ tasks = [
%w[bundle exec rake brakeman],
%w[bundle exec license_finder],
%w[yarn run eslint],
- %w[bundle exec rubocop --require rubocop-rspec]
+ %w[bundle exec rubocop --require rubocop-rspec],
+ %w[scripts/lint-conflicts.sh]
]
failed_tasks = tasks.reduce({}) do |failures, task|
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index 02bbc48dc59..19ee5e3bb7e 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -48,7 +48,7 @@ describe Projects::BlobController do
let(:id) { 'markdown/doc' }
it 'redirects' do
expect(subject)
- .to redirect_to("/#{project.path_with_namespace}/tree/markdown/doc")
+ .to redirect_to("/#{project.full_path}/tree/markdown/doc")
end
end
end
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index 9cd4e9dbf84..24defb4d657 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -33,7 +33,7 @@ describe Projects::BranchesController do
let(:ref) { "master" }
it 'redirects' do
expect(subject)
- .to redirect_to("/#{project.path_with_namespace}/tree/merge_branch")
+ .to redirect_to("/#{project.full_path}/tree/merge_branch")
end
end
@@ -42,7 +42,7 @@ describe Projects::BranchesController do
let(:ref) { "master" }
it 'redirects' do
expect(subject)
- .to redirect_to("/#{project.path_with_namespace}/tree/alert('merge');")
+ .to redirect_to("/#{project.full_path}/tree/alert('merge');")
end
end
@@ -82,7 +82,7 @@ describe Projects::BranchesController do
issue_iid: issue.iid
expect(subject)
- .to redirect_to("/#{project.path_with_namespace}/tree/1-feature-branch")
+ .to redirect_to("/#{project.full_path}/tree/1-feature-branch")
end
it 'posts a system note' do
diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb
index e0de62e4454..5af03ae118c 100644
--- a/spec/controllers/projects/graphs_controller_spec.rb
+++ b/spec/controllers/projects/graphs_controller_spec.rb
@@ -24,37 +24,4 @@ describe Projects::GraphsController do
expect(response).to redirect_to action: :charts
end
end
-
- describe 'GET charts' do
- let(:linguist_repository) do
- double(languages: {
- 'Ruby' => 1000,
- 'CoffeeScript' => 350,
- 'NSIS' => 15
- })
- end
-
- let(:expected_values) do
- nsis_color = "##{Digest::SHA256.hexdigest('NSIS')[0...6]}"
- [
- # colors from Linguist:
- { label: "Ruby", color: "#701516", highlight: "#701516" },
- { label: "CoffeeScript", color: "#244776", highlight: "#244776" },
- # colors from SHA256 fallback:
- { label: "NSIS", color: nsis_color, highlight: nsis_color }
- ]
- end
-
- before do
- allow(Linguist::Repository).to receive(:new).and_return(linguist_repository)
- end
-
- it 'sets the correct colour according to language' do
- get(:charts, namespace_id: project.namespace, project_id: project, id: 'master')
-
- expected_values.each do |val|
- expect(assigns(:languages)).to include(a_hash_including(val))
- end
- end
- end
end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 2fce4b7a85f..0bfe83f1d98 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -609,7 +609,7 @@ describe Projects::MergeRequestsController do
end
it 'links to the environment on that project' do
- expect(json_response.first['url']).to match /#{forked.path_with_namespace}/
+ expect(json_response.first['url']).to match /#{forked.full_path}/
end
end
end
diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb
index 16cd2e076e5..775f3998f5d 100644
--- a/spec/controllers/projects/tree_controller_spec.rb
+++ b/spec/controllers/projects/tree_controller_spec.rb
@@ -81,7 +81,7 @@ describe Projects::TreeController do
context 'redirect to blob' do
let(:id) { 'master/README.md' }
it 'redirects' do
- redirect_url = "/#{project.path_with_namespace}/blob/master/README.md"
+ redirect_url = "/#{project.full_path}/blob/master/README.md"
expect(subject)
.to redirect_to(redirect_url)
end
@@ -107,7 +107,7 @@ describe Projects::TreeController do
it 'redirects to the new directory' do
expect(subject)
- .to redirect_to("/#{project.path_with_namespace}/tree/#{branch_name}/#{path}")
+ .to redirect_to("/#{project.full_path}/tree/#{branch_name}/#{path}")
expect(flash[:notice]).to eq('The directory has been successfully created.')
end
end
@@ -118,7 +118,7 @@ describe Projects::TreeController do
it 'does not allow overwriting of existing files' do
expect(subject)
- .to redirect_to("/#{project.path_with_namespace}/tree/master")
+ .to redirect_to("/#{project.full_path}/tree/master")
expect(flash[:alert]).to eq('A file with this name already exists')
end
end
diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb
index 113665ff11b..b5e2ec60072 100644
--- a/spec/factories/milestones.rb
+++ b/spec/factories/milestones.rb
@@ -17,7 +17,7 @@ FactoryGirl.define do
state "closed"
end
- after(:build) do |milestone, evaluator|
+ after(:build, :stub) do |milestone, evaluator|
if evaluator.group
milestone.group = evaluator.group
elsif evaluator.group_id
diff --git a/spec/factories/notification_settings.rb b/spec/factories/notification_settings.rb
index b5e96d18b8f..ee41997e41a 100644
--- a/spec/factories/notification_settings.rb
+++ b/spec/factories/notification_settings.rb
@@ -3,6 +3,5 @@ FactoryGirl.define do
source factory: :empty_project
user
level 3
- events []
end
end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 485ed48d2de..a04befe809a 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -64,7 +64,7 @@ FactoryGirl.define do
# We delete hooks so that gitlab-shell will not try to authenticate with
# an API that isn't running
- FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.path_with_namespace}.git", 'hooks'))
+ FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.disk_path}.git", 'hooks'))
end
end
@@ -72,7 +72,7 @@ FactoryGirl.define do
after(:create) do |project|
raise "Failed to create repository!" unless project.create_repository
- FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.path_with_namespace}.git", 'refs'))
+ FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.disk_path}.git", 'refs'))
end
end
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 97ffc54415c..034682dae27 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -32,11 +32,13 @@ describe 'Admin > Users > Impersonation Tokens', js: true do
check "api"
check "read_user"
- expect { click_on "Create impersonation token" }.to change { PersonalAccessTokensFinder.new(impersonation: true).execute.count }
+ click_on "Create impersonation token"
+
expect(active_impersonation_tokens).to have_text(name)
expect(active_impersonation_tokens).to have_text('In')
expect(active_impersonation_tokens).to have_text('api')
expect(active_impersonation_tokens).to have_text('read_user')
+ expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1)
end
end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index 15ec6f20763..0c9fcc60d30 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -282,7 +282,7 @@ describe 'Commits' do
end
# verified and the gpg user has a gitlab profile
- click_on 'Verified'
+ click_on 'Verified', match: :first
within '.popover' do
expect(page).to have_content 'This commit was signed with a verified signature.'
expect(page).to have_content 'Nannie Bernhard'
@@ -295,7 +295,7 @@ describe 'Commits' do
visit project_commits_path(project, :'signed-commits')
- click_on 'Verified'
+ click_on 'Verified', match: :first
within '.popover' do
expect(page).to have_content 'This commit was signed with a verified signature.'
expect(page).to have_content 'Nannie Bernhard'
diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb
index 11a74276898..d7f3d91e625 100644
--- a/spec/features/merge_requests/create_new_mr_spec.rb
+++ b/spec/features/merge_requests/create_new_mr_spec.rb
@@ -67,8 +67,8 @@ feature 'Create New Merge Request', js: true do
visit project_new_merge_request_path(project, merge_request: { target_project_id: private_project.id })
- expect(page).not_to have_content private_project.path_with_namespace
- expect(page).to have_content project.path_with_namespace
+ expect(page).not_to have_content private_project.full_path
+ expect(page).to have_content project.full_path
end
end
@@ -78,8 +78,8 @@ feature 'Create New Merge Request', js: true do
visit project_new_merge_request_path(project, merge_request: { source_project_id: private_project.id })
- expect(page).not_to have_content private_project.path_with_namespace
- expect(page).to have_content project.path_with_namespace
+ expect(page).not_to have_content private_project.full_path
+ expect(page).to have_content project.full_path
end
end
diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb
index dbe98a38197..1dc89665020 100644
--- a/spec/features/projects/wiki/markdown_preview_spec.rb
+++ b/spec/features/projects/wiki/markdown_preview_spec.rb
@@ -38,10 +38,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do
expect(page).to have_content("regular link")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
end
end
@@ -60,10 +60,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do
expect(page).to have_content("regular link")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
end
end
@@ -82,10 +82,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do
expect(page).to have_content("regular link")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
end
end
end
@@ -115,10 +115,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do
expect(page).to have_content("regular link")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
end
end
@@ -132,10 +132,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do
expect(page).to have_content("regular link")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
end
end
@@ -149,10 +149,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do
expect(page).to have_content("regular link")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
+ expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
end
end
end
diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb
index 9c58e336605..f1e7f5f2be8 100644
--- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb
@@ -20,7 +20,7 @@ describe 'Projects > Wiki > User views Git access wiki page' do
visit project_wiki_path(project, wiki_page)
click_link 'Clone repository'
- expect(page).to have_text("Clone repository #{project.wiki.path_with_namespace}")
+ expect(page).to have_text("Clone repository #{project.wiki.full_path}")
expect(page).to have_text(project.wiki.http_url_to_repo)
end
end
diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb
index 717ac1962d1..9aaed0edf87 100644
--- a/spec/helpers/gitlab_routing_helper_spec.rb
+++ b/spec/helpers/gitlab_routing_helper_spec.rb
@@ -1,6 +1,9 @@
require 'spec_helper'
describe GitlabRoutingHelper do
+ let(:project) { build_stubbed(:empty_project) }
+ let(:group) { build_stubbed(:group) }
+
describe 'Project URL helpers' do
describe '#project_member_path' do
let(:project_member) { create(:project_member) }
@@ -9,14 +12,10 @@ describe GitlabRoutingHelper do
end
describe '#request_access_project_members_path' do
- let(:project) { build_stubbed(:empty_project) }
-
it { expect(request_access_project_members_path(project)).to eq request_access_project_project_members_path(project) }
end
describe '#leave_project_members_path' do
- let(:project) { build_stubbed(:empty_project) }
-
it { expect(leave_project_members_path(project)).to eq leave_project_project_members_path(project) }
end
@@ -35,8 +34,6 @@ describe GitlabRoutingHelper do
describe 'Group URL helpers' do
describe '#group_members_url' do
- let(:group) { build_stubbed(:group) }
-
it { expect(group_members_url(group)).to eq group_group_members_url(group) }
end
@@ -47,14 +44,10 @@ describe GitlabRoutingHelper do
end
describe '#request_access_group_members_path' do
- let(:group) { build_stubbed(:group) }
-
it { expect(request_access_group_members_path(group)).to eq request_access_group_group_members_path(group) }
end
describe '#leave_group_members_path' do
- let(:group) { build_stubbed(:group) }
-
it { expect(leave_group_members_path(group)).to eq leave_group_group_members_path(group) }
end
@@ -70,4 +63,44 @@ describe GitlabRoutingHelper do
it { expect(resend_invite_group_member_path(group_member)).to eq resend_invite_group_group_member_path(group_member.source, group_member) }
end
end
+
+ describe '#milestone_path' do
+ context 'for a group milestone' do
+ let(:milestone) { build_stubbed(:milestone, group: group, iid: 1) }
+
+ it 'links to the group milestone page' do
+ expect(milestone_path(milestone))
+ .to eq(group_milestone_path(group, milestone))
+ end
+ end
+
+ context 'for a project milestone' do
+ let(:milestone) { build_stubbed(:milestone, project: project, iid: 1) }
+
+ it 'links to the project milestone page' do
+ expect(milestone_path(milestone))
+ .to eq(project_milestone_path(project, milestone))
+ end
+ end
+ end
+
+ describe '#milestone_url' do
+ context 'for a group milestone' do
+ let(:milestone) { build_stubbed(:milestone, group: group, iid: 1) }
+
+ it 'links to the group milestone page' do
+ expect(milestone_url(milestone))
+ .to eq(group_milestone_url(group, milestone))
+ end
+ end
+
+ context 'for a project milestone' do
+ let(:milestone) { build_stubbed(:milestone, project: project, iid: 1) }
+
+ it 'links to the project milestone page' do
+ expect(milestone_url(milestone))
+ .to eq(project_milestone_url(project, milestone))
+ end
+ end
+ end
end
diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb
index a8d6044fda7..8fc94ce09db 100644
--- a/spec/helpers/labels_helper_spec.rb
+++ b/spec/helpers/labels_helper_spec.rb
@@ -7,7 +7,7 @@ describe LabelsHelper do
context 'without subject' do
it "uses the label's project" do
- expect(link_to_label(label)).to match %r{<a href="/#{label.project.path_with_namespace}/issues\?label_name%5B%5D=#{label.name}">.*</a>}
+ expect(link_to_label(label)).to match %r{<a href="/#{label.project.full_path}/issues\?label_name%5B%5D=#{label.name}">.*</a>}
end
end
@@ -32,7 +32,7 @@ describe LabelsHelper do
['issue', :issue, 'merge_request', :merge_request].each do |type|
context "set to #{type}" do
it 'links to correct page' do
- expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.path_with_namespace}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>}
+ expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.full_path}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>}
end
end
end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 4b6a351cf70..70eb01c9c44 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -210,11 +210,11 @@ describe MarkupHelper do
describe '#cross_project_reference' do
it 'shows the full MR reference' do
- expect(helper.cross_project_reference(project, merge_request)).to include(project.path_with_namespace)
+ expect(helper.cross_project_reference(project, merge_request)).to include(project.full_path)
end
it 'shows the full issue reference' do
- expect(helper.cross_project_reference(project, issue)).to include(project.path_with_namespace)
+ expect(helper.cross_project_reference(project, issue)).to include(project.full_path)
end
end
end
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index 493a4ff9a93..b2a9e277a1c 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -34,8 +34,8 @@ describe MergeRequestsHelper do
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}" }
- let(:target_title) { "#{project.path_with_namespace}:#{merge_request.target_branch}" }
+ let(:source_title) { "#{fork_project.full_path}:#{merge_request.source_branch}" }
+ let(:target_title) { "#{project.full_path}:#{merge_request.target_branch}" }
it { is_expected.to eq([source_title, target_title]) }
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 45066a60f50..faf26931efc 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -53,13 +53,13 @@ describe ProjectsHelper do
end
it "returns a valid cach key" do
- expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-#{project.commit.id}-readme")
+ expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-#{project.commit.id}-readme")
end
it "returns a valid cache key if HEAD does not exist" do
allow(project).to receive(:commit) { nil }
- expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-nil-readme")
+ expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-nil-readme")
end
end
diff --git a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
index 27532f96f56..32d027b026b 100644
--- a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
@@ -5,7 +5,7 @@ describe Banzai::Filter::AbstractReferenceFilter do
describe '#references_per_project' do
it 'returns a Hash containing references grouped per project paths' do
- doc = Nokogiri::HTML.fragment("#1 #{project.path_with_namespace}#2")
+ doc = Nokogiri::HTML.fragment("#1 #{project.full_path}#2")
filter = described_class.new(doc, project: project)
expect(filter).to receive(:object_class).exactly(4).times.and_return(Issue)
@@ -14,7 +14,7 @@ describe Banzai::Filter::AbstractReferenceFilter do
refs = filter.references_per_project
expect(refs).to be_an_instance_of(Hash)
- expect(refs[project.path_with_namespace]).to eq(Set.new(%w[1 2]))
+ expect(refs[project.full_path]).to eq(Set.new(%w[1 2]))
end
end
@@ -24,10 +24,10 @@ describe Banzai::Filter::AbstractReferenceFilter do
filter = described_class.new(doc, project: project)
expect(filter).to receive(:references_per_project)
- .and_return({ project.path_with_namespace => Set.new(%w[1]) })
+ .and_return({ project.full_path => Set.new(%w[1]) })
expect(filter.projects_per_reference)
- .to eq({ project.path_with_namespace => project })
+ .to eq({ project.full_path => project })
end
end
@@ -37,7 +37,7 @@ describe Banzai::Filter::AbstractReferenceFilter do
context 'with RequestStore disabled' do
it 'returns a list of Projects for a list of paths' do
- expect(filter.find_projects_for_paths([project.path_with_namespace]))
+ expect(filter.find_projects_for_paths([project.full_path]))
.to eq([project])
end
@@ -49,7 +49,7 @@ describe Banzai::Filter::AbstractReferenceFilter do
context 'with RequestStore enabled', :request_store do
it 'returns a list of Projects for a list of paths' do
- expect(filter.find_projects_for_paths([project.path_with_namespace]))
+ expect(filter.find_projects_for_paths([project.full_path]))
.to eq([project])
end
@@ -88,7 +88,7 @@ describe Banzai::Filter::AbstractReferenceFilter do
doc = Nokogiri::HTML.fragment('')
filter = described_class.new(doc, project: project)
- expect(filter.current_project_path).to eq(project.path_with_namespace)
+ expect(filter.current_project_path).to eq(project.full_path)
end
end
end
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 11d48387544..935146c17fc 100644
--- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -100,7 +100,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter do
context 'cross-project / cross-namespace complete reference' do
let(:project2) { create(:project, :public, :repository) }
- let(:reference) { "#{project2.path_with_namespace}@#{commit1.id}...#{commit2.id}" }
+ let(:reference) { "#{project2.full_path}@#{commit1.id}...#{commit2.id}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
@@ -113,20 +113,20 @@ describe Banzai::Filter::CommitRangeReferenceFilter do
doc = reference_filter("Fixed (#{reference}.)")
expect(doc.css('a').first.text)
- .to eql("#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}")
+ .to eql("#{project2.full_path}@#{commit1.short_id}...#{commit2.short_id}")
end
it 'has valid text' do
doc = reference_filter("Fixed (#{reference}.)")
- expect(doc.text).to eql("Fixed (#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}.)")
+ expect(doc.text).to eql("Fixed (#{project2.full_path}@#{commit1.short_id}...#{commit2.short_id}.)")
end
it 'ignores invalid commit IDs on the referenced project' do
- exp = act = "Fixed #{project2.path_with_namespace}@#{commit1.id.reverse}...#{commit2.id}"
+ exp = act = "Fixed #{project2.full_path}@#{commit1.id.reverse}...#{commit2.id}"
expect(reference_filter(act).to_html).to eq exp
- exp = act = "Fixed #{project2.path_with_namespace}@#{commit1.id}...#{commit2.id.reverse}"
+ exp = act = "Fixed #{project2.full_path}@#{commit1.id}...#{commit2.id.reverse}"
expect(reference_filter(act).to_html).to eq exp
end
end
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index fb2a36d1ba1..c7cf1c1d582 100644
--- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -98,18 +98,18 @@ describe Banzai::Filter::CommitReferenceFilter do
let(:namespace) { create(:namespace) }
let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
- let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
+ let(:reference) { "#{project2.full_path}@#{commit.short_id}" }
it 'link has valid text' do
doc = reference_filter("See (#{reference}.)")
- expect(doc.css('a').first.text).to eql("#{project2.path_with_namespace}@#{commit.short_id}")
+ expect(doc.css('a').first.text).to eql("#{project2.full_path}@#{commit.short_id}")
end
it 'has valid text' do
doc = reference_filter("See (#{reference}.)")
- expect(doc.text).to eql("See (#{project2.path_with_namespace}@#{commit.short_id}.)")
+ expect(doc.text).to eql("See (#{project2.full_path}@#{commit.short_id}.)")
end
it 'ignores invalid commit IDs on the referenced project' do
@@ -124,7 +124,7 @@ describe Banzai::Filter::CommitReferenceFilter do
let(:project) { create(:empty_project, namespace: namespace) }
let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
- let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
+ let(:reference) { "#{project2.full_path}@#{commit.short_id}" }
it 'link has valid text' do
doc = reference_filter("See (#{reference}.)")
@@ -150,7 +150,7 @@ describe Banzai::Filter::CommitReferenceFilter do
let(:project) { create(:empty_project, namespace: namespace) }
let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
- let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
+ let(:reference) { "#{project2.full_path}@#{commit.short_id}" }
it 'link has valid text' do
doc = reference_filter("See (#{reference}.)")
diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
index 045bf3e0cc9..024a5cafb41 100644
--- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -127,7 +127,7 @@ describe Banzai::Filter::IssueReferenceFilter do
let(:project2) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project2) }
- let(:reference) { "#{project2.path_with_namespace}##{issue.iid}" }
+ let(:reference) { "#{project2.full_path}##{issue.iid}" }
it 'ignores valid references when cross-reference project uses external tracker' do
expect_any_instance_of(described_class).to receive(:find_object)
@@ -148,13 +148,13 @@ describe Banzai::Filter::IssueReferenceFilter do
it 'link has valid text' do
doc = reference_filter("Fixed (#{reference}.)")
- expect(doc.css('a').first.text).to eql("#{project2.path_with_namespace}##{issue.iid}")
+ expect(doc.css('a').first.text).to eql("#{project2.full_path}##{issue.iid}")
end
it 'has valid text' do
doc = reference_filter("Fixed (#{reference}.)")
- expect(doc.text).to eq("Fixed (#{project2.path_with_namespace}##{issue.iid}.)")
+ expect(doc.text).to eq("Fixed (#{project2.full_path}##{issue.iid}.)")
end
it 'ignores invalid issue IDs on the referenced project' do
@@ -171,7 +171,7 @@ describe Banzai::Filter::IssueReferenceFilter do
let(:project) { create(:empty_project, :public, namespace: namespace) }
let(:project2) { create(:empty_project, :public, namespace: namespace) }
let(:issue) { create(:issue, project: project2) }
- let(:reference) { "#{project2.path_with_namespace}##{issue.iid}" }
+ let(:reference) { "#{project2.full_path}##{issue.iid}" }
it 'ignores valid references when cross-reference project uses external tracker' do
expect_any_instance_of(described_class).to receive(:find_object)
@@ -324,10 +324,10 @@ describe Banzai::Filter::IssueReferenceFilter do
filter = described_class.new(doc, project: project)
expect(filter).to receive(:projects_per_reference)
- .and_return({ project.path_with_namespace => project })
+ .and_return({ project.full_path => project })
expect(filter).to receive(:references_per_project)
- .and_return({ project.path_with_namespace => Set.new([issue.iid]) })
+ .and_return({ project.full_path => Set.new([issue.iid]) })
expect(filter.issues_per_project)
.to eq({ project => { issue.iid => issue } })
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index 1daa6ac7f9e..dfd4c7a7279 100644
--- a/spec/lib/banzai/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -368,7 +368,7 @@ describe Banzai::Filter::LabelReferenceFilter do
describe 'cross-project / cross-namespace complete reference' do
let(:project2) { create(:empty_project) }
let(:label) { create(:label, project: project2, color: '#00ff00') }
- let(:reference) { "#{project2.path_with_namespace}~#{label.name}" }
+ let(:reference) { "#{project2.full_path}~#{label.name}" }
let!(:result) { reference_filter("See #{reference}") }
it 'links to a valid reference' do
@@ -400,7 +400,7 @@ describe Banzai::Filter::LabelReferenceFilter do
let(:project) { create(:empty_project, namespace: namespace) }
let(:project2) { create(:empty_project, namespace: namespace) }
let(:label) { create(:label, project: project2, color: '#00ff00') }
- let(:reference) { "#{project2.path_with_namespace}~#{label.name}" }
+ let(:reference) { "#{project2.full_path}~#{label.name}" }
let!(:result) { reference_filter("See #{reference}") }
it 'links to a valid reference' do
@@ -466,7 +466,7 @@ describe Banzai::Filter::LabelReferenceFilter do
let(:another_group) { create(:group) }
let(:another_project) { create(:empty_project, :public, namespace: another_group) }
let(:group_label) { create(:group_label, group: another_group, color: '#00ff00') }
- let(:reference) { "#{another_project.path_with_namespace}~#{group_label.name}" }
+ let(:reference) { "#{another_project.full_path}~#{group_label.name}" }
let!(:result) { reference_filter("See #{reference}", project: project) }
it 'points to referenced project issues page' do
@@ -501,7 +501,7 @@ describe Banzai::Filter::LabelReferenceFilter do
let(:project) { create(:empty_project, :public, namespace: group) }
let(:another_project) { create(:empty_project, :public, namespace: group) }
let(:group_label) { create(:group_label, group: group, color: '#00ff00') }
- let(:reference) { "#{another_project.path_with_namespace}~#{group_label.name}" }
+ let(:reference) { "#{another_project.full_path}~#{group_label.name}" }
let!(:result) { reference_filter("See #{reference}", project: project) }
it 'points to referenced project issues page' do
@@ -535,7 +535,7 @@ describe Banzai::Filter::LabelReferenceFilter do
let(:group) { create(:group) }
let(:project) { create(:empty_project, :public, namespace: group) }
let(:group_label) { create(:group_label, group: group, color: '#00ff00') }
- let(:reference) { "#{project.path_with_namespace}~#{group_label.name}" }
+ let(:reference) { "#{project.full_path}~#{group_label.name}" }
let!(:result) { reference_filter("See #{reference}", project: project) }
it 'points to referenced project issues page' do
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 683972a3112..b693ae3eca2 100644
--- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -102,7 +102,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter do
context 'cross-project / cross-namespace complete reference' do
let(:project2) { create(:empty_project, :public) }
let(:merge) { create(:merge_request, source_project: project2) }
- let(:reference) { "#{project2.path_with_namespace}!#{merge.iid}" }
+ let(:reference) { "#{project2.full_path}!#{merge.iid}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
@@ -135,7 +135,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter do
let(:project) { create(:empty_project, :public, namespace: namespace) }
let(:project2) { create(:empty_project, :public, namespace: namespace) }
let!(:merge) { create(:merge_request, source_project: project2) }
- let(:reference) { "#{project2.path_with_namespace}!#{merge.iid}" }
+ let(:reference) { "#{project2.full_path}!#{merge.iid}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 8fe05dc2e53..79ff9419e4b 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -152,7 +152,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
let(:namespace) { create(:namespace) }
let(:another_project) { create(:empty_project, :public, namespace: namespace) }
let(:milestone) { create(:milestone, project: another_project) }
- let(:reference) { "#{another_project.path_with_namespace}%#{milestone.iid}" }
+ let(:reference) { "#{another_project.full_path}%#{milestone.iid}" }
let!(:result) { reference_filter("See #{reference}") }
it 'points to referenced project milestone page' do
@@ -164,14 +164,14 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See (#{reference}.)")
expect(doc.css('a').first.text)
- .to eq("#{milestone.name} in #{another_project.path_with_namespace}")
+ .to eq("#{milestone.name} in #{another_project.full_path}")
end
it 'has valid text' do
doc = reference_filter("See (#{reference}.)")
expect(doc.text)
- .to eq("See (#{milestone.name} in #{another_project.path_with_namespace}.)")
+ .to eq("See (#{milestone.name} in #{another_project.full_path}.)")
end
it 'escapes the name attribute' do
@@ -180,7 +180,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.text)
- .to eq "#{milestone.name} in #{another_project.path_with_namespace}"
+ .to eq "#{milestone.name} in #{another_project.full_path}"
end
end
@@ -189,7 +189,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
let(:project) { create(:empty_project, :public, namespace: namespace) }
let(:another_project) { create(:empty_project, :public, namespace: namespace) }
let(:milestone) { create(:milestone, project: another_project) }
- let(:reference) { "#{another_project.path_with_namespace}%#{milestone.iid}" }
+ let(:reference) { "#{another_project.full_path}%#{milestone.iid}" }
let!(:result) { reference_filter("See #{reference}") }
it 'points to referenced project milestone page' do
@@ -257,4 +257,28 @@ describe Banzai::Filter::MilestoneReferenceFilter do
.to eq "#{milestone.name} in #{another_project.path}"
end
end
+
+ describe 'cross project milestone references' do
+ let(:another_project) { create(:empty_project, :public) }
+ let(:project_path) { another_project.full_path }
+ let(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { milestone.to_reference(project) }
+
+ let!(:result) { reference_filter("See #{reference}") }
+
+ it 'points to referenced project milestone page' do
+ expect(result.css('a').first.attr('href')).to eq urls
+ .project_milestone_url(another_project, milestone)
+ end
+
+ it 'contains cross project content' do
+ expect(result.css('a').first.text).to eq "#{milestone.name} in #{project_path}"
+ end
+
+ it 'escapes the name attribute' do
+ allow_any_instance_of(Milestone).to receive(:title).and_return(%{"></a>whatever<a title="})
+ doc = reference_filter("See #{reference}")
+ expect(doc.css('a').first.text).to eq "#{milestone.name} in #{project_path}"
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index ddebf2264d9..e97199672f3 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -26,7 +26,7 @@ describe Banzai::Filter::RelativeLinkFilter do
end
let(:project) { create(:project, :repository) }
- let(:project_path) { project.path_with_namespace }
+ let(:project_path) { project.full_path }
let(:ref) { 'markdown' }
let(:commit) { project.commit(ref) }
let(:project_wiki) { nil }
diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
index 5f548888223..a7eee7a4515 100644
--- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
@@ -83,7 +83,7 @@ describe Banzai::Filter::SnippetReferenceFilter do
let(:namespace) { create(:namespace) }
let(:project2) { create(:empty_project, :public, namespace: namespace) }
let!(:snippet) { create(:project_snippet, project: project2) }
- let(:reference) { "#{project2.path_with_namespace}$#{snippet.id}" }
+ let(:reference) { "#{project2.full_path}$#{snippet.id}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
@@ -116,7 +116,7 @@ describe Banzai::Filter::SnippetReferenceFilter do
let(:project) { create(:empty_project, :public, namespace: namespace) }
let(:project2) { create(:empty_project, :public, namespace: namespace) }
let!(:snippet) { create(:project_snippet, project: project2) }
- let(:reference) { "#{project2.path_with_namespace}$#{snippet.id}" }
+ let(:reference) { "#{project2.full_path}$#{snippet.id}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
index 3bc9635b50e..74a23a9ab5e 100644
--- a/spec/lib/banzai/filter/upload_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb
@@ -52,21 +52,21 @@ describe Banzai::Filter::UploadLinkFilter do
it 'rebuilds relative URL for a link' do
doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
expect(doc.at_css('a')['href'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
doc = filter(nested_link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
expect(doc.at_css('a')['href'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
end
it 'rebuilds relative URL for an image' do
doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
expect(doc.at_css('img')['src'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
doc = filter(nested_image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
expect(doc.at_css('img')['src'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
end
it 'does not modify absolute URL' do
@@ -85,7 +85,7 @@ describe Banzai::Filter::UploadLinkFilter do
.to receive(:image?).with(path).and_return(true)
doc = filter(image(escaped))
- expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png"
+ expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png"
end
end
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 9b89f47ae7e..867f7d55af7 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -14,7 +14,7 @@ describe ExtractsPath do
repo = double(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0',
'release/app', 'release/app/v1.0.0'])
allow(project).to receive(:repository).and_return(repo)
- allow(project).to receive(:path_with_namespace)
+ allow(project).to receive(:full_path)
.and_return('gitlab/gitlab-ci')
allow(request).to receive(:format=)
end
@@ -29,7 +29,7 @@ describe ExtractsPath do
it "log tree path has no escape sequences" do
assign_ref_vars
- expect(@logs_path).to eq("/#{@project.path_with_namespace}/refs/#{ref}/logs_tree/files/ruby/popen.rb")
+ expect(@logs_path).to eq("/#{@project.full_path}/refs/#{ref}/logs_tree/files/ruby/popen.rb")
end
context 'ref contains %20' do
diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb
index db860b01ba4..3af69daa585 100644
--- a/spec/lib/gitlab/backup/repository_spec.rb
+++ b/spec/lib/gitlab/backup/repository_spec.rb
@@ -60,4 +60,58 @@ describe Backup::Repository do
end
end
end
+
+ describe '#empty_repo?' do
+ context 'for a wiki' do
+ let(:wiki) { create(:project_wiki) }
+
+ context 'wiki repo has content' do
+ let!(:wiki_page) { create(:wiki_page, wiki: wiki) }
+
+ before do
+ wiki.repository.exists? # initial cache
+ end
+
+ context '`repository.exists?` is incorrectly cached as false' do
+ before do
+ repo = wiki.repository
+ repo.send(:cache).expire(:exists?)
+ repo.send(:cache).fetch(:exists?) { false }
+ repo.send(:instance_variable_set, :@exists, false)
+ end
+
+ it 'returns false, regardless of bad cache value' do
+ expect(described_class.new.send(:empty_repo?, wiki)).to be_falsey
+ end
+ end
+
+ context '`repository.exists?` is correctly cached as true' do
+ it 'returns false' do
+ expect(described_class.new.send(:empty_repo?, wiki)).to be_falsey
+ end
+ end
+ end
+
+ context 'wiki repo does not have content' do
+ context '`repository.exists?` is incorrectly cached as true' do
+ before do
+ repo = wiki.repository
+ repo.send(:cache).expire(:exists?)
+ repo.send(:cache).fetch(:exists?) { true }
+ repo.send(:instance_variable_set, :@exists, true)
+ end
+
+ it 'returns true, regardless of bad cache value' do
+ expect(described_class.new.send(:empty_repo?, wiki)).to be_truthy
+ end
+ end
+
+ context '`repository.exists?` is correctly cached as false' do
+ it 'returns true' do
+ expect(described_class.new.send(:empty_repo?, wiki)).to be_truthy
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index cd2fa98b14c..d3d841b0668 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -47,14 +47,6 @@ describe Gitlab::Diff::File do
end
end
- describe '#old_content_commit' do
- it 'returns base commit' do
- old_content_commit = diff_file.old_content_commit
-
- expect(old_content_commit.id).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9')
- end
- end
-
describe '#old_blob' do
it 'returns blob of commit of base commit' do
old_data = diff_file.old_blob.data
diff --git a/spec/lib/gitlab/email/message/repository_push_spec.rb b/spec/lib/gitlab/email/message/repository_push_spec.rb
index 7b3291b8315..83c4d177cae 100644
--- a/spec/lib/gitlab/email/message/repository_push_spec.rb
+++ b/spec/lib/gitlab/email/message/repository_push_spec.rb
@@ -117,7 +117,7 @@ describe Gitlab::Email::Message::RepositoryPush do
describe '#subject' do
subject { message.subject }
- it { is_expected.to include "[Git][#{project.path_with_namespace}]" }
+ it { is_expected.to include "[Git][#{project.full_path}]" }
it { is_expected.to include "#{compare.commits.length} commits" }
it { is_expected.to include compare.commits.first.message.split("\n").first }
end
diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
index c3016f63ebf..fef456eb416 100644
--- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
@@ -39,8 +39,8 @@ describe Gitlab::Gfm::UploadsRewriter do
it 'copies files' do
expect(new_files).to all(exist)
expect(old_paths).not_to match_array new_paths
- expect(old_paths).to all(include(old_project.path_with_namespace))
- expect(new_paths).to all(include(new_project.path_with_namespace))
+ expect(old_paths).to all(include(old_project.full_path))
+ expect(new_paths).to all(include(new_project.full_path))
end
it 'does not remove old files' do
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 3c784eda4f8..18320bb23b9 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -78,12 +78,18 @@ describe Gitlab::Git::Blob, seed_helper: true do
context 'large file' do
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, 'files/images/6049019_460s.jpg') }
let(:blob_size) { 111803 }
+ let(:stub_limit) { 1000 }
+
+ before do
+ stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', stub_limit)
+ end
it { expect(blob.size).to eq(blob_size) }
- it { expect(blob.data.length).to eq(blob_size) }
+ it { expect(blob.data.length).to eq(stub_limit) }
it 'check that this test is sane' do
- expect(blob.size).to be <= Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE
+ # It only makes sense to test limiting if the blob is larger than the limit.
+ expect(blob.size).to be > Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE
end
it 'can load all data' do
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 50736d353ad..8e4a1f31ced 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1127,6 +1127,45 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe '#languages' do
+ shared_examples 'languages' do
+ it 'returns exactly the expected results' do
+ languages = repository.languages('4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6')
+ expected_languages = [
+ { value: 66.63, label: "Ruby", color: "#701516", highlight: "#701516" },
+ { value: 22.96, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
+ { value: 7.9, label: "HTML", color: "#e44b23", highlight: "#e44b23" },
+ { value: 2.51, label: "CoffeeScript", color: "#244776", highlight: "#244776" }
+ ]
+
+ expect(languages.size).to eq(expected_languages.size)
+
+ expected_languages.size.times do |i|
+ a = expected_languages[i]
+ b = languages[i]
+
+ expect(a.keys.sort).to eq(b.keys.sort)
+ expect(a[:value]).to be_within(0.1).of(b[:value])
+
+ non_float_keys = a.keys - [:value]
+ expect(a.values_at(*non_float_keys)).to eq(b.values_at(*non_float_keys))
+ end
+ end
+
+ it "uses the repository's HEAD when no ref is passed" do
+ lang = repository.languages.first
+
+ expect(lang[:label]).to eq('Ruby')
+ end
+ end
+
+ it_behaves_like 'languages'
+
+ context 'with rugged', skip_gitaly_mock: true do
+ it_behaves_like 'languages'
+ end
+ end
+
def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
source_branch = repository.branches.find { |branch| branch.name == source_branch_name }
rugged = repository.rugged
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index 0868c793a33..d71e0f84c65 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::GitalyClient::CommitService do
let(:project) { create(:project, :repository) }
let(:storage_name) { project.repository_storage }
- let(:relative_path) { project.path_with_namespace + '.git' }
+ let(:relative_path) { project.disk_path + '.git' }
let(:repository) { project.repository }
let(:repository_message) { repository.gitaly_repository }
let(:revision) { '913c66a37b4a45b9769037c55c2d238bd0942d2e' }
diff --git a/spec/lib/gitlab/gitaly_client/notification_service_spec.rb b/spec/lib/gitlab/gitaly_client/notification_service_spec.rb
index d9597c4aa78..1bcdd5e5497 100644
--- a/spec/lib/gitlab/gitaly_client/notification_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/notification_service_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::GitalyClient::NotificationService do
describe '#post_receive' do
let(:project) { create(:empty_project) }
let(:storage_name) { project.repository_storage }
- let(:relative_path) { project.path_with_namespace + '.git' }
+ let(:relative_path) { project.disk_path + '.git' }
subject { described_class.new(project.repository) }
it 'sends a post_receive message' do
diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
index 0b1c890f956..2ad24119476 100644
--- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::GitalyClient::RefService do
let(:project) { create(:empty_project) }
let(:storage_name) { project.repository_storage }
- let(:relative_path) { project.path_with_namespace + '.git' }
+ let(:relative_path) { project.disk_path + '.git' }
let(:client) { described_class.new(project.repository) }
describe '#branches' do
diff --git a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb
index de50265bc14..fcd90fab547 100644
--- a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb
@@ -9,9 +9,9 @@ describe Gitlab::GithubImport::WikiFormatter do
subject(:wiki) { described_class.new(project) }
- describe '#path_with_namespace' do
+ describe '#disk_path' do
it 'appends .wiki to project path' do
- expect(wiki.path_with_namespace).to eq 'gitlabhq/gitlabhq.wiki'
+ expect(wiki.disk_path).to eq project.disk_path + '.wiki'
end
end
diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb
index 08588a76fe6..0ff64cbe880 100644
--- a/spec/lib/gitlab/import_export/fork_spec.rb
+++ b/spec/lib/gitlab/import_export/fork_spec.rb
@@ -5,7 +5,7 @@ describe 'forked project import' do
let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') }
let!(:project) { create(:empty_project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
+ let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
let(:forked_from_project) { create(:project) }
let(:fork_link) { create(:forked_project_link, forked_from_project: project_with_repo) }
let(:repo_saver) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) }
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 0c7e733b01f..a278f89c1a1 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::ProjectTreeSaver do
describe 'saves the project tree into a json object' do
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
+ let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
index d3be2965bf4..82935af2670 100644
--- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::ImportExport::RepoRestorer do
let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') }
let!(:project) { create(:empty_project) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
+ let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
let(:bundler) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) }
let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) }
let(:restorer) do
diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb
index 87af13e0beb..0ba199bbb05 100644
--- a/spec/lib/gitlab/import_export/repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::ImportExport::RepoSaver do
let(:user) { create(:user) }
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(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
let(:bundler) { described_class.new(project: project, shared: shared) }
before do
diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
index 78137aeff5e..caf08e674d3 100644
--- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::ImportExport::WikiRepoSaver do
let(:user) { create(:user) }
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(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
let(:wiki_bundler) { described_class.new(project: project, shared: shared) }
let!(:project_wiki) { ProjectWiki.new(project, user) }
diff --git a/spec/lib/gitlab/quick_actions/dsl_spec.rb b/spec/lib/gitlab/quick_actions/dsl_spec.rb
index a4bb3f911d7..ff59dc48bcb 100644
--- a/spec/lib/gitlab/quick_actions/dsl_spec.rb
+++ b/spec/lib/gitlab/quick_actions/dsl_spec.rb
@@ -42,13 +42,18 @@ describe Gitlab::QuickActions::Dsl do
command :with_params_parsing do |parsed|
parsed
end
+
+ params '<Comment>'
+ substitution :something do |text|
+ "#{text} Some complicated thing you want in here"
+ end
end
end
describe '.command_definitions' do
it 'returns an array with commands definitions' do
no_args_def, explanation_with_aliases_def, dynamic_description_def,
- cc_def, cond_action_def, with_params_parsing_def =
+ cc_def, cond_action_def, with_params_parsing_def, substitution_def =
DummyClass.command_definitions
expect(no_args_def.name).to eq(:no_args)
@@ -104,6 +109,15 @@ describe Gitlab::QuickActions::Dsl do
expect(with_params_parsing_def.condition_block).to be_nil
expect(with_params_parsing_def.action_block).to be_a_kind_of(Proc)
expect(with_params_parsing_def.parse_params_block).to be_a_kind_of(Proc)
+
+ expect(substitution_def.name).to eq(:something)
+ expect(substitution_def.aliases).to eq([])
+ expect(substitution_def.description).to eq('')
+ expect(substitution_def.explanation).to eq('')
+ expect(substitution_def.params).to eq(['<Comment>'])
+ expect(substitution_def.condition_block).to be_nil
+ expect(substitution_def.action_block.call('text')).to eq('text Some complicated thing you want in here')
+ expect(substitution_def.parse_params_block).to be_nil
end
end
end
diff --git a/spec/lib/gitlab/quick_actions/extractor_spec.rb b/spec/lib/gitlab/quick_actions/extractor_spec.rb
index 9d32938e155..f7c288f2393 100644
--- a/spec/lib/gitlab/quick_actions/extractor_spec.rb
+++ b/spec/lib/gitlab/quick_actions/extractor_spec.rb
@@ -9,6 +9,11 @@ describe Gitlab::QuickActions::Extractor do
command(:assign) { }
command(:labels) { }
command(:power) { }
+ command(:noop_command)
+ substitution(:substitution) { 'foo' }
+ substitution :shrug do |comment|
+ "#{comment} SHRUG"
+ end
end.command_definitions
end
@@ -177,6 +182,38 @@ describe Gitlab::QuickActions::Extractor do
expect(msg).to eq "hello\nworld"
end
+ it 'does not extract noop commands' do
+ msg = %(hello\nworld\n/reopen\n/noop_command)
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['reopen']]
+ expect(msg).to eq "hello\nworld\n/noop_command"
+ end
+
+ it 'extracts and performs substitution commands' do
+ msg = %(hello\nworld\n/reopen\n/substitution)
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['reopen'], ['substitution']]
+ expect(msg).to eq "hello\nworld\nfoo"
+ end
+
+ it 'extracts and performs substitution commands' do
+ msg = %(hello\nworld\n/reopen\n/shrug this is great?)
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['reopen'], ['shrug', 'this is great?']]
+ expect(msg).to eq "hello\nworld\nthis is great? SHRUG"
+ end
+
+ it 'extracts and performs substitution commands with comments' do
+ msg = %(hello\nworld\n/reopen\n/substitution wow this is a thing.)
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['reopen'], ['substitution', 'wow this is a thing.']]
+ expect(msg).to eq "hello\nworld\nfoo"
+ end
+
it 'extracts multiple commands' do
msg = %(hello\n/power @user.name %9.10 ~"bar baz.2" label\nworld\n/reopen)
msg, commands = extractor.extract_commands(msg)
diff --git a/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb b/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb
new file mode 100644
index 00000000000..1bb8bc51c96
--- /dev/null
+++ b/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+describe Gitlab::QuickActions::SubstitutionDefinition do
+ let(:content) do
+ <<EOF
+Hello! Let's do this!
+/sub_name I like this stuff
+EOF
+ end
+ subject do
+ described_class.new(:sub_name, action_block: proc { |text| "#{text} foo" })
+ end
+
+ describe '#perform_substitution!' do
+ it 'returns nil if content is nil' do
+ expect(subject.perform_substitution(self, nil)).to be_nil
+ end
+
+ it 'performs the substitution by default' do
+ expect(subject.perform_substitution(self, content)).to eq <<EOF
+Hello! Let's do this!
+I like this stuff foo
+EOF
+ end
+ end
+
+ describe '#match' do
+ it 'checks the content for the command' do
+ expect(subject.match(content)).to be_truthy
+ end
+
+ it 'returns the match data' do
+ data = subject.match(content)
+ expect(data).to be_a(MatchData)
+ expect(data[1]).to eq('I like this stuff')
+ end
+
+ it 'is nil if content does not have the command' do
+ expect(subject.match('blah')).to be_falsey
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb
index f0ecf59406a..88f73bf90cd 100644
--- a/spec/lib/gitlab/slash_commands/command_spec.rb
+++ b/spec/lib/gitlab/slash_commands/command_spec.rb
@@ -80,7 +80,7 @@ describe Gitlab::SlashCommands::Command do
it 'returns error' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to include('Too many actions defined')
+ expect(subject[:text]).to include("Couldn't find a deployment manual action.")
end
end
end
diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb
index e52aaed7328..c3fb7d5adea 100644
--- a/spec/lib/gitlab/slash_commands/deploy_spec.rb
+++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb
@@ -22,7 +22,7 @@ describe Gitlab::SlashCommands::Deploy do
context 'if no environment is defined' do
it 'does not execute an action' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq("No action found to be executed")
+ expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
@@ -35,12 +35,12 @@ describe Gitlab::SlashCommands::Deploy do
context 'without actions' do
it 'does not execute an action' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq("No action found to be executed")
+ expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
- context 'with action' do
- let!(:manual1) do
+ context 'when single action has been matched' do
+ before do
create(:ci_build, :manual, pipeline: pipeline,
name: 'first',
environment: 'production')
@@ -48,31 +48,61 @@ describe Gitlab::SlashCommands::Deploy do
it 'returns success result' do
expect(subject[:response_type]).to be(:in_channel)
- expect(subject[:text]).to start_with('Deployment started from staging to production')
+ expect(subject[:text])
+ .to start_with('Deployment started from staging to production')
end
+ end
+
+ context 'when more than one action has been matched' do
+ context 'when there is no specific actions with a environment name' do
+ before do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'first',
+ environment: 'production')
- context 'when duplicate action exists' do
- let!(:manual2) do
create(:ci_build, :manual, pipeline: pipeline,
name: 'second',
environment: 'production')
end
- it 'returns error' do
+ it 'returns error about too many actions defined' do
+ expect(subject[:text]).to eq("Couldn't find a deployment manual action.")
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq('Too many actions defined')
end
end
- context 'when teardown action exists' do
- let!(:teardown) do
+ context 'when one of the actions is environement specific action' do
+ before do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'first',
+ environment: 'production')
+
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'production',
+ environment: 'production')
+ end
+
+ it 'deploys to production' do
+ expect(subject[:text])
+ .to start_with('Deployment started from staging to production')
+ expect(subject[:response_type]).to be(:in_channel)
+ end
+ end
+
+ context 'when one of the actions is a teardown action' do
+ before do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'first',
+ environment: 'production')
+
create(:ci_build, :manual, :teardown_environment,
pipeline: pipeline, name: 'teardown', environment: 'production')
end
- it 'returns the success message' do
+ it 'deploys to production' do
+ expect(subject[:text])
+ .to start_with('Deployment started from staging to production')
expect(subject[:response_type]).to be(:in_channel)
- expect(subject[:text]).to start_with('Deployment started from staging to production')
end
end
end
diff --git a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
index dee3c77db27..d16d122c64e 100644
--- a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
+++ b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
@@ -17,8 +17,8 @@ describe Gitlab::SlashCommands::Presenters::Deploy do
end
end
- describe '#no_actions' do
- subject { described_class.new(nil).no_actions }
+ describe '#action_not_found' do
+ subject { described_class.new(nil).action_not_found }
it { is_expected.to have_key(:text) }
it { is_expected.to have_key(:response_type) }
@@ -27,21 +27,7 @@ describe Gitlab::SlashCommands::Presenters::Deploy do
it 'tells the user there is no action' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq("No action found to be executed")
- end
- end
-
- describe '#too_many_actions' do
- subject { described_class.new([]).too_many_actions }
-
- it { is_expected.to have_key(:text) }
- it { is_expected.to have_key(:response_type) }
- it { is_expected.to have_key(:status) }
- it { is_expected.not_to have_key(:attachments) }
-
- it 'tells the user there is no action' do
- expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq("Too many actions defined")
+ expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
end
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index 50422020823..7412f22640c 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(commit)
- expect(url).to eq "#{Settings.gitlab['url']}/#{commit.project.path_with_namespace}/commit/#{commit.id}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{commit.project.full_path}/commit/#{commit.id}"
end
end
@@ -18,7 +18,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(issue)
- expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.full_path}/issues/#{issue.iid}"
end
end
@@ -28,7 +28,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(merge_request)
- expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.full_path}/merge_requests/#{merge_request.iid}"
end
end
@@ -39,7 +39,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(note)
- expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.full_path}/commit/#{note.commit_id}#note_#{note.id}"
end
end
@@ -49,7 +49,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(note)
- expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.full_path}/commit/#{note.commit_id}#note_#{note.id}"
end
end
@@ -60,7 +60,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(note)
- expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}#note_#{note.id}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.full_path}/issues/#{issue.iid}#note_#{note.id}"
end
end
@@ -71,7 +71,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(note)
- expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.full_path}/merge_requests/#{merge_request.iid}#note_#{note.id}"
end
end
@@ -82,7 +82,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(note)
- expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.full_path}/merge_requests/#{merge_request.iid}#note_#{note.id}"
end
end
@@ -93,7 +93,7 @@ describe Gitlab::UrlBuilder do
url = described_class.build(note)
- expect(url).to eq "#{Settings.gitlab['url']}/#{project_snippet.project.path_with_namespace}/snippets/#{note.noteable_id}#note_#{note.id}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{project_snippet.project.full_path}/snippets/#{note.noteable_id}#note_#{note.id}"
end
end
diff --git a/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb b/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb
index 49e750a3f4d..dd634f2c024 100644
--- a/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb
+++ b/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb
@@ -4,7 +4,7 @@ require Rails.root.join('db', 'post_migrate', '20170502101023_cleanup_namespacel
describe CleanupNamespacelessPendingDeleteProjects do
before do
# Stub after_save callbacks that will fail when Project has no namespace
- allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(nil)
+ allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil)
allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil)
end
diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
index 5b633dd349b..cf2d5827306 100644
--- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
+++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
@@ -20,7 +20,7 @@ describe MigrateProcessCommitWorkerJobs do
.find_including_path(project.id)
expect(migration_project[:path_with_namespace])
- .to eq(project.path_with_namespace)
+ .to eq(project.full_path)
end
end
diff --git a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
index 42109fd0743..6f7a730edff 100644
--- a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
+++ b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
@@ -44,7 +44,7 @@ describe TurnNestedGroupsIntoRegularGroupsForMysql do
end
it 'renames projects of the nested group' do
- expect(updated_project.path_with_namespace)
+ expect(updated_project.full_path)
.to eq("#{parent_group.name}-#{child_group.name}/#{updated_project.path}")
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 2285c338599..595c54890ab 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -161,7 +161,7 @@ eos
end
it 'detects issues that this commit is marked as closing' do
- ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
+ ext_ref = "#{other_project.full_path}##{other_issue.iid}"
allow(commit).to receive_messages(
safe_message: "Fixes ##{issue.iid} and #{ext_ref}",
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index b2dd02553c1..d9903b9b951 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -250,7 +250,7 @@ describe MergeRequest do
end
it 'returns a String reference with the full path' do
- expect(merge_request.to_reference(full: true)).to eq(project.path_with_namespace + '!1')
+ expect(merge_request.to_reference(full: true)).to eq(project.full_path + '!1')
end
end
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index 07e296424ca..2a0d102d3fe 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -63,24 +63,20 @@ RSpec.describe NotificationSetting do
end
end
- describe 'event_enabled?' do
+ describe '#event_enabled?' do
before do
subject.update!(user: create(:user))
end
context 'for an event with a matching column name' do
- before do
- subject.update!(events: { new_note: true }.to_json)
- end
-
it 'returns the value of the column' do
- subject.update!(new_note: false)
+ subject.update!(new_note: true)
- expect(subject.event_enabled?(:new_note)).to be(false)
+ expect(subject.event_enabled?(:new_note)).to be(true)
end
context 'when the column has a nil value' do
- it 'returns the value from the events hash' do
+ it 'returns false' do
expect(subject.event_enabled?(:new_note)).to be(false)
end
end
diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb
index add7e85f388..c47f32d8d77 100644
--- a/spec/models/project_label_spec.rb
+++ b/spec/models/project_label_spec.rb
@@ -105,14 +105,14 @@ describe ProjectLabel do
context 'using name' do
it 'returns cross reference with label name' do
expect(label.to_reference(project, format: :name))
- .to eq %Q(#{label.project.path_with_namespace}~"#{label.name}")
+ .to eq %Q(#{label.project.full_path}~"#{label.name}")
end
end
context 'using id' do
it 'returns cross reference with label id' do
expect(label.to_reference(project, format: :id))
- .to eq %Q(#{label.project.path_with_namespace}~#{label.id})
+ .to eq %Q(#{label.project.full_path}~#{label.id})
end
end
end
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index d19dab8fd39..45cc78c8ff4 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -31,9 +31,9 @@ describe GitlabIssueTrackerService do
end
it 'gives the correct path' do
- expect(service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues")
- expect(service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/new")
- expect(service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/432")
+ expect(service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.full_path}/issues")
+ expect(service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.full_path}/issues/new")
+ expect(service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.full_path}/issues/432")
end
end
@@ -43,9 +43,9 @@ describe GitlabIssueTrackerService do
end
it 'gives the correct path' do
- expect(service.issue_tracker_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues")
- expect(service.new_issue_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new")
- expect(service.issue_path(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432")
+ expect(service.issue_tracker_path).to eq("/gitlab/root/#{project.full_path}/issues")
+ expect(service.new_issue_path).to eq("/gitlab/root/#{project.full_path}/issues/new")
+ expect(service.issue_path(432)).to eq("/gitlab/root/#{project.full_path}/issues/432")
end
end
end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 8f34b44930e..bc9374d6dbb 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -135,7 +135,7 @@ describe JiraService do
body: hash_including(
GlobalID: "GitLab",
object: {
- url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{merge_request.diff_head_sha}",
+ url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/#{merge_request.diff_head_sha}",
title: "GitLab: Solved by commit #{merge_request.diff_head_sha}.",
icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
status: { resolved: true }
@@ -159,7 +159,7 @@ describe JiraService do
@jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project))
expect(WebMock).to have_requested(:post, @comment_url).with(
- body: /#{custom_base_url}\/#{project.path_with_namespace}\/commit\/#{merge_request.diff_head_sha}/
+ body: /#{custom_base_url}\/#{project.full_path}\/commit\/#{merge_request.diff_head_sha}/
).once
end
@@ -174,7 +174,7 @@ describe JiraService do
@jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project))
expect(WebMock).to have_requested(:post, @comment_url).with(
- body: /#{Gitlab.config.gitlab.url}\/#{project.path_with_namespace}\/commit\/#{merge_request.diff_head_sha}/
+ body: /#{Gitlab.config.gitlab.url}\/#{project.full_path}\/commit\/#{merge_request.diff_head_sha}/
).once
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 473b7a88d61..29cc9d35fc9 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -306,6 +306,7 @@ describe Project do
it { is_expected.to respond_to(:execute_hooks) }
it { is_expected.to respond_to(:owner) }
it { is_expected.to respond_to(:path_with_namespace) }
+ it { is_expected.to respond_to(:full_path) }
end
describe 'delegation' do
@@ -460,7 +461,7 @@ describe Project do
end
it 'returns the address to create a new issue' do
- address = "p+#{project.path_with_namespace}+#{user.incoming_email_token}@gl.ab"
+ address = "p+#{project.full_path}+#{user.incoming_email_token}@gl.ab"
expect(project.new_issue_address(user)).to eq(address)
end
@@ -1155,6 +1156,33 @@ describe Project do
end
end
+ describe '#pages_url' do
+ let(:group) { create :group, name: group_name }
+ let(:project) { create :empty_project, namespace: group, name: project_name }
+ let(:domain) { 'Example.com' }
+
+ subject { project.pages_url }
+
+ before do
+ allow(Settings.pages).to receive(:host).and_return(domain)
+ allow(Gitlab.config.pages).to receive(:url).and_return('http://example.com')
+ end
+
+ context 'group page' do
+ let(:group_name) { 'Group' }
+ let(:project_name) { 'group.example.com' }
+
+ it { is_expected.to eq("http://group.example.com") }
+ end
+
+ context 'project page' do
+ let(:group_name) { 'Group' }
+ let(:project_name) { 'Project' }
+
+ it { is_expected.to eq("http://group.example.com/project") }
+ end
+ end
+
describe '.search' do
let(:project) { create(:empty_project, description: 'kitten mittens') }
@@ -1341,7 +1369,7 @@ describe Project do
context 'using a regular repository' do
it 'creates the repository' do
expect(shell).to receive(:add_repository)
- .with(project.repository_storage_path, project.path_with_namespace)
+ .with(project.repository_storage_path, project.disk_path)
.and_return(true)
expect(project.repository).to receive(:after_create)
@@ -1351,7 +1379,7 @@ describe Project do
it 'adds an error if the repository could not be created' do
expect(shell).to receive(:add_repository)
- .with(project.repository_storage_path, project.path_with_namespace)
+ .with(project.repository_storage_path, project.disk_path)
.and_return(false)
expect(project.repository).not_to receive(:after_create)
@@ -1384,7 +1412,7 @@ describe Project do
.and_return(false)
allow(shell).to receive(:add_repository)
- .with(project.repository_storage_path, project.path_with_namespace)
+ .with(project.repository_storage_path, project.disk_path)
.and_return(true)
expect(project).to receive(:create_repository).with(force: true)
@@ -1408,7 +1436,7 @@ describe Project do
.and_return(false)
expect(shell).to receive(:add_repository)
- .with(project.repository_storage_path, project.path_with_namespace)
+ .with(project.repository_storage_path, project.disk_path)
.and_return(true)
project.ensure_repository
@@ -1572,7 +1600,7 @@ describe Project do
before do
allow_any_instance_of(Gitlab::Shell).to receive(:import_repository)
- .with(project.repository_storage_path, project.path_with_namespace, project.import_url)
+ .with(project.repository_storage_path, project.disk_path, project.import_url)
.and_return(true)
expect_any_instance_of(Repository).to receive(:after_import)
@@ -1710,7 +1738,7 @@ describe Project do
it 'schedules a RepositoryForkWorker job' do
expect(RepositoryForkWorker).to receive(:perform_async)
.with(project.id, forked_from_project.repository_storage_path,
- forked_from_project.path_with_namespace, project.namespace.full_path)
+ forked_from_project.disk_path, project.namespace.full_path)
project.add_import_job
end
@@ -2238,19 +2266,43 @@ describe Project do
end
describe '#remove_private_deploy_keys' do
- it 'removes the private deploy keys of a project' do
- project = create(:empty_project)
+ let!(:project) { create(:empty_project) }
+
+ context 'for a private deploy key' do
+ let!(:key) { create(:deploy_key, public: false) }
+ let!(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: key, project: project) }
+
+ context 'when the key is not linked to another project' do
+ it 'removes the key' do
+ project.remove_private_deploy_keys
- private_key = create(:deploy_key, public: false)
- public_key = create(:deploy_key, public: true)
+ expect(project.deploy_keys).not_to include(key)
+ end
+ end
- create(:deploy_keys_project, deploy_key: private_key, project: project)
- create(:deploy_keys_project, deploy_key: public_key, project: project)
+ context 'when the key is linked to another project' do
+ before do
+ another_project = create(:empty_project)
+ create(:deploy_keys_project, deploy_key: key, project: another_project)
+ end
- project.remove_private_deploy_keys
+ it 'does not remove the key' do
+ project.remove_private_deploy_keys
- expect(project.deploy_keys.where(public: false).any?).to eq(false)
- expect(project.deploy_keys.where(public: true).any?).to eq(true)
+ expect(project.deploy_keys).to include(key)
+ end
+ end
+ end
+
+ context 'for a public deploy key' do
+ let!(:key) { create(:deploy_key, public: true) }
+ let!(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: key, project: project) }
+
+ it 'does not remove the key' do
+ project.remove_private_deploy_keys
+
+ expect(project.deploy_keys).to include(key)
+ end
end
end
end
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index c6ceb092810..484fcfc88a3 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -15,19 +15,23 @@ describe ProjectWiki do
describe "#path_with_namespace" do
it "returns the project path with namespace with the .wiki extension" do
- expect(subject.path_with_namespace).to eq(project.path_with_namespace + ".wiki")
+ expect(subject.path_with_namespace).to eq(project.full_path + '.wiki')
+ end
+
+ it 'returns the same value as #full_path' do
+ expect(subject.path_with_namespace).to eq(subject.full_path)
end
end
describe '#web_url' do
it 'returns the full web URL to the wiki' do
- expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/wikis/home")
+ expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}/wikis/home")
end
end
describe "#url_to_repo" do
it "returns the correct ssh url to the repo" do
- expect(subject.url_to_repo).to eq(gitlab_shell.url_to_repo(subject.path_with_namespace))
+ expect(subject.url_to_repo).to eq(gitlab_shell.url_to_repo(subject.full_path))
end
end
@@ -41,7 +45,7 @@ describe ProjectWiki do
let(:project) { create :empty_project }
it 'returns the full http url to the repo' do
- expected_url = "#{Gitlab.config.gitlab.url}/#{subject.path_with_namespace}.git"
+ expected_url = "#{Gitlab.config.gitlab.url}/#{subject.full_path}.git"
expect(project_wiki.http_url_to_repo).to eq(expected_url)
expect(project_wiki.http_url_to_repo).not_to include('@')
@@ -50,7 +54,7 @@ describe ProjectWiki do
describe "#wiki_base_path" do
it "returns the wiki base path" do
- wiki_base_path = "#{Gitlab.config.gitlab.relative_url_root}/#{project.path_with_namespace}/wikis"
+ wiki_base_path = "#{Gitlab.config.gitlab.relative_url_root}/#{project.full_path}/wikis"
expect(subject.wiki_base_path).to eq(wiki_base_path)
end
@@ -77,7 +81,7 @@ describe ProjectWiki do
allow_any_instance_of(Gitlab::Shell).to receive(:add_repository) do
create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git")
end
- allow(project).to receive(:path_with_namespace).and_return("non-existant")
+ allow(project).to receive(:full_path).and_return("non-existant")
end
describe '#empty?' do
@@ -269,7 +273,7 @@ describe ProjectWiki do
describe '#create_repo!' do
it 'creates a repository' do
expect(subject).to receive(:init_repo)
- .with(subject.path_with_namespace)
+ .with(subject.full_path)
.and_return(true)
expect(subject.repository).to receive(:after_create)
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 07ed66e127a..0fd3a4d622a 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -962,7 +962,7 @@ describe Repository do
end
it 'returns false if no full path can be constructed' do
- allow(repository).to receive(:path_with_namespace).and_return(nil)
+ allow(repository).to receive(:full_path).and_return(nil)
expect(repository.exists?).to eq(false)
end
diff --git a/spec/requests/api/group_variables_spec.rb b/spec/requests/api/group_variables_spec.rb
new file mode 100644
index 00000000000..402ea057cc5
--- /dev/null
+++ b/spec/requests/api/group_variables_spec.rb
@@ -0,0 +1,221 @@
+require 'spec_helper'
+
+describe API::GroupVariables do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+
+ describe 'GET /groups/:id/variables' do
+ let!(:variable) { create(:ci_group_variable, group: group) }
+
+ context 'authorized user with proper permissions' do
+ before do
+ group.add_master(user)
+ end
+
+ it 'returns group variables' do
+ get api("/groups/#{group.id}/variables", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_a(Array)
+ end
+ end
+
+ context 'authorized user with invalid permissions' do
+ it 'does not return group variables' do
+ get api("/groups/#{group.id}/variables", user)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not return group variables' do
+ get api("/groups/#{group.id}/variables")
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'GET /groups/:id/variables/:key' do
+ let!(:variable) { create(:ci_group_variable, group: group) }
+
+ context 'authorized user with proper permissions' do
+ before do
+ group.add_master(user)
+ end
+
+ it 'returns group variable details' do
+ get api("/groups/#{group.id}/variables/#{variable.key}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['value']).to eq(variable.value)
+ expect(json_response['protected']).to eq(variable.protected?)
+ end
+
+ it 'responds with 404 Not Found if requesting non-existing variable' do
+ get api("/groups/#{group.id}/variables/non_existing_variable", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'authorized user with invalid permissions' do
+ it 'does not return group variable details' do
+ get api("/groups/#{group.id}/variables/#{variable.key}", user)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not return group variable details' do
+ get api("/groups/#{group.id}/variables/#{variable.key}")
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'POST /groups/:id/variables' do
+ context 'authorized user with proper permissions' do
+ let!(:variable) { create(:ci_group_variable, group: group) }
+
+ before do
+ group.add_master(user)
+ end
+
+ it 'creates variable' do
+ expect do
+ post api("/groups/#{group.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2', protected: true
+ end.to change{group.variables.count}.by(1)
+
+ expect(response).to have_http_status(201)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['protected']).to be_truthy
+ end
+
+ it 'creates variable with optional attributes' do
+ expect do
+ post api("/groups/#{group.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2'
+ end.to change{group.variables.count}.by(1)
+
+ expect(response).to have_http_status(201)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['protected']).to be_falsey
+ end
+
+ it 'does not allow to duplicate variable key' do
+ expect do
+ post api("/groups/#{group.id}/variables", user), key: variable.key, value: 'VALUE_2'
+ end.to change{group.variables.count}.by(0)
+
+ expect(response).to have_http_status(400)
+ end
+ end
+
+ context 'authorized user with invalid permissions' do
+ it 'does not create variable' do
+ post api("/groups/#{group.id}/variables", user)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not create variable' do
+ post api("/groups/#{group.id}/variables")
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'PUT /groups/:id/variables/:key' do
+ let!(:variable) { create(:ci_group_variable, group: group) }
+
+ context 'authorized user with proper permissions' do
+ before do
+ group.add_master(user)
+ end
+
+ it 'updates variable data' do
+ initial_variable = group.variables.first
+ value_before = initial_variable.value
+
+ put api("/groups/#{group.id}/variables/#{variable.key}", user), value: 'VALUE_1_UP', protected: true
+
+ updated_variable = group.variables.first
+
+ expect(response).to have_http_status(200)
+ expect(value_before).to eq(variable.value)
+ expect(updated_variable.value).to eq('VALUE_1_UP')
+ expect(updated_variable).to be_protected
+ end
+
+ it 'responds with 404 Not Found if requesting non-existing variable' do
+ put api("/groups/#{group.id}/variables/non_existing_variable", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'authorized user with invalid permissions' do
+ it 'does not update variable' do
+ put api("/groups/#{group.id}/variables/#{variable.key}", user)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not update variable' do
+ put api("/groups/#{group.id}/variables/#{variable.key}")
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'DELETE /groups/:id/variables/:key' do
+ let!(:variable) { create(:ci_group_variable, group: group) }
+
+ context 'authorized user with proper permissions' do
+ before do
+ group.add_master(user)
+ end
+
+ it 'deletes variable' do
+ expect do
+ delete api("/groups/#{group.id}/variables/#{variable.key}", user)
+
+ expect(response).to have_http_status(204)
+ end.to change{group.variables.count}.by(-1)
+ end
+
+ it 'responds with 404 Not Found if requesting non-existing variable' do
+ delete api("/groups/#{group.id}/variables/non_existing_variable", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'authorized user with invalid permissions' do
+ it 'does not delete variable' do
+ delete api("/groups/#{group.id}/variables/#{variable.key}", user)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not delete variable' do
+ delete api("/groups/#{group.id}/variables/#{variable.key}")
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index ce9b9ac1eb3..fb312d3cb7d 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -301,7 +301,7 @@ describe API::Internal do
context 'project as /namespace/project' do
it do
- pull(key, project_with_repo_path('/' + project.path_with_namespace))
+ pull(key, project_with_repo_path('/' + project.full_path))
expect(response).to have_http_status(200)
expect(json_response["status"]).to be_truthy
@@ -312,7 +312,7 @@ describe API::Internal do
context 'project as namespace/project' do
it do
- pull(key, project_with_repo_path(project.path_with_namespace))
+ pull(key, project_with_repo_path(project.full_path))
expect(response).to have_http_status(200)
expect(json_response["status"]).to be_truthy
diff --git a/spec/requests/api/notification_settings_spec.rb b/spec/requests/api/notification_settings_spec.rb
index f619b7e6eaf..d0e7a82e607 100644
--- a/spec/requests/api/notification_settings_spec.rb
+++ b/spec/requests/api/notification_settings_spec.rb
@@ -72,8 +72,8 @@ describe API::NotificationSettings do
expect(response).to have_http_status(200)
expect(json_response['level']).to eq(user.reload.notification_settings_for(project).level)
- expect(json_response['events']['new_note']).to eq(true)
- expect(json_response['events']['new_issue']).to eq(false)
+ expect(json_response['events']['new_note']).to be_truthy
+ expect(json_response['events']['new_issue']).to be_falsey
end
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 66b165b438b..2dc7be22f8f 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -16,38 +16,44 @@ describe API::Users do
it "returns authorization error when the `username` parameter is not passed" do
get api("/users")
- expect(response).to have_http_status(403)
+ expect(response).to have_gitlab_http_status(403)
end
it "returns the user when a valid `username` parameter is passed" do
- user = create(:user)
-
get api("/users"), username: user.username
- expect(response).to have_http_status(200)
+ expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
expect(json_response.size).to eq(1)
expect(json_response[0]['id']).to eq(user.id)
expect(json_response[0]['username']).to eq(user.username)
end
- it "returns authorization error when the `username` parameter refers to an inaccessible user" do
- user = create(:user)
-
- stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
-
- get api("/users"), username: user.username
-
- expect(response).to have_http_status(403)
- end
-
it "returns an empty response when an invalid `username` parameter is passed" do
get api("/users"), username: 'invalid'
- expect(response).to have_http_status(200)
+ expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
expect(json_response.size).to eq(0)
end
+
+ context "when public level is restricted" do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it "returns authorization error when the `username` parameter refers to an inaccessible user" do
+ get api("/users"), username: user.username
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+
+ it "returns authorization error when the `username` parameter is not passed" do
+ get api("/users")
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
end
context "when authenticated" do
@@ -58,10 +64,10 @@ describe API::Users do
end
context 'when authenticate as a regular user' do
- it "renders 403" do
+ it "renders 200" do
get api("/users", user)
- expect(response).to have_gitlab_http_status(403)
+ expect(response).to have_gitlab_http_status(200)
end
end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index d4a3e8b13e1..d5c16d8f601 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -123,7 +123,7 @@ describe 'Git HTTP requests' do
context "when requesting the Wiki" do
let(:wiki) { ProjectWiki.new(project) }
- let(:path) { "/#{wiki.repository.path_with_namespace}.git" }
+ let(:path) { "/#{wiki.repository.full_path}.git" }
context "when the project is public" do
let(:project) { create(:project, :repository, :public, :wiki_enabled) }
@@ -139,7 +139,7 @@ describe 'Git HTTP requests' do
download(path) do |response|
json_body = ActiveSupport::JSON.decode(response.body)
- expect(json_body['RepoPath']).to include(wiki.repository.path_with_namespace)
+ expect(json_body['RepoPath']).to include(wiki.repository.full_path)
end
end
end
@@ -222,7 +222,7 @@ describe 'Git HTTP requests' do
end
context "when the project exists" do
- let(:path) { "#{project.path_with_namespace}.git" }
+ let(:path) { "#{project.full_path}.git" }
context "when the project is public" do
let(:project) { create(:project, :repository, :public) }
@@ -286,7 +286,7 @@ describe 'Git HTTP requests' do
context 'when the request is not from gitlab-workhorse' do
it 'raises an exception' do
expect do
- get("/#{project.path_with_namespace}.git/info/refs?service=git-upload-pack")
+ get("/#{project.full_path}.git/info/refs?service=git-upload-pack")
end.to raise_error(JWT::DecodeError)
end
end
@@ -294,7 +294,7 @@ describe 'Git HTTP requests' do
context 'when the repo is public' do
context 'but the repo is disabled' do
let(:project) { create(:project, :public, :repository, :repository_disabled) }
- let(:path) { "#{project.path_with_namespace}.git" }
+ let(:path) { "#{project.full_path}.git" }
let(:env) { {} }
it_behaves_like 'pulls require Basic HTTP Authentication'
@@ -303,7 +303,7 @@ describe 'Git HTTP requests' do
context 'but the repo is enabled' do
let(:project) { create(:project, :public, :repository, :repository_enabled) }
- let(:path) { "#{project.path_with_namespace}.git" }
+ let(:path) { "#{project.full_path}.git" }
let(:env) { {} }
it_behaves_like 'pulls are allowed'
@@ -421,7 +421,7 @@ describe 'Git HTTP requests' do
@token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "api")
end
- let(:path) { "#{project.path_with_namespace}.git" }
+ let(:path) { "#{project.full_path}.git" }
let(:env) { { user: 'oauth2', password: @token.token } }
it_behaves_like 'pulls are allowed'
@@ -431,7 +431,7 @@ describe 'Git HTTP requests' do
context 'when user has 2FA enabled' do
let(:user) { create(:user, :two_factor) }
let(:access_token) { create(:personal_access_token, user: user) }
- let(:path) { "#{project.path_with_namespace}.git" }
+ let(:path) { "#{project.full_path}.git" }
before do
project.team << [user, :master]
@@ -580,7 +580,7 @@ describe 'Git HTTP requests' do
end
context 'when build created by system is authenticated' do
- let(:path) { "#{project.path_with_namespace}.git" }
+ let(:path) { "#{project.full_path}.git" }
let(:env) { { user: 'gitlab-ci-token', password: build.token } }
it_behaves_like 'pulls are allowed'
@@ -602,7 +602,7 @@ describe 'Git HTTP requests' do
# We are "authenticated" as CI using a valid token here. But we are
# not authorized to see any other project, so return "not found".
it "rejects pulls for other project with 404 Not Found" do
- clone_get("#{other_project.path_with_namespace}.git", env)
+ clone_get("#{other_project.full_path}.git", env)
expect(response).to have_http_status(:not_found)
expect(response.body).to eq(git_access_error(:project_not_found))
@@ -616,7 +616,7 @@ describe 'Git HTTP requests' do
end
shared_examples 'can download code only' do
- let(:path) { "#{project.path_with_namespace}.git" }
+ let(:path) { "#{project.full_path}.git" }
let(:env) { { user: 'gitlab-ci-token', password: build.token } }
it_behaves_like 'pulls are allowed'
@@ -646,7 +646,7 @@ describe 'Git HTTP requests' do
it_behaves_like 'can download code only'
it 'downloads from other project get status 403' do
- clone_get "#{other_project.path_with_namespace}.git", user: 'gitlab-ci-token', password: build.token
+ clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token
expect(response).to have_http_status(:forbidden)
end
@@ -658,7 +658,7 @@ describe 'Git HTTP requests' do
it_behaves_like 'can download code only'
it 'downloads from other project get status 404' do
- clone_get "#{other_project.path_with_namespace}.git", user: 'gitlab-ci-token', password: build.token
+ clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token
expect(response).to have_http_status(:not_found)
end
@@ -671,7 +671,7 @@ describe 'Git HTTP requests' do
let(:project) { create(:project, :repository, :public, path: 'project.git-project') }
context "GET info/refs" do
- let(:path) { "/#{project.path_with_namespace}/info/refs" }
+ let(:path) { "/#{project.full_path}/info/refs" }
context "when no params are added" do
before do
@@ -679,7 +679,7 @@ describe 'Git HTTP requests' do
end
it "redirects to the .git suffix version" do
- expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs")
+ expect(response).to redirect_to("/#{project.full_path}.git/info/refs")
end
end
@@ -691,7 +691,7 @@ describe 'Git HTTP requests' do
end
it "redirects to the .git suffix version" do
- expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
+ expect(response).to redirect_to("/#{project.full_path}.git/info/refs?service=#{params[:service]}")
end
end
@@ -703,7 +703,7 @@ describe 'Git HTTP requests' do
end
it "redirects to the .git suffix version" do
- expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
+ expect(response).to redirect_to("/#{project.full_path}.git/info/refs?service=#{params[:service]}")
end
end
@@ -722,13 +722,13 @@ describe 'Git HTTP requests' do
context "POST git-upload-pack" do
it "fails to find a route" do
- expect { clone_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError)
+ expect { clone_post(project.full_path) }.to raise_error(ActionController::RoutingError)
end
end
context "POST git-receive-pack" do
it "fails to find a route" do
- expect { push_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError)
+ expect { push_post(project.full_path) }.to raise_error(ActionController::RoutingError)
end
end
end
@@ -744,7 +744,7 @@ describe 'Git HTTP requests' do
Blob.decorate(Gitlab::Git::Blob.find(project.repository, 'master', 'bar/branch-test.txt'), project)
end
- get "/#{project.path_with_namespace}/blob/master/info/refs"
+ get "/#{project.full_path}/blob/master/info/refs"
end
it "returns the file" do
@@ -754,7 +754,7 @@ describe 'Git HTTP requests' do
context "when the file does not exist" do
before do
- get "/#{project.path_with_namespace}/blob/master/info/refs"
+ get "/#{project.full_path}/blob/master/info/refs"
end
it "returns not found" do
diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb
index 697b150ab34..4f1a90750b3 100644
--- a/spec/requests/lfs_http_spec.rb
+++ b/spec/requests/lfs_http_spec.rb
@@ -701,7 +701,7 @@ describe 'Git LFS API and storage' do
expect(json_response['objects']).to be_kind_of(Array)
expect(json_response['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
expect(json_response['objects'].first['size']).to eq(1575078)
- expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
+ expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
expect(json_response['objects'].first['actions']['upload']['header']).to eq('Authorization' => authorization)
end
end
diff --git a/spec/requests/request_profiler_spec.rb b/spec/requests/request_profiler_spec.rb
index 51fbfecec4b..9afeb2983b0 100644
--- a/spec/requests/request_profiler_spec.rb
+++ b/spec/requests/request_profiler_spec.rb
@@ -15,7 +15,7 @@ describe 'Request Profiler' do
it 'creates a profile of the request' do
project = create(:project, namespace: user.namespace)
time = Time.now
- path = "/#{project.path_with_namespace}"
+ path = "/#{project.full_path}"
Timecop.freeze(time) do
get path, nil, 'X-Profile-Token' => Gitlab::RequestProfiler.profile_token
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 66a8a93b168..0ae839ce0b3 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -46,7 +46,7 @@ describe Auth::ContainerRegistryAuthenticationService do
shared_examples 'an accessible' do
let(:access) do
[{ 'type' => 'repository',
- 'name' => project.path_with_namespace,
+ 'name' => project.full_path,
'actions' => actions }]
end
@@ -97,7 +97,7 @@ describe Auth::ContainerRegistryAuthenticationService do
describe '#full_access_token' do
let(:project) { create(:empty_project) }
- let(:token) { described_class.full_access_token(project.path_with_namespace) }
+ let(:token) { described_class.full_access_token(project.full_path) }
subject { { token: token } }
@@ -124,7 +124,7 @@ describe Auth::ContainerRegistryAuthenticationService do
end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
it_behaves_like 'a pushable'
@@ -138,7 +138,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'when pulling from root level repository' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'a pullable'
@@ -152,7 +152,7 @@ describe Auth::ContainerRegistryAuthenticationService do
end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push,pull" }
+ { scope: "repository:#{project.full_path}:push,pull" }
end
it_behaves_like 'a pullable'
@@ -165,7 +165,7 @@ describe Auth::ContainerRegistryAuthenticationService do
end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{project.full_path}:pull,push" }
end
it_behaves_like 'an inaccessible'
@@ -178,7 +178,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'allow anyone to pull images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'a pullable'
@@ -187,7 +187,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'disallow anyone to push images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
it_behaves_like 'an inaccessible'
@@ -210,7 +210,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'for internal user' do
context 'allow anyone to pull images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'a pullable'
@@ -219,7 +219,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'disallow anyone to push images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
it_behaves_like 'an inaccessible'
@@ -230,7 +230,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'for external user' do
let(:current_user) { create(:user, external: true) }
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{project.full_path}:pull,push" }
end
it_behaves_like 'an inaccessible'
@@ -255,7 +255,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'allow to pull and push images' do
let(:current_params) do
- { scope: "repository:#{current_project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{current_project.full_path}:pull,push" }
end
it_behaves_like 'a pullable and pushable' do
@@ -270,7 +270,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'for other projects' do
context 'when pulling' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
context 'allow for public' do
@@ -337,7 +337,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'when pushing' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
context 'disallow for all' do
@@ -371,7 +371,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'disallow when pulling' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'an inaccessible'
@@ -399,7 +399,7 @@ describe Auth::ContainerRegistryAuthenticationService do
let(:project) { create(:empty_project, :private) }
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'a forbidden'
@@ -410,7 +410,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'when pulling and pushing' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{project.full_path}:pull,push" }
end
it_behaves_like 'a pullable'
@@ -419,7 +419,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'when pushing' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
it_behaves_like 'a forbidden'
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
index 945a2fe1a6b..e9188a83b89 100644
--- a/spec/services/ci/pipeline_trigger_service_spec.rb
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::PipelineTriggerService, services: true do
+describe Ci::PipelineTriggerService do
let(:project) { create(:project, :repository) }
before do
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 3fb677b65be..82724ccd281 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -453,7 +453,7 @@ describe GitPushService, services: true do
let(:message) { "this is some work.\n\ncloses JIRA-1" }
let(:comment_body) do
{
- body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.path_with_namespace}/commit/#{closing_commit.id}]."
+ body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.full_path}/commit/#{closing_commit.id}]."
}.to_json
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 49d6fc7853f..5b69426cbaa 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -694,17 +694,6 @@ describe NotificationService do
let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } }
let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } }
- it "emails subscribers of the issue's added labels only" do
- notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled)
-
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
- end
-
it "emails the current user if they've opted into notifications about their activity" do
subscriber_to_label_2.notified_of_own_activity = true
notification.relabeled_issue(issue, [group_label_2, label_2], subscriber_to_label_2)
@@ -721,6 +710,12 @@ describe NotificationService do
it "doesn't send email to anyone but subscribers of the given labels" do
notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled)
+ should_not_email(subscriber_to_label_1)
+ should_not_email(subscriber_to_group_label_1)
+ should_not_email(subscriber_to_group_label_2_on_another_project)
+ should_email(subscriber_1_to_group_label_2)
+ should_email(subscriber_2_to_group_label_2)
+ should_email(subscriber_to_label_2)
should_not_email(issue.assignees.first)
should_not_email(issue.author)
should_not_email(@u_watcher)
@@ -730,12 +725,6 @@ describe NotificationService do
should_not_email(@watcher_and_subscriber)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
end
context 'confidential issues' do
@@ -878,11 +867,6 @@ describe NotificationService do
end
describe '#new_merge_request' do
- before do
- update_custom_notification(:new_merge_request, @u_guest_custom, resource: project)
- update_custom_notification(:new_merge_request, @u_custom_global)
- end
-
it do
notification.new_merge_request(merge_request, @u_disabled)
@@ -1008,7 +992,7 @@ describe NotificationService do
let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } }
let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } }
- it "emails subscribers of the merge request's added labels only" do
+ it "doesn't send email to anyone but subscribers of the given labels" do
notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled)
should_not_email(subscriber_to_label_1)
@@ -1017,11 +1001,6 @@ describe NotificationService do
should_email(subscriber_1_to_group_label_2)
should_email(subscriber_2_to_group_label_2)
should_email(subscriber_to_label_2)
- end
-
- it "doesn't send email to anyone but subscribers of the given labels" do
- notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled)
-
should_not_email(merge_request.assignee)
should_not_email(merge_request.author)
should_not_email(@u_watcher)
@@ -1031,12 +1010,6 @@ describe NotificationService do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_lazy_participant)
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
end
end
@@ -1081,12 +1054,12 @@ describe NotificationService do
should_email(merge_request.assignee)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
+ should_email(@u_guest_custom)
+ should_email(@u_custom_global)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
- should_email(@u_guest_watcher)
- should_email(@u_custom_global)
- should_email(@u_guest_custom)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb
index 67fe610f92a..c2a6cafa4c8 100644
--- a/spec/services/projects/import_service_spec.rb
+++ b/spec/services/projects/import_service_spec.rb
@@ -26,7 +26,7 @@ describe Projects::ImportService do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The repository could not be created."
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - The repository could not be created."
end
end
@@ -52,7 +52,7 @@ describe Projects::ImportService do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Failed to import the repository"
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Failed to import the repository"
end
it 'does not remove the GitHub remote' do
@@ -86,7 +86,7 @@ describe Projects::ImportService do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Failed to import the repository"
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Failed to import the repository"
end
end
end
@@ -129,7 +129,7 @@ describe Projects::ImportService do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The remote data could not be imported."
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - The remote data could not be imported."
end
it 'fails if importer raise an error' do
@@ -139,7 +139,7 @@ describe Projects::ImportService do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Github: failed to connect API"
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Github: failed to connect API"
end
it 'expires content cache after error' do
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index ae32e85b2a7..2cb60cbcfc4 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -37,18 +37,18 @@ describe Projects::TransferService do
end
it 'executes system hooks' do
- expect_any_instance_of(described_class).to receive(:execute_system_hooks)
-
- transfer_project(project, user, group)
+ transfer_project(project, user, group) do |service|
+ expect(service).to receive(:execute_system_hooks)
+ end
end
end
context 'when transfer fails' do
let!(:original_path) { project_path(project) }
- def attempt_project_transfer
+ def attempt_project_transfer(&block)
expect do
- transfer_project(project, user, group)
+ transfer_project(project, user, group, &block)
end.to raise_error(ActiveRecord::ActiveRecordError)
end
@@ -59,7 +59,7 @@ describe Projects::TransferService do
end
def project_path(project)
- File.join(project.repository_storage_path, "#{project.path_with_namespace}.git")
+ File.join(project.repository_storage_path, "#{project.disk_path}.git")
end
def current_path
@@ -80,9 +80,9 @@ describe Projects::TransferService do
end
it "doesn't run system hooks" do
- expect_any_instance_of(described_class).not_to receive(:execute_system_hooks)
-
- attempt_project_transfer
+ attempt_project_transfer do |service|
+ expect(service).not_to receive(:execute_system_hooks)
+ end
end
end
@@ -120,7 +120,11 @@ describe Projects::TransferService do
end
def transfer_project(project, user, new_namespace)
- Projects::TransferService.new(project, user).execute(new_namespace)
+ service = Projects::TransferService.new(project, user)
+
+ yield(service) if block_given?
+
+ service.execute(new_namespace)
end
context 'visibility level' do
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 42a4a2591ea..92bde2c92bf 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -9,13 +9,13 @@ describe QuickActions::InterpretService do
let(:inprogress) { create(:label, project: project, title: 'In Progress') }
let(:bug) { create(:label, project: project, title: 'Bug') }
let(:note) { build(:note, commit_id: merge_request.diff_head_sha) }
+ let(:service) { described_class.new(project, developer) }
before do
project.team << [developer, :developer]
end
describe '#execute' do
- let(:service) { described_class.new(project, developer) }
let(:merge_request) { create(:merge_request, source_project: project) }
shared_examples 'reopen command' do
@@ -270,6 +270,22 @@ describe QuickActions::InterpretService do
end
end
+ shared_examples 'shrug command' do
+ it 'appends ¯\_(ツ)_/¯ to the comment' do
+ new_content, _ = service.execute(content, issuable)
+
+ expect(new_content).to end_with(described_class::SHRUG)
+ end
+ end
+
+ shared_examples 'tableflip command' do
+ it 'appends (╯°□°)╯︵ ┻━┻ to the comment' do
+ new_content, _ = service.execute(content, issuable)
+
+ expect(new_content).to end_with(described_class::TABLEFLIP)
+ end
+ end
+
it_behaves_like 'reopen command' do
let(:content) { '/reopen' }
let(:issuable) { issue }
@@ -775,6 +791,30 @@ describe QuickActions::InterpretService do
end
end
+ context '/shrug command' do
+ it_behaves_like 'shrug command' do
+ let(:content) { '/shrug people are people' }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'shrug command' do
+ let(:content) { '/shrug' }
+ let(:issuable) { issue }
+ end
+ end
+
+ context '/tableflip command' do
+ it_behaves_like 'tableflip command' do
+ let(:content) { '/tableflip curse your sudden but enviable betrayal' }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'tableflip command' do
+ let(:content) { '/tableflip' }
+ let(:issuable) { issue }
+ end
+ end
+
context '/target_branch command' do
let(:non_empty_project) { create(:project, :repository) }
let(:another_merge_request) { create(:merge_request, author: developer, source_project: non_empty_project) }
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index cb59493c343..5c20263a532 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -667,7 +667,7 @@ describe SystemNoteService do
end
it 'mentions referenced project' do
- expect(subject.note).to include new_project.path_with_namespace
+ expect(subject.note).to include new_project.full_path
end
end
@@ -873,7 +873,7 @@ describe SystemNoteService do
describe "existing reference" do
before do
allow(JIRA::Resource::Remotelink).to receive(:all).and_return([])
- message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.path_with_namespace}|http://localhost/#{project.path_with_namespace}/commit/#{commit.id}]:\n'#{commit.title.chomp}'"
+ message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.full_path}|http://localhost/#{project.full_path}/commit/#{commit.id}]:\n'#{commit.title.chomp}'"
allow_any_instance_of(JIRA::Resource::Issue).to receive(:comments).and_return([OpenStruct.new(body: message)])
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 85335643921..609998d6e9c 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -129,10 +129,14 @@ RSpec.configure do |config|
config.before(:example, :migration) do
ActiveRecord::Migrator
.migrate(migrations_paths, previous_migration.version)
+
+ ActiveRecord::Base.descendants.each(&:reset_column_information)
end
config.after(:example, :migration) do
ActiveRecord::Migrator.migrate(migrations_paths)
+
+ ActiveRecord::Base.descendants.each(&:reset_column_information)
end
config.around(:each, :nested_groups) do |example|
diff --git a/spec/support/notify_shared_examples.rb b/spec/support/notify_shared_examples.rb
index 76411065265..70799bce721 100644
--- a/spec/support/notify_shared_examples.rb
+++ b/spec/support/notify_shared_examples.rb
@@ -50,7 +50,7 @@ shared_examples 'an email with X-GitLab headers containing project details' do
aggregate_failures do
is_expected.to have_header('X-GitLab-Project', /#{project.name}/)
is_expected.to have_header('X-GitLab-Project-Id', /#{project.id}/)
- is_expected.to have_header('X-GitLab-Project-Path', /#{project.path_with_namespace}/)
+ is_expected.to have_header('X-GitLab-Project-Path', /#{project.full_path}/)
end
end
end
diff --git a/spec/support/project_hook_data_shared_example.rb b/spec/support/project_hook_data_shared_example.rb
index 7dbaa6a6459..1eb405d4be8 100644
--- a/spec/support/project_hook_data_shared_example.rb
+++ b/spec/support/project_hook_data_shared_example.rb
@@ -8,7 +8,7 @@ RSpec.shared_examples 'project hook data with deprecateds' do |project_key: :pro
expect(data[project_key][:git_ssh_url]).to eq(project.ssh_url_to_repo)
expect(data[project_key][:namespace]).to eq(project.namespace.name)
expect(data[project_key][:visibility_level]).to eq(project.visibility_level)
- expect(data[project_key][:path_with_namespace]).to eq(project.path_with_namespace)
+ expect(data[project_key][:path_with_namespace]).to eq(project.full_path)
expect(data[project_key][:default_branch]).to eq(project.default_branch)
expect(data[project_key][:homepage]).to eq(project.web_url)
expect(data[project_key][:url]).to eq(project.url_to_repo)
@@ -27,7 +27,7 @@ RSpec.shared_examples 'project hook data' do |project_key: :project|
expect(data[project_key][:git_ssh_url]).to eq(project.ssh_url_to_repo)
expect(data[project_key][:namespace]).to eq(project.namespace.name)
expect(data[project_key][:visibility_level]).to eq(project.visibility_level)
- expect(data[project_key][:path_with_namespace]).to eq(project.path_with_namespace)
+ expect(data[project_key][:path_with_namespace]).to eq(project.full_path)
expect(data[project_key][:default_branch]).to eq(project.default_branch)
end
end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 86f9568c12e..f0603dfadde 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -144,10 +144,13 @@ module TestEnv
end
def start_gitaly(gitaly_dir)
- gitaly_exec = File.join(gitaly_dir, 'gitaly')
- gitaly_config = File.join(gitaly_dir, 'config.toml')
- log_file = Rails.root.join('log/gitaly-test.log').to_s
- @gitaly_pid = Bundler.with_original_env { spawn(gitaly_exec, gitaly_config, [:out, :err] => log_file) }
+ if ENV['CI'].present?
+ # Gitaly has been spawned outside this process already
+ return
+ end
+
+ spawn_script = Rails.root.join('scripts/gitaly-test-spawn').to_s
+ @gitaly_pid = Bundler.with_original_env { IO.popen([spawn_script], &:read).to_i }
end
def stop_gitaly
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 71580a788d0..fae92451b46 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -117,7 +117,7 @@ describe 'gitlab:app namespace rake task' do
describe 'backup creation and deletion using custom_hooks' do
let(:project) { create(:project, :repository) }
- let(:user_backup_path) { "repositories/#{project.path_with_namespace}" }
+ let(:user_backup_path) { "repositories/#{project.disk_path}" }
before(:each) do
@origin_cd = Dir.pwd
@@ -261,8 +261,8 @@ describe 'gitlab:app namespace rake task' do
%W{tar -tvf #{@backup_tar} repositories}
)
expect(exit_status).to eq(0)
- expect(tar_contents).to match("repositories/#{project_a.path_with_namespace}.bundle")
- expect(tar_contents).to match("repositories/#{project_b.path_with_namespace}.bundle")
+ expect(tar_contents).to match("repositories/#{project_a.disk_path}.bundle")
+ expect(tar_contents).to match("repositories/#{project_b.disk_path}.bundle")
end
end
end # backup_create task
diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb
index d42d2423f15..695231c7d15 100644
--- a/spec/tasks/gitlab/gitaly_rake_spec.rb
+++ b/spec/tasks/gitlab/gitaly_rake_spec.rb
@@ -41,6 +41,16 @@ describe 'gitlab:gitaly namespace rake task' do
end
describe 'gmake/make' do
+ let(:command_preamble) { %w[/usr/bin/env -u BUNDLE_GEMFILE] }
+
+ before(:all) do
+ @old_env_ci = ENV.delete('CI')
+ end
+
+ after(:all) do
+ ENV['CI'] = @old_env_ci if @old_env_ci
+ end
+
before do
FileUtils.mkdir_p(clone_path)
expect(Dir).to receive(:chdir).with(clone_path).and_call_original
@@ -49,12 +59,12 @@ describe 'gitlab:gitaly namespace rake task' do
context 'gmake is available' do
before do
expect_any_instance_of(Object).to receive(:checkout_or_clone_version)
- allow_any_instance_of(Object).to receive(:run_command!).with(['gmake']).and_return(true)
+ allow_any_instance_of(Object).to receive(:run_command!).with(command_preamble + ['gmake']).and_return(true)
end
it 'calls gmake in the gitaly directory' do
expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['/usr/bin/gmake', 0])
- expect_any_instance_of(Object).to receive(:run_command!).with(['gmake']).and_return(true)
+ expect_any_instance_of(Object).to receive(:run_command!).with(command_preamble + ['gmake']).and_return(true)
run_rake_task('gitlab:gitaly:install', clone_path)
end
@@ -63,12 +73,12 @@ describe 'gitlab:gitaly namespace rake task' do
context 'gmake is not available' do
before do
expect_any_instance_of(Object).to receive(:checkout_or_clone_version)
- allow_any_instance_of(Object).to receive(:run_command!).with(['make']).and_return(true)
+ allow_any_instance_of(Object).to receive(:run_command!).with(command_preamble + ['make']).and_return(true)
end
it 'calls make in the gitaly directory' do
expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['', 42])
- expect_any_instance_of(Object).to receive(:run_command!).with(['make']).and_return(true)
+ expect_any_instance_of(Object).to receive(:run_command!).with(command_preamble + ['make']).and_return(true)
run_rake_task('gitlab:gitaly:install', clone_path)
end
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index 309b3172da1..05f971dfd13 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -9,17 +9,51 @@ describe GitGarbageCollectWorker do
subject { described_class.new }
describe "#perform" do
- it "flushes ref caches when the task is 'gc'" do
- expect(subject).to receive(:command).with(:gc).and_return([:the, :command])
- expect(Gitlab::Popen).to receive(:popen)
- .with([:the, :command], project.repository.path_to_repo).and_return(["", 0])
+ shared_examples 'flushing ref caches' do |gitaly|
+ it "flushes ref caches when the task if 'gc'" do
+ expect(subject).to receive(:command).with(:gc).and_return([:the, :command])
+
+ if gitaly
+ expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect)
+ .and_return(nil)
+ else
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([:the, :command], project.repository.path_to_repo).and_return(["", 0])
+ end
+
+ expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
+ expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
+ expect_any_instance_of(Repository).to receive(:branch_count).and_call_original
+ expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
+
+ subject.perform(project.id)
+ end
+ end
+
+ context "with Gitaly turned on" do
+ it_should_behave_like 'flushing ref caches', true
+ end
+
+ context "with Gitaly turned off", skip_gitaly_mock: true do
+ it_should_behave_like 'flushing ref caches', false
+ end
- expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
- expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
- expect_any_instance_of(Repository).to receive(:branch_count).and_call_original
- expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
+ context "repack_full" do
+ it "calls Gitaly" do
+ expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_full)
+ .and_return(nil)
- subject.perform(project.id)
+ subject.perform(project.id, :full_repack)
+ end
+ end
+
+ context "repack_incremental" do
+ it "calls Gitaly" do
+ expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_incremental)
+ .and_return(nil)
+
+ subject.perform(project.id, :incremental_repack)
+ end
end
shared_examples 'gc tasks' do
diff --git a/spec/workers/namespaceless_project_destroy_worker_spec.rb b/spec/workers/namespaceless_project_destroy_worker_spec.rb
index 8533b7b85e9..f9e23d648ec 100644
--- a/spec/workers/namespaceless_project_destroy_worker_spec.rb
+++ b/spec/workers/namespaceless_project_destroy_worker_spec.rb
@@ -5,7 +5,7 @@ describe NamespacelessProjectDestroyWorker do
before do
# Stub after_save callbacks that will fail when Project has no namespace
- allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(nil)
+ allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil)
allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil)
end