summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop.yml3
-rw-r--r--CHANGELOG38
-rw-r--r--CONTRIBUTING.md13
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock49
-rw-r--r--README.md12
-rw-r--r--app/assets/javascripts/merge_request_widget.js.coffee20
-rw-r--r--app/assets/stylesheets/framework/avatar.scss1
-rw-r--r--app/assets/stylesheets/framework/blocks.scss44
-rw-r--r--app/assets/stylesheets/framework/buttons.scss9
-rw-r--r--app/assets/stylesheets/framework/header.scss4
-rw-r--r--app/assets/stylesheets/framework/mobile.scss2
-rw-r--r--app/assets/stylesheets/framework/nav.scss61
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss13
-rw-r--r--app/assets/stylesheets/framework/tables.scss4
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap.scss2
-rw-r--r--app/assets/stylesheets/framework/typography.scss4
-rw-r--r--app/assets/stylesheets/framework/variables.scss11
-rw-r--r--app/assets/stylesheets/pages/builds.scss9
-rw-r--r--app/assets/stylesheets/pages/commit.scss26
-rw-r--r--app/assets/stylesheets/pages/detail_page.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss20
-rw-r--r--app/assets/stylesheets/pages/milestone.scss4
-rw-r--r--app/assets/stylesheets/pages/notes.scss9
-rw-r--r--app/assets/stylesheets/pages/profile.scss18
-rw-r--r--app/assets/stylesheets/pages/projects.scss2
-rw-r--r--app/assets/stylesheets/pages/status.scss2
-rw-r--r--app/assets/stylesheets/pages/todos.scss9
-rw-r--r--app/assets/stylesheets/pages/tree.scss2
-rw-r--r--app/controllers/admin/impersonations_controller.rb2
-rw-r--r--app/controllers/admin/users_controller.rb2
-rw-r--r--app/controllers/application_controller.rb2
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/graphs_controller.rb4
-rw-r--r--app/controllers/registrations_controller.rb7
-rw-r--r--app/helpers/blob_helper.rb2
-rw-r--r--app/helpers/nav_helper.rb13
-rw-r--r--app/helpers/projects_helper.rb17
-rw-r--r--app/models/appearance.rb13
-rw-r--r--app/models/application_setting.rb16
-rw-r--r--app/models/audit_event.rb4
-rw-r--r--app/models/broadcast_message.rb4
-rw-r--r--app/models/ci/build.rb14
-rw-r--r--app/models/ci/commit.rb10
-rw-r--r--app/models/ci/runner.rb14
-rw-r--r--app/models/ci/trigger.rb2
-rw-r--r--app/models/ci/variable.rb6
-rw-r--r--app/models/commit_status.rb17
-rw-r--r--app/models/concerns/issuable.rb9
-rw-r--r--app/models/deploy_key.rb6
-rw-r--r--app/models/email.rb2
-rw-r--r--app/models/event.rb4
-rw-r--r--app/models/generic_commit_status.rb17
-rw-r--r--app/models/group.rb21
-rw-r--r--app/models/hooks/project_hook.rb1
-rw-r--r--app/models/hooks/service_hook.rb1
-rw-r--r--app/models/hooks/system_hook.rb1
-rw-r--r--app/models/hooks/web_hook.rb1
-rw-r--r--app/models/identity.rb4
-rw-r--r--app/models/issue.rb9
-rw-r--r--app/models/key.rb6
-rw-r--r--app/models/label.rb20
-rw-r--r--app/models/label_link.rb2
-rw-r--r--app/models/lfs_object.rb4
-rw-r--r--app/models/member.rb8
-rw-r--r--app/models/members/group_member.rb8
-rw-r--r--app/models/members/project_member.rb8
-rw-r--r--app/models/merge_request.rb13
-rw-r--r--app/models/merge_request_diff.rb4
-rw-r--r--app/models/milestone.rb8
-rw-r--r--app/models/namespace.rb20
-rw-r--r--app/models/note.rb8
-rw-r--r--app/models/notification_setting.rb13
-rw-r--r--app/models/personal_snippet.rb6
-rw-r--r--app/models/project.rb84
-rw-r--r--app/models/project_group_link.rb12
-rw-r--r--app/models/project_import_data.rb9
-rw-r--r--app/models/project_services/asana_service.rb13
-rw-r--r--app/models/project_services/assembla_service.rb13
-rw-r--r--app/models/project_services/bamboo_service.rb13
-rw-r--r--app/models/project_services/buildkite_service.rb13
-rw-r--r--app/models/project_services/builds_email_service.rb13
-rw-r--r--app/models/project_services/campfire_service.rb13
-rw-r--r--app/models/project_services/ci_service.rb13
-rw-r--r--app/models/project_services/custom_issue_tracker_service.rb13
-rw-r--r--app/models/project_services/drone_ci_service.rb13
-rw-r--r--app/models/project_services/emails_on_push_service.rb13
-rw-r--r--app/models/project_services/external_wiki_service.rb13
-rw-r--r--app/models/project_services/flowdock_service.rb13
-rw-r--r--app/models/project_services/gemnasium_service.rb13
-rw-r--r--app/models/project_services/gitlab_ci_service.rb13
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb13
-rw-r--r--app/models/project_services/hipchat_service.rb13
-rw-r--r--app/models/project_services/irker_service.rb13
-rw-r--r--app/models/project_services/issue_tracker_service.rb13
-rw-r--r--app/models/project_services/jira_service.rb13
-rw-r--r--app/models/project_services/pivotaltracker_service.rb13
-rw-r--r--app/models/project_services/pushover_service.rb13
-rw-r--r--app/models/project_services/redmine_service.rb13
-rw-r--r--app/models/project_services/slack_service.rb13
-rw-r--r--app/models/project_services/teamcity_service.rb13
-rw-r--r--app/models/project_snippet.rb6
-rw-r--r--app/models/project_wiki.rb2
-rw-r--r--app/models/protected_branch.rb2
-rw-r--r--app/models/release.rb2
-rw-r--r--app/models/repository.rb22
-rw-r--r--app/models/security_event.rb4
-rw-r--r--app/models/sent_notification.rb8
-rw-r--r--app/models/service.rb13
-rw-r--r--app/models/snippet.rb6
-rw-r--r--app/models/spam_log.rb17
-rw-r--r--app/models/subscription.rb2
-rw-r--r--app/models/user.rb53
-rw-r--r--app/services/create_branch_service.rb5
-rw-r--r--app/services/create_tag_service.rb44
-rw-r--r--app/services/git_push_service.rb1
-rw-r--r--app/services/git_tag_push_service.rb1
-rw-r--r--app/services/issues/move_service.rb15
-rw-r--r--app/services/merge_requests/build_service.rb36
-rw-r--r--app/services/projects/destroy_service.rb4
-rw-r--r--app/services/system_note_service.rb6
-rw-r--r--app/views/admin/builds/_build.html.haml26
-rw-r--r--app/views/admin/builds/index.html.haml3
-rw-r--r--app/views/admin/logs/show.html.haml2
-rw-r--r--app/views/admin/users/index.html.haml2
-rw-r--r--app/views/dashboard/todos/index.html.haml6
-rw-r--r--app/views/devise/sessions/two_factor.html.haml4
-rw-r--r--app/views/devise/shared/_signup_box.html.haml4
-rw-r--r--app/views/events/_event.html.haml2
-rw-r--r--app/views/events/_event_last_push.html.haml2
-rw-r--r--app/views/explore/groups/index.html.haml2
-rw-r--r--app/views/explore/snippets/index.html.haml2
-rw-r--r--app/views/groups/activity.html.haml1
-rw-r--r--app/views/groups/edit.html.haml2
-rw-r--r--app/views/groups/group_members/index.html.haml1
-rw-r--r--app/views/groups/issues.html.haml3
-rw-r--r--app/views/groups/merge_requests.html.haml3
-rw-r--r--app/views/groups/milestones/index.html.haml3
-rw-r--r--app/views/groups/projects.html.haml1
-rw-r--r--app/views/groups/show.html.haml34
-rw-r--r--app/views/help/ui.html.haml6
-rw-r--r--app/views/layouts/_page.html.haml2
-rw-r--r--app/views/layouts/group.html.haml2
-rw-r--r--app/views/layouts/group_settings.html.haml3
-rw-r--r--app/views/layouts/header/_default.html.haml1
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml4
-rw-r--r--app/views/layouts/nav/_explore.html.haml2
-rw-r--r--app/views/layouts/nav/_group.html.haml20
-rw-r--r--app/views/layouts/nav/_group_settings.html.haml40
-rw-r--r--app/views/profiles/show.html.haml4
-rw-r--r--app/views/projects/_last_push.html.haml2
-rw-r--r--app/views/projects/_readme.html.haml2
-rw-r--r--app/views/projects/artifacts/browse.html.haml2
-rw-r--r--app/views/projects/branches/index.html.haml2
-rw-r--r--app/views/projects/builds/index.html.haml4
-rw-r--r--app/views/projects/builds/show.html.haml4
-rw-r--r--app/views/projects/ci/builds/_build.html.haml9
-rw-r--r--app/views/projects/commit/_ci_commit.html.haml6
-rw-r--r--app/views/projects/commit/_commit_box.html.haml26
-rw-r--r--app/views/projects/commit/branches.html.haml1
-rw-r--r--app/views/projects/commits/_head.html.haml3
-rw-r--r--app/views/projects/commits/show.html.haml2
-rw-r--r--app/views/projects/compare/index.html.haml2
-rw-r--r--app/views/projects/compare/show.html.haml2
-rw-r--r--app/views/projects/empty.html.haml2
-rw-r--r--app/views/projects/graphs/ci.html.haml2
-rw-r--r--app/views/projects/graphs/commits.html.haml2
-rw-r--r--app/views/projects/graphs/languages.html.haml2
-rw-r--r--app/views/projects/graphs/show.html.haml2
-rw-r--r--app/views/projects/imports/new.html.haml2
-rw-r--r--app/views/projects/issues/_issue.html.haml14
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml14
-rw-r--r--app/views/projects/merge_requests/widget/_heading.html.haml7
-rw-r--r--app/views/projects/milestones/show.html.haml10
-rw-r--r--app/views/projects/network/_head.html.haml2
-rw-r--r--app/views/projects/releases/edit.html.haml2
-rw-r--r--app/views/projects/show.html.haml2
-rw-r--r--app/views/projects/snippets/index.html.haml2
-rw-r--r--app/views/projects/tags/index.html.haml2
-rw-r--r--app/views/projects/tags/show.html.haml2
-rw-r--r--app/views/projects/wikis/git_access.html.haml2
-rw-r--r--app/views/search/_results.html.haml2
-rw-r--r--app/views/shared/issuable/_filter.html.haml4
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--app/views/shared/milestones/_top.html.haml2
-rw-r--r--app/views/shared/snippets/_header.html.haml2
-rw-r--r--app/views/sherlock/file_samples/show.html.haml2
-rw-r--r--app/views/sherlock/queries/show.html.haml2
-rw-r--r--app/views/sherlock/transactions/index.html.haml2
-rw-r--r--app/views/sherlock/transactions/show.html.haml2
-rw-r--r--app/views/users/show.html.haml4
-rw-r--r--app/workers/repository_check/single_repository_worker.rb34
-rwxr-xr-xbin/background_jobs2
-rwxr-xr-xbin/web4
-rw-r--r--config/gitlab.teatro.yml1
-rw-r--r--config/gitlab.yml.example1
-rw-r--r--config/initializers/devise_async.rb1
-rw-r--r--config/initializers/metrics.rb37
-rw-r--r--config/initializers/trusted_proxies.rb3
-rw-r--r--db/fixtures/development/10_merge_requests.rb5
-rw-r--r--db/migrate/20160508194200_remove_wall_enabled_from_projects.rb5
-rw-r--r--db/schema.rb21
-rw-r--r--doc/api/build_triggers.md12
-rw-r--r--doc/api/commits.md2
-rw-r--r--doc/api/issues.md15
-rw-r--r--doc/api/merge_requests.md22
-rw-r--r--doc/api/notes.md10
-rw-r--r--doc/api/users.md80
-rw-r--r--doc/ci/docker/using_docker_build.md6
-rw-r--r--doc/ci/docker/using_docker_images.md8
-rw-r--r--doc/ci/examples/README.md4
-rw-r--r--doc/ci/examples/php.md6
-rw-r--r--doc/ci/examples/test-and-deploy-python-application-to-heroku.md10
-rw-r--r--doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md6
-rw-r--r--doc/ci/services/mysql.md4
-rw-r--r--doc/ci/services/postgres.md2
-rw-r--r--doc/ci/services/redis.md2
-rw-r--r--doc/ci/ssh_keys/README.md2
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/instrumentation.md129
-rw-r--r--doc/development/performance.md258
-rw-r--r--doc/development/testing.md1
-rw-r--r--doc/install/installation.md56
-rw-r--r--doc/install/requirements.md9
-rw-r--r--doc/update/patch_versions.md4
-rw-r--r--doc/workflow/lfs/manage_large_binaries_with_git_lfs.md2
-rw-r--r--docker/README.md6
-rw-r--r--features/groups.feature4
-rw-r--r--features/project/create.feature16
-rw-r--r--features/steps/group/milestones.rb6
-rw-r--r--features/steps/groups.rb4
-rw-r--r--features/steps/project/commits/tags.rb4
-rw-r--r--features/steps/project/create.rb26
-rw-r--r--features/steps/user.rb4
-rw-r--r--lib/api/commits.rb8
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/helpers.rb16
-rw-r--r--lib/gitlab/backend/shell.rb18
-rw-r--r--lib/gitlab/bitbucket_import/client.rb2
-rw-r--r--lib/gitlab/git_access.rb11
-rw-r--r--lib/gitlab/github_import/comment_formatter.rb21
-rw-r--r--lib/gitlab/push_data_builder.rb2
-rw-r--r--lib/gitlab/sanitizers/svg.rb37
-rw-r--r--lib/gitlab/sanitizers/svg/whitelist.rb107
-rw-r--r--lib/gitlab/url_builder.rb2
-rw-r--r--lib/tasks/auto_annotate_models.rake44
-rw-r--r--spec/factories/projects.rb11
-rw-r--r--spec/features/issues_spec.rb2
-rw-r--r--spec/features/login_spec.rb2
-rw-r--r--spec/features/projects/developer_views_empty_project_instructions_spec.rb63
-rw-r--r--spec/features/signup_spec.rb24
-rw-r--r--spec/features/users_spec.rb16
-rw-r--r--spec/fixtures/sanitized.svg50
-rw-r--r--spec/fixtures/unsanitized.svg50
-rw-r--r--spec/helpers/blob_helper_spec.rb12
-rw-r--r--spec/helpers/projects_helper_spec.rb19
-rw-r--r--spec/initializers/trusted_proxies_spec.rb51
-rw-r--r--spec/javascripts/merge_request_widget_spec.js.coffee55
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_import/client_spec.rb26
-rw-r--r--spec/lib/gitlab/github_import/comment_formatter_spec.rb30
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb2
-rw-r--r--spec/models/label_spec.rb8
-rw-r--r--spec/models/milestone_spec.rb8
-rw-r--r--spec/models/project_spec.rb1
-rw-r--r--spec/models/project_wiki_spec.rb4
-rw-r--r--spec/models/repository_spec.rb29
-rw-r--r--spec/requests/api/commits_spec.rb35
-rw-r--r--spec/requests/api/issues_spec.rb21
-rw-r--r--spec/requests/api/merge_requests_spec.rb28
-rw-r--r--spec/requests/api/tags_spec.rb4
-rw-r--r--spec/services/create_tag_service_spec.rb53
-rw-r--r--spec/services/issues/move_service_spec.rb38
-rw-r--r--spec/services/merge_requests/build_service_spec.rb181
-rw-r--r--spec/services/system_note_service_spec.rb9
-rw-r--r--spec/spec_helper.rb6
-rw-r--r--spec/workers/repository_check/single_repository_worker_spec.rb33
277 files changed, 2779 insertions, 969 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 83ed6c38678..9f179efa3ce 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -953,10 +953,9 @@ Performance/DoubleStartEndWith:
Performance/EndWith:
Enabled: false
-# TODO: Enable LstripRstrip Cop.
# Use `strip` instead of `lstrip.rstrip`.
Performance/LstripRstrip:
- Enabled: false
+ Enabled: true
# TODO: Enable RangeInclude Cop.
# Use `Range#cover?` instead of `Range#include?`.
diff --git a/CHANGELOG b/CHANGELOG
index b6527780bbf..f8ae187348d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,26 +1,56 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.8.0 (unreleased)
+ - Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen)
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
+ - Escape HTML in commit titles in system note messages
+ - Improve multiple branch push performance by memoizing permission checking
+ - Log to application.log when an admin starts and stops impersonating a user
+ - Updated gitlab_git to 10.1.0
+ - GitAccess#protected_tag? no longer loads all tags just to check if a single one exists
+ - Reduce delay in destroying a project from 1-minute to immediately
- Make build status canceled if any of the jobs was canceled and none failed
+ - Upgrade Sidekiq to 4.1.2
+ - Sanitize repo paths in new project error message
+ - Bump mail_room to 0.7.0 to fix stuck IDLE connections
- Remove future dates from contribution calendar graph.
- Support e-mail notifications for comments on project snippets
- Use ActionDispatch Remote IP for Akismet checking
- Fix error when visiting commit builds page before build was updated
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
+ - Update SVG sanitizer to conform to SVG 1.1
- Updated search UI
- Display informative message when new milestone is created
- - Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea)
+ - Sanitize milestones and labels titles
- Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea)
- Added button to toggle whitespaces changes on diff view
- - Backport GitLab Enterprise support from EE
+ - Backport GitHub Enterprise import support from EE
+ - Create tags using Rugged for performance reasons. !3745
+ - API: Expose Issue#user_notes_count. !3126 (Anton Popov)
- Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718
- Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes)
- Added multiple colors for labels in dropdowns when dups happen.
-
-v 8.7.2 (unreleased)
+ - Improve description for the Two-factor Authentication sign-in screen. (Connor Shea)
+ - API support for the 'since' and 'until' operators on commit requests (Paco Guzman)
+ - Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko)
+ - Expire repository exists? and has_visible_content? caches after a push if necessary
+ - Fix unintentional filtering bug in issues sorted by milestone due (Takuya Noguchi)
+
+v 8.7.4
+ - Fix always showing build notification message when switching between merge requests
+ - Fix links on wiki pages for relative url setups. !4026 (Artem Sidorenko)
+
+v 8.7.3
+ - Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented
+ - Merge request widget displays TeamCity build state and code coverage correctly again.
+ - Fix the line code when importing PR review comments from GitHub. !4010
+ - Wikis are now initialized on legacy projects when checking repositories
+
+v 8.7.2
- The "New Branch" button is now loaded asynchronously
- Fix error 500 when trying to create a wiki page
+ - Updated spacing between notification label and button
+ - Label titles in filters are now escaped properly
v 8.7.1
- Throttle the update of `project.last_activity_at` to 1 minute. !3848
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 084c2d616a9..9fe4cf7b0f6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -142,6 +142,16 @@ code snippet right after your description in a new line: `~"feature proposal"`.
Please keep feature proposals as small and simple as possible, complex ones
might be edited to make them small and simple.
+You are encouraged to use the template below for feature proposals.
+
+```
+## Description including problem, use cases, benefits, and/or goals
+
+## Proposal
+
+## Links / references
+```
+
For changes in the interface, it can be helpful to create a mockup first.
If you want to create something yourself, consider opening an issue first to
discuss whether it is interesting to include this in GitLab.
@@ -349,7 +359,7 @@ on your merge request feel free to mention one of the Merge Marshalls in the
Please ensure that your merge request meets the contribution acceptance criteria.
When having your code reviewed and when reviewing merge requests please take the
-[Thoughtbot code review guide] into account.
+[code review guidelines](doc/development/code_review.md) into account.
### Merge request description format
@@ -523,4 +533,3 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab1.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/gitlab1.atype/
-[Thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review
diff --git a/Gemfile b/Gemfile
index 25c13fda575..1137ef4d72b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -20,6 +20,7 @@ gem "pg", '~> 0.18.2', group: :postgres
# Authentication libraries
gem 'devise', '~> 3.5.4'
gem 'doorkeeper', '~> 3.1'
+gem 'devise-async', '~> 0.9.0'
gem 'omniauth', '~> 1.3.1'
gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6'
@@ -269,7 +270,7 @@ group :development, :test do
gem 'database_cleaner', '~> 1.4.0'
gem 'factory_girl_rails', '~> 4.6.0'
- gem 'rspec-rails', '~> 3.3.0'
+ gem 'rspec-rails', '~> 3.4.0'
gem 'rspec-retry'
gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2'
@@ -319,7 +320,7 @@ gem "newrelic_rpm", '~> 3.14'
gem 'octokit', '~> 4.3.0'
-gem "mail_room", "~> 0.6.1"
+gem "mail_room", "~> 0.7"
gem 'email_reply_parser', '~> 0.5.8'
diff --git a/Gemfile.lock b/Gemfile.lock
index b1e954e0884..fe083c2b566 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -134,7 +134,7 @@ GEM
execjs
coffee-script-source (1.10.0)
colorize (0.7.7)
- concurrent-ruby (1.0.1)
+ concurrent-ruby (1.0.2)
connection_pool (2.2.0)
coveralls (0.8.13)
json (~> 1.8)
@@ -164,6 +164,8 @@ GEM
responders
thread_safe (~> 0.1)
warden (~> 1.2.3)
+ devise-async (0.9.0)
+ devise (~> 3.2)
devise-two-factor (2.0.1)
activesupport
attr_encrypted (~> 1.3.2)
@@ -351,7 +353,7 @@ GEM
posix-spawn (~> 0.3)
gitlab_emoji (0.3.1)
gemojione (~> 2.2, >= 2.2.1)
- gitlab_git (10.0.1)
+ gitlab_git (10.1.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
@@ -465,7 +467,7 @@ GEM
systemu (~> 2.6.2)
mail (2.6.4)
mime-types (>= 1.16, < 4)
- mail_room (0.6.1)
+ mail_room (0.7.0)
method_source (0.8.2)
mime-types (2.99.1)
mimemagic (0.3.0)
@@ -662,29 +664,29 @@ GEM
chunky_png
rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2)
- rspec (3.3.0)
- rspec-core (~> 3.3.0)
- rspec-expectations (~> 3.3.0)
- rspec-mocks (~> 3.3.0)
- rspec-core (3.3.2)
- rspec-support (~> 3.3.0)
- rspec-expectations (3.3.1)
+ rspec (3.4.0)
+ rspec-core (~> 3.4.0)
+ rspec-expectations (~> 3.4.0)
+ rspec-mocks (~> 3.4.0)
+ rspec-core (3.4.4)
+ rspec-support (~> 3.4.0)
+ rspec-expectations (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.3.0)
- rspec-mocks (3.3.2)
+ rspec-support (~> 3.4.0)
+ rspec-mocks (3.4.1)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.3.0)
- rspec-rails (3.3.3)
+ rspec-support (~> 3.4.0)
+ rspec-rails (3.4.2)
actionpack (>= 3.0, < 4.3)
activesupport (>= 3.0, < 4.3)
railties (>= 3.0, < 4.3)
- rspec-core (~> 3.3.0)
- rspec-expectations (~> 3.3.0)
- rspec-mocks (~> 3.3.0)
- rspec-support (~> 3.3.0)
+ rspec-core (~> 3.4.0)
+ rspec-expectations (~> 3.4.0)
+ rspec-mocks (~> 3.4.0)
+ rspec-support (~> 3.4.0)
rspec-retry (0.4.5)
rspec-core
- rspec-support (3.3.0)
+ rspec-support (3.4.1)
rubocop (0.38.0)
parser (>= 2.3.0.6, < 3.0)
powerpack (~> 0.1)
@@ -738,7 +740,7 @@ GEM
rack
shoulda-matchers (2.8.0)
activesupport (>= 3.0.0)
- sidekiq (4.1.1)
+ sidekiq (4.1.2)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
redis (~> 3.2, >= 3.2.1)
@@ -920,6 +922,7 @@ DEPENDENCIES
database_cleaner (~> 1.4.0)
default_value_for (~> 3.0.0)
devise (~> 3.5.4)
+ devise-async (~> 0.9.0)
devise-two-factor (~> 2.0.0)
diffy (~> 3.0.3)
doorkeeper (~> 3.1)
@@ -961,7 +964,7 @@ DEPENDENCIES
letter_opener_web (~> 1.3.0)
licensee (~> 8.0.0)
loofah (~> 2.0.3)
- mail_room (~> 0.6.1)
+ mail_room (~> 0.7)
method_source (~> 0.8)
minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6)
@@ -1011,7 +1014,7 @@ DEPENDENCIES
responders (~> 2.0)
rouge (~> 1.10.1)
rqrcode-rails3 (~> 0.1.7)
- rspec-rails (~> 3.3.0)
+ rspec-rails (~> 3.4.0)
rspec-retry
rubocop (~> 0.38.0)
ruby-fogbugz (~> 0.2.1)
@@ -1058,4 +1061,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
- 1.11.2
+ 1.12.1
diff --git a/README.md b/README.md
index afa60116ebb..418d06a45a5 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# GitLab
-[![build status](https://ci.gitlab.com/projects/1/status.svg?ref=master)](https://ci.gitlab.com/projects/1?ref=master)
+[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![Build Status](https://semaphoreci.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/400484/shields_badge.svg)](https://semaphoreci.com/gitlabhq/gitlabhq)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.svg?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
@@ -20,6 +20,10 @@ To see how GitLab looks please see the [features page on our website](https://ab
- Completely free and open source (MIT Expat license)
- Powered by [Ruby on Rails](https://github.com/rails/rails)
+## Hiring
+
+We're hiring developers, support people, and production engineers all the time, please see our [jobs page](https://about.gitlab.com/jobs/).
+
## Editions
There are two editions of GitLab:
@@ -31,11 +35,11 @@ There are two editions of GitLab:
On [about.gitlab.com](https://about.gitlab.com/) you can find more information about:
-- [Subscriptions](https://about.gitlab.com/subscription/)
+- [Subscriptions](https://about.gitlab.com/pricing/)
- [Consultancy](https://about.gitlab.com/consultancy/)
- [Community](https://about.gitlab.com/community/)
- [Hosted GitLab.com](https://about.gitlab.com/gitlab-com/) use GitLab as a free service
-- [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/) with additional features aimed at larger organizations.
+- [GitLab Enterprise Edition](https://about.gitlab.com/features/#enterprise) with additional features aimed at larger organizations.
- [GitLab CI](https://about.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab.
## Requirements
@@ -80,7 +84,7 @@ There are a lot of [third-party applications integrating with GitLab](https://ab
## GitLab release cycle
-For more information about the release process see the [release documentation](http://doc.gitlab.com/ce/release/).
+For more information about the release process see the [release documentation](https://gitlab.com/gitlab-org/release-tools/blob/master/README.md).
## Upgrading
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index 065626beeb8..f58647988a2 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -9,11 +9,12 @@ class @MergeRequestWidget
constructor: (@opts) ->
$('#modal_merge_info').modal(show: false)
@firstCICheck = true
- @readyForCICheck = true
+ @readyForCICheck = false
clearInterval @fetchBuildStatusInterval
@clearEventListeners()
@addEventListeners()
+ @getCIStatus(false)
@pollCIStatus()
notifyPermissions()
@@ -68,20 +69,18 @@ class @MergeRequestWidget
$.getJSON @opts.ci_status_url, (data) =>
@readyForCICheck = true
- if @firstCICheck
- @firstCICheck = false
- @opts.ci_status = data.status
-
- if @opts.ci_status is ''
- @opts.ci_status = data.status
+ if data.status is ''
return
- if data.status isnt @opts.ci_status and data.status?
+ if @firstCICheck || data.status isnt @opts.ci_status and data.status?
+ @opts.ci_status = data.status
@showCIStatus data.status
if data.coverage
@showCICoverage data.coverage
- if showNotification
+ # The first check should only update the UI, a notification
+ # should only be displayed on status changes
+ if showNotification and not @firstCICheck
status = @ciLabelForStatus(data.status)
if status is "preparing"
@@ -104,8 +103,7 @@ class @MergeRequestWidget
@close()
Turbolinks.visit _this.opts.builds_path
)
-
- @opts.ci_status = data.status
+ @firstCICheck = false
showCIStatus: (state) ->
$('.ci_widget').hide()
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index 5aa425dab6c..f5ce70b606b 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -28,6 +28,7 @@
&.s46 { width: 46px; height: 46px; margin-right: 15px; }
&.s48 { width: 48px; height: 48px; margin-right: 10px; }
&.s60 { width: 60px; height: 60px; margin-right: 12px; }
+ &.s70 { width: 70px; height: 70px; margin-right: 14px; }
&.s90 { width: 90px; height: 90px; margin-right: 15px; }
&.s110 { width: 110px; height: 110px; margin-right: 15px; }
&.s140 { width: 140px; height: 140px; margin-right: 20px; }
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index e72e4aa47ef..434a26d57c6 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -18,7 +18,7 @@
line-height: 36px;
}
-.gray-content-block {
+.row-content-block {
margin-top: 0;
margin-bottom: -$gl-padding;
background-color: $background-color;
@@ -81,6 +81,11 @@
margin-left: 10px;
}
}
+
+ &.build-content {
+ background-color: $white-light;
+ border-top: none;
+ }
}
.cover-block {
@@ -113,7 +118,7 @@
line-height: 1.1;
h1 {
- color: #313236;
+ color: $gl-gray-dark;
margin-bottom: 6px;
font-size: 23px;
}
@@ -150,6 +155,41 @@
right: auto;
}
}
+
+ &.groups-cover-block {
+ background: $white-light;
+ border-bottom: 1px solid $border-color;
+ text-align: left;
+ padding: 24px 0;
+
+ .group-info {
+ .cover-title {
+ margin-top: 9px;
+ }
+
+ p {
+ margin-bottom: 0;
+ }
+ }
+
+ @media (max-width: $screen-xs-max) {
+ text-align: center;
+
+ .avatar {
+ float: none;
+ }
+ }
+ }
+
+ .group-info {
+
+ h1 {
+ display: inline;
+ font-weight: normal;
+ font-size: 24px;
+ color: $gl-title-color;
+ }
+ }
}
.block-connector {
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 062da397b6b..eaf85bb17ca 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -59,7 +59,7 @@
}
@mixin btn-gray {
- @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, #313236);
+ @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, $gl-gray-dark);
}
@mixin btn-white {
@@ -251,3 +251,10 @@
.btn-file-option {
background: linear-gradient(180deg, $white-light 25%, $gray-light 100%);
}
+
+.btn-build {
+ margin-left: 10px;
+ i {
+ color: $gl-icon-color;
+ }
+}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 5fa10d29a87..97f9d582007 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -30,6 +30,10 @@ header {
border: none;
border-bottom: 1px solid $border-color;
+ &.with-horizontal-nav {
+ border-bottom: none;
+ }
+
.container-fluid {
width: 100% !important;
filter: none;
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index 7eb451c124e..33cbee85987 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -30,7 +30,7 @@
}
.rss-btn {
- display: none !important;
+ display: none;
}
.project-home-links {
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 5fe687dcec3..7c18e93a261 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -26,8 +26,8 @@
}
&.active a {
- color: #000;
- border-bottom: 2px solid #4688f1;
+ border-bottom: 2px solid $link-underline-blue;
+ color: $black;
}
.badge {
@@ -140,6 +140,12 @@
}
}
+ .project-filter-form {
+ input {
+ background-color: $background-color;
+ }
+ }
+
@media (max-width: $screen-xs-max) {
padding-bottom: 0;
@@ -187,13 +193,31 @@
}
.layout-nav {
+ position: fixed;
+ top: $header-height;
+ width: 100%;
+ z-index: 1;
background: $background-color;
border-bottom: 1px solid $border-color;
+ transition-duration: .3s;
.controls {
float: right;
- position: relative;
- top: 10px;
+ padding: 7px 5px 0 0;
+
+ i {
+ color: $layout-link-gray;
+ }
+
+ .fa-rss,
+ .fa-cog {
+ font-size: 16px;
+ }
+
+ .fa-caret-down {
+ margin-left: 5px;
+ color: $gl-icon-color;
+ }
.dropdown {
margin-left: 7px;
@@ -202,5 +226,34 @@
.nav-links {
border-bottom: none;
+ height: 51px;
+ white-space: nowrap;
+ overflow-x: auto;
+
+ li {
+
+ a {
+ padding-top: 10px;
+ }
+
+ a, i {
+ color: $layout-link-gray;
+ }
+
+ &.active {
+ a, i {
+ color: $black;
+ }
+ }
+
+ .badge {
+ color: $gl-icon-color;
+ }
+ }
}
+
+}
+
+.page-with-layout-nav {
+ margin-top: 50px;
}
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index 18189e985c4..e940fd7286e 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -3,6 +3,7 @@
position: absolute;
width: 58px;
cursor: pointer;
+ margin-top: 8px;
}
.page-with-sidebar {
@@ -62,7 +63,7 @@
float: left;
height: $header-height;
width: 100%;
- padding: 11px 0 11px 22px;
+ padding-left: 22px;
overflow: hidden;
outline: none;
transition-duration: .3s;
@@ -85,7 +86,7 @@
margin: 0;
margin-left: 50px;
font-size: 19px;
- line-height: 41px;
+ line-height: 50px;
font-weight: normal;
}
}
@@ -254,6 +255,10 @@
}
}
}
+
+ .layout-nav {
+ padding-right: $sidebar_collapsed_width;
+ }
}
.page-sidebar-expanded {
@@ -280,6 +285,10 @@
}
}
}
+
+ .layout-nav {
+ padding-right: $sidebar_width;
+ }
}
.right-sidebar-collapsed {
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index 75b770ae5a2..b42075c98d0 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -32,13 +32,11 @@ table {
th {
background-color: $background-color;
font-weight: normal;
- font-size: 15px;
- border-bottom: 1px solid $border-color;
+ border-bottom: none;
}
td {
border-color: $table-border-color;
- border-bottom: 1px solid $border-color;
}
}
}
diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss
index 96bab7880c2..6a45c34ccbb 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap.scss
@@ -81,7 +81,7 @@
// Labels
.label {
- padding: 2px 4px;
+ padding: 4px 5px;
font-size: 13px;
font-style: normal;
font-weight: normal;
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index b2535ddf4bd..2779cd56788 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -42,14 +42,14 @@
margin: 24px 0 12px;
padding: 0 0 10px;
border-bottom: 1px solid #e7e9ed;
- color: #313236;
+ color: $gl-gray-dark;
}
h2 {
font-size: 1.2em;
font-weight: 600;
margin: 24px 0 12px;
- color: #313236;
+ color: $gl-gray-dark;
}
h3 {
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index b8ed7e8a74c..ccb4e5381b7 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -12,7 +12,7 @@ $gutter_inner_width: 258px;
*/
$border-color: #e5e5e5;
$focus-border-color: #3aabf0;
-$table-border-color: #eef0f2;
+$table-border-color: #ececec;
$background-color: #fafafa;
/*
@@ -20,7 +20,7 @@ $background-color: #fafafa;
*/
$gl-font-size: 15px;
$gl-title-color: #333;
-$gl-text-color: #555;
+$gl-text-color: #5c5c5c;
$gl-text-green: #4a2;
$gl-text-red: #d12f19;
$gl-text-orange: #d90;
@@ -30,6 +30,7 @@ $gl-placeholder-color: #8f8f8f;
$gl-icon-color: $gl-placeholder-color;
$gl-grayish-blue: #7f8fa4;
$gl-gray: $gl-text-color;
+$gl-gray-dark: #313236;
$gl-header-color: $gl-title-color;
/*
@@ -65,7 +66,7 @@ $gl-padding-top: 10px;
$row-hover: #f4f8fe;
$progress-color: #c0392b;
$avatar_radius: 50%;
-$header-height: 58px;
+$header-height: 50px;
$fixed-layout-width: 1280px;
$gl-avatar-size: 40px;
$error-exclamation-point: #e62958;
@@ -74,6 +75,9 @@ $btn-transparent-color: #8f8f8f;
$settings-icon-size: 18px;
$provider-btn-group-border: #e5e5e5;
$provider-btn-not-active-color: #4688f1;
+$link-underline-blue: #4a8bee;
+$layout-link-gray: #7e7c7c;
+$todo-alert-blue: #428bca;
/*
* Color schema
@@ -108,6 +112,7 @@ $red-light: #e52c5a;
$red-normal: #d22852;
$red-dark: darken($red-normal, 5%);
+$black: #000;
$black-transparent: rgba(0, 0, 0, 0.3);
$border-white-light: #f1f2f4;
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 201f3e5ca46..aa41565f812 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -83,3 +83,12 @@
}
}
}
+
+table.builds {
+
+ .build-link {
+ a {
+ color: $gl-dark-link-color;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index 358d2f4ab9d..c2cd227571f 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -31,9 +31,23 @@
}
.commit-committer-link,
.commit-author-link {
- color: #444;
+ color: $gl-gray;
font-weight: bold;
}
+
+ .time_ago {
+ margin-left: 8px;
+ }
+
+ .fa-clipboard {
+ color: $dropdown-title-btn-color;
+ }
+
+ .commit-info {
+ &.branches {
+ margin-left: 8px;
+ }
+ }
}
.commit-box {
@@ -42,7 +56,7 @@
.commit-title {
margin: 0;
font-size: 23px;
- color: #313236;
+ color: $gl-gray-dark;
}
.commit-description {
@@ -83,6 +97,14 @@
}
}
+.commit-action-buttons {
+ i {
+ color: $gl-icon-color;
+ font-size: 13px;
+ margin-right: 3px;
+ }
+}
+
/*
* Commit message textarea for web editor and
* custom merge request message
diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss
index 3438dbe4958..5e61e61d85c 100644
--- a/app/assets/stylesheets/pages/detail_page.scss
+++ b/app/assets/stylesheets/pages/detail_page.scss
@@ -22,7 +22,7 @@
.title {
margin: 0;
font-size: 23px;
- color: #313236;
+ color: $gl-gray-dark;
}
.description {
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 4ef548ffbe7..c4005ba1e69 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -104,7 +104,7 @@
font-weight: 600;
font-size: 17px;
margin: 5px 0;
- color: #313236;
+ color: $gl-gray-dark;
}
p:last-child {
@@ -136,7 +136,7 @@
}
.label-branch {
- color: #313236;
+ color: $gl-gray-dark;
font-family: $monospace_font;
font-weight: bold;
overflow: hidden;
@@ -272,3 +272,19 @@
display: inline-block;
width: 250px;
}
+
+.table-holder {
+ .builds {
+
+ th {
+ background-color: $white-light;
+ color: $gl-placeholder-color;
+ }
+
+ th,
+ td {
+ padding: 16px;
+ }
+ }
+}
+
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
index d0e72a4422c..b94f524b513 100644
--- a/app/assets/stylesheets/pages/milestone.scss
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -28,7 +28,7 @@ li.milestone {
// Issue title
span a {
- color: rgba(0,0,0,0.64);
+ color: $gl-text-color;
}
}
}
@@ -51,7 +51,7 @@ li.milestone {
margin-top: 7px;
.issuable-number {
- color: rgba(0,0,0,0.44);
+ color: $gl-placeholder-color;
margin-right: 5px;
}
.avatar {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 9619d65db85..624c8249f7e 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -114,10 +114,6 @@ ul.notes {
word-break: keep-all;
}
}
-
- a {
- word-break: break-all;
- }
}
.note-header {
@@ -172,6 +168,11 @@ ul.notes {
.notes {
background-color: $white-light;
}
+
+ a code {
+ top: 0;
+ margin-right: 0;
+ }
}
}
}
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 01f98479623..abc5a0e9877 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -205,3 +205,21 @@
text-align: center;
}
}
+
+.user-profile {
+ @media (max-width: $screen-xs-max) {
+ .cover-block {
+ padding-top: 20px;
+ }
+
+ .cover-controls {
+ position: static;
+ margin-bottom: 20px;
+
+ .btn {
+ display: inline-block;
+ width: 48%;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 99108e9bfc4..c20f04653fc 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -178,7 +178,7 @@
.option-title {
font-weight: normal;
display: inline-block;
- color: #313236;
+ color: $gl-gray-dark;
}
.option-descr {
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index dbb6daf0d70..2370d35924e 100644
--- a/app/assets/stylesheets/pages/status.scss
+++ b/app/assets/stylesheets/pages/status.scss
@@ -1,7 +1,7 @@
.container-fluid {
.ci-status {
padding: 2px 7px;
- margin-right: 5px;
+ margin-right: 10px;
border: 1px solid #eee;
white-space: nowrap;
@include border-radius(4px);
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index 75f78569e3c..e51c3491dae 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -6,9 +6,16 @@
.navbar-nav {
li {
.badge.todos-pending-count {
- background-color: $gl-icon-color;
margin-top: -5px;
font-weight: normal;
+ background: $todo-alert-blue;
+ margin-left: -17px;
+ font-size: 11px;
+ color: white;
+ padding: 3px;
+ padding-top: 1px;
+ padding-bottom: 1px;
+ border-radius: 3px;
}
}
}
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index 25b5e95583e..a84fc2e0318 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -16,7 +16,7 @@
tr {
> td, > th {
- line-height: 26px;
+ line-height: 23px;
}
&:hover {
diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb
index 2db824c87ef..8be35f00a77 100644
--- a/app/controllers/admin/impersonations_controller.rb
+++ b/app/controllers/admin/impersonations_controller.rb
@@ -7,6 +7,8 @@ class Admin::ImpersonationsController < Admin::ApplicationController
warden.set_user(impersonator, scope: :user)
+ Gitlab::AppLogger.info("User #{original_user.username} has stopped impersonating #{impersonator.username}")
+
session[:impersonator_id] = nil
redirect_to admin_user_path(original_user)
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index b8976fa09a9..f2f654c7bcd 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -41,6 +41,8 @@ class Admin::UsersController < Admin::ApplicationController
warden.set_user(user, scope: :user)
+ Gitlab::AppLogger.info("User #{current_user.username} has started impersonating #{user.username}")
+
flash[:alert] = "You are now impersonating #{user.username}"
redirect_to root_path
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 1c53b0b21a3..17b3f49aed1 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -117,7 +117,7 @@ class ApplicationController < ActionController::Base
end
def after_sign_out_path_for(resource)
- current_application_settings.after_sign_out_path || new_user_session_path
+ current_application_settings.after_sign_out_path.presence || new_user_session_path
end
def abilities
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 1420b96840c..a52c614b259 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -15,7 +15,7 @@ class Projects::CommitsController < Projects::ApplicationController
if search.present?
@repository.find_commits_by_message(search, @ref, @path, @limit, @offset).compact
else
- @repository.commits(@ref, @path, @limit, @offset)
+ @repository.commits(@ref, path: @path, limit: @limit, offset: @offset)
end
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index d13ea9f34b6..092ef32e6e3 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -17,7 +17,7 @@ class Projects::GraphsController < Projects::ApplicationController
end
def commits
- @commits = @project.repository.commits(@ref, nil, 2000, 0, true)
+ @commits = @project.repository.commits(@ref, limit: 2000, skip_merges: true)
@commits_graph = Gitlab::Graphs::Commits.new(@commits)
@commits_per_week_days = @commits_graph.commits_per_week_days
@commits_per_time = @commits_graph.commits_per_time
@@ -55,7 +55,7 @@ class Projects::GraphsController < Projects::ApplicationController
private
def fetch_graph
- @commits = @project.repository.commits(@ref, nil, 6000, 0, true)
+ @commits = @project.repository.commits(@ref, limit: 6000, skip_merges: true)
@log = []
@commits.each do |commit|
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 059b88e2253..352bff19383 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -8,6 +8,13 @@ class RegistrationsController < Devise::RegistrationsController
def create
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
+ # To avoid duplicate form fields on the login page, the registration form
+ # names fields using `new_user`, but Devise still wants the params in
+ # `user`.
+ if params["new_#{resource_name}"].present? && params[resource_name].blank?
+ params[resource_name] = params.delete(:"new_#{resource_name}")
+ end
+
super
else
flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code."
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 474c6f27374..93241b3afb7 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -131,7 +131,7 @@ module BlobHelper
# elements and attributes. Note that this whitelist is by no means complete
# and may omit some elements.
def sanitize_svg(blob)
- blob.data = Loofah.scrub_fragment(blob.data, :strip).to_xml
+ blob.data = Gitlab::Sanitizers::SVG.clean(blob.data)
blob
end
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 5d86bd490a8..3aa41030453 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -34,10 +34,13 @@ module NavHelper
end
def nav_header_class
- if nav_menu_collapsed?
- "header-collapsed"
- else
- "header-expanded"
- end
+ class_name =
+ if nav_menu_collapsed?
+ "header-collapsed"
+ else
+ "header-expanded"
+ end
+ class_name += " with-horizontal-nav" if defined?(nav) && nav
+ class_name
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 3d5e61d2c18..85f8854d2eb 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -200,16 +200,13 @@ module ProjectsHelper
end
def repository_size(project = @project)
- "#{project.repository_size} MB"
- rescue
- # In order to prevent 500 error
- # when application cannot allocate memory
- # to calculate repo size - just show 'Unknown'
- 'unknown'
+ size_in_bytes = project.repository_size * 1.megabyte
+ number_to_human_size(size_in_bytes, delimiter: ',', precision: 2)
end
def default_url_to_repo(project = @project)
- if default_clone_protocol == "ssh"
+ case default_clone_protocol
+ when 'ssh'
project.ssh_url_to_repo
else
project.http_url_to_repo
@@ -341,4 +338,10 @@ module ProjectsHelper
)
end
end
+
+ def sanitize_repo_path(message)
+ return '' unless message.present?
+
+ message.strip.gsub(Gitlab.config.gitlab_shell.repos_path.chomp('/'), "[REPOS PATH]")
+ end
end
diff --git a/app/models/appearance.rb b/app/models/appearance.rb
index 4cf8dd9a8ce..4528760fefa 100644
--- a/app/models/appearance.rb
+++ b/app/models/appearance.rb
@@ -1,3 +1,16 @@
+# == Schema Information
+#
+# Table name: appearances
+#
+# id :integer not null, primary key
+# title :string
+# description :text
+# header_logo :string
+# logo :string
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
class Appearance < ActiveRecord::Base
validates :title, presence: true
validates :description, presence: true
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 36f88154232..72ec91d2909 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -10,21 +10,20 @@
# sign_in_text :text
# created_at :datetime
# updated_at :datetime
-# home_page_url :string(255)
+# home_page_url :string
# default_branch_protection :integer default(2)
# restricted_visibility_levels :text
# version_check_enabled :boolean default(TRUE)
# max_attachment_size :integer default(10), not null
# default_project_visibility :integer
# default_snippet_visibility :integer
-# default_group_visibility :integer
# restricted_signup_domains :text
# user_oauth_applications :boolean default(TRUE)
-# after_sign_out_path :string(255)
+# after_sign_out_path :string
# session_expire_delay :integer default(10080), not null
# import_sources :text
# help_page_text :text
-# admin_notification_email :string(255)
+# admin_notification_email :string
# shared_runners_enabled :boolean default(TRUE), not null
# max_artifacts_size :integer default(100), not null
# runners_registration_token :string
@@ -32,8 +31,6 @@
# two_factor_grace_period :integer default(48)
# metrics_enabled :boolean default(FALSE)
# metrics_host :string default("localhost")
-# metrics_username :string
-# metrics_password :string
# metrics_pool_size :integer default(16)
# metrics_timeout :integer default(10)
# metrics_method_call_threshold :integer default(10)
@@ -41,9 +38,16 @@
# recaptcha_site_key :string
# recaptcha_private_key :string
# metrics_port :integer default(8089)
+# metrics_sample_interval :integer default(15)
# sentry_enabled :boolean default(FALSE)
# sentry_dsn :string
+# akismet_enabled :boolean default(FALSE)
+# akismet_api_key :string
# email_author_in_body :boolean default(FALSE)
+# default_group_visibility :integer
+# repository_checks_enabled :boolean default(FALSE)
+# metrics_packet_size :integer default(1)
+# shared_runners_text :text
#
class ApplicationSetting < ActiveRecord::Base
diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb
index 0ed0dd98a59..44b090260e7 100644
--- a/app/models/audit_event.rb
+++ b/app/models/audit_event.rb
@@ -4,9 +4,9 @@
#
# id :integer not null, primary key
# author_id :integer not null
-# type :string(255) not null
+# type :string not null
# entity_id :integer not null
-# entity_type :string(255) not null
+# entity_type :string not null
# details :text
# created_at :datetime
# updated_at :datetime
diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb
index 8a0a8a4c2a9..075ac733bfc 100644
--- a/app/models/broadcast_message.rb
+++ b/app/models/broadcast_message.rb
@@ -8,8 +8,8 @@
# ends_at :datetime
# created_at :datetime
# updated_at :datetime
-# color :string(255)
-# font :string(255)
+# color :string
+# font :string
#
class BroadcastMessage < ActiveRecord::Base
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 553cd447971..4bc3a225e2c 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -4,7 +4,7 @@
#
# id :integer not null, primary key
# project_id :integer
-# status :string(255)
+# status :string
# finished_at :datetime
# trace :text
# created_at :datetime
@@ -15,19 +15,19 @@
# commit_id :integer
# commands :text
# job_id :integer
-# name :string(255)
+# name :string
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
-# stage :string(255)
+# stage :string
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
-# ref :string(255)
+# ref :string
# user_id :integer
-# type :string(255)
-# target_url :string(255)
-# description :string(255)
+# type :string
+# target_url :string
+# description :string
# artifacts_file :text
# gl_project_id :integer
# artifacts_metadata :text
diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb
index f2667e5476b..4ac4e0fb8b2 100644
--- a/app/models/ci/commit.rb
+++ b/app/models/ci/commit.rb
@@ -4,9 +4,9 @@
#
# id :integer not null, primary key
# project_id :integer
-# ref :string(255)
-# sha :string(255)
-# before_sha :string(255)
+# ref :string
+# sha :string
+# before_sha :string
# push_data :text
# created_at :datetime
# updated_at :datetime
@@ -14,6 +14,10 @@
# yaml_errors :text
# committed_at :datetime
# gl_project_id :integer
+# status :string
+# started_at :datetime
+# finished_at :datetime
+# duration :integer
#
module Ci
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 90349a07594..add59a08892 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -3,18 +3,18 @@
# Table name: ci_runners
#
# id :integer not null, primary key
-# token :string(255)
+# token :string
# created_at :datetime
# updated_at :datetime
-# description :string(255)
+# description :string
# contacted_at :datetime
# active :boolean default(TRUE), not null
# is_shared :boolean default(FALSE)
-# name :string(255)
-# version :string(255)
-# revision :string(255)
-# platform :string(255)
-# architecture :string(255)
+# name :string
+# version :string
+# revision :string
+# platform :string
+# architecture :string
#
module Ci
diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb
index 2b9a457c8ab..4f3f4d79fac 100644
--- a/app/models/ci/trigger.rb
+++ b/app/models/ci/trigger.rb
@@ -3,7 +3,7 @@
# Table name: ci_triggers
#
# id :integer not null, primary key
-# token :string(255)
+# token :string
# project_id :integer
# deleted_at :datetime
# created_at :datetime
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index e786bd7dd93..4229fe085a1 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -4,11 +4,11 @@
#
# id :integer not null, primary key
# project_id :integer
-# key :string(255)
+# key :string
# value :text
# encrypted_value :text
-# encrypted_value_salt :string(255)
-# encrypted_value_iv :string(255)
+# encrypted_value_salt :string
+# encrypted_value_iv :string
# gl_project_id :integer
#
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index aa56314aa16..1260c448de3 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -4,7 +4,7 @@
#
# id :integer not null, primary key
# project_id :integer
-# status :string(255)
+# status :string
# finished_at :datetime
# trace :text
# created_at :datetime
@@ -15,21 +15,24 @@
# commit_id :integer
# commands :text
# job_id :integer
-# name :string(255)
+# name :string
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
-# stage :string(255)
+# stage :string
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
-# ref :string(255)
+# ref :string
# user_id :integer
-# type :string(255)
-# target_url :string(255)
-# description :string(255)
+# type :string
+# target_url :string
+# description :string
# artifacts_file :text
# gl_project_id :integer
+# artifacts_metadata :text
+# erased_by_id :integer
+# erased_at :datetime
#
class CommitStatus < ActiveRecord::Base
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index d5166e81474..7a3db742030 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -35,13 +35,14 @@ module Issuable
scope :only_opened, -> { with_state(:opened) }
scope :only_reopened, -> { with_state(:reopened) }
scope :closed, -> { with_state(:closed) }
- scope :order_milestone_due_desc, -> { joins(:milestone).reorder('milestones.due_date DESC, milestones.id DESC') }
- scope :order_milestone_due_asc, -> { joins(:milestone).reorder('milestones.due_date ASC, milestones.id ASC') }
+ scope :order_milestone_due_desc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date DESC, milestones.id DESC') }
+ scope :order_milestone_due_asc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date ASC, milestones.id ASC') }
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
scope :join_project, -> { joins(:project) }
scope :references_project, -> { references(:project) }
scope :non_archived, -> { join_project.where(projects: { archived: false }) }
+ scope :outer_join_milestone, -> { joins("LEFT OUTER JOIN milestones ON milestones.id = #{table_name}.milestone_id") }
delegate :name,
:email,
@@ -159,6 +160,10 @@ module Issuable
notes.awards.where(note: "thumbsup").count
end
+ def user_notes_count
+ notes.user.count
+ end
+
def subscribed_without_subscriptions?(user)
participants(user).include?(user)
end
diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb
index 9ab663c04ad..43cf625f770 100644
--- a/app/models/deploy_key.rb
+++ b/app/models/deploy_key.rb
@@ -7,9 +7,9 @@
# created_at :datetime
# updated_at :datetime
# key :text
-# title :string(255)
-# type :string(255)
-# fingerprint :string(255)
+# title :string
+# type :string
+# fingerprint :string
# public :boolean default(FALSE), not null
#
diff --git a/app/models/email.rb b/app/models/email.rb
index b323d1edd10..eae2472f337 100644
--- a/app/models/email.rb
+++ b/app/models/email.rb
@@ -4,7 +4,7 @@
#
# id :integer not null, primary key
# user_id :integer not null
-# email :string(255) not null
+# email :string not null
# created_at :datetime
# updated_at :datetime
#
diff --git a/app/models/event.rb b/app/models/event.rb
index 897518aadc7..25c7c3e6dc7 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -3,9 +3,9 @@
# Table name: events
#
# id :integer not null, primary key
-# target_type :string(255)
+# target_type :string
# target_id :integer
-# title :string(255)
+# title :string
# data :text
# project_id :integer
# created_at :datetime
diff --git a/app/models/generic_commit_status.rb b/app/models/generic_commit_status.rb
index 97f4f03a9a5..d4afd8cbe84 100644
--- a/app/models/generic_commit_status.rb
+++ b/app/models/generic_commit_status.rb
@@ -4,7 +4,7 @@
#
# id :integer not null, primary key
# project_id :integer
-# status :string(255)
+# status :string
# finished_at :datetime
# trace :text
# created_at :datetime
@@ -15,21 +15,24 @@
# commit_id :integer
# commands :text
# job_id :integer
-# name :string(255)
+# name :string
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
-# stage :string(255)
+# stage :string
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
-# ref :string(255)
+# ref :string
# user_id :integer
-# type :string(255)
-# target_url :string(255)
-# description :string(255)
+# type :string
+# target_url :string
+# description :string
# artifacts_file :text
# gl_project_id :integer
+# artifacts_metadata :text
+# erased_by_id :integer
+# erased_at :datetime
#
class GenericCommitStatus < CommitStatus
diff --git a/app/models/group.rb b/app/models/group.rb
index 1f8432e3320..cff76877958 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -2,16 +2,17 @@
#
# Table name: namespaces
#
-# id :integer not null, primary key
-# name :string(255) not null
-# path :string(255) not null
-# owner_id :integer
-# visibility_level :integer default(20), not null
-# created_at :datetime
-# updated_at :datetime
-# type :string(255)
-# description :string(255) default(""), not null
-# avatar :string(255)
+# id :integer not null, primary key
+# name :string not null
+# path :string not null
+# owner_id :integer
+# created_at :datetime
+# updated_at :datetime
+# type :string
+# description :string default(""), not null
+# avatar :string
+# share_with_group_lock :boolean default(FALSE)
+# visibility_level :integer default(20), not null
#
require 'carrierwave/orm/activerecord'
diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb
index d149511b868..2b8f34a0568 100644
--- a/app/models/hooks/project_hook.rb
+++ b/app/models/hooks/project_hook.rb
@@ -16,6 +16,7 @@
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
+# wiki_page_events :boolean default(FALSE), not null
# token :string
#
diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb
index f45145eeb3a..0e176de5ef8 100644
--- a/app/models/hooks/service_hook.rb
+++ b/app/models/hooks/service_hook.rb
@@ -16,6 +16,7 @@
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
+# wiki_page_events :boolean default(FALSE), not null
# token :string
#
diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb
index 012cc8ec005..ad508cbbcb8 100644
--- a/app/models/hooks/system_hook.rb
+++ b/app/models/hooks/system_hook.rb
@@ -16,6 +16,7 @@
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
+# wiki_page_events :boolean default(FALSE), not null
# token :string
#
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 1e3b4815596..8e58c9583ab 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -16,6 +16,7 @@
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
+# wiki_page_events :boolean default(FALSE), not null
# token :string
#
diff --git a/app/models/identity.rb b/app/models/identity.rb
index e1915b079d4..ef4d5f99091 100644
--- a/app/models/identity.rb
+++ b/app/models/identity.rb
@@ -3,8 +3,8 @@
# Table name: identities
#
# id :integer not null, primary key
-# extern_uid :string(255)
-# provider :string(255)
+# extern_uid :string
+# provider :string
# user_id :integer
# created_at :datetime
# updated_at :datetime
diff --git a/app/models/issue.rb b/app/models/issue.rb
index ea1bfb776ee..abaa509707c 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -3,20 +3,23 @@
# Table name: issues
#
# id :integer not null, primary key
-# title :string(255)
+# title :string
# assignee_id :integer
# author_id :integer
# project_id :integer
# created_at :datetime
# updated_at :datetime
# position :integer default(0)
-# branch_name :string(255)
+# branch_name :string
# description :text
# milestone_id :integer
-# state :string(255)
+# state :string
# iid :integer
# updated_by_id :integer
# moved_to_id :integer
+# confidential :boolean default(FALSE)
+# deleted_at :datetime
+# due_date :date
#
require 'carrierwave/orm/activerecord'
diff --git a/app/models/key.rb b/app/models/key.rb
index 0282ad18139..b2b57849f8a 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -7,9 +7,9 @@
# created_at :datetime
# updated_at :datetime
# key :text
-# title :string(255)
-# type :string(255)
-# fingerprint :string(255)
+# title :string
+# type :string
+# fingerprint :string
# public :boolean default(FALSE), not null
#
diff --git a/app/models/label.rb b/app/models/label.rb
index 60bdce32952..8a24a6e69b3 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -2,14 +2,14 @@
#
# Table name: labels
#
-# id :integer not null, primary key
-# title :string(255)
-# color :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# template :boolean default(FALSE)
-# description :string(255)
+# id :integer not null, primary key
+# title :string
+# color :string
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# template :boolean default(FALSE)
+# description :string
#
class Label < ActiveRecord::Base
@@ -117,6 +117,10 @@ class Label < ActiveRecord::Base
LabelsHelper::text_color_for_bg(self.color)
end
+ def title=(value)
+ write_attribute(:title, Sanitize.clean(value.to_s)) if value.present?
+ end
+
private
def label_format_reference(format = :id)
diff --git a/app/models/label_link.rb b/app/models/label_link.rb
index b94c9c777af..7b8e872b6dd 100644
--- a/app/models/label_link.rb
+++ b/app/models/label_link.rb
@@ -5,7 +5,7 @@
# id :integer not null, primary key
# label_id :integer
# target_id :integer
-# target_type :string(255)
+# target_type :string
# created_at :datetime
# updated_at :datetime
#
diff --git a/app/models/lfs_object.rb b/app/models/lfs_object.rb
index 86b1b7e2f99..927e764af92 100644
--- a/app/models/lfs_object.rb
+++ b/app/models/lfs_object.rb
@@ -3,11 +3,11 @@
# Table name: lfs_objects
#
# id :integer not null, primary key
-# oid :string(255) not null
+# oid :string not null
# size :integer not null
# created_at :datetime
# updated_at :datetime
-# file :string(255)
+# file :string
#
class LfsObject < ActiveRecord::Base
diff --git a/app/models/member.rb b/app/models/member.rb
index 60efafef211..cca82da89f1 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -5,15 +5,15 @@
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
-# source_type :string(255) not null
+# source_type :string not null
# user_id :integer
# notification_level :integer not null
-# type :string(255)
+# type :string
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
-# invite_email :string(255)
-# invite_token :string(255)
+# invite_email :string
+# invite_token :string
# invite_accepted_at :datetime
#
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index 9fb474a1a93..a48c1943e6f 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -5,15 +5,15 @@
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
-# source_type :string(255) not null
+# source_type :string not null
# user_id :integer
# notification_level :integer not null
-# type :string(255)
+# type :string
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
-# invite_email :string(255)
-# invite_token :string(255)
+# invite_email :string
+# invite_token :string
# invite_accepted_at :datetime
#
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 07ddb02ae9d..143350a0b55 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -5,15 +5,15 @@
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
-# source_type :string(255) not null
+# source_type :string not null
# user_id :integer
# notification_level :integer not null
-# type :string(255)
+# type :string
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
-# invite_email :string(255)
-# invite_token :string(255)
+# invite_email :string
+# invite_token :string
# invite_accepted_at :datetime
#
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index d00919c3b0c..4175e1e5fba 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -3,28 +3,29 @@
# Table name: merge_requests
#
# id :integer not null, primary key
-# target_branch :string(255) not null
-# source_branch :string(255) not null
+# target_branch :string not null
+# source_branch :string not null
# source_project_id :integer not null
# author_id :integer
# assignee_id :integer
-# title :string(255)
+# title :string
# created_at :datetime
# updated_at :datetime
# milestone_id :integer
-# state :string(255)
-# merge_status :string(255)
+# state :string
+# merge_status :string
# target_project_id :integer not null
# iid :integer
# description :text
# position :integer default(0)
# locked_at :datetime
# updated_by_id :integer
-# merge_error :string(255)
+# merge_error :string
# merge_params :text
# merge_when_build_succeeds :boolean default(FALSE), not null
# merge_user_id :integer
# merge_commit_sha :string
+# deleted_at :datetime
#
class MergeRequest < ActiveRecord::Base
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 0580cafdd1b..8951e92a0b8 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -3,12 +3,14 @@
# Table name: merge_request_diffs
#
# id :integer not null, primary key
-# state :string(255)
+# state :string
# st_commits :text
# st_diffs :text
# merge_request_id :integer not null
# created_at :datetime
# updated_at :datetime
+# base_commit_sha :string
+# real_size :string
#
class MergeRequestDiff < ActiveRecord::Base
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 986184dd301..b19935cad6f 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -3,13 +3,13 @@
# Table name: milestones
#
# id :integer not null, primary key
-# title :string(255) not null
+# title :string not null
# project_id :integer not null
# description :text
# due_date :date
# created_at :datetime
# updated_at :datetime
-# state :string(255)
+# state :string
# iid :integer
#
@@ -129,6 +129,10 @@ class Milestone < ActiveRecord::Base
nil
end
+ def title=(value)
+ write_attribute(:title, Sanitize.clean(value.to_s)) if value.present?
+ end
+
# Sorts the issues for the given IDs.
#
# This method runs a single SQL query using a CASE statement to update the
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 55842df1e2d..741e912171d 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -2,15 +2,17 @@
#
# Table name: namespaces
#
-# id :integer not null, primary key
-# name :string(255) not null
-# path :string(255) not null
-# owner_id :integer
-# created_at :datetime
-# updated_at :datetime
-# type :string(255)
-# description :string(255) default(""), not null
-# avatar :string(255)
+# id :integer not null, primary key
+# name :string not null
+# path :string not null
+# owner_id :integer
+# created_at :datetime
+# updated_at :datetime
+# type :string
+# description :string default(""), not null
+# avatar :string
+# share_with_group_lock :boolean default(FALSE)
+# visibility_level :integer default(20), not null
#
class Namespace < ActiveRecord::Base
diff --git a/app/models/note.rb b/app/models/note.rb
index 71b4293d57a..deee2b9e885 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -4,14 +4,14 @@
#
# id :integer not null, primary key
# note :text
-# noteable_type :string(255)
+# noteable_type :string
# author_id :integer
# created_at :datetime
# updated_at :datetime
# project_id :integer
-# attachment :string(255)
-# line_code :string(255)
-# commit_id :string(255)
+# attachment :string
+# line_code :string
+# commit_id :string
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index 5001738f411..846773752a6 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -1,3 +1,16 @@
+# == Schema Information
+#
+# Table name: notification_settings
+#
+# id :integer not null, primary key
+# user_id :integer not null
+# source_id :integer not null
+# source_type :string not null
+# level :integer default(0), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
class NotificationSetting < ActiveRecord::Base
enum level: { disabled: 0, participating: 1, watch: 2, global: 3, mention: 4 }
diff --git a/app/models/personal_snippet.rb b/app/models/personal_snippet.rb
index 452f3913eef..1d5f4c50254 100644
--- a/app/models/personal_snippet.rb
+++ b/app/models/personal_snippet.rb
@@ -3,14 +3,14 @@
# Table name: snippets
#
# id :integer not null, primary key
-# title :string(255)
+# title :string
# content :text
# author_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
-# file_name :string(255)
-# type :string(255)
+# file_name :string
+# type :string
# visibility_level :integer default(0), not null
#
diff --git a/app/models/project.rb b/app/models/project.rb
index af62e8ecd90..05e14185a3e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2,41 +2,45 @@
#
# Table name: projects
#
-# id :integer not null, primary key
-# name :string(255)
-# path :string(255)
-# description :text
-# created_at :datetime
-# updated_at :datetime
-# creator_id :integer
-# issues_enabled :boolean default(TRUE), not null
-# wall_enabled :boolean default(TRUE), not null
-# merge_requests_enabled :boolean default(TRUE), not null
-# wiki_enabled :boolean default(TRUE), not null
-# namespace_id :integer
-# issues_tracker :string(255) default("gitlab"), not null
-# issues_tracker_id :string(255)
-# snippets_enabled :boolean default(TRUE), not null
-# last_activity_at :datetime
-# import_url :string(255)
-# visibility_level :integer default(0), not null
-# archived :boolean default(FALSE), not null
-# avatar :string(255)
-# import_status :string(255)
-# repository_size :float default(0.0)
-# star_count :integer default(0), not null
-# import_type :string(255)
-# import_source :string(255)
-# commit_count :integer default(0)
-# import_error :text
-# ci_id :integer
-# builds_enabled :boolean default(TRUE), not null
-# shared_runners_enabled :boolean default(TRUE), not null
-# runners_token :string
-# build_coverage_regex :string
-# build_allow_git_fetch :boolean default(TRUE), not null
-# build_timeout :integer default(3600), not null
-# pending_delete :boolean
+# id :integer not null, primary key
+# name :string
+# path :string
+# description :text
+# created_at :datetime
+# updated_at :datetime
+# creator_id :integer
+# issues_enabled :boolean default(TRUE), not null
+# merge_requests_enabled :boolean default(TRUE), not null
+# wiki_enabled :boolean default(TRUE), not null
+# namespace_id :integer
+# issues_tracker :string default("gitlab"), not null
+# issues_tracker_id :string
+# snippets_enabled :boolean default(TRUE), not null
+# last_activity_at :datetime
+# import_url :string
+# visibility_level :integer default(0), not null
+# archived :boolean default(FALSE), not null
+# avatar :string
+# import_status :string
+# repository_size :float default(0.0)
+# star_count :integer default(0), not null
+# import_type :string
+# import_source :string
+# commit_count :integer default(0)
+# import_error :text
+# ci_id :integer
+# builds_enabled :boolean default(TRUE), not null
+# shared_runners_enabled :boolean default(TRUE), not null
+# runners_token :string
+# build_coverage_regex :string
+# build_allow_git_fetch :boolean default(TRUE), not null
+# build_timeout :integer default(3600), not null
+# pending_delete :boolean default(FALSE)
+# public_builds :boolean default(TRUE), not null
+# main_language :string
+# pushes_since_gc :integer default(0)
+# last_repository_check_failed :boolean
+# last_repository_check_at :datetime
#
require 'carrierwave/orm/activerecord'
@@ -62,7 +66,6 @@ class Project < ActiveRecord::Base
default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests
default_value_for :builds_enabled, gitlab_config_features.builds
default_value_for :wiki_enabled, gitlab_config_features.wiki
- default_value_for :wall_enabled, false
default_value_for :snippets_enabled, gitlab_config_features.snippets
default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
@@ -762,7 +765,7 @@ class Project < ActiveRecord::Base
# Check if current branch name is marked as protected in the system
def protected_branch?(branch_name)
- protected_branches.where(name: branch_name).any?
+ protected_branch_names.include?(branch_name)
end
def developers_can_push_to_protected_branch?(branch_name)
@@ -1034,4 +1037,11 @@ class Project < ActiveRecord::Base
def wiki
@wiki ||= ProjectWiki.new(self, self.owner)
end
+
+ def schedule_delete!(user_id, params)
+ # Queue this task for after the commit, so once we mark pending_delete it will run
+ run_after_commit { ProjectDestroyWorker.perform_async(id, user_id, params) }
+
+ update_attribute(:pending_delete, true)
+ end
end
diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb
index e52a6bd7c84..66f5a609bf5 100644
--- a/app/models/project_group_link.rb
+++ b/app/models/project_group_link.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: project_group_links
+#
+# id :integer not null, primary key
+# project_id :integer not null
+# group_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# group_access :integer default(30), not null
+#
+
class ProjectGroupLink < ActiveRecord::Base
GUEST = 10
REPORTER = 20
diff --git a/app/models/project_import_data.rb b/app/models/project_import_data.rb
index 2c0ae312f1b..7830f764ed3 100644
--- a/app/models/project_import_data.rb
+++ b/app/models/project_import_data.rb
@@ -2,9 +2,12 @@
#
# Table name: project_import_data
#
-# id :integer not null, primary key
-# project_id :integer
-# data :text
+# id :integer not null, primary key
+# project_id :integer
+# data :text
+# encrypted_credentials :text
+# encrypted_credentials_iv :string
+# encrypted_credentials_salt :string
#
require 'carrierwave/orm/activerecord'
diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb
index 792ad804575..368485a060a 100644
--- a/app/models/project_services/asana_service.rb
+++ b/app/models/project_services/asana_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
require 'asana'
diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb
index 29d841faed8..ffb7455b014 100644
--- a/app/models/project_services/assembla_service.rb
+++ b/app/models/project_services/assembla_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class AssemblaService < Service
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index 060062aaf7a..c36ee95e378 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class BambooService < CiService
diff --git a/app/models/project_services/buildkite_service.rb b/app/models/project_services/buildkite_service.rb
index 861cc974ec4..f9f4897a065 100644
--- a/app/models/project_services/buildkite_service.rb
+++ b/app/models/project_services/buildkite_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
require "addressable/uri"
diff --git a/app/models/project_services/builds_email_service.rb b/app/models/project_services/builds_email_service.rb
index 6ab6d7417b7..20cdfcaffb2 100644
--- a/app/models/project_services/builds_email_service.rb
+++ b/app/models/project_services/builds_email_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class BuildsEmailService < Service
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
index 6e8f0842524..28c969fe57f 100644
--- a/app/models/project_services/campfire_service.rb
+++ b/app/models/project_services/campfire_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class CampfireService < Service
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index d9f0849d147..9bc8f982da6 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
# Base class for CI services
diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb
index 88a3e9218cb..4d1319eb6f8 100644
--- a/app/models/project_services/custom_issue_tracker_service.rb
+++ b/app/models/project_services/custom_issue_tracker_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class CustomIssueTrackerService < IssueTrackerService
diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb
index b4724bb647e..d8e00e018cc 100644
--- a/app/models/project_services/drone_ci_service.rb
+++ b/app/models/project_services/drone_ci_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class DroneCiService < CiService
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index b831577cd97..2dbd29062df 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class EmailsOnPushService < Service
diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb
index b402b68665a..5469049bb5e 100644
--- a/app/models/project_services/external_wiki_service.rb
+++ b/app/models/project_services/external_wiki_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class ExternalWikiService < Service
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 8605ce66e48..3dc1e0fbe8b 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
require "flowdock-git-hook"
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
index 61babe9cfe5..b4c311cf664 100644
--- a/app/models/project_services/gemnasium_service.rb
+++ b/app/models/project_services/gemnasium_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
require "gemnasium/gitlab_service"
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 33f0d7ea01a..a92f7226083 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
# TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index eaa5654b9c6..1adaeeb3b2b 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class GitlabIssueTrackerService < IssueTrackerService
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 064ef8e8674..f9ddf588722 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class HipchatService < Service
diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb
index 04c714bfaad..b9a592d7096 100644
--- a/app/models/project_services/irker_service.rb
+++ b/app/models/project_services/irker_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
require 'uri'
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index c5501e06411..98a3a7c6b86 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class IssueTrackerService < Service
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index b4418ba9284..ba68658f0bd 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class JiraService < IssueTrackerService
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index c9a890c7e3f..acaa0c39365 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class PivotaltrackerService < Service
diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb
index e76d9eca2ab..a640c8cb440 100644
--- a/app/models/project_services/pushover_service.rb
+++ b/app/models/project_services/pushover_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class PushoverService < Service
diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb
index de974354c77..e2137e92c62 100644
--- a/app/models/project_services/redmine_service.rb
+++ b/app/models/project_services/redmine_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class RedmineService < IssueTrackerService
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index 7092b757549..83ffa53a407 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class SlackService < Service
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index 8dceee5e2c5..4015da31509 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
class TeamcityService < CiService
diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb
index d48f0546159..b4b2807eba4 100644
--- a/app/models/project_snippet.rb
+++ b/app/models/project_snippet.rb
@@ -3,14 +3,14 @@
# Table name: snippets
#
# id :integer not null, primary key
-# title :string(255)
+# title :string
# content :text
# author_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
-# file_name :string(255)
-# type :string(255)
+# file_name :string
+# type :string
# visibility_level :integer default(0), not null
#
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index 7c1a61bb0bf..c91cb70ae25 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -40,7 +40,7 @@ class ProjectWiki
end
def wiki_base_path
- ["/", @project.path_with_namespace, "/wikis"].join('')
+ [Gitlab.config.gitlab.url, "/", @project.path_with_namespace, "/wikis"].join('')
end
# Returns the Gollum::Wiki object.
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
index 8ebd790a89e..3d2052c892c 100644
--- a/app/models/protected_branch.rb
+++ b/app/models/protected_branch.rb
@@ -4,7 +4,7 @@
#
# id :integer not null, primary key
# project_id :integer not null
-# name :string(255) not null
+# name :string not null
# created_at :datetime
# updated_at :datetime
# developers_can_push :boolean default(FALSE), not null
diff --git a/app/models/release.rb b/app/models/release.rb
index 89f70278af5..dc700d1ea5a 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -3,7 +3,7 @@
# Table name: releases
#
# id :integer not null, primary key
-# tag :string(255)
+# tag :string
# description :text
# project_id :integer
# created_at :datetime
diff --git a/app/models/repository.rb b/app/models/repository.rb
index b4319297e43..7aebfe279fb 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -87,13 +87,15 @@ class Repository
nil
end
- def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false)
+ def commits(ref, path: nil, limit: nil, offset: nil, skip_merges: false, after: nil, before: nil)
options = {
repo: raw_repository,
ref: ref,
path: path,
limit: limit,
offset: offset,
+ after: after,
+ before: before,
# --follow doesn't play well with --skip. See:
# https://gitlab.com/gitlab-org/gitlab-ce/issues/3574#note_3040520
follow: false,
@@ -146,10 +148,20 @@ class Repository
find_branch(branch_name)
end
- def add_tag(tag_name, ref, message = nil)
- before_push_tag
+ def add_tag(user, tag_name, target, message = nil)
+ oldrev = Gitlab::Git::BLANK_SHA
+ ref = Gitlab::Git::TAG_REF_PREFIX + tag_name
+ target = commit(target).try(:id)
+
+ return false unless target
+
+ options = { message: message, tagger: user_to_committer(user) } if message
+
+ GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do
+ rugged.tags.create(tag_name, target, options)
+ end
- gitlab_shell.add_tag(path_with_namespace, tag_name, ref, message)
+ find_tag(tag_name)
end
def rm_branch(user, branch_name)
@@ -575,7 +587,7 @@ class Repository
end
def contributors
- commits = self.commits(nil, nil, 2000, 0, true)
+ commits = self.commits(nil, limit: 2000, offset: 0, skip_merges: true)
commits.group_by(&:author_email).map do |email, commits|
contributor = Gitlab::Contributor.new
diff --git a/app/models/security_event.rb b/app/models/security_event.rb
index 68c00adad59..0bee03974f1 100644
--- a/app/models/security_event.rb
+++ b/app/models/security_event.rb
@@ -4,9 +4,9 @@
#
# id :integer not null, primary key
# author_id :integer not null
-# type :string(255) not null
+# type :string not null
# entity_id :integer not null
-# entity_type :string(255) not null
+# entity_type :string not null
# details :text
# created_at :datetime
# updated_at :datetime
diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb
index 77115597d71..99279a2e083 100644
--- a/app/models/sent_notification.rb
+++ b/app/models/sent_notification.rb
@@ -5,11 +5,11 @@
# id :integer not null, primary key
# project_id :integer
# noteable_id :integer
-# noteable_type :string(255)
+# noteable_type :string
# recipient_id :integer
-# commit_id :string(255)
-# line_code :string(255)
-# reply_key :string(255) not null
+# commit_id :string
+# reply_key :string not null
+# line_code :string
#
class SentNotification < ActiveRecord::Base
diff --git a/app/models/service.rb b/app/models/service.rb
index 2645b8321d7..bf16a545307 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -3,12 +3,12 @@
# Table name: services
#
# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
+# type :string
+# title :string
# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
@@ -17,6 +17,9 @@
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
+# category :string default("common"), not null
+# default :boolean default(FALSE)
+# wiki_page_events :boolean default(TRUE)
#
# To add new service you should build a class inherited from Service
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 0fd08061925..2f905a90942 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -3,14 +3,14 @@
# Table name: snippets
#
# id :integer not null, primary key
-# title :string(255)
+# title :string
# content :text
# author_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
-# file_name :string(255)
-# type :string(255)
+# file_name :string
+# type :string
# visibility_level :integer default(0), not null
#
diff --git a/app/models/spam_log.rb b/app/models/spam_log.rb
index 12df68ef83b..f49eb7d88e2 100644
--- a/app/models/spam_log.rb
+++ b/app/models/spam_log.rb
@@ -1,3 +1,20 @@
+# == Schema Information
+#
+# Table name: spam_logs
+#
+# id :integer not null, primary key
+# user_id :integer
+# source_ip :string
+# user_agent :string
+# via_api :boolean
+# project_id :integer
+# noteable_type :string
+# title :string
+# description :text
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
class SpamLog < ActiveRecord::Base
belongs_to :user
diff --git a/app/models/subscription.rb b/app/models/subscription.rb
index dd800ce110f..242faa7d32e 100644
--- a/app/models/subscription.rb
+++ b/app/models/subscription.rb
@@ -5,7 +5,7 @@
# id :integer not null, primary key
# user_id :integer
# subscribable_id :integer
-# subscribable_type :string(255)
+# subscribable_type :string
# subscribed :boolean
# created_at :datetime
# updated_at :datetime
diff --git a/app/models/user.rb b/app/models/user.rb
index b6f405c6981..56d6de610f0 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -3,55 +3,55 @@
# Table name: users
#
# id :integer not null, primary key
-# email :string(255) default(""), not null
-# encrypted_password :string(255) default(""), not null
-# reset_password_token :string(255)
+# email :string default(""), not null
+# encrypted_password :string default(""), not null
+# reset_password_token :string
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0)
# current_sign_in_at :datetime
# last_sign_in_at :datetime
-# current_sign_in_ip :string(255)
-# last_sign_in_ip :string(255)
+# current_sign_in_ip :string
+# last_sign_in_ip :string
# created_at :datetime
# updated_at :datetime
-# name :string(255)
+# name :string
# admin :boolean default(FALSE), not null
# projects_limit :integer default(10)
-# skype :string(255) default(""), not null
-# linkedin :string(255) default(""), not null
-# twitter :string(255) default(""), not null
-# authentication_token :string(255)
+# skype :string default(""), not null
+# linkedin :string default(""), not null
+# twitter :string default(""), not null
+# authentication_token :string
# theme_id :integer default(1), not null
-# bio :string(255)
+# bio :string
# failed_attempts :integer default(0)
# locked_at :datetime
-# username :string(255)
+# username :string
# can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null
-# state :string(255)
+# state :string
# color_scheme_id :integer default(1), not null
# notification_level :integer default(1), not null
# password_expires_at :datetime
# created_by_id :integer
# last_credential_check_at :datetime
-# avatar :string(255)
-# confirmation_token :string(255)
+# avatar :string
+# confirmation_token :string
# confirmed_at :datetime
# confirmation_sent_at :datetime
-# unconfirmed_email :string(255)
+# unconfirmed_email :string
# hide_no_ssh_key :boolean default(FALSE)
-# website_url :string(255) default(""), not null
-# notification_email :string(255)
+# website_url :string default(""), not null
+# notification_email :string
# hide_no_password :boolean default(FALSE)
# password_automatically_set :boolean default(FALSE)
-# location :string(255)
-# encrypted_otp_secret :string(255)
-# encrypted_otp_secret_iv :string(255)
-# encrypted_otp_secret_salt :string(255)
+# location :string
+# encrypted_otp_secret :string
+# encrypted_otp_secret_iv :string
+# encrypted_otp_secret_salt :string
# otp_required_for_login :boolean default(FALSE), not null
# otp_backup_codes :text
-# public_email :string(255) default(""), not null
+# public_email :string default(""), not null
# dashboard :integer default(0)
# project_view :integer default(0)
# consumed_timestep :integer
@@ -59,7 +59,8 @@
# hide_project_limit :boolean default(FALSE)
# unlock_token :string
# otp_grace_period_started_at :datetime
-# external :boolean default(FALSE)
+# ldap_email :boolean default(FALSE), not null
+# external :boolean default(FALSE)
#
require 'carrierwave/orm/activerecord'
@@ -85,13 +86,13 @@ class User < ActiveRecord::Base
default_value_for :theme_id, gitlab_config.default_theme
devise :two_factor_authenticatable,
- otp_secret_encryption_key: File.read(Rails.root.join('.secret')).chomp
+ otp_secret_encryption_key: Gitlab::Application.config.secret_key_base
alias_attribute :two_factor_enabled, :otp_required_for_login
devise :two_factor_backupable, otp_number_of_backup_codes: 10
serialize :otp_backup_codes, JSON
- devise :lockable, :recoverable, :rememberable, :trackable,
+ devise :lockable, :async, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable
attr_accessor :force_random_password
diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb
index 707c2f7ff85..9f4481a8153 100644
--- a/app/services/create_branch_service.rb
+++ b/app/services/create_branch_service.rb
@@ -43,9 +43,4 @@ class CreateBranchService < BaseService
out[:branch] = branch
out
end
-
- def build_push_data(project, user, branch)
- Gitlab::PushDataBuilder.
- build(project, user, Gitlab::Git::BLANK_SHA, branch.target, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}", [])
- end
end
diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb
index 55985380d31..91ed0e354d0 100644
--- a/app/services/create_tag_service.rb
+++ b/app/services/create_tag_service.rb
@@ -1,50 +1,30 @@
require_relative 'base_service'
class CreateTagService < BaseService
- def execute(tag_name, ref, message, release_description = nil)
+ def execute(tag_name, target, message, release_description = nil)
valid_tag = Gitlab::GitRefValidator.validate(tag_name)
- if valid_tag == false
- return error('Tag name invalid')
- end
+ return error('Tag name invalid') unless valid_tag
repository = project.repository
- existing_tag = repository.find_tag(tag_name)
- if existing_tag
- return error('Tag already exists')
- end
-
message.strip! if message
- repository.add_tag(tag_name, ref, message)
- new_tag = repository.find_tag(tag_name)
+ new_tag = nil
+ begin
+ new_tag = repository.add_tag(current_user, tag_name, target, message)
+ rescue Rugged::TagError
+ return error("Tag #{tag_name} already exists")
+ rescue GitHooksService::PreReceiveError
+ return error('Tag creation was rejected by Git hook')
+ end
if new_tag
- push_data = create_push_data(project, current_user, new_tag)
- EventCreateService.new.push(project, current_user, push_data)
- project.execute_hooks(push_data.dup, :tag_push_hooks)
- project.execute_services(push_data.dup, :tag_push_hooks)
- CreateCommitBuildsService.new.execute(project, current_user, push_data)
-
if release_description
CreateReleaseService.new(@project, @current_user).
execute(tag_name, release_description)
end
-
- success(new_tag)
+ success.merge(tag: new_tag)
else
- error('Invalid reference name')
+ error("Target #{target} is invalid")
end
end
-
- def success(branch)
- out = super()
- out[:tag] = branch
- out
- end
-
- def create_push_data(project, user, tag)
- commits = [project.commit(tag.target)].compact
- Gitlab::PushDataBuilder.
- build(project, user, Gitlab::Git::BLANK_SHA, tag.target, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", commits, tag.message)
- end
end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index b7af80055bf..66136b62617 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -17,6 +17,7 @@ class GitPushService < BaseService
# 6. Checks if the project's main language has changed
#
def execute
+ @project.repository.after_create if @project.empty_repo?
@project.repository.after_push_commit(branch_name, params[:newrev])
if push_remove_branch?
diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb
index 64271d8bc5c..7410442609d 100644
--- a/app/services/git_tag_push_service.rb
+++ b/app/services/git_tag_push_service.rb
@@ -2,6 +2,7 @@ class GitTagPushService < BaseService
attr_accessor :push_data
def execute
+ project.repository.after_create if project.empty_repo?
project.repository.before_push_tag
@push_data = build_push_data
diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb
index 82e7090f1ea..e61628086f0 100644
--- a/app/services/issues/move_service.rb
+++ b/app/services/issues/move_service.rb
@@ -41,14 +41,25 @@ module Issues
private
def create_new_issue
- new_params = { id: nil, iid: nil, label_ids: [], milestone: nil,
+ new_params = { id: nil, iid: nil, label_ids: cloneable_label_ids,
+ milestone_id: cloneable_milestone_id,
project: @new_project, author: @old_issue.author,
description: rewrite_content(@old_issue.description) }
- new_params = @old_issue.serializable_hash.merge(new_params)
+ new_params = @old_issue.serializable_hash.symbolize_keys.merge(new_params)
CreateService.new(@new_project, @current_user, new_params).execute
end
+ def cloneable_label_ids
+ @new_project.labels
+ .where(title: @old_issue.labels.pluck(:title)).pluck(:id)
+ end
+
+ def cloneable_milestone_id
+ @new_project.milestones
+ .find_by(title: @old_issue.milestone.try(:title)).try(:id)
+ end
+
def rewrite_notes
@old_issue.notes.find_each do |note|
new_note = note.dup
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index 3544752d47a..cd4230aa5e4 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -41,21 +41,45 @@ module MergeRequests
merge_request.can_be_created = false
end
+ set_title_and_description(merge_request)
+ end
+
+ private
+
+ # When your branch name starts with an iid followed by a dash this pattern will be
+ # interpreted as the user wants to close that issue on this project.
+ #
+ # For example:
+ # - Issue 112 exists, title: Emoji don't show up in commit title
+ # - Source branch is: 112-fix-mep-mep
+ #
+ # Will lead to:
+ # - Appending `Closes #112` to the description
+ # - Setting the title as 'Resolves "Emoji don't show up in commit title"' if there is
+ # more than one commit in the MR
+ #
+ def set_title_and_description(merge_request)
+ if match = merge_request.source_branch.match(/\A(\d+)-/)
+ iid = match[1]
+ end
+
commits = merge_request.compare_commits
if commits && commits.count == 1
commit = commits.first
merge_request.title = commit.title
merge_request.description ||= commit.description.try(:strip)
+ elsif iid && (issue = merge_request.target_project.get_issue(iid)) && !issue.try(:confidential?)
+ case issue
+ when Issue
+ merge_request.title = "Resolve \"#{issue.title}\""
+ when ExternalIssue
+ merge_request.title = "Resolve #{issue.title}"
+ end
else
merge_request.title = merge_request.source_branch.titleize.humanize
end
- # When your branch name starts with an iid followed by a dash this pattern will
- # be interpreted as the use wants to close that issue on this project
- # Pattern example: 112-fix-mep-mep
- # Will lead to appending `Closes #112` to the description
- if match = merge_request.source_branch.match(/\A(\d+)-/)
- iid = match[1]
+ if iid
closes_issue = "Closes ##{iid}"
if merge_request.description.present?
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index df5054f08d7..19aab999e00 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -7,9 +7,7 @@ module Projects
DELETED_FLAG = '+deleted'
def pending_delete!
- project.update_attribute(:pending_delete, true)
-
- ProjectDestroyWorker.perform_in(1.minute, project.id, current_user.id, params)
+ project.schedule_delete!(current_user.id, params)
end
def execute
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 82a0e2fd1f5..4bdb1b0c074 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -351,7 +351,7 @@ class SystemNoteService
# Returns an Array of Strings
def self.new_commit_summary(new_commits)
new_commits.collect do |commit|
- "* #{commit.short_id} - #{commit.title}"
+ "* #{commit.short_id} - #{escape_html(commit.title)}"
end
end
@@ -433,4 +433,8 @@ class SystemNoteService
body = "Moved #{direction} #{cross_reference}"
create_note(noteable: noteable, project: project, author: author, note: body)
end
+
+ def self.escape_html(text)
+ Rack::Utils.escape_html(text)
+ end
end
diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml
index 3571eefd570..967151bc33b 100644
--- a/app/views/admin/builds/_build.html.haml
+++ b/app/views/admin/builds/_build.html.haml
@@ -35,15 +35,15 @@
%td
#{build.stage} / #{build.name}
- .pull-right
- - if build.tags.any?
- - build.tags.each do |tag|
- %span.label.label-primary
- = tag
- - if build.try(:trigger_request)
- %span.label.label-info triggered
- - if build.try(:allow_failure)
- %span.label.label-danger allowed to fail
+ %td
+ - if build.tags.any?
+ - build.tags.each do |tag|
+ %span.label.label-primary
+ = tag
+ - if build.try(:trigger_request)
+ %span.label.label-info triggered
+ - if build.try(:allow_failure)
+ %span.label.label-danger allowed to fail
%td.duration
- if build.duration
@@ -61,12 +61,12 @@
%td
.pull-right
- if can?(current_user, :read_build, project) && build.artifacts?
- = link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts' do
+ = link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts', class: 'btn btn-build' do
%i.fa.fa-download
- if can?(current_user, :update_build, build.project)
- if build.active?
- = link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel' do
+ = link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && build.retryable?
- = link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry' do
- %i.fa.fa-repeat
+ = link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
+ %i.fa.fa-refresh
diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml
index 5931efdefe6..804d7851bdb 100644
--- a/app/views/admin/builds/index.html.haml
+++ b/app/views/admin/builds/index.html.haml
@@ -19,7 +19,7 @@
- if @all_builds.running_or_pending.any?
= link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
-.gray-content-block.second-block
+.row-content-block.second-block
#{(@scope || 'running').capitalize} builds
%ul.content-list
@@ -38,6 +38,7 @@
%th Ref
%th Runner
%th Name
+ %th Tags
%th Duration
%th Finished at
%th
diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml
index 4b475a4d8fa..698feb571ac 100644
--- a/app/views/admin/logs/show.html.haml
+++ b/app/views/admin/logs/show.html.haml
@@ -7,7 +7,7 @@
%li{ class: (klass == Gitlab::GitLogger ? 'active' : '') }
= link_to klass::file_name, "##{klass::file_name_noext}",
'data-toggle' => 'tab'
-.gray-content-block
+.row-content-block
To prevent performance issues admin logs output the last 2000 lines
.tab-content
- loggers.each do |klass|
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 0ee8dc962b9..d6743081c8e 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -32,7 +32,7 @@
Without projects
%small.badge= number_with_delimiter(User.without_projects.count)
- .gray-content-block.second-block
+ .row-content-block.second-block
.pull-right
.dropdown.inline
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 49ab8aad1d5..fc42e5dcc66 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -8,14 +8,14 @@
= link_to todos_filter_path(state: 'pending') do
%span
To do
- %span{class: 'badge'}
+ %span.badge
= todos_pending_count
- todo_done_active = ('active' if params[:state] == 'done')
%li{class: "todos-done #{todo_done_active}"}
= link_to todos_filter_path(state: 'done') do
%span
Done
- %span{class: 'badge'}
+ %span.badge
= todos_done_count
.nav-controls
@@ -25,7 +25,7 @@
= icon('spinner spin')
.todos-filters
- .gray-content-block.second-block
+ .row-content-block.second-block
= form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form' do
.filter-item.inline
= select_tag('project_id', todo_projects_options,
diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml
index 22b2c1a186b..c9d1e454a5e 100644
--- a/app/views/devise/sessions/two_factor.html.haml
+++ b/app/views/devise/sessions/two_factor.html.haml
@@ -4,7 +4,7 @@
%h3 Two-factor Authentication
.login-body
= form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f|
- = f.text_field :otp_attempt, class: 'form-control', placeholder: 'Two-factor authentication code', required: true, autofocus: true
- %p.help-block.hint If you've lost your phone, you may enter one of your recovery codes.
+ = f.text_field :otp_attempt, class: 'form-control', placeholder: 'Two-factor Authentication code', required: true, autofocus: true
+ %p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.
.prepend-top-20
= f.submit "Verify code", class: "btn btn-save"
diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml
index e5607dacd0d..510215bb8cd 100644
--- a/app/views/devise/shared/_signup_box.html.haml
+++ b/app/views/devise/shared/_signup_box.html.haml
@@ -6,7 +6,7 @@
.login-heading
%h3 Create an account
.login-body
- = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
+ = form_for(resource, as: "new_#{resource_name}", url: registration_path(resource_name)) do |f|
.devise-errors
= devise_error_messages!
%div
@@ -16,7 +16,7 @@
%div
= f.email_field :email, class: "form-control middle", placeholder: "Email", required: true
.form-group.append-bottom-20#password-strength
- = f.password_field :password, class: "form-control bottom", id: "user_password_sign_up", placeholder: "Password", required: true
+ = f.password_field :password, class: "form-control bottom", placeholder: "Password", required: true
%div
- if current_application_settings.recaptcha_enabled
= recaptcha_tags
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 5d622582088..e4629bae0e6 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -5,7 +5,7 @@
= cache [event, current_application_settings, "v2.2"] do
- if event.author
- = link_to user_path(event.author.username) do
+ = link_to user_path(event.author) do
= image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:''
- else
= image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:''
diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml
index 5753158c24d..a1a282178e7 100644
--- a/app/views/events/_event_last_push.html.haml
+++ b/app/views/events/_event_last_push.html.haml
@@ -1,5 +1,5 @@
- if show_last_push_widget?(event)
- .gray-content-block.clear-block.last-push-widget
+ .row-content-block.clear-block.last-push-widget
.event-last-push
.event-last-push-text
%span You pushed to
diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml
index 8ffca96bb4e..57f6e7e0612 100644
--- a/app/views/explore/groups/index.html.haml
+++ b/app/views/explore/groups/index.html.haml
@@ -6,7 +6,7 @@
- else
= render 'explore/head'
-.gray-content-block.clearfix
+.row-content-block.clearfix
.pull-left
= form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f|
= hidden_field_tag :sort, @sort
diff --git a/app/views/explore/snippets/index.html.haml b/app/views/explore/snippets/index.html.haml
index 0f100c39ffb..9b838b9f3b7 100644
--- a/app/views/explore/snippets/index.html.haml
+++ b/app/views/explore/snippets/index.html.haml
@@ -6,7 +6,7 @@
- else
= render 'explore/head'
-.gray-content-block
+.row-content-block
- if current_user
.pull-right
= link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do
diff --git a/app/views/groups/activity.html.haml b/app/views/groups/activity.html.haml
index f73e1d9e865..aaad265b3ee 100644
--- a/app/views/groups/activity.html.haml
+++ b/app/views/groups/activity.html.haml
@@ -3,7 +3,6 @@
= auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity")
- page_title "Activity"
-- header_title group_title(@group, "Activity", activity_group_path(@group))
%section.activities
= render 'activities'
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index a698cbbe9db..92cd4c553d0 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -1,5 +1,3 @@
-- header_title group_title(@group, "Settings", edit_group_path(@group))
-
.panel.panel-default.prepend-top-default
.panel-heading
Group settings
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index 6b7fd5746d6..0eb6bbd4420 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -1,5 +1,4 @@
- page_title "Members"
-- header_title group_title(@group, "Members", group_group_members_path(@group))
.group-members-page.prepend-top-default
- if current_user && current_user.can?(:admin_group_member, @group)
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index aea35c50862..4434f1cbd35 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -1,5 +1,4 @@
- page_title "Issues"
-- header_title group_title(@group, "Issues", issues_group_path(@group))
= content_for :meta_tags do
- if current_user
= auto_discovery_link_tag(:atom, issues_group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} issues")
@@ -16,7 +15,7 @@
= render 'shared/issuable/filter', type: :issues
-.gray-content-block.second-block
+.row-content-block.second-block
Only issues from
%strong #{@group.name}
group are listed here.
diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml
index e1c9dd931ee..e6953d94531 100644
--- a/app/views/groups/merge_requests.html.haml
+++ b/app/views/groups/merge_requests.html.haml
@@ -1,5 +1,4 @@
- page_title "Merge Requests"
-- header_title group_title(@group, "Merge Requests", merge_requests_group_path(@group))
.top-area
= render 'shared/issuable/nav', type: :merge_requests
@@ -8,7 +7,7 @@
= render 'shared/issuable/filter', type: :merge_requests
-.gray-content-block.second-block
+.row-content-block.second-block
Only merge requests from
%strong #{@group.name}
group are listed here.
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index ab307708b75..121a7de3ad7 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -1,5 +1,4 @@
- page_title "Milestones"
-- header_title group_title(@group, "Milestones", group_milestones_path(@group))
.top-area
= render 'shared/milestones_filter'
@@ -10,7 +9,7 @@
= icon('plus')
New Milestone
-.gray-content-block
+.row-content-block
Only milestones from
%strong #{@group.name}
group are listed here.
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index dd75766121e..c2f2d9912f7 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -1,5 +1,4 @@
- page_title "Projects"
-- header_title group_title(@group, "Projects", projects_group_path(@group))
.panel.panel-default.prepend-top-default
.panel-heading
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 3d16ecb097a..77c297255b8 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -4,28 +4,20 @@
- if current_user
= auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity")
-.cover-block
- .cover-controls
- - if @group && can?(current_user, :admin_group, @group)
- = link_to icon('pencil'), edit_group_path(@group), class: 'btn'
- - if current_user
- = link_to icon('rss'), group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn'
-
- .avatar-holder
+.cover-block.groups-cover-block
+ .container-fluid.container-limited
= link_to group_icon(@group), target: '_blank' do
- = image_tag group_icon(@group), class: "avatar group-avatar s90"
- .cover-title
- %h1
- = @group.name
- %span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) }
- = visibility_level_icon(@group.visibility_level, fw: false)
-
- .cover-desc.username
- @#{@group.path}
-
- - if @group.description.present?
- .cover-desc.description
- = markdown(@group.description, pipeline: :description)
+ = image_tag group_icon(@group), class: "avatar group-avatar s70"
+ .group-info
+ .cover-title
+ %h1
+ @#{@group.path}
+ %span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) }
+ = visibility_level_icon(@group.visibility_level, fw: false)
+
+ - if @group.description.present?
+ .cover-desc.description
+ = markdown(@group.description, pipeline: :description)
%div{ class: container_class }
.top-area
diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
index f12df5c8ffe..d676bc28c89 100644
--- a/app/views/help/ui.html.haml
+++ b/app/views/help/ui.html.haml
@@ -48,14 +48,14 @@
.lead
Gray content block with side padding using
- %code .gray-content-block
+ %code .row-content-block
.example
- .gray-content-block
+ .row-content-block
%h4 Normal block inside content
= lorem
- .gray-content-block.second-block
+ .row-content-block.second-block
%h4 Second block
= lorem
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index ad8a2e1e6c7..3c3bc41bf0e 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -26,7 +26,7 @@
.layout-nav
.container-fluid
= render "layouts/nav/#{nav}"
- .content-wrapper
+ .content-wrapper{ class: ('page-with-layout-nav' if defined?(nav) && nav) }
= render "layouts/flash"
= yield :flash_message
%div{ class: (container_class unless @no_container) }
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 2e483b7148d..f06acc98ca1 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,6 +1,6 @@
- page_title @group.name
- page_description @group.description unless page_description
- header_title group_title(@group) unless header_title
-- sidebar "group" unless sidebar
+- nav "group"
= render template: "layouts/application"
diff --git a/app/views/layouts/group_settings.html.haml b/app/views/layouts/group_settings.html.haml
index a1a1fc2f858..66b115e36de 100644
--- a/app/views/layouts/group_settings.html.haml
+++ b/app/views/layouts/group_settings.html.haml
@@ -1,5 +1,4 @@
- page_title "Settings"
-- header_title group_title(@group, "Settings", edit_group_path(@group))
-- sidebar "group_settings"
+- nav "group"
= render template: "layouts/group"
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index cde9e1b918b..86930d4eaaf 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -23,6 +23,7 @@
= icon('wrench fw')
%li
= link_to dashboard_todos_path, title: 'Todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
+ = icon('bell fw')
%span.badge.todos-pending-count
= todos_pending_count
- if current_user.can_create_project?
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index ca49c313ff7..fad4224e945 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -15,12 +15,12 @@
= icon('dashboard fw')
%span
Activity
- = nav_link(controller: :groups) do
+ = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to dashboard_groups_path, title: 'Groups' do
= icon('group fw')
%span
Groups
- = nav_link(controller: :milestones) do
+ = nav_link(controller: 'dashboard/milestones') do
= link_to dashboard_milestones_path, title: 'Milestones' do
= icon('clock-o fw')
%span
diff --git a/app/views/layouts/nav/_explore.html.haml b/app/views/layouts/nav/_explore.html.haml
index f08c5edf99c..3b40006a0cc 100644
--- a/app/views/layouts/nav/_explore.html.haml
+++ b/app/views/layouts/nav/_explore.html.haml
@@ -4,7 +4,7 @@
= icon('bookmark fw')
%span
Projects
- = nav_link(controller: :groups) do
+ = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to explore_groups_path, title: 'Groups' do
= icon('group fw')
%span
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index 55940741dc0..3438005863a 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -1,12 +1,6 @@
-%ul.nav.nav-sidebar
- = nav_link do
- = link_to root_path, title: 'Go to dashboard', class: 'back-link' do
- = icon('caret-square-o-left fw')
- %span
- Go to dashboard
-
- %li.separate-item
+= render 'layouts/nav/group_settings'
+%ul.nav-links
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
= link_to group_path(@group), title: 'Home' do
= icon('group fw')
@@ -28,22 +22,16 @@
%span
Issues
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- %span.count= number_with_delimiter(issues.count)
+ %span.badge.count= number_with_delimiter(issues.count)
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
= icon('tasks fw')
%span
Merge Requests
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- %span.count= number_with_delimiter(merge_requests.count)
+ %span.badge.count= number_with_delimiter(merge_requests.count)
= nav_link(controller: [:group_members]) do
= link_to group_group_members_path(@group), title: 'Members' do
= icon('users fw')
%span
Members
- - if can?(current_user, :admin_group, @group)
- = nav_link(html_options: { class: "separate-item" }) do
- = link_to edit_group_path(@group), title: 'Settings' do
- = icon ('cogs fw')
- %span
- Settings
diff --git a/app/views/layouts/nav/_group_settings.html.haml b/app/views/layouts/nav/_group_settings.html.haml
index 56a92fe9103..e391ec7f2b7 100644
--- a/app/views/layouts/nav/_group_settings.html.haml
+++ b/app/views/layouts/nav/_group_settings.html.haml
@@ -1,20 +1,20 @@
-%ul.nav.nav-sidebar
- = nav_link do
- = link_to group_path(@group), title: 'Go to group', class: 'back-link' do
- = icon('caret-square-o-left fw')
- %span
- Go to group
-
- %li.separate-item
-
- %ul.sidebar-subnav
- = nav_link(path: 'groups#edit') do
- = link_to edit_group_path(@group), title: 'Group Settings' do
- = icon ('pencil-square-o fw')
- %span
- Group Settings
- = nav_link(path: 'groups#projects') do
- = link_to projects_group_path(@group), title: 'Projects' do
- = icon('folder fw')
- %span
- Projects
+- if current_user
+ - if access = @group.users.find_by(id: current_user.id)
+ .controls
+ %span.dropdown.group-settings-dropdown
+ %a.dropdown-new.btn.btn-default#group-settings-button{href: '#', 'data-toggle' => 'dropdown'}
+ = icon('cog')
+ = icon('caret-down')
+ %ul.dropdown-menu.dropdown-menu-align-right
+ - if can?(current_user, :admin_group, @group)
+ = nav_link(path: 'groups#projects') do
+ = link_to projects_group_path(@group), title: 'Projects' do
+ Projects
+ %li.divider
+ %li
+ = link_to edit_group_path(@group) do
+ Edit Group
+ %li
+ = link_to leave_group_group_members_path(@group),
+ data: { confirm: leave_group_message(@group.name) }, method: :delete, title: 'Leave group' do
+ Leave Group
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index f59d27f7ed0..eef50d887c7 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -8,11 +8,11 @@
%p
- if @user.avatar?
You can change your avatar here
- - if Gitlab.config.gravatar.enabled
+ - if gravatar_enabled?
or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host}
- else
You can upload an avatar here
- - if Gitlab.config.gravatar.enabled
+ - if gravatar_enabled?
or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host}
.col-lg-9
.clearfix.avatar-image.append-bottom-default
diff --git a/app/views/projects/_last_push.html.haml b/app/views/projects/_last_push.html.haml
index f0a3e416db7..7c2b8d01508 100644
--- a/app/views/projects/_last_push.html.haml
+++ b/app/views/projects/_last_push.html.haml
@@ -1,7 +1,7 @@
- if event = last_push_event
- if show_last_push_widget?(event)
- .gray-content-block.top-block.clear-block.hidden-xs
+ .row-content-block.top-block.clear-block.hidden-xs
.event-last-push
.event-last-push-text
%span You pushed to
diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml
index a9908eaecca..369a847e7d4 100644
--- a/app/views/projects/_readme.html.haml
+++ b/app/views/projects/_readme.html.haml
@@ -7,7 +7,7 @@
= cache(readme_cache_key) do
= render_readme(readme)
- else
- .gray-content-block.second-block.center
+ .row-content-block.second-block.center
%h3.page-title
This project does not have a README yet
- if can?(current_user, :push_code, @project)
diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml
index 84034c8bf16..49f95ff37db 100644
--- a/app/views/projects/artifacts/browse.html.haml
+++ b/app/views/projects/artifacts/browse.html.haml
@@ -1,7 +1,7 @@
- page_title 'Artifacts', "#{@build.name} (##{@build.id})", 'Builds'
= render 'projects/builds/header_title'
-.top-block.gray-content-block.clearfix
+.top-block.row-content-block.clearfix
.pull-right
= link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build),
class: 'btn btn-default download' do
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 88266e21230..ac7790421a4 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -1,7 +1,7 @@
- page_title "Branches"
= render "projects/commits/header_title"
= render "projects/commits/head"
-.gray-content-block
+.row-content-block
.pull-right
- if can? current_user, :push_code, @project
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
index 0406fc21d77..2e8015d119b 100644
--- a/app/views/projects/builds/index.html.haml
+++ b/app/views/projects/builds/index.html.haml
@@ -9,6 +9,7 @@
%span.badge.js-totalbuilds-count
= number_with_delimiter(@all_builds.count(:id))
+
%li{class: ('active' if @scope == 'running')}
= link_to project_builds_path(@project, scope: :running) do
Running
@@ -34,7 +35,7 @@
= icon('wrench')
%span CI Lint
-.gray-content-block
+.row-content-block
#{(@scope || 'running').capitalize} builds from this project
%ul.content-list
@@ -52,6 +53,7 @@
%th Ref
%th Stage
%th Name
+ %th Tags
%th Duration
%th Finished at
- if @project.build_coverage_enabled?
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index 99d72aa7935..c0f7a7686f0 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -2,7 +2,7 @@
= render "header_title"
.build-page
- .gray-content-block.top-block
+ .row-content-block.top-block
Build ##{@build.id} for commit
%strong.monospace= link_to @build.commit.short_sha, ci_status_path(@build.commit)
from
@@ -34,7 +34,7 @@
%i.fa.fa-warning
This build was retried.
- .gray-content-block.middle-block
+ .row-content-block.middle-block
.build-head
.clearfix
= ci_status_with_icon(@build.status)
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index e123eb1cc7a..8e95f040273 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -40,6 +40,7 @@
%td
= build.name
+ %td
.label-container
- if build.tags.any?
- build.tags.each do |tag|
@@ -68,12 +69,12 @@
%td
.pull-right
- if can?(current_user, :read_build, build) && build.artifacts?
- = link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts' do
+ = link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts', class: 'btn btn-build' do
%i.fa.fa-download
- if can?(current_user, :update_build, build)
- if build.active?
- = link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel' do
+ = link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && build.retryable?
- = link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry' do
- %i.fa.fa-repeat
+ = link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
+ %i.fa.fa-refresh
diff --git a/app/views/projects/commit/_ci_commit.html.haml b/app/views/projects/commit/_ci_commit.html.haml
index d3acd33116c..e849aefb188 100644
--- a/app/views/projects/commit/_ci_commit.html.haml
+++ b/app/views/projects/commit/_ci_commit.html.haml
@@ -1,4 +1,4 @@
-.gray-content-block.middle-block
+.row-content-block.build-content.middle-block
.pull-right
- if can?(current_user, :update_build, @project)
- if ci_commit.builds.latest.failed.any?(&:retryable?)
@@ -40,6 +40,7 @@
%th Build ID
%th Stage
%th Name
+ %th Tags
%th Duration
%th Finished at
- if @project.build_coverage_enabled?
@@ -49,7 +50,7 @@
= render builds, coverage: @project.build_coverage_enabled?, stage: true, ref: false, allow_retry: true
- if ci_commit.retried.any?
- .gray-content-block.second-block
+ .row-content-block.second-block
Retried builds
.table-holder
@@ -61,6 +62,7 @@
%th Ref
%th Stage
%th Name
+ %th Tags
%th Duration
%th Finished at
- if @project.build_coverage_enabled?
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 3d7c18a5f58..01163e526b2 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -1,4 +1,4 @@
-.pull-right
+.pull-right.commit-action-buttons
%div
- if @notes_count > 0
%span.btn.disabled.btn-grouped
@@ -22,10 +22,12 @@
%div
%p
- %span.light Commit
- = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
- = clipboard_button(clipboard_text: @commit.id)
.commit-info-row
+ - if @commit.status
+ = link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status ci-#{@commit.status}" do
+ = ci_icon_for_status(@commit.status)
+ build:
+ = ci_label_for_status(@commit.status)
%span.light Authored by
%strong
= commit_author_link(@commit, avatar: true, size: 24)
@@ -39,19 +41,15 @@
#{time_ago_with_tooltip(@commit.committed_date)}
.commit-info-row
+ %span.light Commit
+ = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
+ = clipboard_button(clipboard_text: @commit.id)
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
-- if @commit.status
- .pull-right
- = link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status ci-#{@commit.status}" do
- = ci_icon_for_status(@commit.status)
- build:
- = ci_label_for_status(@commit.status)
-
-.commit-info-row.branches
- %i.fa.fa-spinner.fa-spin
+ %span.commit-info.branches
+ %i.fa.fa-spinner.fa-spin
.commit-box.content-block
%h3.commit-title
@@ -61,4 +59,4 @@
= preserve(markdown(escape_once(@commit.description), pipeline: :single_line))
:javascript
- $(".commit-info-row.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}");
+ $(".commit-info.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}");
diff --git a/app/views/projects/commit/branches.html.haml b/app/views/projects/commit/branches.html.haml
index 82aac1fbd15..2b0c9a4b4de 100644
--- a/app/views/projects/commit/branches.html.haml
+++ b/app/views/projects/commit/branches.html.haml
@@ -3,7 +3,6 @@
- branch = commit_default_branch(@project, @branches)
= link_to(namespace_project_tree_path(@project.namespace, @project, branch)) do
%span.label.label-gray
- %i.fa.fa-code-fork
= branch
- if @branches.any? || @tags.any?
= link_to("#", class: "js-details-expand") do
diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml
index 7a5b0d993db..d1bd76ab529 100644
--- a/app/views/projects/commits/_head.html.haml
+++ b/app/views/projects/commits/_head.html.haml
@@ -2,7 +2,8 @@
= nav_link(controller: [:commit, :commits]) do
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
Commits
- %span.badge= number_with_delimiter(@repository.commit_count)
+ %span.badge
+ = number_with_delimiter(@repository.commit_count)
= nav_link(controller: %w(network)) do
= link_to namespace_project_network_path(@project.namespace, @project, current_ref) do
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index bcdb09208aa..088eaa28013 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -6,7 +6,7 @@
= render "head"
-.gray-content-block.second-block
+.row-content-block.second-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'commits'
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index 02be5a2d07f..5e188dd0f3c 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -2,7 +2,7 @@
= render "projects/commits/header_title"
= render "projects/commits/head"
-.gray-content-block
+.row-content-block
Compare branches, tags or commit ranges.
%br
Fill input field with commit id like
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index da731f28bb6..62525168239 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -3,7 +3,7 @@
= render "projects/commits/head"
-.gray-content-block
+.row-content-block
= render "form"
- if @commits.present?
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 52d093871b4..1a2e59752fe 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -7,7 +7,7 @@
= render "home_panel"
-.gray-content-block.second-block.center
+.row-content-block.second-block.center
%h3.page-title
The repository for this project is empty
- if can?(current_user, :push_code, @project)
diff --git a/app/views/projects/graphs/ci.html.haml b/app/views/projects/graphs/ci.html.haml
index 6fa77cc10c6..9f05be9982b 100644
--- a/app/views/projects/graphs/ci.html.haml
+++ b/app/views/projects/graphs/ci.html.haml
@@ -1,7 +1,7 @@
- page_title "Continuous Integration", "Graphs"
= render "header_title"
= render 'head'
-.gray-content-block.append-bottom-default
+.row-content-block.append-bottom-default
.oneline
A collection of graphs for Continuous Integration
diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml
index fc465ab273b..da9f648cc9c 100644
--- a/app/views/projects/graphs/commits.html.haml
+++ b/app/views/projects/graphs/commits.html.haml
@@ -2,7 +2,7 @@
= render "header_title"
= render 'head'
-.gray-content-block.append-bottom-default
+.row-content-block.append-bottom-default
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs_commits'
%ul.breadcrumb.repo-breadcrumb
diff --git a/app/views/projects/graphs/languages.html.haml b/app/views/projects/graphs/languages.html.haml
index a7fab5b6d72..ebecab1dbfc 100644
--- a/app/views/projects/graphs/languages.html.haml
+++ b/app/views/projects/graphs/languages.html.haml
@@ -2,7 +2,7 @@
= render "header_title"
= render 'head'
-.gray-content-block.append-bottom-default
+.row-content-block.append-bottom-default
.oneline
Programming languages used in this repository
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 882e7d6b6ee..ad4a932d391 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -2,7 +2,7 @@
= render "header_title"
= render 'head'
-.gray-content-block.append-bottom-default
+.row-content-block.append-bottom-default
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs'
%ul.breadcrumb.repo-breadcrumb
diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml
index 6027fb23360..a8a8caf7280 100644
--- a/app/views/projects/imports/new.html.haml
+++ b/app/views/projects/imports/new.html.haml
@@ -10,7 +10,7 @@
.panel-body
%pre
:preserve
- #{@project.import_error.try(:strip)}
+ #{sanitize_repo_path(@project.import_error)}
= form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f|
= render "shared/import_form", f: f
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 9ad86ed71c9..5cf70ea3bb7 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -28,16 +28,10 @@
= downvotes
- note_count = issue.notes.user.nonawards.count
- - if note_count > 0
- %li
- = link_to issue_path(issue) + "#notes" do
- = icon('comments')
- = note_count
- - else
- %li
- = link_to issue_path(issue) + "#notes", class: "issue-no-comments" do
- = icon('comments')
- = note_count
+ %li
+ = link_to issue_path(issue, anchor: 'notes'), class: ('issue-no-comments' if note_count.zero?) do
+ = icon('comments')
+ = note_count
.issue-info
#{issue.to_reference} &middot;
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index e740fe8c84d..73c6a95f5ca 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -36,16 +36,10 @@
= downvotes
- note_count = merge_request.mr_and_commit_notes.user.nonawards.count
- - if note_count > 0
- %li
- = link_to merge_request_path(merge_request) + "#notes" do
- = icon('comments')
- = note_count
- - else
- %li
- = link_to merge_request_path(merge_request) + "#notes", class: "merge-request-no-comments" do
- = icon('comments')
- = note_count
+ %li
+ = link_to merge_request_path(merge_request, anchor: 'notes'), class: ('merge-request-no-comments' if note_count.zero?) do
+ = icon('comments')
+ = note_count
.merge-request-info
#{merge_request.to_reference} &middot;
diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml
index 2ec0d20a879..4d381754610 100644
--- a/app/views/projects/merge_requests/widget/_heading.html.haml
+++ b/app/views/projects/merge_requests/widget/_heading.html.haml
@@ -41,9 +41,4 @@
.ci_widget.ci-error{style: "display:none"}
= icon("times-circle")
- Could not connect to the CI server. Please check your settings and try again.
-
- :javascript
- $(function() {
- merge_request_widget.getCIStatus(false);
- });
+ Could not connect to the CI server. Please check your settings and try again. \ No newline at end of file
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 56543ccd062..6ec84660157 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -24,15 +24,15 @@
- else
= link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-nr btn-grouped"
- = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-nr" do
- = icon('trash-o')
- Delete
-
= link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped btn-nr" do
= icon('pencil-square-o')
Edit
-.detail-page-description.milestone-detail.second-block
+ = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-danger" do
+ = icon('trash-o')
+ Delete
+
+.detail-page-description.milestone-detail
%h2.title
= markdown escape_once(@milestone.title), pipeline: :single_line
%div
diff --git a/app/views/projects/network/_head.html.haml b/app/views/projects/network/_head.html.haml
index 28a617538b5..c609c505def 100644
--- a/app/views/projects/network/_head.html.haml
+++ b/app/views/projects/network/_head.html.haml
@@ -1,4 +1,4 @@
-.gray-content-block.append-bottom-default
+.row-content-block.append-bottom-default
.tree-ref-holder
= render partial: 'shared/ref_switcher', locals: {destination: 'graph'}
diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml
index 6f0b32aa165..0d59cec322c 100644
--- a/app/views/projects/releases/edit.html.haml
+++ b/app/views/projects/releases/edit.html.haml
@@ -2,7 +2,7 @@
= render "projects/commits/header_title"
= render "projects/commits/head"
-.gray-content-block
+.row-content-block
.oneline
.title
Release notes for tag
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index d854ac21725..74feb9e3282 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -12,7 +12,7 @@
= render 'projects/last_push'
= render "home_panel"
-.project-stats.gray-content-block.second-block
+.project-stats.row-content-block.second-block
%ul.nav
%li
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index 4af963e14da..103ff447464 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -1,7 +1,7 @@
- page_title "Snippets"
= render "header_title"
-.gray-content-block.top-block
+.row-content-block.top-block
.pull-right
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do
= icon('plus')
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index 760347de0a9..dc6ece30dd2 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -2,7 +2,7 @@
= render "projects/commits/header_title"
= render "projects/commits/head"
-.gray-content-block
+.row-content-block
- if can? current_user, :push_code, @project
.pull-right
= link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index 1dc9b799a95..9c916fd02de 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -2,7 +2,7 @@
= render "projects/commits/header_title"
= render "projects/commits/head"
-.gray-content-block
+.row-content-block
.pull-right
- if can?(current_user, :push_code, @project)
= link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn has-tooltip', title: 'Edit release notes' do
diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml
index dd27ea2b11b..ba3f2cadc48 100644
--- a/app/views/projects/wikis/git_access.html.haml
+++ b/app/views/projects/wikis/git_access.html.haml
@@ -2,7 +2,7 @@
= render "header_title"
= render 'nav'
-.gray-content-block
+.row-content-block
%span.oneline
Git access for
%strong= @project_wiki.path_with_namespace
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 711337f308e..252c37532e1 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,7 +1,7 @@
- if @search_objects.empty?
= render partial: "search/results/empty"
- else
- .gray-content-block
+ .row-content-block
= search_entries_info(@search_objects, @scope, @search_term)
- unless @show_snippets
- if @project
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index fc1101646fb..9474462cbd1 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -1,5 +1,5 @@
.issues-filters
- .issues-details-filters.gray-content-block.second-block
+ .issues-details-filters.row-content-block.second-block
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do
- if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
.check-all-holder
@@ -48,7 +48,7 @@
= button_tag "Update issues", class: "btn update_selected_issues btn-save"
- if !@labels.nil?
- .gray-content-block.second-block.filtered-labels{ class: ("hidden" if !@labels.any?) }
+ .row-content-block.second-block.filtered-labels{ class: ("hidden" if !@labels.any?) }
- if @labels.any?
= render "shared/labels_row", labels: @labels
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 18b091df39b..5c52cc6d1da 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -116,7 +116,7 @@
= link_to 'Change branches', mr_change_branches_path(@merge_request)
- is_footer = !(issuable.is_a?(MergeRequest) && issuable.new_record?)
-.gray-content-block{class: (is_footer ? "footer-block" : "middle-block")}
+.row-content-block{class: (is_footer ? "footer-block" : "middle-block")}
- if issuable.new_record?
= f.submit "Submit #{issuable.class.model_name.human.downcase}", class: 'btn btn-create'
- else
diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml
index cab8743a077..7ff947a51db 100644
--- a/app/views/shared/milestones/_top.html.haml
+++ b/app/views/shared/milestones/_top.html.haml
@@ -24,7 +24,7 @@
- else
= link_to 'Reopen Milestone', group_milestone_path(group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
-.detail-page-description.gray-content-block.second-block
+.detail-page-description.milestone-detail
%h2.title
= markdown escape_once(milestone.title), pipeline: :single_line
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
index 3c445f67236..e65b1814872 100644
--- a/app/views/shared/snippets/_header.html.haml
+++ b/app/views/shared/snippets/_header.html.haml
@@ -20,6 +20,6 @@
- else
= render "snippets/actions"
-.detail-page-description.gray-content-block.second-block
+.detail-page-description.row-content-block.second-block
%h2.title
= markdown escape_once(@snippet.title), pipeline: :single_line
diff --git a/app/views/sherlock/file_samples/show.html.haml b/app/views/sherlock/file_samples/show.html.haml
index cfd11e45b6a..94d4dd4fa7d 100644
--- a/app/views/sherlock/file_samples/show.html.haml
+++ b/app/views/sherlock/file_samples/show.html.haml
@@ -3,7 +3,7 @@
- header_title t('sherlock.title'), sherlock_transactions_path
-.gray-content-block
+.row-content-block
.pull-right
= link_to(sherlock_transaction_path(@transaction), class: 'btn') do
%i.fa.fa-arrow-left
diff --git a/app/views/sherlock/queries/show.html.haml b/app/views/sherlock/queries/show.html.haml
index 83f61ce4b07..fc2863dca8e 100644
--- a/app/views/sherlock/queries/show.html.haml
+++ b/app/views/sherlock/queries/show.html.haml
@@ -9,7 +9,7 @@
%a(href="#tab-backtrace" data-toggle="tab")
= t('sherlock.backtrace')
-.gray-content-block
+.row-content-block
.pull-right
= link_to(sherlock_transaction_path(@transaction), class: 'btn') do
%i.fa.fa-arrow-left
diff --git a/app/views/sherlock/transactions/index.html.haml b/app/views/sherlock/transactions/index.html.haml
index 010e1a2a902..da969c02765 100644
--- a/app/views/sherlock/transactions/index.html.haml
+++ b/app/views/sherlock/transactions/index.html.haml
@@ -1,7 +1,7 @@
- page_title t('sherlock.title')
- header_title t('sherlock.title'), sherlock_transactions_path
-.gray-content-block
+.row-content-block
.pull-right
= link_to(destroy_all_sherlock_transactions_path,
class: 'btn btn-danger',
diff --git a/app/views/sherlock/transactions/show.html.haml b/app/views/sherlock/transactions/show.html.haml
index 9d4b0b2724c..8aa6b437d95 100644
--- a/app/views/sherlock/transactions/show.html.haml
+++ b/app/views/sherlock/transactions/show.html.haml
@@ -16,7 +16,7 @@
%span.badge
#{@transaction.file_samples.length}
-.gray-content-block
+.row-content-block
.pull-right
= link_to(sherlock_transactions_path, class: 'btn') do
%i.fa.fa-arrow-left
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 0dff27f9654..3c0b89c6741 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -85,7 +85,7 @@
%div{ class: container_class }
.tab-content
#activity.tab-pane
- .gray-content-block.calender-block.white.second-block.hidden-xs
+ .row-content-block.calender-block.white.second-block.hidden-xs
%div{ class: container_class }
.user-calendar{data: {href: user_calendar_path}}
%h4.center.light
@@ -98,7 +98,7 @@
#groups.tab-pane
- # This tab is always loaded via AJAX
- #contributed.contributed-projects.tab-pane
+ #contributed.tab-pane
- # This tab is always loaded via AJAX
#projects.tab-pane
diff --git a/app/workers/repository_check/single_repository_worker.rb b/app/workers/repository_check/single_repository_worker.rb
index a76729e3c74..f2d12ba5a7d 100644
--- a/app/workers/repository_check/single_repository_worker.rb
+++ b/app/workers/repository_check/single_repository_worker.rb
@@ -1,9 +1,9 @@
module RepositoryCheck
class SingleRepositoryWorker
include Sidekiq::Worker
-
+
sidekiq_options retry: false
-
+
def perform(project_id)
project = Project.find(project_id)
project.update_columns(
@@ -11,20 +11,32 @@ module RepositoryCheck
last_repository_check_at: Time.now,
)
end
-
+
private
-
+
def check(project)
- repositories = [project.repository]
- repositories << project.wiki.repository if project.wiki_enabled?
- # Use 'map do', not 'all? do', to prevent short-circuiting
- repositories.map { |repository| git_fsck(repository.path_to_repo) }.all?
+ if !git_fsck(project.repository)
+ false
+ elsif project.wiki_enabled?
+ # Historically some projects never had their wiki repos initialized;
+ # this happens on project creation now. Let's initialize an empty repo
+ # if it is not already there.
+ begin
+ project.create_wiki
+ rescue Rugged::RepositoryError
+ end
+
+ git_fsck(project.wiki.repository)
+ else
+ true
+ end
end
-
- def git_fsck(path)
+
+ def git_fsck(repository)
+ path = repository.path_to_repo
cmd = %W(nice git --git-dir=#{path} fsck)
output, status = Gitlab::Popen.popen(cmd)
-
+
if status.zero?
true
else
diff --git a/bin/background_jobs b/bin/background_jobs
index 1f67d732949..25a578a1c49 100755
--- a/bin/background_jobs
+++ b/bin/background_jobs
@@ -37,7 +37,7 @@ start_no_deamonize()
start_sidekiq()
{
- bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile "$@"
+ exec bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile "$@"
}
load_ok()
diff --git a/bin/web b/bin/web
index 03fe7a6354b..ecd0bbd10b0 100755
--- a/bin/web
+++ b/bin/web
@@ -19,12 +19,12 @@ get_unicorn_pid()
start()
{
- $unicorn_cmd -D
+ exec $unicorn_cmd -D
}
start_foreground()
{
- $unicorn_cmd
+ exec $unicorn_cmd
}
stop()
diff --git a/config/gitlab.teatro.yml b/config/gitlab.teatro.yml
index f0656400beb..01c8dc5ff98 100644
--- a/config/gitlab.teatro.yml
+++ b/config/gitlab.teatro.yml
@@ -15,7 +15,6 @@ production: &base
issues: true
merge_requests: true
wiki: true
- wall: false
snippets: false
visibility_level: "private" # can be "private" | "internal" | "public"
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 07ce4b6d715..e682bcb976d 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -152,7 +152,6 @@ production: &base
## Gravatar
## For Libravatar see: http://doc.gitlab.com/ce/customization/libravatar.html
gravatar:
- enabled: true # Use user avatar image from Gravatar.com (default: true)
# gravatar urls: possible placeholders: %{hash} %{size} %{email}
# plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon
# ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon
diff --git a/config/initializers/devise_async.rb b/config/initializers/devise_async.rb
new file mode 100644
index 00000000000..05a1852cdbd
--- /dev/null
+++ b/config/initializers/devise_async.rb
@@ -0,0 +1 @@
+Devise::Async.backend = :sidekiq
diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb
index 283936d0efc..b2d08d87bac 100644
--- a/config/initializers/metrics.rb
+++ b/config/initializers/metrics.rb
@@ -61,12 +61,30 @@ if Gitlab::Metrics.enabled?
config.instrument_instance_methods(const)
end
- Dir[Rails.root.join('app', 'finders', '*.rb')].each do |path|
- const = File.basename(path, '.rb').camelize.constantize
-
- config.instrument_instance_methods(const)
+ # Path to search => prefix to strip from constant
+ paths_to_instrument = {
+ ['app', 'finders'] => ['app', 'finders'],
+ ['app', 'mailers', 'emails'] => ['app', 'mailers'],
+ ['app', 'services', '**'] => ['app', 'services'],
+ ['lib', 'gitlab', 'diff'] => ['lib'],
+ ['lib', 'gitlab', 'email', 'message'] => ['lib']
+ }
+
+ paths_to_instrument.each do |(path, prefix)|
+ prefix = Rails.root.join(*prefix)
+
+ Dir[Rails.root.join(*path + ['*.rb'])].each do |file_path|
+ path = Pathname.new(file_path).relative_path_from(prefix)
+ const = path.to_s.sub('.rb', '').camelize.constantize
+
+ config.instrument_methods(const)
+ config.instrument_instance_methods(const)
+ end
end
+ config.instrument_methods(Premailer::Adapter::Nokogiri)
+ config.instrument_instance_methods(Premailer::Adapter::Nokogiri)
+
[
:Blame, :Branch, :BranchCollection, :Blob, :Commit, :Diff, :Repository,
:Tag, :TagCollection, :Tree
@@ -97,17 +115,6 @@ if Gitlab::Metrics.enabled?
config.instrument_methods(Gitlab::ReferenceExtractor)
config.instrument_instance_methods(Gitlab::ReferenceExtractor)
- # Instrument all service classes
- services = Rails.root.join('app', 'services')
-
- Dir[services.join('**', '*.rb')].each do |file_path|
- path = Pathname.new(file_path).relative_path_from(services)
- const = path.to_s.sub('.rb', '').camelize.constantize
-
- config.instrument_methods(const)
- config.instrument_instance_methods(const)
- end
-
# Instrument the classes used for checking if somebody has push access.
config.instrument_instance_methods(Gitlab::GitAccess)
config.instrument_instance_methods(Gitlab::GitAccessWiki)
diff --git a/config/initializers/trusted_proxies.rb b/config/initializers/trusted_proxies.rb
index b8cc025bae2..d256a16d42b 100644
--- a/config/initializers/trusted_proxies.rb
+++ b/config/initializers/trusted_proxies.rb
@@ -1,2 +1,3 @@
-Rails.application.config.action_dispatch.trusted_proxies =
+Rails.application.config.action_dispatch.trusted_proxies = (
[ '127.0.0.1', '::1' ] + Array(Gitlab.config.gitlab.trusted_proxies)
+).map { |proxy| IPAddr.new(proxy) }
diff --git a/db/fixtures/development/10_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb
index 0825776ffaa..87fb8e3300d 100644
--- a/db/fixtures/development/10_merge_requests.rb
+++ b/db/fixtures/development/10_merge_requests.rb
@@ -1,6 +1,9 @@
Gitlab::Seeder.quiet do
+ # Limit the number of merge requests per project to avoid long seeds
+ MAX_NUM_MERGE_REQUESTS = 10
+
Project.all.reject(&:empty_repo?).each do |project|
- branches = project.repository.branch_names
+ branches = project.repository.branch_names.sample(MAX_NUM_MERGE_REQUESTS * 2)
branches.each do |branch_name|
break if branches.size < 2
diff --git a/db/migrate/20160508194200_remove_wall_enabled_from_projects.rb b/db/migrate/20160508194200_remove_wall_enabled_from_projects.rb
new file mode 100644
index 00000000000..aa560bc0f0c
--- /dev/null
+++ b/db/migrate/20160508194200_remove_wall_enabled_from_projects.rb
@@ -0,0 +1,5 @@
+class RemoveWallEnabledFromProjects < ActiveRecord::Migration
+ def change
+ remove_column :projects, :wall_enabled, :boolean, default: true, null: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 04aee737e4c..71d953afe30 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: 20160421130527) do
+ActiveRecord::Schema.define(version: 20160508194200) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -70,16 +70,16 @@ ActiveRecord::Schema.define(version: 20160421130527) do
t.string "recaptcha_site_key"
t.string "recaptcha_private_key"
t.integer "metrics_port", default: 8089
+ t.boolean "akismet_enabled", default: false
+ t.string "akismet_api_key"
t.integer "metrics_sample_interval", default: 15
t.boolean "sentry_enabled", default: false
t.string "sentry_dsn"
- t.boolean "akismet_enabled", default: false
- t.string "akismet_api_key"
t.boolean "email_author_in_body", default: false
t.integer "default_group_visibility"
t.boolean "repository_checks_enabled", default: false
- t.integer "metrics_packet_size", default: 1
t.text "shared_runners_text"
+ t.integer "metrics_packet_size", default: 1
end
create_table "audit_events", force: :cascade do |t|
@@ -426,10 +426,10 @@ ActiveRecord::Schema.define(version: 20160421130527) do
t.string "state"
t.integer "iid"
t.integer "updated_by_id"
- t.integer "moved_to_id"
t.boolean "confidential", default: false
t.datetime "deleted_at"
t.date "due_date"
+ t.integer "moved_to_id"
end
add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree
@@ -716,8 +716,8 @@ ActiveRecord::Schema.define(version: 20160421130527) do
t.integer "project_id"
t.text "data"
t.text "encrypted_credentials"
- t.text "encrypted_credentials_iv"
- t.text "encrypted_credentials_salt"
+ t.string "encrypted_credentials_iv"
+ t.string "encrypted_credentials_salt"
end
create_table "projects", force: :cascade do |t|
@@ -728,7 +728,6 @@ ActiveRecord::Schema.define(version: 20160421130527) do
t.datetime "updated_at"
t.integer "creator_id"
t.boolean "issues_enabled", default: true, null: false
- t.boolean "wall_enabled", default: true, null: false
t.boolean "merge_requests_enabled", default: true, null: false
t.boolean "wiki_enabled", default: true, null: false
t.integer "namespace_id"
@@ -816,9 +815,9 @@ ActiveRecord::Schema.define(version: 20160421130527) do
t.string "type"
t.string "title"
t.integer "project_id"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.boolean "active", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "active", default: false, null: false
t.text "properties"
t.boolean "template", default: false
t.boolean "push_events", default: true
diff --git a/doc/api/build_triggers.md b/doc/api/build_triggers.md
index 4a12e962b62..0881a7d7a90 100644
--- a/doc/api/build_triggers.md
+++ b/doc/api/build_triggers.md
@@ -101,8 +101,18 @@ DELETE /projects/:id/triggers/:token
| Attribute | Type | required | Description |
|-----------|---------|----------|--------------------------|
| `id` | integer | yes | The ID of a project |
-| `token` | string | yes | The `token` of a project |
+| `token` | string | yes | The `token` of a trigger |
```
curl -X DELETE -H "PRIVATE_TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/triggers/7b9148c158980bbd9bcea92c17522d"
```
+
+```json
+{
+ "created_at": "2015-12-23T16:25:56.760Z",
+ "deleted_at": "2015-12-24T12:32:20.100Z",
+ "last_used": null,
+ "token": "7b9148c158980bbd9bcea92c17522d",
+ "updated_at": "2015-12-24T12:32:20.100Z"
+}
+```
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 6341440c58b..57c2e1d9b87 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -12,6 +12,8 @@ GET /projects/:id/repository/commits
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `ref_name` | string | no | The name of a repository branch or tag or if not given the default branch |
+| `since` | string | no | Only commits after or in this date will be returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ |
+| `until` | string | no | Only commits before or in this date will be returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ |
```bash
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/repository/commits"
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 3e78149f442..fc7a7ae0c0c 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -77,7 +77,8 @@ Example response:
"created_at" : "2016-01-04T15:31:51.081Z",
"iid" : 6,
"labels" : [],
- "subscribed" : false
+ "subscribed" : false,
+ "user_notes_count": 1
}
]
```
@@ -154,7 +155,8 @@ Example response:
"title" : "Ut commodi ullam eos dolores perferendis nihil sunt.",
"updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z",
- "subscribed" : false
+ "subscribed" : false,
+ "user_notes_count": 1
}
]
```
@@ -216,7 +218,8 @@ Example response:
"title" : "Ut commodi ullam eos dolores perferendis nihil sunt.",
"updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z",
- "subscribed": false
+ "subscribed": false,
+ "user_notes_count": 1
}
```
@@ -271,7 +274,8 @@ Example response:
"description" : null,
"updated_at" : "2016-01-07T12:44:33.959Z",
"milestone" : null,
- "subscribed" : true
+ "subscribed" : true,
+ "user_notes_count": 0
}
```
@@ -329,7 +333,8 @@ Example response:
"id" : 85,
"assignee" : null,
"milestone" : null,
- "subscribed" : true
+ "subscribed" : true,
+ "user_notes_count": 0
}
```
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 2057f9d77aa..8217e30fe25 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -67,7 +67,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
- "subscribed" : false
+ "subscribed" : false,
+ "user_notes_count": 1
}
]
```
@@ -130,7 +131,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
- "subscribed" : true
+ "subscribed" : true,
+ "user_notes_count": 1
}
```
@@ -230,6 +232,7 @@ Parameters:
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
"subscribed" : true,
+ "user_notes_count": 1,
"changes": [
{
"old_path": "VERSION",
@@ -308,7 +311,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
- "subscribed" : true
+ "subscribed" : true,
+ "user_notes_count": 0
}
```
@@ -378,7 +382,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
- "subscribed" : true
+ "subscribed" : true,
+ "user_notes_count": 1
}
```
@@ -472,7 +477,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
- "subscribed" : true
+ "subscribed" : true,
+ "user_notes_count": 1
}
```
@@ -537,7 +543,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
- "subscribed" : true
+ "subscribed" : true,
+ "user_notes_count": 1
}
```
@@ -602,7 +609,8 @@ Example response:
"title" : "Consequatur vero maxime deserunt laboriosam est voluptas dolorem.",
"created_at" : "2016-01-04T15:31:51.081Z",
"iid" : 6,
- "labels" : []
+ "labels" : [],
+ "user_notes_count": 1
},
]
```
diff --git a/doc/api/notes.md b/doc/api/notes.md
index 7aa1c2155bf..a6b5b1787fd 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -15,7 +15,7 @@ GET /projects/:id/issues/:issue_id/notes
Parameters:
- `id` (required) - The ID of a project
-- `issue_id` (required) - The ID of an issue
+- `issue_id` (required) - The IID of an issue (not ID)
```json
[
@@ -73,7 +73,7 @@ GET /projects/:id/issues/:issue_id/notes/:note_id
Parameters:
- `id` (required) - The ID of a project
-- `issue_id` (required) - The ID of a project issue
+- `issue_id` (required) - The IID of a project issue (not ID)
- `note_id` (required) - The ID of an issue note
### Create new issue note
@@ -87,7 +87,7 @@ POST /projects/:id/issues/:issue_id/notes
Parameters:
- `id` (required) - The ID of a project
-- `issue_id` (required) - The ID of an issue
+- `issue_id` (required) - The IID of an issue (not ID)
- `body` (required) - The content of a note
- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z
@@ -102,7 +102,7 @@ PUT /projects/:id/issues/:issue_id/notes/:note_id
Parameters:
- `id` (required) - The ID of a project
-- `issue_id` (required) - The ID of an issue
+- `issue_id` (required) - The IID of an issue (not ID)
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
@@ -120,7 +120,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
-| `issue_id` | integer | yes | The ID of an issue |
+| `issue_id` | integer | yes | The IID of an issue |
| `note_id` | integer | yes | The ID of a note |
```bash
diff --git a/doc/api/users.md b/doc/api/users.md
index 7d2b4897cff..7e848586dbd 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -20,6 +20,7 @@ GET /users
"name": "John Smith",
"state": "active",
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
+ "web_url": "http://localhost:3000/u/john_smith"
},
{
"id": 2,
@@ -27,6 +28,7 @@ GET /users
"name": "Jack Smith",
"state": "blocked",
"avatar_url": "http://gravatar.com/../e32131cd8.jpeg",
+ "web_url": "http://localhost:3000/u/jack_smith"
}
]
```
@@ -45,21 +47,31 @@ GET /users
"email": "john@example.com",
"name": "John Smith",
"state": "active",
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/1/index.jpg",
+ "web_url": "http://localhost:3000/u/john_smith",
"created_at": "2012-05-23T08:00:58Z",
+ "is_admin": false,
"bio": null,
+ "location": null,
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
- "extern_uid": "john.smith",
- "provider": "provider_name",
+ "last_sign_in_at": "2012-06-01T11:41:01Z",
+ "confirmed_at": "2012-05-23T09:05:22Z",
"theme_id": 1,
"color_scheme_id": 2,
- "is_admin": false,
- "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
+ "projects_limit": 100,
+ "current_sign_in_at": "2012-06-02T06:36:55Z",
+ "identities": [
+ {"provider": "github", "extern_uid": "2435223452345"},
+ {"provider": "bitbucket", "extern_uid": "john.smith"},
+ {"provider": "google_oauth2", "extern_uid": "8776128412476123468721346"}
+ ],
"can_create_group": true,
- "current_sign_in_at": "2014-03-19T13:12:15Z",
- "two_factor_enabled": true
+ "can_create_project": true,
+ "two_factor_enabled": true,
+ "external": false
},
{
"id": 2,
@@ -67,24 +79,27 @@ GET /users
"email": "jack@example.com",
"name": "Jack Smith",
"state": "blocked",
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/2/index.jpg",
+ "web_url": "http://localhost:3000/u/jack_smith",
"created_at": "2012-05-23T08:01:01Z",
+ "is_admin": false,
"bio": null,
"location": null,
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
- "extern_uid": "jack.smith",
- "provider": "provider_name",
+ "last_sign_in_at": null,
+ "confirmed_at": "2012-05-30T16:53:06.148Z",
"theme_id": 1,
"color_scheme_id": 3,
- "is_admin": false,
- "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
- "can_create_group": true,
- "can_create_project": true,
"projects_limit": 100,
"current_sign_in_at": "2014-03-19T17:54:13Z",
- "two_factor_enabled": false
+ "identities": [],
+ "can_create_group": true,
+ "can_create_project": true,
+ "two_factor_enabled": true,
+ "external": false
}
]
```
@@ -124,6 +139,7 @@ Parameters:
"name": "John Smith",
"state": "active",
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
+ "web_url": "http://localhost:3000/u/john_smith",
"created_at": "2012-05-23T08:00:58Z",
"is_admin": false,
"bio": null,
@@ -152,23 +168,31 @@ Parameters:
"email": "john@example.com",
"name": "John Smith",
"state": "active",
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/1/index.jpg",
+ "web_url": "http://localhost:3000/u/john_smith",
"created_at": "2012-05-23T08:00:58Z",
- "confirmed_at": "2012-05-23T08:00:58Z",
- "last_sign_in_at": "2015-03-23T08:00:58Z",
+ "is_admin": false,
"bio": null,
"location": null,
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
- "extern_uid": "john.smith",
- "provider": "provider_name",
+ "last_sign_in_at": "2012-06-01T11:41:01Z",
+ "confirmed_at": "2012-05-23T09:05:22Z",
"theme_id": 1,
"color_scheme_id": 2,
- "is_admin": false,
+ "projects_limit": 100,
+ "current_sign_in_at": "2012-06-02T06:36:55Z",
+ "identities": [
+ {"provider": "github", "extern_uid": "2435223452345"},
+ {"provider": "bitbucket", "extern_uid": "john.smith"},
+ {"provider": "google_oauth2", "extern_uid": "8776128412476123468721346"}
+ ],
"can_create_group": true,
"can_create_project": true,
- "projects_limit": 100
+ "two_factor_enabled": true,
+ "external": false
}
```
@@ -261,21 +285,33 @@ GET /user
"username": "john_smith",
"email": "john@example.com",
"name": "John Smith",
- "private_token": "dd34asd13as",
"state": "active",
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/1/index.jpg",
+ "web_url": "http://localhost:3000/u/john_smith",
"created_at": "2012-05-23T08:00:58Z",
+ "is_admin": false,
"bio": null,
"location": null,
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
+ "last_sign_in_at": "2012-06-01T11:41:01Z",
+ "confirmed_at": "2012-05-23T09:05:22Z",
"theme_id": 1,
"color_scheme_id": 2,
- "is_admin": false,
+ "projects_limit": 100,
+ "current_sign_in_at": "2012-06-02T06:36:55Z",
+ "identities": [
+ {"provider": "github", "extern_uid": "2435223452345"},
+ {"provider": "bitbucket", "extern_uid": "john_smith"},
+ {"provider": "google_oauth2", "extern_uid": "8776128412476123468721346"}
+ ],
"can_create_group": true,
"can_create_project": true,
- "projects_limit": 100
+ "two_factor_enabled": true,
+ "external": false,
+ "private_token": "dd34asd13as"
}
```
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index 5fb086b1dd9..ca52a483a59 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -41,9 +41,9 @@ GitLab Runner then executes build scripts as `gitlab-runner` user.
--description "My Runner"
```
-2. Install Docker on server.
+2. Install Docker Engine on server.
- For more information how to install Docker on different systems checkout the [Supported installations](https://docs.docker.com/installation/).
+ For more information how to install Docker Engine on different systems checkout the [Supported installations](https://docs.docker.com/engine/installation/).
3. Add `gitlab-runner` user to `docker` group:
@@ -151,4 +151,4 @@ In order to do that follow the steps:
An example project using this approach can be found here: https://gitlab.com/gitlab-examples/docker.
[docker-in-docker]: https://blog.docker.com/2013/09/docker-can-now-run-within-docker/
-[docker-cap]: https://docs.docker.com/reference/run/#runtime-privilege-and-linux-capabilities
+[docker-cap]: https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 84212fb3c61..56ac2195c49 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -64,7 +64,7 @@ You can see some widely used services examples in the relevant documentation of
### How is service linked to the build
To better understand how the container linking works, read
-[Linking containers together](https://docs.docker.com/userguide/dockerlinks/).
+[Linking containers together][linking-containers].
To summarize, if you add `mysql` as service to your application, the image will
then be used to create a container that is linked to the build container.
@@ -273,7 +273,7 @@ creation.
[Docker Fundamentals]: https://docs.docker.com/engine/understanding-docker/
[hub]: https://hub.docker.com/
[linking-containers]: https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/
-[tutum/wordpress]: https://registry.hub.docker.com/u/tutum/wordpress/
-[postgres-hub]: https://registry.hub.docker.com/u/library/postgres/
-[mysql-hub]: https://registry.hub.docker.com/u/library/mysql/
+[tutum/wordpress]: https://hub.docker.com/r/tutum/wordpress/
+[postgres-hub]: https://hub.docker.com/r/_/postgres/
+[mysql-hub]: https://hub.docker.com/r/_/mysql/
[runner-priv-reg]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/configuration/advanced-configuration.md#using-a-private-docker-registry
diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md
index cc059dc4376..61294be599d 100644
--- a/doc/ci/examples/README.md
+++ b/doc/ci/examples/README.md
@@ -4,12 +4,12 @@
- [Test and deploy a Ruby application to Heroku](test-and-deploy-ruby-application-to-heroku.md)
- [Test and deploy a Python application to Heroku](test-and-deploy-python-application-to-heroku.md)
- [Test a Clojure application](test-clojure-application.md)
-- [Using `dpl` as deployment tool](deployment/README.md)
+- [Using `dpl` as deployment tool](../deployment/README.md)
- Help your favorite programming language and GitLab by sending a merge request
with a guide for that language.
## Outside the documentation
-- [Blost post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/)
+- [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/)
- [Repo's with examples for various languages](https://gitlab.com/groups/gitlab-examples)
- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md
index db077927126..26953014502 100644
--- a/doc/ci/examples/php.md
+++ b/doc/ci/examples/php.md
@@ -60,7 +60,7 @@ docker-php-ext-install pdo_mysql
You might wonder what `docker-php-ext-install` is. In short, it is a script
provided by the official php docker image that you can use to easilly install
extensions. For more information read the the documentation at
-<https://hub.docker.com/_/php/>.
+<https://hub.docker.com/r/_/php/>.
Now that we created the script that contains all prerequisites for our build
environment, let's add it in `.gitlab-ci.yml`:
@@ -92,7 +92,7 @@ Finally, commit your files and push them to GitLab to see your build succeeding
The final `.gitlab-ci.yml` should look similar to this:
```yaml
-# Select image from https://hub.docker.com/_/php/
+# Select image from https://hub.docker.com/r/_/php/
image: php:5.6
before_script:
@@ -278,7 +278,7 @@ that runs on [GitLab.com](https://gitlab.com) using our publicly available
Want to hack on it? Simply fork it, commit and push your changes. Within a few
moments the changes will be picked by a public runner and the build will begin.
-[php-hub]: https://hub.docker.com/_/php/
+[php-hub]: https://hub.docker.com/r/_/php/
[phpenv]: https://github.com/phpenv/phpenv
[phpenv-installation]: https://github.com/phpenv/phpenv#installation
[php-example-repo]: https://gitlab.com/gitlab-examples/php
diff --git a/doc/ci/examples/test-and-deploy-python-application-to-heroku.md b/doc/ci/examples/test-and-deploy-python-application-to-heroku.md
index a236da53fe9..e4d3970deac 100644
--- a/doc/ci/examples/test-and-deploy-python-application-to-heroku.md
+++ b/doc/ci/examples/test-and-deploy-python-application-to-heroku.md
@@ -8,7 +8,7 @@ This is what the `.gitlab-ci.yml` file looks like for this project:
```yaml
test:
script:
- # this configures django application to use attached postgres database that is run on `postgres` host
+ # this configures Django application to use attached postgres database that is run on `postgres` host
- export DATABASE_URL=postgres://postgres:@postgres:5432/python-test-app
- apt-get update -qy
- apt-get install -y python-dev python-pip
@@ -37,7 +37,7 @@ production:
```
This project has three jobs:
-1. `test` - used to test rails application,
+1. `test` - used to test Django application,
2. `staging` - used to automatically deploy staging environment every push to `master` branch
3. `production` - used to automatically deploy production environmnet for every created tag
@@ -61,12 +61,12 @@ gitlab-ci-multi-runner register \
--non-interactive \
--url "https://gitlab.com/ci/" \
--registration-token "PROJECT_REGISTRATION_TOKEN" \
- --description "python-3.2" \
+ --description "python-3.5" \
--executor "docker" \
- --docker-image python:3.2 \
+ --docker-image python:3.5 \
--docker-postgres latest
```
-With the command above, you create a runner that uses [python:3.2](https://registry.hub.docker.com/u/library/python/) image and uses [postgres](https://registry.hub.docker.com/u/library/postgres/) database.
+With the command above, you create a runner that uses [python:3.5](https://hub.docker.com/r/_/python/) image and uses [postgres](https://hub.docker.com/r/_/postgres/) database.
To access PostgreSQL database you need to connect to `host: postgres` as user `postgres` without password.
diff --git a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
index f5645d586ae..08c10d391ea 100644
--- a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
+++ b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
@@ -1,5 +1,5 @@
## Test and Deploy a ruby application
-This example will guide you how to run tests in your Ruby application and deploy it automatically as Heroku application.
+This example will guide you how to run tests in your Ruby on Rails application and deploy it automatically as Heroku application.
You can checkout the example [source](https://gitlab.com/ayufan/ruby-getting-started) and check [CI status](https://gitlab.com/ayufan/ruby-getting-started/builds?scope=all).
@@ -32,7 +32,7 @@ production:
```
This project has three jobs:
-1. `test` - used to test rails application,
+1. `test` - used to test Rails application,
2. `staging` - used to automatically deploy staging environment every push to `master` branch
3. `production` - used to automatically deploy production environmnet for every created tag
@@ -62,6 +62,6 @@ gitlab-ci-multi-runner register \
--docker-postgres latest
```
-With the command above, you create a runner that uses [ruby:2.2](https://registry.hub.docker.com/u/library/ruby/) image and uses [postgres](https://registry.hub.docker.com/u/library/postgres/) database.
+With the command above, you create a runner that uses [ruby:2.2](https://hub.docker.com/r/_/ruby/) image and uses [postgres](https://hub.docker.com/r/_/postgres/) database.
To access PostgreSQL database you need to connect to `host: postgres` as user `postgres` without password.
diff --git a/doc/ci/services/mysql.md b/doc/ci/services/mysql.md
index c66d77122b2..aaf3aa77837 100644
--- a/doc/ci/services/mysql.md
+++ b/doc/ci/services/mysql.md
@@ -16,7 +16,7 @@ services:
- mysql:latest
variables:
- # Configure mysql environment variables (https://hub.docker.com/_/mysql/)
+ # Configure mysql environment variables (https://hub.docker.com/r/_/mysql/)
MYSQL_DATABASE: el_duderino
MYSQL_ROOT_PASSWORD: mysql_strong_password
```
@@ -114,5 +114,5 @@ available [shared runners](../runners/README.md).
Want to hack on it? Simply fork it, commit and push your changes. Within a few
moments the changes will be picked by a public runner and the build will begin.
-[hub-mysql]: https://hub.docker.com/_/mysql/
+[hub-mysql]: https://hub.docker.com/r/_/mysql/
[mysql-example-repo]: https://gitlab.com/gitlab-examples/mysql
diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md
index 17d21dbda1c..f787cc0a124 100644
--- a/doc/ci/services/postgres.md
+++ b/doc/ci/services/postgres.md
@@ -110,5 +110,5 @@ available [shared runners](../runners/README.md).
Want to hack on it? Simply fork it, commit and push your changes. Within a few
moments the changes will be picked by a public runner and the build will begin.
-[hub-pg]: https://hub.docker.com/_/postgres/
+[hub-pg]: https://hub.docker.com/r/_/postgres/
[postgres-example-repo]: https://gitlab.com/gitlab-examples/postgres
diff --git a/doc/ci/services/redis.md b/doc/ci/services/redis.md
index b281e8f9f60..80705024d2f 100644
--- a/doc/ci/services/redis.md
+++ b/doc/ci/services/redis.md
@@ -65,5 +65,5 @@ that runs on [GitLab.com](https://gitlab.com) using our publicly available
Want to hack on it? Simply fork it, commit and push your changes. Within a few
moments the changes will be picked by a public runner and the build will begin.
-[hub-redis]: https://hub.docker.com/_/redis/
+[hub-redis]: https://hub.docker.com/r/_/redis/
[redis-example-repo]: https://gitlab.com/gitlab-examples/redis
diff --git a/doc/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md
index 7f825e6a065..7c0fb225dac 100644
--- a/doc/ci/ssh_keys/README.md
+++ b/doc/ci/ssh_keys/README.md
@@ -57,7 +57,7 @@ before_script:
# WARNING: Use this only with the Docker executor, if you use it with shell
# you will overwrite your user's SSH config.
- mkdir -p ~/.ssh
- - '[[ -f /.dockerinit ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
+ - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
```
As a final step, add the _public_ key from the one you created earlier to the
diff --git a/doc/development/README.md b/doc/development/README.md
index 3f3ef068f96..aa7d54c01d0 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -8,6 +8,7 @@
- [How to dump production data to staging](db_dump.md)
- [Instrumentation](instrumentation.md)
- [Migration Style Guide](migration_style_guide.md) for creating safe migrations
+- [Performance guidelines](performance.md)
- [Rake tasks](rake_tasks.md) for development
- [Shell commands](shell_commands.md) in the GitLab codebase
- [Sidekiq debugging](sidekiq_debugging.md)
diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md
index c1cf2e77c26..9168c70945a 100644
--- a/doc/development/instrumentation.md
+++ b/doc/development/instrumentation.md
@@ -1,12 +1,125 @@
# Instrumenting Ruby Code
-GitLab Performance Monitoring allows instrumenting of custom blocks of Ruby
-code. This can be used to measure the time spent in a specific part of a larger
-chunk of code. The resulting data is stored as a field in the transaction that
-executed the block.
+GitLab Performance Monitoring allows instrumenting of both methods and custom
+blocks of Ruby code. Method instrumentation is the primary form of
+instrumentation with block-based instrumentation only being used when we want to
+drill down to specific regions of code within a method.
-To start measuring a block of Ruby code you should use `Gitlab::Metrics.measure`
-and give it a name:
+## Instrumenting Methods
+
+Instrumenting methods is done by using the `Gitlab::Metrics::Instrumentation`
+module. This module offers a few different methods that can be used to
+instrument code:
+
+* `instrument_method`: instruments a single class method.
+* `instrument_instance_method`: instruments a single instance method.
+* `instrument_class_hierarchy`: given a Class this method will recursively
+ instrument all sub-classes (both class and instance methods).
+* `instrument_methods`: instruments all public class methods of a Module.
+* `instrument_instance_methods`: instruments all public instance methods of a
+ Module.
+
+To remove the need for typing the full `Gitlab::Metrics::Instrumentation`
+namespace you can use the `configure` class method. This method simply yields
+the supplied block while passing `Gitlab::Metrics::Instrumentation` as its
+argument. An example:
+
+```
+Gitlab::Metrics::Instrumentation.configure do |conf|
+ conf.instrument_method(Foo, :bar)
+ conf.instrument_method(Foo, :baz)
+end
+```
+
+Using this method is in general preferred over directly calling the various
+instrumentation methods.
+
+Method instrumentation should be added in the initializer
+`config/initializers/metrics.rb`.
+
+### Examples
+
+Instrumenting a single method:
+
+```
+Gitlab::Metrics::Instrumentation.configure do |conf|
+ conf.instrument_method(User, :find_by)
+end
+```
+
+Instrumenting an entire class hierarchy:
+
+```
+Gitlab::Metrics::Instrumentation.configure do |conf|
+ conf.instrument_class_hierarchy(ActiveRecord::Base)
+end
+```
+
+Instrumenting all public class methods:
+
+```
+Gitlab::Metrics::Instrumentation.configure do |conf|
+ conf.instrument_methods(User)
+end
+```
+
+### Checking Instrumented Methods
+
+The easiest way to check if a method has been instrumented is to check its
+source location. For example:
+
+```
+method = Rugged::TagCollection.instance_method(:[])
+
+method.source_location
+```
+
+If the source location points to `lib/gitlab/metrics/instrumentation.rb` you
+know the method has been instrumented.
+
+If you're using Pry you can use the `$` command to display the source code of a
+method (along with its source location), this is easier than running the above
+Ruby code. In case of the above snippet you'd run the following:
+
+```
+$ Rugged::TagCollection#[]
+```
+
+This will print out something along the lines of:
+
+```
+From: /path/to/your/gitlab/lib/gitlab/metrics/instrumentation.rb @ line 148:
+Owner: #<Module:0x0055f0865c6d50>
+Visibility: public
+Number of lines: 21
+
+def #{name}(#{args_signature})
+ trans = Gitlab::Metrics::Instrumentation.transaction
+
+ if trans
+ start = Time.now
+ retval = super
+ duration = (Time.now - start) * 1000.0
+
+ if duration >= Gitlab::Metrics.method_call_threshold
+ trans.increment(:method_duration, duration)
+
+ trans.add_metric(Gitlab::Metrics::Instrumentation::SERIES,
+ { duration: duration },
+ method: #{label.inspect})
+ end
+
+ retval
+ else
+ super
+ end
+end
+```
+
+## Instrumenting Ruby Blocks
+
+Measuring blocks of Ruby code is done by calling `Gitlab::Metrics.measure` and
+passing it a block. For example:
```ruby
Gitlab::Metrics.measure(:foo) do
@@ -14,6 +127,10 @@ Gitlab::Metrics.measure(:foo) do
end
```
+The block is executed and the execution time is stored as a set of fields in the
+currently running transaction. If no transaction is present the block is yielded
+without measuring anything.
+
3 values are measured for a block:
1. The real time elapsed, stored in NAME_real_time.
diff --git a/doc/development/performance.md b/doc/development/performance.md
new file mode 100644
index 00000000000..fb37b3a889c
--- /dev/null
+++ b/doc/development/performance.md
@@ -0,0 +1,258 @@
+# Performance Guidelines
+
+This document describes various guidelines to follow to ensure good and
+consistent performance of GitLab.
+
+## Workflow
+
+The process of solving performance problems is roughly as follows:
+
+1. Make sure there's an issue open somewhere (e.g., on the GitLab CE issue
+ tracker), create one if there isn't. See [#15607][#15607] for an example.
+2. Measure the performance of the code in a production environment such as
+ GitLab.com (see the [Tooling](#tooling) section below). Performance should be
+ measured over a period of _at least_ 24 hours.
+3. Add your findings based on the measurement period (screenshots of graphs,
+ timings, etc) to the issue mentioned in step 1.
+4. Solve the problem.
+5. Create a merge request, assign the "performance" label and ping the right
+ people (e.g. [@yorickpeterse][yorickpeterse] and [@joshfng][joshfng]).
+6. Once a change has been deployed make sure to _again_ measure for at least 24
+ hours to see if your changes have any impact on the production environment.
+7. Repeat until you're done.
+
+When providing timings make sure to provide:
+
+* The 95th percentile
+* The 99th percentile
+* The mean
+
+When providing screenshots of graphs, make sure that both the X and Y axes and
+the legend are clearly visible. If you happen to have access to GitLab.com's own
+monitoring tools you should also provide a link to any relevant
+graphs/dashboards.
+
+## Tooling
+
+GitLab provides two built-in tools to aid the process of improving performance:
+
+* [Sherlock](doc/development/profiling.md#sherlock)
+* [GitLab Performance Monitoring](doc/monitoring/performance/monitoring.md)
+
+GitLab employees can use GitLab.com's performance monitoring systems located at
+<http://performance.gitlab.net>, this requires you to log in using your
+`@gitlab.com` Email address. Non-GitLab employees are advised to set up their
+own InfluxDB + Grafana stack.
+
+## Benchmarks
+
+Benchmarks are almost always useless. Benchmarks usually only test small bits of
+code in isolation and often only measure the best case scenario. On top of that,
+benchmarks for libraries (e.g., a Gem) tend to be biased in favour of the
+library. After all there's little benefit to an author publishing a benchmark
+that shows they perform worse than their competitors.
+
+Benchmarks are only really useful when you need a rough (emphasis on "rough")
+understanding of the impact of your changes. For example, if a certain method is
+slow a benchmark can be used to see if the changes you're making have any impact
+on the method's performance. However, even when a benchmark shows your changes
+improve performance there's no guarantee the performance also improves in a
+production environment.
+
+When writing benchmarks you should almost always use
+[benchmark-ips](https://github.com/evanphx/benchmark-ips). Ruby's `Benchmark`
+module that comes with the standard library is rarely useful as it runs either a
+single iteration (when using `Benchmark.bm`) or two iterations (when using
+`Benchmark.bmbm`). Running this few iterations means external factors (e.g. a
+video streaming in the background) can very easily skew the benchmark
+statistics.
+
+Another problem with the `Benchmark` module is that it displays timings, not
+iterations. This means that if a piece of code completes in a very short period
+of time it can be very difficult to compare the timings before and after a
+certain change. This in turn leads to patterns such as the following:
+
+```ruby
+Benchmark.bmbm(10) do |bench|
+ bench.report 'do something' do
+ 100.times do
+ ... work here ...
+ end
+ end
+end
+```
+
+This however leads to the question: how many iterations should we run to get
+meaningful statistics?
+
+The benchmark-ips Gem basically takes care of all this and much more, and as a
+result of this should be used instead of the `Benchmark` module.
+
+In short:
+
+1. Don't trust benchmarks you find on the internet.
+2. Never make claims based on just benchmarks, always measure in production to
+ confirm your findings.
+3. X being N times faster than Y is meaningless if you don't know what impact it
+ will actually have on your production environment.
+4. A production environment is the _only_ benchmark that always tells the truth
+ (unless your performance monitoring systems are not set up correctly).
+5. If you must write a benchmark use the benchmark-ips Gem instead of Ruby's
+ `Benchmark` module.
+
+## Importance of Changes
+
+When working on performance improvements, it's important to always ask yourself
+the question "How important is it to improve the performance of this piece of
+code?". Not every piece of code is equally important and it would be a waste to
+spend a week trying to improve something that only impacts a tiny fraction of
+our users. For example, spending a week trying to squeeze 10 milliseconds out of
+a method is a waste of time when you could have spent a week squeezing out 10
+seconds elsewhere.
+
+There is no clear set of steps that you can follow to determine if a certain
+piece of code is worth optimizing. The only two things you can do are:
+
+1. Think about what the code does, how it's used, how many times it's called and
+ how much time is spent in it relative to the total execution time (e.g., the
+ total time spent in a web request).
+2. Ask others (preferably in the form of an issue).
+
+Some examples of changes that aren't really important/worth the effort:
+
+* Replacing double quotes with single quotes.
+* Replacing usage of Array with Set when the list of values is very small.
+* Replacing library A with library B when both only take up 0.1% of the total
+ execution time.
+* Calling `freeze` on every string (see [String Freezing](#string-freezing)).
+
+## Slow Operations & Sidekiq
+
+Slow operations (e.g. merging branches) or operations that are prone to errors
+(using external APIs) should be performed in a Sidekiq worker instead of
+directly in a web request as much as possible. This has numerous benefits such
+as:
+
+1. An error won't prevent the request from completing.
+2. The process being slow won't affect the loading time of a page.
+3. In case of a failure it's easy to re-try the process (Sidekiq takes care of
+ this automatically).
+4. By isolating the code from a web request it will hopefully be easier to test
+ and maintain.
+
+It's especially important to use Sidekiq as much as possible when dealing with
+Git operations as these operations can take quite some time to complete
+depending on the performance of the underlying storage system.
+
+## Git Operations
+
+Care should be taken to not run unnecessary Git operations. For example,
+retrieving the list of branch names using `Repository#branch_names` can be done
+without an explicit check if a repository exists or not. In other words, instead
+of this:
+
+```ruby
+if repository.exists?
+ repository.branch_names.each do |name|
+ ...
+ end
+end
+```
+
+You can just write:
+
+```ruby
+repository.branch_names.each do |name|
+ ...
+end
+```
+
+## Caching
+
+Operations that will often return the same result should be cached using Redis,
+in particular Git operations. When caching data in Redis, make sure the cache is
+flushed whenever needed. For example, a cache for the list of tags should be
+flushed whenever a new tag is pushed or a tag is removed.
+
+When adding cache expiration code for repositories, this code should be placed
+in one of the before/after hooks residing in the Repository class. For example,
+if a cache should be flushed after importing a repository this code should be
+added to `Repository#after_import`. This ensures the cache logic stays within
+the Repository class instead of leaking into other classes.
+
+When caching data, make sure to also memoize the result in an instance variable.
+While retrieving data from Redis is much faster than raw Git operations, it still
+has overhead. By caching the result in an instance variable, repeated calls to
+the same method won't end up retrieving data from Redis upon every call. When
+memoizing cached data in an instance variable, make sure to also reset the
+instance variable when flushing the cache. An example:
+
+
+```ruby
+def first_branch
+ @first_branch ||= cache.fetch(:first_branch) { branches.first }
+end
+
+def expire_first_branch_cache
+ cache.expire(:first_branch)
+ @first_branch = nil
+end
+```
+
+## Anti-Patterns
+
+This is a collection of [anti-patterns][anti-pattern] that should be avoided
+unless these changes have a measurable, significant and positive impact on
+production environments.
+
+### String Freezing
+
+In recent Ruby versions calling `freeze` on a String leads to it being allocated
+only once and re-used. For example, on Ruby 2.3 this will only allocate the
+"foo" String once:
+
+```ruby
+10.times do
+ 'foo'.freeze
+end
+```
+
+Blindly adding a `.freeze` call to every String is an anti-pattern that should
+be avoided unless one can prove (using production data) the call actually has a
+positive impact on performance.
+
+This feature of Ruby wasn't really meant to make things faster directly, instead
+it was meant to reduce the number of allocations. Depending on the size of the
+String and how frequently it would be allocated (before the `.freeze` call was
+added), this _may_ make things faster, but there's no guarantee it will.
+
+Another common flavour of this is to not only freeze a String, but also assign
+it to a constant, for example:
+
+```ruby
+SOME_CONSTANT = 'foo'.freeze
+
+9000.times do
+ SOME_CONSTANT
+end
+```
+
+The only reason you should be doing this is to prevent somebody from mutating
+the global String. However, since you can just re-assign constants in Ruby
+there's nothing stopping somebody from doing this elsewhere in the code:
+
+```ruby
+SOME_CONSTANT = 'bar'
+```
+
+### Moving Allocations to Constants
+
+Storing an object as a constant so you only allocate it once _may_ improve
+performance, but there's no guarantee this will. Looking up constants has an
+impact on runtime performance, and as such, using a constant instead of
+referencing an object directly may even slow code down.
+
+[#15607]: https://gitlab.com/gitlab-org/gitlab-ce/issues/15607
+[yorickpeterse]: https://gitlab.com/u/yorickpeterse
+[joshfng]: https://gitlab.com/u/joshfng
+[anti-pattern]: https://en.wikipedia.org/wiki/Anti-pattern
diff --git a/doc/development/testing.md b/doc/development/testing.md
index 672e3fb4649..33eed29ba5c 100644
--- a/doc/development/testing.md
+++ b/doc/development/testing.md
@@ -64,6 +64,7 @@ the command line via `bundle exec teaspoon`, or via a web browser at
methods.
- Use `context` to test branching logic.
- Don't `describe` symbols (see [Gotchas](gotchas.md#dont-describe-symbols)).
+- Don't supply the `:each` argument to hooks since it's the default.
- Prefer `not_to` to `to_not`.
- Try to match the ordering of tests to the ordering within the class.
- Try to follow the [Four-Phase Test][four-phase-test] pattern, using newlines
diff --git a/doc/install/installation.md b/doc/install/installation.md
index e721e70a596..e3af3022262 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -157,22 +157,64 @@ Create a `git` user for GitLab:
## 5. Database
-We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](database_mysql.md). *Note*: because we need to make use of extensions you need at least pgsql 9.1.
+We recommend using a PostgreSQL database. For MySQL check the
+[MySQL setup guide](database_mysql.md).
- # Install the database packages
- sudo apt-get install -y postgresql postgresql-client libpq-dev
+> **Note**: because we need to make use of extensions you need at least pgsql 9.1.
- # Create a user for GitLab
+1. Install the database packages:
+
+ ```bash
+ sudo apt-get install -y postgresql postgresql-client libpq-dev postgresql-contrib
+ ```
+
+1. Create a database user for GitLab:
+
+ ```bash
sudo -u postgres psql -d template1 -c "CREATE USER git CREATEDB;"
+ ```
+
+1. Create the GitLab production database and grant all privileges on database:
- # Create the GitLab production database & grant all privileges on database
+ ```bash
sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production OWNER git;"
+ ```
+
+1. Create the `pg_trgm` extension (required for GitLab 8.6+):
+
+ ```bash
+ sudo -u postgres psql -d template1 -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
+ ```
+
+1. Try connecting to the new database with the new user:
- # Try connecting to the new database with the new user
+ ```bash
sudo -u git -H psql -d gitlabhq_production
+ ```
+
+1. Check if the `pg_trgm` extension is enabled:
+
+ ```bash
+ SELECT true AS enabled
+ FROM pg_available_extensions
+ WHERE name = 'pg_trgm'
+ AND installed_version IS NOT NULL;
+ ```
+
+ If the extension is enabled this will produce the following output:
- # Quit the database session
+ ```
+ enabled
+ ---------
+ t
+ (1 row)
+ ```
+
+1. Quit the database session:
+
+ ```bash
gitlabhq_production> \q
+ ```
## 6. Redis
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 58f409746cd..df8e8bdc476 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -64,7 +64,10 @@ If you have enough RAM memory and a recent CPU the speed of GitLab is mainly lim
### Memory
You need at least 2GB of addressable memory (RAM + swap) to install and use GitLab!
-With less memory GitLab will give strange errors during the reconfigure run and 500 errors during usage.
+The operating system and any other running applications will also be using memory
+so keep in mind that you need at least 2GB available before running GitLab. With
+less memory GitLab will give strange errors during the reconfigure run and 500
+errors during usage.
- 512MB RAM + 1.5GB of swap is the absolute minimum but we strongly **advise against** this amount of memory. See the unicorn worker section below for more advice.
- 1GB RAM + 1GB swap supports up to 100 users but it will be very slow
@@ -77,6 +80,10 @@ With less memory GitLab will give strange errors during the reconfigure run and
- 128GB RAM supports up to 32,000 users
- More users? Run it on [multiple application servers](https://about.gitlab.com/high-availability/)
+We recommend having at least 1GB of swap on your server, even if you currently have
+enough available RAM. Having swap will help reduce the chance of errors occuring
+if your available memory changes.
+
Notice: The 25 workers of Sidekiq will show up as separate processes in your process overview (such as top or htop) but they share the same RAM allocation since Sidekiq is a multithreaded application. Please see the section below about Unicorn workers for information about many you need of those.
## Gitlab Runner
diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md
index 60729316cde..b4283a526f3 100644
--- a/doc/update/patch_versions.md
+++ b/doc/update/patch_versions.md
@@ -57,10 +57,10 @@ sudo -u git -H make
cd /home/git/gitlab
# PostgreSQL
-sudo -u git -H bundle install --without development test mysql --deployment
+sudo -u git -H bundle install --without development test mysql --with postgres --deployment
# MySQL
-sudo -u git -H bundle install --without development test postgres --deployment
+sudo -u git -H bundle install --without development test postgres --with mysql --deployment
# Optional: clean up old gems
sudo -u git -H bundle clean
diff --git a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
index 31620044b15..83db44c10b1 100644
--- a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
+++ b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
@@ -152,4 +152,4 @@ If you are using OS X you can use `osxkeychain` to store and encrypt your creden
For Windows, you can use `wincred` or Microsoft's [Git Credential Manager for Windows](https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases).
More details about various methods of storing the user credentials can be found
-on [Git Credential Storage documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage). \ No newline at end of file
+on [Git Credential Storage documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage).
diff --git a/docker/README.md b/docker/README.md
index 7514d610aec..ee1f32adc26 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -1,7 +1,7 @@
# GitLab Docker images
-* The official GitLab Community Edition Docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ce/).
-* The official GitLab Enterprise Edition Docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ee/).
+* The official GitLab Community Edition Docker image is [available on Docker Hub](https://hub.docker.com/r/gitlab/gitlab-ce/).
+* The official GitLab Enterprise Edition Docker image is [available on Docker Hub](https://hub.docker.com/r/gitlab/gitlab-ee/).
* The complete usage guide can be found in [Using GitLab Docker images](http://doc.gitlab.com/omnibus/docker/)
* The Dockerfile used for building public images is in [Omnibus Repository](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/docker)
-* Check the guide for [creating Omnibus-based Docker Image](http://doc.gitlab.com/omnibus/build/README.html#Build-Docker-image)
+* Check the guide for [creating Omnibus-based Docker Image](http://doc.gitlab.com/omnibus/build/README.html#build-docker-image)
diff --git a/features/groups.feature b/features/groups.feature
index 419a5d3963d..49e939807b5 100644
--- a/features/groups.feature
+++ b/features/groups.feature
@@ -7,10 +7,6 @@ Feature: Groups
When I visit group "NonExistentGroup" page
Then page status code should be 404
- Scenario: I should have back to group button
- When I visit group "Owned" page
- Then I should see back to dashboard button
-
@javascript
Scenario: I should see group "Owned" dashboard list
When I visit group "Owned" page
diff --git a/features/project/create.feature b/features/project/create.feature
index 27136798e36..67336d73bf7 100644
--- a/features/project/create.feature
+++ b/features/project/create.feature
@@ -7,20 +7,8 @@ Feature: Project Create
@javascript
Scenario: User create a project
Given I sign in as a user
- When I visit new project page
- And I have an ssh key
- And fill project form with valid data
- Then I should see project page
- And I should see empty project instuctions
-
- @javascript
- Scenario: Empty project instructions
- Given I sign in as a user
And I have an ssh key
When I visit new project page
And fill project form with valid data
- Then I see empty project instuctions
- And I click on HTTP
- Then Remote url should update to http link
- And If I click on SSH
- Then Remote url should update to ssh link
+ Then I should see project page
+ And I should see empty project instructions
diff --git a/features/steps/group/milestones.rb b/features/steps/group/milestones.rb
index a167d259837..f5fddab357d 100644
--- a/features/steps/group/milestones.rb
+++ b/features/steps/group/milestones.rb
@@ -5,7 +5,9 @@ class Spinach::Features::GroupMilestones < Spinach::FeatureSteps
include SharedUser
step 'I click on group milestones' do
- click_link 'Milestones'
+ page.within('.layout-nav') do
+ click_link 'Milestones'
+ end
end
step 'I should see group milestones index page has no milestones' do
@@ -84,7 +86,7 @@ class Spinach::Features::GroupMilestones < Spinach::FeatureSteps
end
step 'I click on the "Labels" tab' do
- page.within('.nav-links') do
+ page.within('.content .nav-links') do
page.find(:xpath, "//a[@href='#tab-labels']").click
end
end
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index e5b7db4c5e3..483370f41c6 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -4,10 +4,6 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
include SharedGroup
include SharedUser
- step 'I should see back to dashboard button' do
- expect(page).to have_content 'Go to dashboard'
- end
-
step 'I should see group "Owned"' do
expect(page).to have_content '@owned'
end
diff --git a/features/steps/project/commits/tags.rb b/features/steps/project/commits/tags.rb
index eff4234a44a..912ba580efd 100644
--- a/features/steps/project/commits/tags.rb
+++ b/features/steps/project/commits/tags.rb
@@ -57,11 +57,11 @@ class Spinach::Features::ProjectCommitsTags < Spinach::FeatureSteps
end
step 'I should see new an error that tag ref is invalid' do
- expect(page).to have_content 'Invalid reference name'
+ expect(page).to have_content 'Target foo is invalid'
end
step 'I should see new an error that tag already exists' do
- expect(page).to have_content 'Tag already exists'
+ expect(page).to have_content 'Tag v1.0.0 already exists'
end
step "I visit tag 'v1.1.0' page" do
diff --git a/features/steps/project/create.rb b/features/steps/project/create.rb
index 422b151eaa2..5f5f806df36 100644
--- a/features/steps/project/create.rb
+++ b/features/steps/project/create.rb
@@ -13,33 +13,9 @@ class Spinach::Features::ProjectCreate < Spinach::FeatureSteps
expect(current_path).to eq namespace_project_path(Project.last.namespace, Project.last)
end
- step 'I should see empty project instuctions' do
+ step 'I should see empty project instructions' do
expect(page).to have_content "git init"
expect(page).to have_content "git remote"
expect(page).to have_content Project.last.url_to_repo
end
-
- step 'I see empty project instuctions' do
- expect(page).to have_content "git init"
- expect(page).to have_content "git remote"
- expect(page).to have_content Project.last.url_to_repo
- end
-
- step 'I click on HTTP' do
- find('#clone-dropdown').click
- find('.http-selector').click
- end
-
- step 'Remote url should update to http link' do
- expect(page).to have_content "git remote add origin #{Project.last.http_url_to_repo}"
- end
-
- step 'If I click on SSH' do
- find('#clone-dropdown').click
- find('.ssh-selector').click
- end
-
- step 'Remote url should update to ssh link' do
- expect(page).to have_content "git remote add origin #{Project.last.url_to_repo}"
- end
end
diff --git a/features/steps/user.rb b/features/steps/user.rb
index 3230234cb6d..b1d088f07f9 100644
--- a/features/steps/user.rb
+++ b/features/steps/user.rb
@@ -12,7 +12,7 @@ class Spinach::Features::User < Spinach::FeatureSteps
user = User.find_by(name: 'John Doe')
project = contributed_project
- # Issue controbution
+ # Issue contribution
issue_params = { title: 'Bug in old browser' }
Issues::CreateService.new(project, user, issue_params).execute
@@ -28,7 +28,7 @@ class Spinach::Features::User < Spinach::FeatureSteps
end
step 'I should see contributed projects' do
- page.within '.contributed-projects' do
+ page.within '#contributed' do
expect(page).to have_content(@contributed_project.name)
end
end
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 4544a41b1e3..93a3a5ce089 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -12,14 +12,20 @@ module API
# Parameters:
# id (required) - The ID of a project
# ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used
+ # since (optional) - Only commits after or in this date will be returned
+ # until (optional) - Only commits before or in this date will be returned
# Example Request:
# GET /projects/:id/repository/commits
get ":id/repository/commits" do
+ datetime_attributes! :since, :until
+
page = (params[:page] || 0).to_i
per_page = (params[:per_page] || 20).to_i
ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
+ after = params[:since]
+ before = params[:until]
- commits = user_project.repository.commits(ref, nil, per_page, page * per_page)
+ commits = user_project.repository.commits(ref, limit: per_page, offset: page * per_page, after: after, before: before)
present commits, with: Entities::RepoCommit
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 716ca6f7ed9..2870a6a40ef 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -170,10 +170,10 @@ module API
expose :label_names, as: :labels
expose :milestone, using: Entities::Milestone
expose :assignee, :author, using: Entities::UserBasic
-
expose :subscribed do |issue, options|
issue.subscribed?(options[:current_user])
end
+ expose :user_notes_count
end
class MergeRequest < ProjectEntity
@@ -187,10 +187,10 @@ module API
expose :milestone, using: Entities::Milestone
expose :merge_when_build_succeeds
expose :merge_status
-
expose :subscribed do |merge_request, options|
merge_request.subscribed?(options[:current_user])
end
+ expose :user_notes_count
end
class MergeRequestChanges < MergeRequest
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 5bbf721321d..40c967453fb 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -183,6 +183,22 @@ module API
Gitlab::Access.options_with_owner.values.include? level.to_i
end
+ # Checks the occurrences of datetime attributes, each attribute if present in the params hash must be in ISO 8601
+ # format (YYYY-MM-DDTHH:MM:SSZ) or a Bad Request error is invoked.
+ #
+ # Parameters:
+ # keys (required) - An array consisting of elements that must be parseable as dates from the params hash
+ def datetime_attributes!(*keys)
+ keys.each do |key|
+ begin
+ params[key] = Time.xmlschema(params[key]) if params[key].present?
+ rescue ArgumentError
+ message = "\"" + key.to_s + "\" must be a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ"
+ render_api_error!(message, 400)
+ end
+ end
+ end
+
def issuable_order_by
if params["order_by"] == 'updated_at'
'updated_at'
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index 5e2fb863a8f..132f9cd1966 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -79,24 +79,6 @@ module Gitlab
'rm-project', "#{name}.git"])
end
- # Add repository tag from passed ref
- #
- # path - project path with namespace
- # tag_name - new tag name
- # ref - HEAD for new tag
- # message - optional message for tag (annotated tag)
- #
- # Ex.
- # add_tag("gitlab/gitlab-ci", "v4.0", "master")
- # add_tag("gitlab/gitlab-ci", "v4.0", "master", "message")
- #
- def add_tag(path, tag_name, ref, message = nil)
- cmd = %W(#{gitlab_shell_path}/bin/gitlab-projects create-tag #{path}.git
- #{tag_name} #{ref})
- cmd << message unless message.nil? || message.empty?
- Gitlab::Utils.system_silent(cmd)
- end
-
# Gc repository
#
# path - project path with namespace
diff --git a/lib/gitlab/bitbucket_import/client.rb b/lib/gitlab/bitbucket_import/client.rb
index 9bb507b5edd..9b83292ef33 100644
--- a/lib/gitlab/bitbucket_import/client.rb
+++ b/lib/gitlab/bitbucket_import/client.rb
@@ -12,7 +12,7 @@ module Gitlab
token_secret = import_data_credentials[:bb_session][:bitbucket_access_token_secret]
new(token, token_secret)
else
- raise Projects::ImportService::Error, "Unable to find project import data credentials for project ID: #{@project.id}"
+ raise Projects::ImportService::Error, "Unable to find project import data credentials for project ID: #{project.id}"
end
end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 3ed1eec517c..d2a0e316cbe 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -122,20 +122,25 @@ module Gitlab
build_status_object(true)
end
+ def can_user_do_action?(action)
+ @permission_cache ||= {}
+ @permission_cache[action] ||= user.can?(action, project)
+ end
+
def change_access_check(change)
oldrev, newrev, ref = change.split(' ')
action =
if project.protected_branch?(branch_name(ref))
protected_branch_action(oldrev, newrev, branch_name(ref))
- elsif protected_tag?(tag_name(ref))
+ elsif (tag_ref = tag_name(ref)) && protected_tag?(tag_ref)
# Prevent any changes to existing git tag unless user has permissions
:admin_project
else
:push_code
end
- unless user.can?(action, project)
+ unless can_user_do_action?(action)
status =
case action
when :force_push_code_to_protected_branches
@@ -176,7 +181,7 @@ module Gitlab
end
def protected_tag?(tag_name)
- project.repository.tag_names.include?(tag_name)
+ project.repository.tag_exists?(tag_name)
end
def user_allowed?
diff --git a/lib/gitlab/github_import/comment_formatter.rb b/lib/gitlab/github_import/comment_formatter.rb
index 7d58e53991a..7d679eaec6a 100644
--- a/lib/gitlab/github_import/comment_formatter.rb
+++ b/lib/gitlab/github_import/comment_formatter.rb
@@ -28,13 +28,26 @@ module Gitlab
end
def line_code
- if on_diff?
- Gitlab::Diff::LineCode.generate(raw_data.path, raw_data.position, 0)
- end
+ return unless on_diff?
+
+ parsed_lines = Gitlab::Diff::Parser.new.parse(diff_hunk.lines)
+ generate_line_code(parsed_lines.to_a.last)
+ end
+
+ def generate_line_code(line)
+ Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
def on_diff?
- raw_data.path && raw_data.position
+ diff_hunk.present?
+ end
+
+ def diff_hunk
+ raw_data.diff_hunk
+ end
+
+ def file_path
+ raw_data.path
end
def note
diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb
index 67622f321a6..c8f12577112 100644
--- a/lib/gitlab/push_data_builder.rb
+++ b/lib/gitlab/push_data_builder.rb
@@ -66,7 +66,7 @@ module Gitlab
# This method provide a sample data generated with
# existing project and commits to test webhooks
def build_sample(project, user)
- commits = project.repository.commits(project.default_branch, nil, 3)
+ commits = project.repository.commits(project.default_branch, limit: 3)
ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{project.default_branch}"
build(project, user, commits.last.id, commits.first.id, ref, commits)
end
diff --git a/lib/gitlab/sanitizers/svg.rb b/lib/gitlab/sanitizers/svg.rb
new file mode 100644
index 00000000000..b98589dff89
--- /dev/null
+++ b/lib/gitlab/sanitizers/svg.rb
@@ -0,0 +1,37 @@
+require_relative "svg/whitelist"
+
+module Gitlab
+ module Sanitizers
+ module SVG
+ def self.clean(data)
+ Loofah.xml_document(data).scrub!(Scrubber.new).to_s
+ end
+
+ class Scrubber < Loofah::Scrubber
+ # http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#embedding-custom-non-visible-data-with-the-data-*-attributes
+ DATA_ATTR_PATTERN = /\Adata-(?!xml)[a-z_][\w.\u00E0-\u00F6\u00F8-\u017F\u01DD-\u02AF-]*\z/u
+
+ def scrub(node)
+ unless ALLOWED_ELEMENTS.include?(node.name)
+ node.unlink
+ else
+ node.attributes.each do |attr_name, attr|
+ valid_attributes = ALLOWED_ATTRIBUTES[node.name]
+
+ unless valid_attributes && valid_attributes.include?(attr_name)
+ if ALLOWED_DATA_ATTRIBUTES_IN_ELEMENTS.include?(node.name) &&
+ attr_name.start_with?('data-')
+ # Arbitrary data attributes are allowed. Verify that the attribute
+ # is a valid data attribute.
+ attr.unlink unless attr_name =~ DATA_ATTR_PATTERN
+ else
+ attr.unlink
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/sanitizers/svg/whitelist.rb b/lib/gitlab/sanitizers/svg/whitelist.rb
new file mode 100644
index 00000000000..917e795b29e
--- /dev/null
+++ b/lib/gitlab/sanitizers/svg/whitelist.rb
@@ -0,0 +1,107 @@
+# Generated from:
+# SVG element list: https://www.w3.org/TR/SVG/eltindex.html
+# SVG Attribute list: https://www.w3.org/TR/SVG/attindex.html
+module Gitlab
+ module Sanitizers
+ module SVG
+ ALLOWED_ELEMENTS = %w[
+ a altGlyph altGlyphDef altGlyphItem animate
+ animateColor animateMotion animateTransform circle clipPath color-profile
+ cursor defs desc ellipse feBlend feColorMatrix feComponentTransfer
+ feComposite feConvolveMatrix feDiffuseLighting feDisplacementMap
+ feDistantLight feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur
+ feImage feMerge feMergeNode feMorphology feOffset fePointLight
+ feSpecularLighting feSpotLight feTile feTurbulence filter font font-face
+ font-face-format font-face-name font-face-src font-face-uri foreignObject
+ g glyph glyphRef hkern image line linearGradient marker mask metadata
+ missing-glyph mpath path pattern polygon polyline radialGradient rect
+ script set stop style svg switch symbol text textPath title tref tspan use
+ view vkern].freeze
+
+ ALLOWED_DATA_ATTRIBUTES_IN_ELEMENTS = %w[svg].freeze
+
+ ALLOWED_ATTRIBUTES = {
+ 'a' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage target text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'altGlyph' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight format glyph-orientation-horizontal glyph-orientation-vertical glyphRef id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'altGlyphDef' => %w[id xml:base xml:lang xml:space],
+ 'altGlyphItem' => %w[id xml:base xml:lang xml:space],
+ 'animate' => %w[accumulate additive alignment-baseline attributeName attributeType baseline-shift begin by calcMode clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dur enable-background end externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight from glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning keySplines keyTimes letter-spacing lighting-color marker-end marker-mid marker-start mask max min onbegin onend onload onrepeat opacity overflow pointer-events repeatCount repeatDur requiredExtensions requiredFeatures restart shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width systemLanguage text-anchor text-decoration text-rendering to unicode-bidi values visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'animateColor' => %w[accumulate additive alignment-baseline attributeName attributeType baseline-shift begin by calcMode clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dur enable-background end externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight from glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning keySplines keyTimes letter-spacing lighting-color marker-end marker-mid marker-start mask max min onbegin onend onload onrepeat opacity overflow pointer-events repeatCount repeatDur requiredExtensions requiredFeatures restart shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width systemLanguage text-anchor text-decoration text-rendering to unicode-bidi values visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'animateMotion' => %w[accumulate additive begin by calcMode dur end externalResourcesRequired fill from id keyPoints keySplines keyTimes max min onbegin onend onload onrepeat origin path repeatCount repeatDur requiredExtensions requiredFeatures restart rotate systemLanguage to values xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'animateTransform' => %w[accumulate additive attributeName attributeType begin by calcMode dur end externalResourcesRequired fill from id keySplines keyTimes max min onbegin onend onload onrepeat repeatCount repeatDur requiredExtensions requiredFeatures restart systemLanguage to type values xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'circle' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events r requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'clipPath' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule clipPathUnits color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'color-profile' => %w[id local name rendering-intent xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'cursor' => %w[externalResourcesRequired id requiredExtensions requiredFeatures systemLanguage x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'defs' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'desc' => %w[class id style xml:base xml:lang xml:space],
+ 'ellipse' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rx ry shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'feBlend' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask mode opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feColorMatrix' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering type unicode-bidi values visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feComponentTransfer' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feComposite' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 k1 k2 k3 k4 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity operator overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feConvolveMatrix' => %w[alignment-baseline baseline-shift bias class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display divisor dominant-baseline edgeMode enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelMatrix kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity order overflow pointer-events preserveAlpha result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style targetX targetY text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feDiffuseLighting' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor diffuseConstant direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style surfaceScale text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feDisplacementMap' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result scale shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xChannelSelector xml:base xml:lang xml:space y yChannelSelector],
+ 'feDistantLight' => %w[azimuth elevation id xml:base xml:lang xml:space],
+ 'feFlood' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feFuncA' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
+ 'feFuncB' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
+ 'feFuncG' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
+ 'feFuncR' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
+ 'feGaussianBlur' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stdDeviation stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feImage' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events preserveAspectRatio result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'feMerge' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feMergeNode' => %w[id xml:base xml:lang xml:space],
+ 'feMorphology' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity operator overflow pointer-events radius result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feOffset' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'fePointLight' => %w[id x xml:base xml:lang xml:space y z],
+ 'feSpecularLighting' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering specularConstant specularExponent stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style surfaceScale text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feSpotLight' => %w[id limitingConeAngle pointsAtX pointsAtY pointsAtZ specularExponent x xml:base xml:lang xml:space y z],
+ 'feTile' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feTurbulence' => %w[alignment-baseline baseFrequency baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask numOctaves opacity overflow pointer-events result seed shape-rendering stitchTiles stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering type unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'filter' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter filterRes filterUnits flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events primitiveUnits shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'font' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x horiz-origin-y id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'font-face' => %w[accent-height alphabetic ascent bbox cap-height descent font-family font-size font-stretch font-style font-variant font-weight hanging id ideographic mathematical overline-position overline-thickness panose-1 slope stemh stemv strikethrough-position strikethrough-thickness underline-position underline-thickness unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical widths x-height xml:base xml:lang xml:space],
+ 'font-face-format' => %w[id string xml:base xml:lang xml:space],
+ 'font-face-name' => %w[id name xml:base xml:lang xml:space],
+ 'font-face-src' => %w[id xml:base xml:lang xml:space],
+ 'font-face-uri' => %w[id xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'foreignObject' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'g' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'glyph' => %w[alignment-baseline arabic-form baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x id image-rendering kerning lang letter-spacing lighting-color marker-end marker-mid marker-start mask opacity orientation overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'glyphRef' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight format glyph-orientation-horizontal glyph-orientation-vertical glyphRef id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'hkern' => %w[g1 g2 id k u1 u2 xml:base xml:lang xml:space],
+ 'image' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'line' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode x1 x2 xml:base xml:lang xml:space y1 y2],
+ 'linearGradient' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical gradientTransform gradientUnits id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering spreadMethod stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x1 x2 xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space y1 y2],
+ 'marker' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start markerHeight markerUnits markerWidth mask opacity orient overflow pointer-events preserveAspectRatio refX refY shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi viewBox visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'mask' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask maskContentUnits maskUnits opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'metadata' => %w[id xml:base xml:lang xml:space],
+ 'missing-glyph' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'mpath' => %w[externalResourcesRequired id xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'path' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pathLength pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'pattern' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow patternContentUnits patternTransform patternUnits pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi viewBox visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'polygon' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events points requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'polyline' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events points requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'radialGradient' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight fx fy glyph-orientation-horizontal glyph-orientation-vertical gradientTransform gradientUnits id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events r shape-rendering spreadMethod stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space],
+ 'rect' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rx ry shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'script' => %w[externalResourcesRequired id type xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'set' => %w[attributeName attributeType begin dur end externalResourcesRequired fill id max min onbegin onend onload onrepeat repeatCount repeatDur requiredExtensions requiredFeatures restart systemLanguage to xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'stop' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask offset opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'style' => %w[id media title type xml:base xml:lang xml:space],
+ 'svg' => %w[alignment-baseline baseProfile baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering contentScriptType contentStyleType cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onabort onactivate onclick onerror onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup onresize onscroll onunload onzoom opacity overflow pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi version viewBox visibility width word-spacing writing-mode x xml:base xml:lang xml:space xmlns y zoomAndPan],
+ 'switch' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'symbol' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events preserveAspectRatio shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi viewBox visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'text' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength transform unicode-bidi visibility word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'textPath' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask method onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering spacing startOffset stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space],
+ 'title' => %w[class id style xml:base xml:lang xml:space],
+ 'tref' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode x xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'tspan' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'use' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'view' => %w[externalResourcesRequired id preserveAspectRatio viewBox viewTarget xml:base xml:lang xml:space zoomAndPan],
+ 'vkern' => %w[g1 g2 id k u1 u2 xml:base xml:lang xml:space]
+ }.freeze
+ end
+ end
+end
diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb
index 2bbbd3074e8..67a09d5abf5 100644
--- a/lib/gitlab/url_builder.rb
+++ b/lib/gitlab/url_builder.rb
@@ -62,7 +62,7 @@ module Gitlab
end
def wiki_page_url
- "#{Gitlab.config.gitlab.url}#{object.wiki.wiki_base_path}/#{object.slug}"
+ "#{object.wiki.wiki_base_path}/#{object.slug}"
end
end
end
diff --git a/lib/tasks/auto_annotate_models.rake b/lib/tasks/auto_annotate_models.rake
new file mode 100644
index 00000000000..16bad4bd2bd
--- /dev/null
+++ b/lib/tasks/auto_annotate_models.rake
@@ -0,0 +1,44 @@
+if Rails.env.development?
+ task :set_annotation_options do
+ # You can override any of these by setting an environment variable of the
+ # same name.
+ Annotate.set_defaults(
+ 'routes' => 'false',
+ 'position_in_routes' => 'before',
+ 'position_in_class' => 'before',
+ 'position_in_test' => 'before',
+ 'position_in_fixture' => 'before',
+ 'position_in_factory' => 'before',
+ 'position_in_serializer' => 'before',
+ 'show_foreign_keys' => 'true',
+ 'show_indexes' => 'false',
+ 'simple_indexes' => 'false',
+ 'model_dir' => 'app/models',
+ 'root_dir' => '',
+ 'include_version' => 'false',
+ 'require' => '',
+ 'exclude_tests' => 'true',
+ 'exclude_fixtures' => 'true',
+ 'exclude_factories' => 'true',
+ 'exclude_serializers' => 'true',
+ 'exclude_scaffolds' => 'true',
+ 'exclude_controllers' => 'true',
+ 'exclude_helpers' => 'true',
+ 'ignore_model_sub_dir' => 'false',
+ 'ignore_columns' => nil,
+ 'ignore_unknown_models' => 'false',
+ 'hide_limit_column_types' => 'integer,boolean',
+ 'skip_on_db_migrate' => 'false',
+ 'format_bare' => 'true',
+ 'format_rdoc' => 'false',
+ 'format_markdown' => 'false',
+ 'sort' => 'false',
+ 'force' => 'false',
+ 'trace' => 'false',
+ 'wrapper_open' => nil,
+ 'wrapper_close' => nil,
+ )
+ end
+
+ Annotate.load_tasks
+end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index c14b99606ba..4d61345696a 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -10,7 +10,6 @@
# updated_at :datetime
# creator_id :integer
# issues_enabled :boolean default(TRUE), not null
-# wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer
@@ -61,6 +60,12 @@ FactoryGirl.define do
trait :private do
visibility_level Gitlab::VisibilityLevel::PRIVATE
end
+
+ trait :empty_repo do
+ after(:create) do |project|
+ project.create_repository
+ end
+ end
end
# Project with empty repository
@@ -68,9 +73,7 @@ FactoryGirl.define do
# This is a case when you just created a project
# but not pushed any code there yet
factory :project_empty_repo, parent: :empty_project do
- after :create do |project|
- project.create_repository
- end
+ empty_repo
end
# Project with test repository
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index b57131f68d5..d5755c293c5 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -264,12 +264,14 @@ describe 'Issues', feature: true do
visit namespace_project_issues_path(project.namespace, project, sort: sort_value_milestone_soon)
expect(first_issue).to include('foo')
+ expect(last_issue).to include('baz')
end
it 'sorts by least recently due milestone' do
visit namespace_project_issues_path(project.namespace, project, sort: sort_value_milestone_later)
expect(first_issue).to include('bar')
+ expect(last_issue).to include('baz')
end
end
diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb
index 4433ef2d6f1..8c38dd5b122 100644
--- a/spec/features/login_spec.rb
+++ b/spec/features/login_spec.rb
@@ -37,7 +37,7 @@ feature 'Login', feature: true do
end
def enter_code(code)
- fill_in 'Two-factor authentication code', with: code
+ fill_in 'Two-factor Authentication code', with: code
click_button 'Verify code'
end
diff --git a/spec/features/projects/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/developer_views_empty_project_instructions_spec.rb
new file mode 100644
index 00000000000..0c51fe72ca4
--- /dev/null
+++ b/spec/features/projects/developer_views_empty_project_instructions_spec.rb
@@ -0,0 +1,63 @@
+require 'rails_helper'
+
+feature 'Developer views empty project instructions', feature: true do
+ let(:project) { create(:empty_project, :empty_repo) }
+ let(:developer) { create(:user) }
+
+ background do
+ project.team << [developer, :developer]
+
+ login_as(developer)
+ end
+
+ context 'without an SSH key' do
+ scenario 'defaults to HTTP' do
+ visit_project
+
+ expect_instructions_for('http')
+ end
+
+ scenario 'switches to SSH', js: true do
+ visit_project
+
+ select_protocol('SSH')
+
+ expect_instructions_for('ssh')
+ end
+ end
+
+ context 'with an SSH key' do
+ background do
+ create(:personal_key, user: developer)
+ end
+
+ scenario 'defaults to SSH' do
+ visit_project
+
+ expect_instructions_for('ssh')
+ end
+
+ scenario 'switches to HTTP', js: true do
+ visit_project
+
+ select_protocol('HTTP')
+
+ expect_instructions_for('http')
+ end
+ end
+
+ def visit_project
+ visit namespace_project_path(project.namespace, project)
+ end
+
+ def select_protocol(protocol)
+ find('#clone-dropdown').click
+ find(".#{protocol.downcase}-selector").click
+ end
+
+ def expect_instructions_for(protocol)
+ msg = :"#{protocol.downcase}_url_to_repo"
+
+ expect(page).to have_content("git clone #{project.send(msg)}")
+ end
+end
diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb
index 51b754ff85c..58aabd913eb 100644
--- a/spec/features/signup_spec.rb
+++ b/spec/features/signup_spec.rb
@@ -7,10 +7,10 @@ feature 'Signup', feature: true do
visit root_path
- fill_in 'user_name', with: user.name
- fill_in 'user_username', with: user.username
- fill_in 'user_email', with: user.email
- fill_in 'user_password_sign_up', with: user.password
+ fill_in 'new_user_name', with: user.name
+ fill_in 'new_user_username', with: user.username
+ fill_in 'new_user_email', with: user.email
+ fill_in 'new_user_password', with: user.password
click_button "Sign up"
expect(current_path).to eq users_almost_there_path
@@ -25,10 +25,10 @@ feature 'Signup', feature: true do
visit root_path
- fill_in 'user_name', with: user.name
- fill_in 'user_username', with: user.username
- fill_in 'user_email', with: existing_user.email
- fill_in 'user_password_sign_up', with: user.password
+ fill_in 'new_user_name', with: user.name
+ fill_in 'new_user_username', with: user.username
+ fill_in 'new_user_email', with: existing_user.email
+ fill_in 'new_user_password', with: user.password
click_button "Sign up"
expect(current_path).to eq user_registration_path
@@ -42,10 +42,10 @@ feature 'Signup', feature: true do
visit root_path
- fill_in 'user_name', with: user.name
- fill_in 'user_username', with: user.username
- fill_in 'user_email', with: existing_user.email
- fill_in 'user_password_sign_up', with: user.password
+ fill_in 'new_user_name', with: user.name
+ fill_in 'new_user_username', with: user.username
+ fill_in 'new_user_email', with: existing_user.email
+ fill_in 'new_user_password', with: user.password
click_button "Sign up"
expect(current_path).to eq user_registration_path
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index c1248162031..cf116040394 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -5,10 +5,10 @@ feature 'Users', feature: true do
scenario 'GET /users/sign_in creates a new user account' do
visit new_user_session_path
- fill_in 'user_name', with: 'Name Surname'
- fill_in 'user_username', with: 'Great'
- fill_in 'user_email', with: 'name@mail.com'
- fill_in 'user_password_sign_up', with: 'password1234'
+ fill_in 'new_user_name', with: 'Name Surname'
+ fill_in 'new_user_username', with: 'Great'
+ fill_in 'new_user_email', with: 'name@mail.com'
+ fill_in 'new_user_password', with: 'password1234'
expect { click_button 'Sign up' }.to change { User.count }.by(1)
end
@@ -31,10 +31,10 @@ feature 'Users', feature: true do
scenario 'Should show one error if email is already taken' do
visit new_user_session_path
- fill_in 'user_name', with: 'Another user name'
- fill_in 'user_username', with: 'anotheruser'
- fill_in 'user_email', with: user.email
- fill_in 'user_password_sign_up', with: '12341234'
+ fill_in 'new_user_name', with: 'Another user name'
+ fill_in 'new_user_username', with: 'anotheruser'
+ fill_in 'new_user_email', with: user.email
+ fill_in 'new_user_password', with: '12341234'
expect { click_button 'Sign up' }.to change { User.count }.by(0)
expect(page).to have_text('Email has already been taken')
expect(number_of_errors_on_page(page)).to be(1), 'errors on page:\n #{errors_on_page page}'
diff --git a/spec/fixtures/sanitized.svg b/spec/fixtures/sanitized.svg
new file mode 100644
index 00000000000..8f84b8f5e20
--- /dev/null
+++ b/spec/fixtures/sanitized.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 622 682">
+
+ <defs>
+ <style>.cls-1{fill:#30353e;}.cls-2{fill:#8c929d;}.cls-3{fill:#fc6d26;}.cls-4{fill:#e24329;}.cls-5{fill:#fca326;}</style>
+ </defs>
+ <title>stacked_wm</title>
+ <path id="bg" class="cls-1" d="M622,681H0V-1H622V681h0Z"/>
+ <g id="g12">
+ <path id="path14" class="cls-2" d="M316.89,497.72h-19l0.06,141.74H375V621.93h-58l-0.06-124.22h0Z"/>
+ </g>
+ <g id="g24">
+ <path id="path26" class="cls-2" d="M448.32,614.57a32.46,32.46,0,0,1-23.59,10c-14.5,0-20.35-7.14-20.35-16.45,0-14.07,9.74-20.77,30.52-20.77a86.46,86.46,0,0,1,13.42,1.08v26.19h0Zm-19.7-85.91a63.45,63.45,0,0,0-40.5,14.53l6.73,11.66c7.79-4.54,17.32-9.09,31-9.09,15.58,0,22.51,8,22.51,21.42v6.93a81.48,81.48,0,0,0-13.2-1.08c-33.33,0-50.22,11.69-50.22,36.14,0,21.86,13.42,32.89,33.76,32.89,13.71,0,26.84-6.28,31.38-16.45l3.46,13.85h13.42V567c0-22.94-10-38.3-38.31-38.3h0Z"/>
+ </g>
+ <g id="g28">
+ <path id="path30" class="cls-2" d="M528.4,625.18c-7.14,0-13.42-.87-18.18-3V556.58c6.49-5.41,14.5-9.31,24.68-9.31,18.4,0,25.54,13,25.54,34,0,29.86-11.47,43.93-32,43.93m8-96.52a34.88,34.88,0,0,0-26.19,11.58V522l-0.06-24.24H491.54L491.6,636c9.31,3.9,22.08,6.06,35.93,6.06,35.5,0,52.6-22.72,52.6-61.89,0-30.95-15.8-51.51-43.73-51.51"/>
+ </g>
+ <g id="g32">
+ <path id="path34" class="cls-2" d="M109.84,513.08c16.88,0,27.7,5.63,34.85,11.25l8.19-14.18c-11.16-9.78-26.16-15-42.17-15-40.47,0-68.83,24.67-68.83,74.44,0,52.15,30.59,72.5,65.58,72.5a111,111,0,0,0,42.21-8.22l-0.4-55.72V560.58H97.32v17.53h33.12l0.4,42.31c-4.33,2.16-11.9,3.9-22.08,3.9-28.14,0-47-17.7-47-55,0-37.87,19.48-56.26,48.05-56.26"/>
+ </g>
+ <g id="g36">
+ <path id="path38" class="cls-2" d="M243.79,497.72H225.17l0.06,23.8v82.23c0,22.94,10,38.3,38.31,38.3A64.16,64.16,0,0,0,275,641V624.31a57,57,0,0,1-8.66.65c-15.58,0-22.51-8-22.51-21.42v-56.7H275V531.26H243.85l-0.06-33.54h0Z"/>
+ </g>
+ <path id="path40" class="cls-2" d="M177.94,639.46h18.61V531.26H177.94v108.2h0Z"/>
+ <path id="path42" class="cls-2" d="M177.94,516.33h18.61V497.72H177.94v18.61h0Z"/>
+ <g id="g44">
+ <path id="path46" class="cls-3" d="M525.05,266.23l-24-74L453.36,45.6a8.19,8.19,0,0,0-15.58,0L390.12,192.24H231.88L184.22,45.6a8.19,8.19,0,0,0-15.58,0L121,192.24l-24,74a16.38,16.38,0,0,0,6,18.31L311,435.71,519.1,284.54a16.38,16.38,0,0,0,6-18.31"/>
+ </g>
+ <g id="g48">
+ <path id="path50" class="cls-4" d="M311,435.71h0l79.12-243.47H231.88L311,435.71h0Z"/>
+ </g>
+ <g id="g56">
+ <path id="path58" class="cls-3" d="M311,435.71L231.88,192.24H121L311,435.71h0Z"/>
+ </g>
+ <g id="g64">
+ <path id="path66" class="cls-5" d="M121,192.24h0l-24,74a16.37,16.37,0,0,0,6,18.31L311,435.7,121,192.24h0Z"/>
+ </g>
+ <g id="g72">
+ <path id="path74" class="cls-4" d="M121,192.24H231.88L184.22,45.6a8.19,8.19,0,0,0-15.58,0L121,192.24h0Z"/>
+ </g>
+ <g id="g76">
+ <path id="path78" class="cls-3" d="M311,435.71l79.12-243.47H501L311,435.71h0Z"/>
+ </g>
+ <g id="g80">
+ <path id="path82" class="cls-5" d="M501,192.24h0l24,74a16.37,16.37,0,0,1-6,18.31L311,435.7,501,192.24h0Z"/>
+ </g>
+ <g id="g84">
+ <path id="path86" class="cls-4" d="M501,192.24H390.12L437.78,45.6a8.19,8.19,0,0,1,15.58,0L501,192.24h0Z"/>
+ </g>
+</svg>
diff --git a/spec/fixtures/unsanitized.svg b/spec/fixtures/unsanitized.svg
new file mode 100644
index 00000000000..3957557334b
--- /dev/null
+++ b/spec/fixtures/unsanitized.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 622 682" filterMe="test">
+ <iframe src="http://www.google.com"></iframe>
+ <defs>
+ <style>.cls-1{fill:#30353e;}.cls-2{fill:#8c929d;}.cls-3{fill:#fc6d26;}.cls-4{fill:#e24329;}.cls-5{fill:#fca326;}</style>
+ </defs>
+ <title>stacked_wm</title>
+ <path id="bg" class="cls-1" d="M622,681H0V-1H622V681h0Z"/>
+ <g id="g12">
+ <path id="path14" class="cls-2" d="M316.89,497.72h-19l0.06,141.74H375V621.93h-58l-0.06-124.22h0Z"/>
+ </g>
+ <g id="g24">
+ <path id="path26" class="cls-2" d="M448.32,614.57a32.46,32.46,0,0,1-23.59,10c-14.5,0-20.35-7.14-20.35-16.45,0-14.07,9.74-20.77,30.52-20.77a86.46,86.46,0,0,1,13.42,1.08v26.19h0Zm-19.7-85.91a63.45,63.45,0,0,0-40.5,14.53l6.73,11.66c7.79-4.54,17.32-9.09,31-9.09,15.58,0,22.51,8,22.51,21.42v6.93a81.48,81.48,0,0,0-13.2-1.08c-33.33,0-50.22,11.69-50.22,36.14,0,21.86,13.42,32.89,33.76,32.89,13.71,0,26.84-6.28,31.38-16.45l3.46,13.85h13.42V567c0-22.94-10-38.3-38.31-38.3h0Z"/>
+ </g>
+ <g id="g28">
+ <path id="path30" class="cls-2" d="M528.4,625.18c-7.14,0-13.42-.87-18.18-3V556.58c6.49-5.41,14.5-9.31,24.68-9.31,18.4,0,25.54,13,25.54,34,0,29.86-11.47,43.93-32,43.93m8-96.52a34.88,34.88,0,0,0-26.19,11.58V522l-0.06-24.24H491.54L491.6,636c9.31,3.9,22.08,6.06,35.93,6.06,35.5,0,52.6-22.72,52.6-61.89,0-30.95-15.8-51.51-43.73-51.51"/>
+ </g>
+ <g id="g32">
+ <path id="path34" class="cls-2" d="M109.84,513.08c16.88,0,27.7,5.63,34.85,11.25l8.19-14.18c-11.16-9.78-26.16-15-42.17-15-40.47,0-68.83,24.67-68.83,74.44,0,52.15,30.59,72.5,65.58,72.5a111,111,0,0,0,42.21-8.22l-0.4-55.72V560.58H97.32v17.53h33.12l0.4,42.31c-4.33,2.16-11.9,3.9-22.08,3.9-28.14,0-47-17.7-47-55,0-37.87,19.48-56.26,48.05-56.26"/>
+ </g>
+ <g id="g36">
+ <path id="path38" class="cls-2" d="M243.79,497.72H225.17l0.06,23.8v82.23c0,22.94,10,38.3,38.31,38.3A64.16,64.16,0,0,0,275,641V624.31a57,57,0,0,1-8.66.65c-15.58,0-22.51-8-22.51-21.42v-56.7H275V531.26H243.85l-0.06-33.54h0Z"/>
+ </g>
+ <path id="path40" class="cls-2" d="M177.94,639.46h18.61V531.26H177.94v108.2h0Z"/>
+ <path id="path42" class="cls-2" d="M177.94,516.33h18.61V497.72H177.94v18.61h0Z"/>
+ <g id="g44">
+ <path id="path46" class="cls-3" d="M525.05,266.23l-24-74L453.36,45.6a8.19,8.19,0,0,0-15.58,0L390.12,192.24H231.88L184.22,45.6a8.19,8.19,0,0,0-15.58,0L121,192.24l-24,74a16.38,16.38,0,0,0,6,18.31L311,435.71,519.1,284.54a16.38,16.38,0,0,0,6-18.31"/>
+ </g>
+ <g id="g48">
+ <path id="path50" class="cls-4" d="M311,435.71h0l79.12-243.47H231.88L311,435.71h0Z"/>
+ </g>
+ <g id="g56">
+ <path id="path58" class="cls-3" d="M311,435.71L231.88,192.24H121L311,435.71h0Z"/>
+ </g>
+ <g id="g64">
+ <path id="path66" class="cls-5" d="M121,192.24h0l-24,74a16.37,16.37,0,0,0,6,18.31L311,435.7,121,192.24h0Z"/>
+ </g>
+ <g id="g72">
+ <path id="path74" class="cls-4" d="M121,192.24H231.88L184.22,45.6a8.19,8.19,0,0,0-15.58,0L121,192.24h0Z"/>
+ </g>
+ <g id="g76">
+ <path id="path78" class="cls-3" d="M311,435.71l79.12-243.47H501L311,435.71h0Z"/>
+ </g>
+ <g id="g80">
+ <path id="path82" class="cls-5" d="M501,192.24h0l24,74a16.37,16.37,0,0,1-6,18.31L311,435.7,501,192.24h0Z"/>
+ </g>
+ <g id="g84">
+ <path id="path86" class="cls-4" d="M501,192.24H390.12L437.78,45.6a8.19,8.19,0,0,1,15.58,0L501,192.24h0Z"/>
+ </g>
+</svg>
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index 87849230dbe..6d1c02db297 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -67,4 +67,16 @@ describe BlobHelper do
expect(result).to eq(expected)
end
end
+
+ describe "#sanitize_svg" do
+ let(:input_svg_path) { File.join(Rails.root, 'spec', 'fixtures', 'unsanitized.svg') }
+ let(:data) { open(input_svg_path).read }
+ let(:expected_svg_path) { File.join(Rails.root, 'spec', 'fixtures', 'sanitized.svg') }
+ let(:expected) { open(expected_svg_path).read }
+
+ it 'should retain essential elements' do
+ blob = OpenStruct.new(data: data)
+ expect(sanitize_svg(blob).data).to eq(expected)
+ end
+ end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 62389188d2c..ac5af8740dc 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -88,18 +88,18 @@ describe ProjectsHelper do
end
describe 'default_clone_protocol' do
- describe 'using HTTP' do
+ context 'when user is not logged in and gitlab protocol is HTTP' do
it 'returns HTTP' do
- expect(helper).to receive(:current_user).and_return(nil)
+ allow(helper).to receive(:current_user).and_return(nil)
expect(helper.send(:default_clone_protocol)).to eq('http')
end
end
- describe 'using HTTPS' do
+ context 'when user is not logged in and gitlab protocol is HTTPS' do
it 'returns HTTPS' do
- allow(Gitlab.config.gitlab).to receive(:protocol).and_return('https')
- expect(helper).to receive(:current_user).and_return(nil)
+ stub_config_setting(protocol: 'https')
+ allow(helper).to receive(:current_user).and_return(nil)
expect(helper.send(:default_clone_protocol)).to eq('https')
end
@@ -131,4 +131,13 @@ describe ProjectsHelper do
end
end
end
+
+ describe '#sanitized_import_error' do
+ it 'removes the repo path' do
+ repo = File.join(Gitlab.config.gitlab_shell.repos_path, '/namespace/test.git')
+ import_error = "Could not clone #{repo}\n"
+
+ expect(sanitize_repo_path(import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git')
+ end
+ end
end
diff --git a/spec/initializers/trusted_proxies_spec.rb b/spec/initializers/trusted_proxies_spec.rb
new file mode 100644
index 00000000000..4bb149f25ff
--- /dev/null
+++ b/spec/initializers/trusted_proxies_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe 'trusted_proxies', lib: true do
+ context 'with default config' do
+ before do
+ set_trusted_proxies([])
+ end
+
+ it 'preserves private IPs as remote_ip' do
+ request = stub_request('HTTP_X_FORWARDED_FOR' => '10.1.5.89')
+ expect(request.remote_ip).to eq('10.1.5.89')
+ end
+
+ it 'filters out localhost from remote_ip' do
+ request = stub_request('HTTP_X_FORWARDED_FOR' => '1.1.1.1, 10.1.5.89, 127.0.0.1')
+ expect(request.remote_ip).to eq('10.1.5.89')
+ end
+ end
+
+ context 'with private IP ranges added' do
+ before do
+ set_trusted_proxies([ "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" ])
+ end
+
+ it 'filters out private and local IPs from remote_ip' do
+ request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 10.1.5.89, 127.0.0.1')
+ expect(request.remote_ip).to eq('1.1.1.1')
+ end
+ end
+
+ context 'with proxy IP added' do
+ before do
+ set_trusted_proxies([ "60.98.25.47" ])
+ end
+
+ it 'filters out proxy IP from remote_ip' do
+ request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 60.98.25.47, 127.0.0.1')
+ expect(request.remote_ip).to eq('1.1.1.1')
+ end
+ end
+
+ def stub_request(headers = {})
+ ActionDispatch::RemoteIp.new(Proc.new { }, false, Rails.application.config.action_dispatch.trusted_proxies).call(headers)
+ ActionDispatch::Request.new(headers)
+ end
+
+ def set_trusted_proxies(proxies = [])
+ stub_config_setting('trusted_proxies' => proxies)
+ load File.join(__dir__, '../../config/initializers/trusted_proxies.rb')
+ end
+end
diff --git a/spec/javascripts/merge_request_widget_spec.js.coffee b/spec/javascripts/merge_request_widget_spec.js.coffee
new file mode 100644
index 00000000000..92b7eeb1116
--- /dev/null
+++ b/spec/javascripts/merge_request_widget_spec.js.coffee
@@ -0,0 +1,55 @@
+#= require merge_request_widget
+
+describe 'MergeRequestWidget', ->
+
+ beforeEach ->
+ window.notifyPermissions = () ->
+ window.notify = () ->
+ @opts = {
+ ci_status_url:"http://sampledomain.local/ci/getstatus",
+ ci_status:"",
+ ci_message: {
+ normal: "Build {{status}} for \"{{title}}\"",
+ preparing: "{{status}} build for \"{{title}}\""
+ },
+ ci_title: {
+ preparing: "{{status}} build",
+ normal: "Build {{status}}"
+ },
+ gitlab_icon:"gitlab_logo.png",
+ builds_path:"http://sampledomain.local/sampleBuildsPath"
+ }
+ @class = new MergeRequestWidget(@opts)
+ @ciStatusData = {"title":"Sample MR title","sha":"12a34bc5","status":"success","coverage":98}
+
+ describe 'getCIStatus', ->
+ beforeEach ->
+ spyOn(jQuery, 'getJSON').and.callFake (req, cb) =>
+ cb(@ciStatusData)
+
+ it 'should call showCIStatus even if a notification should not be displayed', ->
+ spy = spyOn(@class, 'showCIStatus').and.stub()
+ @class.getCIStatus(false)
+ expect(spy).toHaveBeenCalledWith(@ciStatusData.status)
+
+ it 'should call showCIStatus when a notification should be displayed', ->
+ spy = spyOn(@class, 'showCIStatus').and.stub()
+ @class.getCIStatus(true)
+ expect(spy).toHaveBeenCalledWith(@ciStatusData.status)
+
+ it 'should call showCICoverage when the coverage rate is set', ->
+ spy = spyOn(@class, 'showCICoverage').and.stub()
+ @class.getCIStatus(false)
+ expect(spy).toHaveBeenCalledWith(@ciStatusData.coverage)
+
+ it 'should not call showCICoverage when the coverage rate is not set', ->
+ @ciStatusData.coverage = null
+ spy = spyOn(@class, 'showCICoverage').and.stub()
+ @class.getCIStatus(false)
+ expect(spy).not.toHaveBeenCalled()
+
+ it 'should not display a notification on the first check after the widget has been created', ->
+ spy = spyOn(window, 'notify')
+ @class = new MergeRequestWidget(@opts)
+ @class.getCIStatus(true)
+ expect(spy).not.toHaveBeenCalled()
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index ebf3d7489b5..5beb61dac5c 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -43,7 +43,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
milestone.update_attribute(:title, %{"></a>whatever<a title="})
doc = reference_filter("milestone #{reference}")
- expect(doc.text).to eq "milestone #{milestone.title}"
+ expect(doc.text).to eq "milestone \">whatever"
end
it 'includes default classes' do
diff --git a/spec/lib/gitlab/bitbucket_import/client_spec.rb b/spec/lib/gitlab/bitbucket_import/client_spec.rb
index aa0699f2ebf..af839f42421 100644
--- a/spec/lib/gitlab/bitbucket_import/client_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/client_spec.rb
@@ -34,18 +34,32 @@ describe Gitlab::BitbucketImport::Client, lib: true do
it 'retrieves issues over a number of pages' do
stub_request(:get,
"https://bitbucket.org/api/1.0/repositories/#{project_id}/issues?limit=50&sort=utc_created_on&start=0").
- to_return(status: 200,
- body: first_sample_data.to_json,
- headers: {})
+ to_return(status: 200,
+ body: first_sample_data.to_json,
+ headers: {})
stub_request(:get,
"https://bitbucket.org/api/1.0/repositories/#{project_id}/issues?limit=50&sort=utc_created_on&start=50").
- to_return(status: 200,
- body: second_sample_data.to_json,
- headers: {})
+ to_return(status: 200,
+ body: second_sample_data.to_json,
+ headers: {})
issues = client.issues(project_id)
expect(issues.count).to eq(95)
end
end
+
+ context 'project import' do
+ it 'calls .from_project with no errors' do
+ project = create(:empty_project)
+ project.create_or_update_import_data(credentials:
+ { user: "git",
+ password: nil,
+ bb_session: { bitbucket_access_token: "test",
+ bitbucket_access_token_secret: "test" } })
+ project.import_url = "ssh://git@bitbucket.org/test/test.git"
+
+ expect { described_class.from_project(project) }.to_not raise_error
+ end
+ end
end
diff --git a/spec/lib/gitlab/github_import/comment_formatter_spec.rb b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
index a324a82e69f..55e86d4ceac 100644
--- a/spec/lib/gitlab/github_import/comment_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
@@ -2,23 +2,25 @@ require 'spec_helper'
describe Gitlab::GithubImport::CommentFormatter, lib: true do
let(:project) { create(:project) }
- let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') }
+ let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2013-04-10T20:09:31Z') }
let(:updated_at) { DateTime.strptime('2014-03-03T18:58:10Z') }
- let(:base_data) do
+ let(:base) do
{
body: "I'm having a problem with this.",
user: octocat,
+ commit_id: nil,
+ diff_hunk: nil,
created_at: created_at,
updated_at: updated_at
}
end
- subject(:comment) { described_class.new(project, raw_data)}
+ subject(:comment) { described_class.new(project, raw)}
describe '#attributes' do
context 'when do not reference a portion of the diff' do
- let(:raw_data) { OpenStruct.new(base_data) }
+ let(:raw) { double(base) }
it 'returns formatted attributes' do
expected = {
@@ -36,24 +38,23 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do
end
context 'when on a portion of the diff' do
- let(:diff_data) do
+ let(:diff) do
{
body: 'Great stuff',
commit_id: '6dcb09b5b57875f334f61aebed695e2e4193db5e',
- diff_hunk: '@@ -16,33 +16,40 @@ public class Connection : IConnection...',
- path: 'file1.txt',
- position: 1
+ diff_hunk: "@@ -1,5 +1,9 @@\n class User\n def name\n- 'John Doe'\n+ 'Jane Doe'",
+ path: 'file1.txt'
}
end
- let(:raw_data) { OpenStruct.new(base_data.merge(diff_data)) }
+ let(:raw) { double(base.merge(diff)) }
it 'returns formatted attributes' do
expected = {
project: project,
note: "*Created by: octocat*\n\nGreat stuff",
commit_id: '6dcb09b5b57875f334f61aebed695e2e4193db5e',
- line_code: 'ce1be0ff4065a6e9415095c95f25f47a633cef2b_0_1',
+ line_code: 'ce1be0ff4065a6e9415095c95f25f47a633cef2b_4_3',
author_id: project.creator_id,
created_at: created_at,
updated_at: updated_at
@@ -64,15 +65,10 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do
end
context 'when author is a GitLab user' do
- let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) }
+ let(:raw) { double(base.merge(user: octocat)) }
- it 'returns project#creator_id as author_id when is not a GitLab user' do
- expect(comment.attributes.fetch(:author_id)).to eq project.creator_id
- end
-
- it 'returns GitLab user id as author_id when is a GitLab user' do
+ it 'returns GitLab user id as author_id' do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
-
expect(comment.attributes.fetch(:author_id)).to eq gl_user.id
end
end
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index bf11472407a..c8d3bc01395 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -112,7 +112,7 @@ describe Gitlab::UrlBuilder, lib: true do
wiki_page = build(:wiki_page)
url = described_class.build(wiki_page)
- expect(url).to eq "#{Gitlab.config.gitlab.url}#{wiki_page.wiki.wiki_base_path}/#{wiki_page.slug}"
+ expect(url).to eq "#{Gitlab.config.gitlab.url}/#{wiki_page.wiki.project.path_with_namespace}/wikis/#{wiki_page.slug}"
end
end
end
diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb
index 0614ca1e7c9..b61c55a3f6d 100644
--- a/spec/models/label_spec.rb
+++ b/spec/models/label_spec.rb
@@ -55,6 +55,14 @@ describe Label, models: true do
end
end
+ describe "#title" do
+ let(:label) { create(:label, title: "<b>test</b>") }
+
+ it "sanitizes title" do
+ expect(label.title).to eq("test")
+ end
+ end
+
describe '#to_reference' do
context 'using id' do
it 'returns a String reference to the object' do
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 72a4ea70228..e2c89a4b3e6 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -34,6 +34,14 @@ describe Milestone, models: true do
let(:issue) { create(:issue) }
let(:user) { create(:user) }
+ describe "#title" do
+ let(:milestone) { create(:milestone, title: "<b>test</b>") }
+
+ it "sanitizes title" do
+ expect(milestone.title).to eq("test")
+ end
+ end
+
describe "unique milestone title per project" do
it "shouldn't accept the same title in a project twice" do
new_milestone = Milestone.new(project: milestone.project, title: milestone.title)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 5b1cf71337e..3a8a6c2c166 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -10,7 +10,6 @@
# updated_at :datetime
# creator_id :integer
# issues_enabled :boolean default(TRUE), not null
-# wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 532e3f013fd..ea659f417f2 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -38,7 +38,9 @@ describe ProjectWiki, models: true do
describe "#wiki_base_path" do
it "returns the wiki base path" do
- wiki_base_path = "/#{project.path_with_namespace}/wikis"
+ gitlab_url = Gitlab.config.gitlab.url
+ wiki_base_path = "#{gitlab_url}/#{project.path_with_namespace}/wikis"
+
expect(subject.wiki_base_path).to eq(wiki_base_path)
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 397bb5a8028..34a13f9b5c9 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -561,7 +561,7 @@ describe Repository, models: true do
end
describe :skip_merged_commit do
- subject { repository.commits(Gitlab::Git::BRANCH_REF_PREFIX + "'test'", nil, 100, 0, true).map{ |k| k.id } }
+ subject { repository.commits(Gitlab::Git::BRANCH_REF_PREFIX + "'test'", limit: 100, skip_merges: true).map{ |k| k.id } }
it { is_expected.not_to include('e56497bb5f03a90a51293fc6d516788730953899') }
end
@@ -858,13 +858,30 @@ describe Repository, models: true do
end
describe '#add_tag' do
- it 'adds a tag' do
- expect(repository).to receive(:before_push_tag)
+ context 'with a valid target' do
+ let(:user) { build_stubbed(:user) }
- expect_any_instance_of(Gitlab::Shell).to receive(:add_tag).
- with(repository.path_with_namespace, '8.5', 'master', 'foo')
+ it 'creates the tag using rugged' do
+ expect(repository.rugged.tags).to receive(:create).
+ with('8.5', repository.commit('master').id,
+ hash_including(message: 'foo',
+ tagger: hash_including(name: user.name, email: user.email))).
+ and_call_original
- repository.add_tag('8.5', 'master', 'foo')
+ repository.add_tag(user, '8.5', 'master', 'foo')
+ end
+
+ it 'returns a Gitlab::Git::Tag object' do
+ tag = repository.add_tag(user, '8.5', 'master', 'foo')
+
+ expect(tag).to be_a(Gitlab::Git::Tag)
+ end
+ end
+
+ context 'with an invalid target' do
+ it 'returns false' do
+ expect(repository.add_tag(user, '8.5', 'bar', 'foo')).to be false
+ end
end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index e28998d51b5..cb82ca7802d 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -32,6 +32,41 @@ describe API::API, api: true do
expect(response.status).to eq(401)
end
end
+
+ context "since optional parameter" do
+ it "should return project commits since provided parameter" do
+ commits = project.repository.commits("master")
+ since = commits.second.created_at
+
+ get api("/projects/#{project.id}/repository/commits?since=#{since.utc.iso8601}", user)
+
+ expect(json_response.size).to eq 2
+ expect(json_response.first["id"]).to eq(commits.first.id)
+ expect(json_response.second["id"]).to eq(commits.second.id)
+ end
+ end
+
+ context "until optional parameter" do
+ it "should return project commits until provided parameter" do
+ commits = project.repository.commits("master")
+ before = commits.second.created_at
+
+ get api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user)
+
+ expect(json_response.size).to eq(commits.size - 1)
+ expect(json_response.first["id"]).to eq(commits.second.id)
+ expect(json_response.second["id"]).to eq(commits.third.id)
+ end
+ end
+
+ context "invalid xmlschema date parameters" do
+ it "should return an invalid parameter error message" do
+ get api("/projects/#{project.id}/repository/commits?since=invalid-date", user)
+
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to include "\"since\" must be a timestamp in ISO 8601 format"
+ end
+ end
end
describe "GET /projects:id/repository/commits/:sha" do
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index f88e39cad9e..9dd43f4fab3 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -39,6 +39,7 @@ describe API::API, api: true do
let!(:empty_milestone) do
create(:milestone, title: '2.0.0', project: project)
end
+ let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) }
before { project.team << [user, :reporter] }
@@ -232,8 +233,28 @@ describe API::API, api: true do
end
describe "GET /projects/:id/issues/:issue_id" do
+ it 'exposes known attributes' do
+ get api("/projects/#{project.id}/issues/#{issue.id}", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response['id']).to eq(issue.id)
+ expect(json_response['iid']).to eq(issue.iid)
+ expect(json_response['project_id']).to eq(issue.project.id)
+ expect(json_response['title']).to eq(issue.title)
+ expect(json_response['description']).to eq(issue.description)
+ expect(json_response['state']).to eq(issue.state)
+ expect(json_response['created_at']).to be_present
+ expect(json_response['updated_at']).to be_present
+ expect(json_response['labels']).to eq(issue.label_names)
+ expect(json_response['milestone']).to be_a Hash
+ expect(json_response['assignee']).to be_a Hash
+ expect(json_response['author']).to be_a Hash
+ expect(json_response['user_notes_count']).to be(1)
+ end
+
it "should return a project issue by id" do
get api("/projects/#{project.id}/issues/#{issue.id}", user)
+
expect(response.status).to eq(200)
expect(json_response['title']).to eq(issue.title)
expect(json_response['iid']).to eq(issue.iid)
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 1fa7e76894f..4b0111df149 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -113,6 +113,34 @@ describe API::API, api: true do
end
describe "GET /projects/:id/merge_requests/:merge_request_id" do
+ it 'exposes known attributes' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response['id']).to eq(merge_request.id)
+ expect(json_response['iid']).to eq(merge_request.iid)
+ expect(json_response['project_id']).to eq(merge_request.project.id)
+ expect(json_response['title']).to eq(merge_request.title)
+ expect(json_response['description']).to eq(merge_request.description)
+ expect(json_response['state']).to eq(merge_request.state)
+ expect(json_response['created_at']).to be_present
+ expect(json_response['updated_at']).to be_present
+ expect(json_response['labels']).to eq(merge_request.label_names)
+ expect(json_response['milestone']).to be_nil
+ expect(json_response['assignee']).to be_a Hash
+ expect(json_response['author']).to be_a Hash
+ expect(json_response['target_branch']).to eq(merge_request.target_branch)
+ expect(json_response['source_branch']).to eq(merge_request.source_branch)
+ expect(json_response['upvotes']).to eq(0)
+ expect(json_response['downvotes']).to eq(0)
+ expect(json_response['source_project_id']).to eq(merge_request.source_project.id)
+ expect(json_response['target_project_id']).to eq(merge_request.target_project.id)
+ expect(json_response['work_in_progress']).to be_falsy
+ expect(json_response['merge_when_build_succeeds']).to be_falsy
+ expect(json_response['merge_status']).to eq('can_be_merged')
+ expect(json_response['user_notes_count']).to be(2)
+ end
+
it "should return merge_request" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)
expect(response.status).to eq(200)
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index edcb2bedbf7..12e170b232f 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -147,7 +147,7 @@ describe API::API, api: true do
tag_name: 'v8.0.0',
ref: 'master'
expect(response.status).to eq(400)
- expect(json_response['message']).to eq('Tag already exists')
+ expect(json_response['message']).to eq('Tag v8.0.0 already exists')
end
it 'should return 400 if ref name is invalid' do
@@ -155,7 +155,7 @@ describe API::API, api: true do
tag_name: 'mytag',
ref: 'foo'
expect(response.status).to eq(400)
- expect(json_response['message']).to eq('Invalid reference name')
+ expect(json_response['message']).to eq('Target foo is invalid')
end
end
diff --git a/spec/services/create_tag_service_spec.rb b/spec/services/create_tag_service_spec.rb
new file mode 100644
index 00000000000..91f9e663b66
--- /dev/null
+++ b/spec/services/create_tag_service_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+describe CreateTagService, services: true do
+ let(:project) { create(:project) }
+ let(:repository) { project.repository }
+ let(:user) { create(:user) }
+ let(:service) { described_class.new(project, user) }
+
+ describe '#execute' do
+ it 'creates the tag and returns success' do
+ response = service.execute('v42.42.42', 'master', 'Foo')
+
+ expect(response[:status]).to eq(:success)
+ expect(response[:tag]).to be_a Gitlab::Git::Tag
+ expect(response[:tag].name).to eq('v42.42.42')
+ end
+
+ context 'when target is invalid' do
+ it 'returns an error' do
+ response = service.execute('v1.1.0', 'foo', 'Foo')
+
+ expect(response).to eq(status: :error,
+ message: 'Target foo is invalid')
+ end
+ end
+
+ context 'when tag already exists' do
+ it 'returns an error' do
+ expect(repository).to receive(:add_tag).
+ with(user, 'v1.1.0', 'master', 'Foo').
+ and_raise(Rugged::TagError)
+
+ response = service.execute('v1.1.0', 'master', 'Foo')
+
+ expect(response).to eq(status: :error,
+ message: 'Tag v1.1.0 already exists')
+ end
+ end
+
+ context 'when pre-receive hook fails' do
+ it 'returns an error' do
+ expect(repository).to receive(:add_tag).
+ with(user, 'v1.1.0', 'master', 'Foo').
+ and_raise(GitHooksService::PreReceiveError)
+
+ response = service.execute('v1.1.0', 'master', 'Foo')
+
+ expect(response).to eq(status: :error,
+ message: 'Tag creation was rejected by Git hook')
+ end
+ end
+ end
+end
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index 2a5e4ac3ec4..c15e26189a5 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -7,10 +7,11 @@ describe Issues::MoveService, services: true do
let(:description) { 'Some issue description' }
let(:old_project) { create(:project) }
let(:new_project) { create(:project) }
+ let(:milestone1) { create(:milestone, project_id: old_project.id, title: 'v9.0') }
let(:old_issue) do
create(:issue, title: title, description: description,
- project: old_project, author: author)
+ project: old_project, author: author, milestone: milestone1)
end
let(:move_service) do
@@ -21,11 +22,24 @@ describe Issues::MoveService, services: true do
before do
old_project.team << [user, :reporter]
new_project.team << [user, :reporter]
+
+ ['label1', 'label2'].each do |label|
+ old_issue.labels << create(:label,
+ project_id: old_project.id,
+ title: label)
+ end
+
+ new_project.labels << create(:label, title: 'label1')
+ new_project.labels << create(:label, title: 'label2')
end
end
describe '#execute' do
shared_context 'issue move executed' do
+ let!(:milestone2) do
+ create(:milestone, project_id: new_project.id, title: 'v9.0')
+ end
+
let!(:new_issue) { move_service.execute(old_issue, new_project) }
end
@@ -39,6 +53,23 @@ describe Issues::MoveService, services: true do
expect(new_issue.project).to eq new_project
end
+ it 'assigns milestone to new issue' do
+ expect(new_issue.reload.milestone.title).to eq 'v9.0'
+ expect(new_issue.reload.milestone).to eq(milestone2)
+ end
+
+ it 'assign labels to new issue' do
+ expected_label_titles = new_issue.reload.labels.map(&:title)
+ expect(expected_label_titles).to include 'label1'
+ expect(expected_label_titles).to include 'label2'
+ expect(expected_label_titles.size).to eq 2
+
+ new_issue.labels.each do |label|
+ expect(new_project.labels).to include(label)
+ expect(old_project.labels).not_to include(label)
+ end
+ end
+
it 'rewrites issue title' do
expect(new_issue.title).to eq title
end
@@ -72,11 +103,6 @@ describe Issues::MoveService, services: true do
expect(new_issue.author).to eq author
end
- it 'removes data that is invalid in new context' do
- expect(new_issue.milestone).to be_nil
- expect(new_issue.labels).to be_empty
- end
-
it 'creates a new internal id for issue' do
expect(new_issue.iid).to be 1
end
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
new file mode 100644
index 00000000000..782d74ec5ec
--- /dev/null
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -0,0 +1,181 @@
+require 'spec_helper'
+
+describe MergeRequests::BuildService, services: true do
+ include RepoHelpers
+
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:issue_confidential) { false }
+ let(:issue) { create(:issue, project: project, title: 'A bug', confidential: issue_confidential) }
+ let(:description) { nil }
+ let(:source_branch) { 'feature-branch' }
+ let(:target_branch) { 'master' }
+ let(:merge_request) { service.execute }
+ let(:compare) { double(:compare, commits: commits) }
+ let(:commit_1) { double(:commit_1, safe_message: "Initial commit\n\nCreate the app") }
+ let(:commit_2) { double(:commit_2, safe_message: 'This is a bad commit message!') }
+ let(:commits) { nil }
+
+ let(:service) do
+ MergeRequests::BuildService.new(project, user,
+ description: description,
+ source_branch: source_branch,
+ target_branch: target_branch)
+ end
+
+ before do
+ allow(CompareService).to receive_message_chain(:new, :execute).and_return(compare)
+ end
+
+ describe 'execute' do
+ context 'missing source branch' do
+ let(:source_branch) { '' }
+
+ it 'forbids the merge request from being created' do
+ expect(merge_request.can_be_created).to eq(false)
+ end
+
+ it 'adds an error message to the merge request' do
+ expect(merge_request.errors).to contain_exactly('You must select source and target branch')
+ end
+ end
+
+ context 'missing target branch' do
+ let(:target_branch) { '' }
+
+ it 'forbids the merge request from being created' do
+ expect(merge_request.can_be_created).to eq(false)
+ end
+
+ it 'adds an error message to the merge request' do
+ expect(merge_request.errors).to contain_exactly('You must select source and target branch')
+ end
+ end
+
+ context 'no commits in the diff' do
+ let(:commits) { [] }
+
+ it 'forbids the merge request from being created' do
+ expect(merge_request.can_be_created).to eq(false)
+ end
+ end
+
+ context 'one commit in the diff' do
+ let(:commits) { [commit_1] }
+
+ it 'allows the merge request to be created' do
+ expect(merge_request.can_be_created).to eq(true)
+ end
+
+ it 'uses the title of the commit as the title of the merge request' do
+ expect(merge_request.title).to eq(commit_1.safe_message.split("\n").first)
+ end
+
+ it 'uses the description of the commit as the description of the merge request' do
+ expect(merge_request.description).to eq(commit_1.safe_message.split(/\n+/, 2).last)
+ end
+
+ context 'merge request already has a description set' do
+ let(:description) { 'Merge request description' }
+
+ it 'keeps the description from the initial params' do
+ expect(merge_request.description).to eq(description)
+ end
+ end
+
+ context 'commit has no description' do
+ let(:commits) { [commit_2] }
+
+ it 'uses the title of the commit as the title of the merge request' do
+ expect(merge_request.title).to eq(commit_2.safe_message)
+ end
+
+ it 'sets the description to nil' do
+ expect(merge_request.description).to be_nil
+ end
+ end
+
+ context 'branch starts with issue IID followed by a hyphen' do
+ let(:source_branch) { "#{issue.iid}-fix-issue" }
+
+ it 'appends "Closes #$issue-iid" to the description' do
+ expect(merge_request.description).to eq("#{commit_1.safe_message.split(/\n+/, 2).last}\nCloses ##{issue.iid}")
+ end
+
+ context 'merge request already has a description set' do
+ let(:description) { 'Merge request description' }
+
+ it 'appends "Closes #$issue-iid" to the description' do
+ expect(merge_request.description).to eq("#{description}\nCloses ##{issue.iid}")
+ end
+ end
+
+ context 'commit has no description' do
+ let(:commits) { [commit_2] }
+
+ it 'sets the description to "Closes #$issue-iid"' do
+ expect(merge_request.description).to eq("Closes ##{issue.iid}")
+ end
+ end
+ end
+ end
+
+ context 'more than one commit in the diff' do
+ let(:commits) { [commit_1, commit_2] }
+
+ it 'allows the merge request to be created' do
+ expect(merge_request.can_be_created).to eq(true)
+ end
+
+ it 'uses the title of the branch as the merge request title' do
+ expect(merge_request.title).to eq('Feature branch')
+ end
+
+ it 'does not add a description' do
+ expect(merge_request.description).to be_nil
+ end
+
+ context 'merge request already has a description set' do
+ let(:description) { 'Merge request description' }
+
+ it 'keeps the description from the initial params' do
+ expect(merge_request.description).to eq(description)
+ end
+ end
+
+ context 'branch starts with GitLab issue IID followed by a hyphen' do
+ let(:source_branch) { "#{issue.iid}-fix-issue" }
+
+ it 'sets the title to: Resolves "$issue-title"' do
+ expect(merge_request.title).to eq("Resolve \"#{issue.title}\"")
+ end
+
+ context 'issue does not exist' do
+ let(:source_branch) { "#{issue.iid.succ}-fix-issue" }
+
+ it 'uses the title of the branch as the merge request title' do
+ expect(merge_request.title).to eq("#{issue.iid.succ} fix issue")
+ end
+ end
+
+ context 'issue is confidential' do
+ let(:issue_confidential) { true }
+
+ it 'uses the title of the branch as the merge request title' do
+ expect(merge_request.title).to eq("#{issue.iid} fix issue")
+ end
+ end
+ end
+
+ context 'branch starts with external issue IID followed by a hyphen' do
+ let(:source_branch) { '12345-fix-issue' }
+
+ before { allow(project).to receive(:default_issues_tracker?).and_return(false) }
+
+ it 'sets the title to: Resolves External Issue $issue-iid' do
+ expect(merge_request.title).to eq('Resolve External Issue 12345')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 240eae10052..5fbf2ae5247 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -506,6 +506,15 @@ describe SystemNoteService, services: true do
end
end
+ describe '.new_commit_summary' do
+ it 'escapes HTML titles' do
+ commit = double(title: '<pre>This is a test</pre>', short_id: '12345678')
+ escaped = '* 12345678 - &lt;pre&gt;This is a test&lt;&#x2F;pre&gt;'
+
+ expect(described_class.new_commit_summary([commit])).to eq([escaped])
+ end
+ end
+
include JiraServiceHelper
describe 'JIRA integration' do
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 596d607f2a1..576d16e7ea3 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -51,10 +51,4 @@ FactoryGirl::SyntaxRunner.class_eval do
include RSpec::Mocks::ExampleMethods
end
-# Work around a Rails 4.2.5.1 issue
-# See https://github.com/rspec/rspec-rails/issues/1532
-RSpec::Rails::ViewRendering::EmptyTemplatePathSetDecorator.class_eval do
- alias_method :find_all_anywhere, :find_all
-end
-
ActiveRecord::Migration.maintain_test_schema!
diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb
index 087e4c667d8..5a03bb77ebd 100644
--- a/spec/workers/repository_check/single_repository_worker_spec.rb
+++ b/spec/workers/repository_check/single_repository_worker_spec.rb
@@ -12,7 +12,7 @@ describe RepositoryCheck::SingleRepositoryWorker do
subject.perform(project.id)
expect(project.reload.last_repository_check_failed).to eq(false)
- destroy_wiki(project)
+ break_wiki(project)
subject.perform(project.id)
expect(project.reload.last_repository_check_failed).to eq(true)
@@ -20,15 +20,38 @@ describe RepositoryCheck::SingleRepositoryWorker do
it 'skips wikis when disabled' do
project = create(:project_empty_repo, wiki_enabled: false)
- # Make sure the test would fail if it checked the wiki repo
- destroy_wiki(project)
+ # Make sure the test would fail if the wiki repo was checked
+ break_wiki(project)
subject.perform(project.id)
expect(project.reload.last_repository_check_failed).to eq(false)
end
- def destroy_wiki(project)
- FileUtils.rm_rf(project.wiki.repository.path_to_repo)
+ it 'creates missing wikis' do
+ project = create(:project_empty_repo, wiki_enabled: true)
+ FileUtils.rm_rf(wiki_path(project))
+
+ subject.perform(project.id)
+
+ expect(project.reload.last_repository_check_failed).to eq(false)
+ end
+
+ it 'does not create a wiki if the main repo does not exist at all' do
+ project = create(:project_empty_repo)
+ FileUtils.rm_rf(project.repository.path_to_repo)
+ FileUtils.rm_rf(wiki_path(project))
+
+ subject.perform(project.id)
+
+ expect(File.exist?(wiki_path(project))).to eq(false)
+ end
+
+ def break_wiki(project)
+ FileUtils.rm_rf(wiki_path(project) + '/objects')
+ end
+
+ def wiki_path(project)
+ project.wiki.repository.path_to_repo
end
end