summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2015-09-09 12:01:38 +0100
committerDouwe Maan <douwe@gitlab.com>2015-09-09 12:01:38 +0100
commit2c8d5aeaf332e25c030b7287919958bc7809e831 (patch)
treea6e308f25ba67279e713d0ed907d1e72f7f758b0
parent58c487e28b3f10c8a871dc82f7d79a45c7876f15 (diff)
parente0da2c352325c1cb2ede88a73434ed7afc037481 (diff)
downloadgitlab-ce-2c8d5aeaf332e25c030b7287919958bc7809e831.tar.gz
Merge branch 'master' into reply-by-email-docs
-rw-r--r--CHANGELOG39
-rw-r--r--Gemfile12
-rw-r--r--Gemfile.lock24
-rwxr-xr-xapp/assets/fonts/OFL.txt92
-rwxr-xr-xapp/assets/fonts/SourceSansPro-Black.ttfbin0 -> 148368 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-BlackItalic.ttfbin0 -> 116360 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-Bold.ttfbin0 -> 148932 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-BoldItalic.ttfbin0 -> 116192 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-ExtraLight.ttfbin0 -> 150528 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-ExtraLightItalic.ttfbin0 -> 117140 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-Italic.ttfbin0 -> 117328 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-Light.ttfbin0 -> 150244 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-LightItalic.ttfbin0 -> 116960 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-Regular.ttfbin0 -> 149972 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-Semibold.ttfbin0 -> 149636 bytes
-rwxr-xr-xapp/assets/fonts/SourceSansPro-SemiboldItalic.ttfbin0 -> 116424 bytes
-rw-r--r--app/assets/javascripts/activities.js.coffee4
-rw-r--r--app/assets/javascripts/application.js.coffee18
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee5
-rw-r--r--app/assets/javascripts/notes.js.coffee1
-rw-r--r--app/assets/javascripts/projects_list.js.coffee2
-rw-r--r--app/assets/javascripts/syntax_highlight.coffee12
-rw-r--r--app/assets/javascripts/zen_mode.js.coffee2
-rw-r--r--app/assets/stylesheets/application.scss1
-rw-r--r--app/assets/stylesheets/base/fonts.scss25
-rw-r--r--app/assets/stylesheets/base/gl_variables.scss27
-rw-r--r--app/assets/stylesheets/base/layout.scss4
-rw-r--r--app/assets/stylesheets/base/mixins.scss62
-rw-r--r--app/assets/stylesheets/base/variables.scss27
-rw-r--r--app/assets/stylesheets/generic/avatar.scss7
-rw-r--r--app/assets/stylesheets/generic/blocks.scss34
-rw-r--r--app/assets/stylesheets/generic/buttons.scss16
-rw-r--r--app/assets/stylesheets/generic/common.scss49
-rw-r--r--app/assets/stylesheets/generic/filters.scss25
-rw-r--r--app/assets/stylesheets/generic/header.scss97
-rw-r--r--app/assets/stylesheets/generic/lists.scss56
-rw-r--r--app/assets/stylesheets/generic/mobile.scss17
-rw-r--r--app/assets/stylesheets/generic/selects.scss8
-rw-r--r--app/assets/stylesheets/generic/sidebar.scss108
-rw-r--r--app/assets/stylesheets/generic/typography.scss5
-rw-r--r--app/assets/stylesheets/highlight/dark.scss6
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss6
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss5
-rw-r--r--app/assets/stylesheets/highlight/solarized_light.scss5
-rw-r--r--app/assets/stylesheets/highlight/white.scss5
-rw-r--r--app/assets/stylesheets/pages/commit.scss4
-rw-r--r--app/assets/stylesheets/pages/commits.scss6
-rw-r--r--app/assets/stylesheets/pages/dashboard.scss44
-rw-r--r--app/assets/stylesheets/pages/events.scss86
-rw-r--r--app/assets/stylesheets/pages/issuable.scss11
-rw-r--r--app/assets/stylesheets/pages/issues.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss2
-rw-r--r--app/assets/stylesheets/pages/projects.scss190
-rw-r--r--app/assets/stylesheets/pages/search.scss18
-rw-r--r--app/assets/stylesheets/pages/snippets.scss24
-rw-r--r--app/assets/stylesheets/pages/tree.scss7
-rw-r--r--app/assets/stylesheets/themes/gitlab-theme.scss30
-rw-r--r--app/controllers/admin/abuse_reports_controller.rb9
-rw-r--r--app/controllers/admin/hooks_controller.rb2
-rw-r--r--app/controllers/application_controller.rb13
-rw-r--r--app/controllers/dashboard_controller.rb33
-rw-r--r--app/controllers/projects/hooks_controller.rb3
-rw-r--r--app/controllers/projects/raw_controller.rb5
-rw-r--r--app/controllers/projects/services_controller.rb4
-rw-r--r--app/controllers/projects/snippets_controller.rb11
-rw-r--r--app/controllers/projects/wikis_controller.rb1
-rw-r--r--app/controllers/sessions_controller.rb2
-rw-r--r--app/controllers/users_controller.rb4
-rw-r--r--app/finders/trending_projects_finder.rb18
-rw-r--r--app/helpers/auth_helper.rb6
-rw-r--r--app/helpers/diff_helper.rb4
-rw-r--r--app/helpers/events_helper.rb11
-rw-r--r--app/helpers/gitlab_markdown_helper.rb55
-rw-r--r--app/helpers/groups_helper.rb9
-rw-r--r--app/helpers/page_layout_helper.rb8
-rw-r--r--app/helpers/preferences_helper.rb27
-rw-r--r--app/helpers/wiki_helper.rb24
-rw-r--r--app/mailers/email_rejection_mailer.rb2
-rw-r--r--app/models/abuse_report.rb12
-rw-r--r--app/models/hooks/web_hook.rb5
-rw-r--r--app/models/issue.rb27
-rw-r--r--app/models/merge_request.rb1
-rw-r--r--app/models/note.rb1
-rw-r--r--app/models/project.rb2
-rw-r--r--app/models/project_services/buildkite_service.rb9
-rw-r--r--app/models/project_services/ci_service.rb37
-rw-r--r--app/models/project_services/drone_ci_service.rb190
-rw-r--r--app/models/project_services/gitlab_ci_service.rb6
-rw-r--r--app/models/sent_notification.rb13
-rw-r--r--app/models/service.rb1
-rw-r--r--app/models/user.rb114
-rw-r--r--app/services/notification_service.rb11
-rw-r--r--app/views/admin/abuse_reports/_abuse_report.html.haml13
-rw-r--r--app/views/admin/abuse_reports/index.html.haml2
-rw-r--r--app/views/admin/hooks/index.html.haml8
-rw-r--r--app/views/dashboard/_activities.html.haml4
-rw-r--r--app/views/dashboard/_activity_head.html.haml7
-rw-r--r--app/views/dashboard/_groups_head.html.haml2
-rw-r--r--app/views/dashboard/_projects.html.haml6
-rw-r--r--app/views/dashboard/_projects_head.html.haml4
-rw-r--r--app/views/dashboard/activity.html.haml9
-rw-r--r--app/views/dashboard/groups/index.html.haml38
-rw-r--r--app/views/dashboard/issues.html.haml12
-rw-r--r--app/views/dashboard/merge_requests.html.haml7
-rw-r--r--app/views/dashboard/milestones/index.html.haml28
-rw-r--r--app/views/dashboard/projects/starred.html.haml20
-rw-r--r--app/views/dashboard/show.html.haml13
-rw-r--r--app/views/devise/sessions/_new_crowd.html.haml9
-rw-r--r--app/views/devise/shared/_signin_box.html.haml10
-rw-r--r--app/views/events/_commit.html.haml2
-rw-r--r--app/views/events/_event.html.haml4
-rw-r--r--app/views/events/_event_last_push.html.haml2
-rw-r--r--app/views/events/event/_note.html.haml3
-rw-r--r--app/views/explore/groups/index.html.haml19
-rw-r--r--app/views/explore/projects/_filter.html.haml2
-rw-r--r--app/views/explore/projects/_project.html.haml24
-rw-r--r--app/views/explore/projects/_projects.html.haml6
-rw-r--r--app/views/explore/projects/index.html.haml12
-rw-r--r--app/views/explore/projects/starred.html.haml13
-rw-r--r--app/views/explore/projects/trending.html.haml24
-rw-r--r--app/views/groups/_projects.html.haml4
-rw-r--r--app/views/groups/issues.html.haml25
-rw-r--r--app/views/groups/merge_requests.html.haml23
-rw-r--r--app/views/groups/milestones/index.html.haml26
-rw-r--r--app/views/groups/show.html.haml4
-rw-r--r--app/views/layouts/_page.html.haml11
-rw-r--r--app/views/layouts/dashboard.html.haml3
-rw-r--r--app/views/layouts/explore.html.haml3
-rw-r--r--app/views/layouts/group.html.haml3
-rw-r--r--app/views/layouts/header/_default.html.haml21
-rw-r--r--app/views/layouts/header/_public.html.haml9
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml11
-rw-r--r--app/views/layouts/nav/_project.html.haml2
-rw-r--r--app/views/layouts/profile.html.haml4
-rw-r--r--app/views/layouts/snippets.html.haml2
-rw-r--r--app/views/profiles/notifications/show.html.haml2
-rw-r--r--app/views/profiles/preferences/show.html.haml8
-rw-r--r--app/views/profiles/show.html.haml5
-rw-r--r--app/views/projects/_activity.html.haml3
-rw-r--r--app/views/projects/_home_panel.html.haml2
-rw-r--r--app/views/projects/blame/show.html.haml2
-rw-r--r--app/views/projects/branches/_branch.html.haml13
-rw-r--r--app/views/projects/branches/_commit.html.haml7
-rw-r--r--app/views/projects/branches/index.html.haml8
-rw-r--r--app/views/projects/buttons/_dropdown.html.haml2
-rw-r--r--app/views/projects/commits/_head.html.haml6
-rw-r--r--app/views/projects/commits/show.html.haml25
-rw-r--r--app/views/projects/compare/_form.html.haml2
-rw-r--r--app/views/projects/compare/index.html.haml7
-rw-r--r--app/views/projects/compare/show.html.haml12
-rw-r--r--app/views/projects/deploy_keys/index.html.haml1
-rw-r--r--app/views/projects/diffs/_diffs.html.haml3
-rw-r--r--app/views/projects/diffs/_warning.html.haml2
-rw-r--r--app/views/projects/graphs/commits.html.haml21
-rw-r--r--app/views/projects/hooks/index.html.haml8
-rw-r--r--app/views/projects/issues/_issues.html.haml11
-rw-r--r--app/views/projects/issues/index.html.haml4
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml5
-rw-r--r--app/views/projects/merge_requests/_merge_requests.html.haml11
-rw-r--r--app/views/projects/merge_requests/_show.html.haml3
-rw-r--r--app/views/projects/merge_requests/index.html.haml4
-rw-r--r--app/views/projects/milestones/index.html.haml25
-rw-r--r--app/views/projects/show.html.haml23
-rw-r--r--app/views/projects/snippets/_snippet.html.haml15
-rw-r--r--app/views/projects/snippets/index.html.haml3
-rw-r--r--app/views/projects/tags/_tag.html.haml12
-rw-r--r--app/views/projects/tags/index.html.haml11
-rw-r--r--app/views/projects/tree/_tree.html.haml2
-rw-r--r--app/views/projects/wikis/_main_links.html.haml4
-rw-r--r--app/views/projects/wikis/_nav.html.haml4
-rw-r--r--app/views/projects/wikis/show.html.haml2
-rw-r--r--app/views/search/_category.html.haml2
-rw-r--r--app/views/search/_filter.html.haml6
-rw-r--r--app/views/search/_form.html.haml12
-rw-r--r--app/views/search/_results.html.haml9
-rw-r--r--app/views/search/results/_blob.html.haml2
-rw-r--r--app/views/search/results/_project.html.haml6
-rw-r--r--app/views/search/results/_snippet_blob.html.haml2
-rw-r--r--app/views/search/results/_wiki_blob.html.haml2
-rw-r--r--app/views/search/show.html.haml2
-rw-r--r--app/views/shared/_clone_panel.html.haml6
-rw-r--r--app/views/shared/_event_filter.html.haml2
-rw-r--r--app/views/shared/_file_highlight.html.haml2
-rw-r--r--app/views/shared/_milestones_filter.html.haml7
-rw-r--r--app/views/shared/_project.html.haml16
-rw-r--r--app/views/shared/_projects_list.html.haml17
-rw-r--r--app/views/shared/groups/_group.html.haml22
-rw-r--r--app/views/shared/issuable/_filter.html.haml9
-rw-r--r--app/views/shared/projects/_list.html.haml19
-rw-r--r--app/views/shared/projects/_project.html.haml24
-rw-r--r--app/views/shared/snippets/_snippet.html.haml (renamed from app/views/snippets/_snippet.html.haml)18
-rw-r--r--app/views/snippets/_snippets.html.haml2
-rw-r--r--app/views/snippets/current_user_index.html.haml11
-rw-r--r--app/views/snippets/index.html.haml10
-rw-r--r--app/views/users/_projects.html.haml4
-rw-r--r--app/views/users/show.html.haml4
-rw-r--r--app/workers/email_receiver_worker.rb2
-rw-r--r--app/workers/emails_on_push_worker.rb33
-rw-r--r--app/workers/merge_worker.rb4
-rwxr-xr-xbin/daemon_with_pidfile33
-rwxr-xr-xbin/mail_room4
-rw-r--r--config/gitlab.yml.example5
-rw-r--r--config/initializers/1_settings.rb26
-rw-r--r--config/initializers/7_omniauth.rb2
-rw-r--r--config/initializers/devise.rb2
-rw-r--r--config/initializers/doorkeeper.rb3
-rw-r--r--config/mail_room.yml.example2
-rw-r--r--config/routes.rb30
-rw-r--r--db/migrate/20150817163600_deduplicate_user_identities.rb14
-rw-r--r--db/migrate/20150824002011_add_enable_ssl_verification.rb5
-rw-r--r--db/schema.rb59
-rw-r--r--doc/api/README.md1
-rw-r--r--doc/api/keys.md46
-rw-r--r--doc/api/services.md506
-rw-r--r--doc/development/rake_tasks.md6
-rw-r--r--doc/gitlab-basics/command-line-commands.md5
-rw-r--r--doc/install/installation.md29
-rw-r--r--doc/integration/crowd.md58
-rw-r--r--doc/integration/omniauth.md1
-rw-r--r--doc/reply_by_email/README.md4
-rw-r--r--doc/update/7.14-to-8.0.md159
-rw-r--r--doc/web_hooks/web_hooks.md4
-rw-r--r--doc/workflow/importing/README.md4
-rw-r--r--doc/workflow/importing/import_projects_from_github.md2
-rw-r--r--features/admin/hooks.feature9
-rw-r--r--features/dashboard/dashboard.feature8
-rw-r--r--features/dashboard/event_filters.feature8
-rw-r--r--features/login_form.feature5
-rw-r--r--features/project/commits/commits.feature1
-rw-r--r--features/project/hooks.feature5
-rw-r--r--features/project/wiki.feature12
-rw-r--r--features/steps/admin/hooks.rb15
-rw-r--r--features/steps/dashboard/starred_projects.rb2
-rw-r--r--features/steps/login_form.rb25
-rw-r--r--features/steps/project/commits/commits.rb11
-rw-r--r--features/steps/project/hooks.rb13
-rw-r--r--features/steps/project/merge_requests.rb7
-rw-r--r--features/steps/project/wiki.rb9
-rw-r--r--features/steps/shared/active_tab.rb4
-rw-r--r--features/steps/shared/diff_note.rb2
-rw-r--r--features/steps/shared/paths.rb4
-rw-r--r--features/user.feature5
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/helpers.rb26
-rw-r--r--lib/api/keys.rb20
-rw-r--r--lib/api/services.rb86
-rw-r--r--lib/gitlab/backend/grack_auth.rb49
-rw-r--r--lib/gitlab/bitbucket_import/client.rb23
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb34
-rw-r--r--lib/gitlab/color_schemes.rb67
-rw-r--r--lib/gitlab/current_settings.rb14
-rw-r--r--lib/gitlab/github_import/importer.rb3
-rw-r--r--lib/gitlab/gitlab_import/importer.rb3
-rw-r--r--lib/gitlab/import_formatter.rb4
-rw-r--r--lib/gitlab/ldap/user.rb11
-rw-r--r--lib/gitlab/markdown.rb65
-rw-r--r--lib/gitlab/markdown/autolink_filter.rb1
-rw-r--r--lib/gitlab/markdown/commit_range_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/commit_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/cross_project_reference.rb2
-rw-r--r--lib/gitlab/markdown/emoji_filter.rb3
-rw-r--r--lib/gitlab/markdown/external_issue_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/external_link_filter.rb1
-rw-r--r--lib/gitlab/markdown/issue_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/label_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/merge_request_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/reference_filter.rb4
-rw-r--r--lib/gitlab/markdown/relative_link_filter.rb1
-rw-r--r--lib/gitlab/markdown/sanitization_filter.rb1
-rw-r--r--lib/gitlab/markdown/snippet_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/syntax_highlight_filter.rb39
-rw-r--r--lib/gitlab/markdown/table_of_contents_filter.rb1
-rw-r--r--lib/gitlab/markdown/task_list_filter.rb1
-rw-r--r--lib/gitlab/markdown/user_reference_filter.rb2
-rw-r--r--lib/gitlab/reference_extractor.rb10
-rw-r--r--lib/gitlab/themes.rb18
-rw-r--r--lib/gitlab/url_builder.rb8
-rw-r--r--lib/redcarpet/render/gitlab_html.rb46
-rwxr-xr-xlib/support/init.d/gitlab76
-rwxr-xr-xlib/support/init.d/gitlab.default.example10
-rw-r--r--lib/support/nginx/gitlab44
-rw-r--r--lib/support/nginx/gitlab-ssl44
-rw-r--r--lib/tasks/gitlab/check.rake13
-rw-r--r--lib/tasks/services.rake89
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb37
-rw-r--r--spec/factories/abuse_reports.rb12
-rw-r--r--spec/factories/merge_requests.rb1
-rw-r--r--spec/factories/notes.rb1
-rw-r--r--spec/features/gitlab_flavored_markdown_spec.rb2
-rw-r--r--spec/features/markdown_spec.rb10
-rw-r--r--spec/helpers/events_helper_spec.rb5
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb13
-rw-r--r--spec/helpers/preferences_helper_spec.rb92
-rw-r--r--spec/javascripts/zen_mode_spec.js.coffee5
-rw-r--r--spec/lib/gitlab/bitbucket_import/client_spec.rb34
-rw-r--r--spec/lib/gitlab/color_schemes_spec.rb45
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb22
-rw-r--r--spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb5
-rw-r--r--spec/lib/gitlab/markdown/commit_reference_filter_spec.rb5
-rw-r--r--spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb5
-rw-r--r--spec/lib/gitlab/markdown/issue_reference_filter_spec.rb5
-rw-r--r--spec/lib/gitlab/markdown/label_reference_filter_spec.rb5
-rw-r--r--spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb5
-rw-r--r--spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb5
-rw-r--r--spec/lib/gitlab/markdown/user_reference_filter_spec.rb6
-rw-r--r--spec/lib/gitlab/themes_spec.rb3
-rw-r--r--spec/models/abuse_report_spec.rb12
-rw-r--r--spec/models/application_setting_spec.rb1
-rw-r--r--spec/models/issue_spec.rb27
-rw-r--r--spec/models/merge_request_spec.rb1
-rw-r--r--spec/models/note_spec.rb1
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb107
-rw-r--r--spec/models/user_spec.rb108
-rw-r--r--spec/requests/api/keys_spec.rb39
-rw-r--r--spec/requests/api/services_spec.rb99
-rw-r--r--spec/services/notification_service_spec.rb11
-rw-r--r--spec/support/services_shared_context.rb21
-rw-r--r--spec/workers/emails_on_push_worker_spec.rb34
-rw-r--r--spec/workers/merge_worker_spec.rb28
-rw-r--r--spec/workers/post_receive_spec.rb2
321 files changed, 3987 insertions, 1717 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 67ded53ad79..247eb1e3643 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,7 +1,16 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.0.0 (unreleased)
- - Fix Error 500 in API when accessing a group that has an avatar (Stan Hu)
+ - Fix URL construction for merge requests, issues, notes, and commits for relative URL config (Stan Hu)
+ - Omit filename in Content-Disposition header in raw file download to avoid RFC 6266 encoding issues (Stan HU)
+ - Fix broken Wiki Page History (Stan Hu)
+ - Prevent anchors from being hidden by header (Stan Hu)
+ - Fix bug where only the first 15 Bitbucket issues would be imported (Stan Hu)
+ - Sort issues by creation date in Bitbucket importer (Stan Hu)
+ - Upgrade gitlab_git to 7.2.15 to fix `git blame` errors with ISO-encoded files (Stan Hu)
+ - Prevent too many redirects upon login when home page URL is set to external_url (Stan Hu)
+ - Improve dropdown positioning on the project home page (Hannes Rosenögger)
+ - Upgrade browser gem to 1.0.0 to avoid warning in IE11 compatibilty mode (Stan Hu)
- Remove user OAuth tokens from the database and request new tokens each session (Stan Hu)
- Only show recent push event if the branch still exists or a recent merge request has not been created (Stan Hu)
- Remove satellites
@@ -13,6 +22,31 @@ v 8.0.0 (unreleased)
- Search for comments should be case insensetive
- Create cross-reference for closing references on commits pushed to non-default branches (Maël Valais)
- Ability to search milestones
+ - Gracefully handle SMTP user input errors (e.g. incorrect email addresses) to prevent Sidekiq retries (Stan Hu)
+ - Move dashboard activity to separate page (for your projects and starred projects)
+ - Improve performance of git blame
+ - Limit content width to 1200px for most of pages to improve readability on big screens
+ - Fix 500 error when submit project snippet without body
+ - Improve search page usability
+ - Bring more UI consistency in way how projects, snippets and groups lists are rendered
+ - Make all profiles public
+ - Fixed login failure when extern_uid changes (Joel Koglin)
+ - Don't notify users without access to the project when they are (accidentally) mentioned in a note.
+ - Retrieving oauth token with LDAP credentials
+ - Load Application settings from running database unless env var USE_DB=false
+ - Added Drone CI integration (Kirill Zaitsev)
+ - Refactored service API and added automatically service docs generator (Kirill Zaitsev)
+ - Added web_url key project hook_attrs (Kirill Zaitsev)
+ - Add ability to get user information by ID of an SSH key via the API
+ - Fix bug which IE cannot show image at markdown when the image is raw file of gitlab
+ - Add support for Crowd
+
+v 7.14.1
+ - Improve abuse reports management from admin area
+ - Fix "Reload with full diff" URL button in compare branch view (Stan Hu)
+ - Only include base URL in OmniAuth full_host parameter (Stan Hu)
+ - Fix Error 500 in API when accessing a group that has an avatar (Stan Hu)
+ - Ability to enable SSL verification for Webhooks
v 7.14.0
- Fix bug where non-project members of the target project could set labels on new merge requests.
@@ -90,7 +124,7 @@ v 7.13.4
v 7.13.3
- Fix bug causing Bitbucket importer to crash when OAuth application had been removed.
- Allow users to send abuse reports
- - Remove satellites
+ - Remove satellites
- Link username to profile on Group Members page (Tom Webster)
v 7.13.2
@@ -298,6 +332,7 @@ v 7.11.0
- Protect OmniAuth request phase against CSRF.
- Don't send notifications to mentioned users that don't have access to the project in question.
- Add search issues/MR by number
+ - Change plots to bar graphs in commit statistics screen
- Move snippets UI to fluid layout
- Improve UI for sidebar. Increase separation between navigation and content
- Improve new project command options (Ben Bodenmiller)
diff --git a/Gemfile b/Gemfile
index 3aa3c72e088..cca8fc38e57 100644
--- a/Gemfile
+++ b/Gemfile
@@ -25,6 +25,7 @@ gem 'omniauth-kerberos', group: :kerberos
gem 'omniauth-gitlab'
gem 'omniauth-bitbucket'
gem 'omniauth-saml', '~> 1.4.0'
+gem 'omniauth_crowd'
gem 'doorkeeper', '2.1.3'
gem "rack-oauth2", "~> 1.0.5"
@@ -34,16 +35,11 @@ gem 'rqrcode-rails3'
gem 'attr_encrypted', '1.3.4'
# Browser detection
-gem "browser", '~> 0.8.0'
+gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 7.2.14'
-
-# Ruby/Rack Git Smart-HTTP Server Handler
-# GitLab fork with a lot of changes (improved thread-safety, better memory usage etc)
-# For full list of changes see https://github.com/SaitoWu/grack/compare/master...gitlabhq:master
-gem 'gitlab-grack', '~> 2.0.2', require: 'grack'
+gem "gitlab_git", '~> 7.2.15'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
@@ -273,6 +269,6 @@ gem "newrelic_rpm"
gem 'octokit', '3.7.0'
-gem "mail_room", "~> 0.4.0"
+gem "mail_room", "~> 0.4.2"
gem 'email_reply_parser'
diff --git a/Gemfile.lock b/Gemfile.lock
index 5278fe243a8..2df318f3382 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -76,7 +76,7 @@ GEM
ruby_parser (~> 3.5.0)
sass (~> 3.0)
terminal-table (~> 1.4)
- browser (0.8.0)
+ browser (1.0.0)
builder (3.2.2)
byebug (3.2.0)
columnize (~> 0.8)
@@ -263,8 +263,6 @@ GEM
flowdock (~> 0.7)
gitlab-grit (>= 2.4.1)
multi_json
- gitlab-grack (2.0.2)
- rack (~> 1.5.1)
gitlab-grit (2.7.2)
charlock_holmes (~> 0.6)
diff-lcs (~> 1.1)
@@ -276,7 +274,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.1.0)
gemojione (~> 2.0)
- gitlab_git (7.2.14)
+ gitlab_git (7.2.15)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
@@ -372,7 +370,7 @@ GEM
systemu (~> 2.6.2)
mail (2.6.3)
mime-types (>= 1.16, < 3)
- mail_room (0.4.0)
+ mail_room (0.4.2)
method_source (0.8.2)
mime-types (1.25.1)
mimemagic (0.3.0)
@@ -436,6 +434,10 @@ GEM
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
+ omniauth_crowd (2.2.3)
+ activesupport
+ nokogiri (>= 1.4.4)
+ omniauth (~> 1.0)
opennebula (4.12.1)
json
nokogiri
@@ -462,7 +464,7 @@ GEM
pyu-ruby-sasl (0.0.3.3)
quiet_assets (1.0.2)
railties (>= 3.1, < 5.0)
- racc (1.4.10)
+ racc (1.4.12)
rack (1.5.5)
rack-accept (0.4.5)
rack (>= 0.4)
@@ -755,7 +757,7 @@ DEPENDENCIES
binding_of_caller
bootstrap-sass (~> 3.0)
brakeman
- browser (~> 0.8.0)
+ browser (~> 1.0.0)
byebug
cal-heatmap-rails (~> 0.0.1)
capybara (~> 2.4.0)
@@ -787,10 +789,9 @@ DEPENDENCIES
gemnasium-gitlab-service (~> 0.2)
github-markup
gitlab-flowdock-git-hook (~> 1.0.1)
- gitlab-grack (~> 2.0.2)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1)
- gitlab_git (~> 7.2.14)
+ gitlab_git (~> 7.2.15)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.1)
gollum-lib (~> 4.0.2)
@@ -808,7 +809,7 @@ DEPENDENCIES
jquery-ui-rails
kaminari (~> 0.15.1)
letter_opener
- mail_room (~> 0.4.0)
+ mail_room (~> 0.4.2)
minitest (~> 5.3.0)
mousetrap-rails
mysql2
@@ -824,6 +825,7 @@ DEPENDENCIES
omniauth-saml (~> 1.4.0)
omniauth-shibboleth
omniauth-twitter
+ omniauth_crowd
org-ruby (= 0.9.12)
pg
poltergeist (~> 1.6.0)
@@ -883,4 +885,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
- 1.10.6
+ 1.10.5
diff --git a/app/assets/fonts/OFL.txt b/app/assets/fonts/OFL.txt
new file mode 100755
index 00000000000..a9b845ed1d4
--- /dev/null
+++ b/app/assets/fonts/OFL.txt
@@ -0,0 +1,92 @@
+Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/app/assets/fonts/SourceSansPro-Black.ttf b/app/assets/fonts/SourceSansPro-Black.ttf
new file mode 100755
index 00000000000..cb89a2d171e
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-Black.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BlackItalic.ttf b/app/assets/fonts/SourceSansPro-BlackItalic.ttf
new file mode 100755
index 00000000000..c719243c0d6
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-BlackItalic.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf b/app/assets/fonts/SourceSansPro-Bold.ttf
new file mode 100755
index 00000000000..50d81bdad58
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-Bold.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BoldItalic.ttf b/app/assets/fonts/SourceSansPro-BoldItalic.ttf
new file mode 100755
index 00000000000..d20dd0c5eca
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-BoldItalic.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf b/app/assets/fonts/SourceSansPro-ExtraLight.ttf
new file mode 100755
index 00000000000..bb4176c6fff
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-ExtraLight.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLightItalic.ttf b/app/assets/fonts/SourceSansPro-ExtraLightItalic.ttf
new file mode 100755
index 00000000000..2c34f3b8dc4
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-ExtraLightItalic.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Italic.ttf b/app/assets/fonts/SourceSansPro-Italic.ttf
new file mode 100755
index 00000000000..e5a1a86e631
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-Italic.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Light.ttf b/app/assets/fonts/SourceSansPro-Light.ttf
new file mode 100755
index 00000000000..5f64679f6b9
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-Light.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-LightItalic.ttf b/app/assets/fonts/SourceSansPro-LightItalic.ttf
new file mode 100755
index 00000000000..88a6778d24f
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-LightItalic.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf b/app/assets/fonts/SourceSansPro-Regular.ttf
new file mode 100755
index 00000000000..91e9ea5757f
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-Regular.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf b/app/assets/fonts/SourceSansPro-Semibold.ttf
new file mode 100755
index 00000000000..5020594826b
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-Semibold.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-SemiboldItalic.ttf b/app/assets/fonts/SourceSansPro-SemiboldItalic.ttf
new file mode 100755
index 00000000000..2c5ad3008c3
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-SemiboldItalic.ttf
Binary files differ
diff --git a/app/assets/javascripts/activities.js.coffee b/app/assets/javascripts/activities.js.coffee
index 777c62dc1b7..63803747413 100644
--- a/app/assets/javascripts/activities.js.coffee
+++ b/app/assets/javascripts/activities.js.coffee
@@ -1,7 +1,7 @@
class @Activities
constructor: ->
Pager.init 20, true
- $(".event_filter_link").bind "click", (event) =>
+ $(".event-filter .btn").bind "click", (event) =>
event.preventDefault()
@toggleFilter($(event.currentTarget))
@reloadActivities()
@@ -12,7 +12,7 @@ class @Activities
toggleFilter: (sender) ->
- sender.parent().toggleClass "active"
+ sender.toggleClass "active"
event_filters = $.cookie("event_filter")
filter = sender.attr("id").split("_")[0]
if event_filters
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index bb0a0c51fd4..8e987ac4e83 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -94,16 +94,18 @@ window.unbindEvents = ->
$(document).off('scroll')
window.shiftWindow = ->
- scrollBy 0, -50
+ scrollBy 0, -100
document.addEventListener("page:fetch", unbindEvents)
-# Scroll the window to avoid the topnav bar
-# https://github.com/twitter/bootstrap/issues/1768
-if location.hash
- setTimeout shiftWindow, 1
window.addEventListener "hashchange", shiftWindow
+window.onload = ->
+ # Scroll the window to avoid the topnav bar
+ # https://github.com/twitter/bootstrap/issues/1768
+ if location.hash
+ setTimeout shiftWindow, 100
+
$ ->
$(".nicescroll").niceScroll(cursoropacitymax: '0.4', cursorcolor: '#FFF', cursorborder: "1px solid #FFF")
@@ -116,6 +118,12 @@ $ ->
$('.remove-row').bind 'ajax:success', ->
$(this).closest('li').fadeOut()
+ $('.js-remove-tr').bind 'ajax:before', ->
+ $(this).hide()
+
+ $('.js-remove-tr').bind 'ajax:success', ->
+ $(this).closest('tr').fadeOut()
+
# Initialize select2 selects
$('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 81e73799271..5bf0b302179 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -51,10 +51,10 @@ class Dispatcher
MergeRequests.init()
when 'dashboard:show', 'root:show'
new Dashboard()
+ when 'dashboard:activity'
new Activities()
when 'dashboard:projects:starred'
new Activities()
- new ProjectsList()
when 'projects:commit:show'
new Commit()
new Diff()
@@ -69,7 +69,6 @@ class Dispatcher
when 'groups:show'
new Activities()
shortcut_handler = new ShortcutsNavigation()
- new ProjectsList()
when 'groups:group_members:index'
new GroupMembers()
new UsersSelect()
@@ -95,8 +94,6 @@ class Dispatcher
when 'users:show'
new User()
new Activities()
- when 'admin:users:show'
- new ProjectsList()
switch path.first()
when 'admin'
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 0021d17d85e..b7f2c63c5a7 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -123,6 +123,7 @@ class @Notes
if @isNewNote(note)
@note_ids.push(note.id)
$('ul.main-notes-list').append(note.html)
+ $('.js-syntax-highlight').syntaxHighlight()
@initTaskList()
###
diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee
index c0e36d1ccc5..db5faf71faf 100644
--- a/app/assets/javascripts/projects_list.js.coffee
+++ b/app/assets/javascripts/projects_list.js.coffee
@@ -8,7 +8,7 @@ class @ProjectsList
$(".projects-list-filter").keyup ->
terms = $(this).val()
- uiBox = $(this).closest('.panel')
+ uiBox = $(this).closest('.projects-list-holder')
if terms == "" || terms == undefined
uiBox.find(".projects-list li").show()
else
diff --git a/app/assets/javascripts/syntax_highlight.coffee b/app/assets/javascripts/syntax_highlight.coffee
new file mode 100644
index 00000000000..71295cd4b08
--- /dev/null
+++ b/app/assets/javascripts/syntax_highlight.coffee
@@ -0,0 +1,12 @@
+# Applies a syntax highlighting color scheme CSS class to any element with the
+# `js-syntax-highlight` class
+#
+# ### Example Markup
+#
+# <div class="js-syntax-highlight"></div>
+#
+$.fn.syntaxHighlight = ->
+ $(this).addClass(gon.user_color_scheme)
+
+$(document).on 'ready page:load', ->
+ $('.js-syntax-highlight').syntaxHighlight()
diff --git a/app/assets/javascripts/zen_mode.js.coffee b/app/assets/javascripts/zen_mode.js.coffee
index 8a0564a9098..a1462cf3cae 100644
--- a/app/assets/javascripts/zen_mode.js.coffee
+++ b/app/assets/javascripts/zen_mode.js.coffee
@@ -38,6 +38,8 @@ class @ZenMode
@active_checkbox = $(checkbox)
@active_checkbox.prop('checked', true)
@active_zen_area = @active_checkbox.parent().find('textarea')
+ # Prevent a user-resized textarea from persisting to fullscreen
+ @active_zen_area.removeAttr('style')
@active_zen_area.focus()
exitZenMode: =>
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 1a5f11df7d1..46f7feddf8d 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -12,6 +12,7 @@
*/
+@import "base/fonts";
@import "base/variables";
@import "base/mixins";
@import "base/layout";
diff --git a/app/assets/stylesheets/base/fonts.scss b/app/assets/stylesheets/base/fonts.scss
new file mode 100644
index 00000000000..e214567eca1
--- /dev/null
+++ b/app/assets/stylesheets/base/fonts.scss
@@ -0,0 +1,25 @@
+/* latin-ext */
+@font-face {
+ font-family: 'Source Sans Pro';
+ font-style: normal;
+ font-weight: 300;
+ src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), font-url('SourceSansPro-Light.ttf');
+}
+@font-face {
+ font-family: 'Source Sans Pro';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Source Sans Pro'), local('SourceSansPro-Regular'), font-url('SourceSansPro-Regular.ttf');
+}
+@font-face {
+ font-family: 'Source Sans Pro';
+ font-style: normal;
+ font-weight: 600;
+ src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), font-url('SourceSansPro-Semibold.ttf');
+}
+@font-face {
+ font-family: 'Source Sans Pro';
+ font-style: normal;
+ font-weight: 700;
+ src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), font-url('SourceSansPro-Bold.ttf');
+}
diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
index 56f4c794e1b..6d3b4b1e73a 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -42,17 +42,18 @@ $font-size-base: $gl-font-size;
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-$padding-base-vertical: 6px;
-$padding-base-horizontal: 14px;
-
+$padding-base-vertical: 9px;
+$padding-base-horizontal: $gl-padding;
+$component-active-color: #fff;
+$component-active-bg: $brand-info;
//== Forms
//
//##
$input-color: $text-color;
-$input-border: #DDD;
-$input-border-focus: $brand-info;
+$input-border: #e7e9ed;
+$input-border-focus: #7F8FA4;
$legend-color: $text-color;
@@ -111,8 +112,8 @@ $alert-border-radius: 0;
$panel-border-radius: 0;
$panel-default-text: $text-color;
-$panel-default-border: $border-color;
-$panel-default-heading-bg: $background-color;
+$panel-default-border: #E7E9ED;
+$panel-default-heading-bg: #F8FAFC;
//== Wells
@@ -131,3 +132,15 @@ $code-bg: #f9f2f4;
$kbd-color: #fff;
$kbd-bg: #333;
+
+//== Buttons
+//
+//##
+$btn-default-color: $gl-text-color;
+$btn-default-bg: #fff;
+$btn-default-border: #e7e9ed;
+
+//== Nav
+//
+//##
+$nav-link-padding: 13px $gl-padding;
diff --git a/app/assets/stylesheets/base/layout.scss b/app/assets/stylesheets/base/layout.scss
index 690d89a5c16..b91c15d8910 100644
--- a/app/assets/stylesheets/base/layout.scss
+++ b/app/assets/stylesheets/base/layout.scss
@@ -20,3 +20,7 @@ html {
.navless-container {
margin-top: 30px;
}
+
+.container-limited {
+ max-width: $fixed-layout-width;
+}
diff --git a/app/assets/stylesheets/base/mixins.scss b/app/assets/stylesheets/base/mixins.scss
index 7beef1845ef..8698109bc4c 100644
--- a/app/assets/stylesheets/base/mixins.scss
+++ b/app/assets/stylesheets/base/mixins.scss
@@ -55,8 +55,11 @@
}
@mixin md-typography {
- font-size: 15px;
- line-height: 1.5;
+ color: #444;
+
+ a {
+ color: #3084bb;
+ }
img {
max-width: 100%;
@@ -157,3 +160,58 @@
white-space: nowrap;
max-width: $max_width;
}
+
+/*
+ * Base mixin for lists in GitLab
+ */
+@mixin basic-list {
+ margin: 5px 0px;
+ padding: 0px;
+ list-style: none;
+
+ > li {
+ padding: 10px 0;
+ border-bottom: 1px solid #EEE;
+ overflow: hidden;
+ display: block;
+ margin: 0px;
+
+ &:last-child {
+ border:none
+ }
+
+ &.active {
+ background: #f9f9f9;
+ a {
+ font-weight: bold;
+ }
+ }
+
+ &.hide {
+ display: none;
+ }
+
+ &.light {
+ a {
+ color: $gl-gray;
+ }
+ }
+ }
+}
+
+@mixin input-big {
+ height: 36px;
+ padding: 5px 10px;
+ font-size: 16px;
+ line-height: 24px;
+ color: #7f8fa4;
+ background-color: #fff;
+ border-color: #e7e9ed;
+}
+
+@mixin btn-big {
+ height: 36px;
+ padding: 5px 10px;
+ font-size: 16px;
+ line-height: 24px;
+}
diff --git a/app/assets/stylesheets/base/variables.scss b/app/assets/stylesheets/base/variables.scss
index cb439a0e0bf..21462b31127 100644
--- a/app/assets/stylesheets/base/variables.scss
+++ b/app/assets/stylesheets/base/variables.scss
@@ -1,27 +1,30 @@
-$style_color: #474D57;
$hover: #FFFAF1;
-$gl-text-color: #222222;
-$gl-link-color: #446e9b;
+$gl-text-color: #54565b;
+$gl-header-color: #4c4e54;
+$gl-link-color: #333c48;
$nprogress-color: #c0392b;
-$gl-font-size: 14px;
+$gl-font-size: 15px;
$list-font-size: 15px;
-$sidebar_collapsed_width: 52px;
+$sidebar_collapsed_width: 62px;
$sidebar_width: 230px;
$avatar_radius: 50%;
$code_font_size: 13px;
$code_line_height: 1.5;
-$border-color: #E5E5E5;
-$background-color: #f5f5f5;
-$header-height: 50px;
-$readable-width: 1100px;
+$border-color: #E7E9ED;
+$background-color: #F8FAFC;
+$header-height: 58px;
+$fixed-layout-width: 1200px;
+$gl-gray: #7f8fa4;
+$gl-padding: 16px;
+$gl-avatar-size: 46px;
/*
* State colors:
*/
$gl-primary: #446e9b;
-$gl-success: #019875;
-$gl-info: #029ACF;
+$gl-success: #44c679;
+$gl-info: #00aaff;
$gl-warning: #EB9532;
$gl-danger: #d9534f;
@@ -35,4 +38,4 @@ $deleted: #f77;
* Fonts
*/
$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
-$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
+$regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/generic/avatar.scss b/app/assets/stylesheets/generic/avatar.scss
index 8595887c3b9..221cb6a04a5 100644
--- a/app/assets/stylesheets/generic/avatar.scss
+++ b/app/assets/stylesheets/generic/avatar.scss
@@ -23,8 +23,12 @@
&.s24 { width: 24px; height: 24px; margin-right: 8px; }
&.s26 { width: 26px; height: 26px; margin-right: 8px; }
&.s32 { width: 32px; height: 32px; margin-right: 10px; }
+ &.s36 { width: 36px; height: 36px; margin-right: 10px; }
+ &.s46 { width: 46px; height: 46px; margin-right: 15px; }
+ &.s48 { width: 48px; height: 48px; margin-right: 10px; }
&.s60 { width: 60px; height: 60px; margin-right: 12px; }
&.s90 { width: 90px; height: 90px; margin-right: 15px; }
+ &.s140 { width: 140px; height: 140px; margin-right: 20px; }
&.s160 { width: 160px; height: 160px; margin-right: 20px; }
}
@@ -38,5 +42,6 @@
&.s32 { font-size: 22px; line-height: 32px; }
&.s60 { font-size: 32px; line-height: 60px; }
&.s90 { font-size: 36px; line-height: 90px; }
- &.s160 { font-size: 96px; line-height: 1.33; }
+ &.s140 { font-size: 72px; line-height: 140px; }
+ &.s160 { font-size: 96px; line-height: 160px; }
}
diff --git a/app/assets/stylesheets/generic/blocks.scss b/app/assets/stylesheets/generic/blocks.scss
index 3536a68f416..abf4657dd58 100644
--- a/app/assets/stylesheets/generic/blocks.scss
+++ b/app/assets/stylesheets/generic/blocks.scss
@@ -1,19 +1,47 @@
.light-well {
- background: #f9f9f9;
+ background-color: #f8fafc;
padding: 15px;
}
.centered-light-block {
text-align: center;
- color: #888;
+ color: $gl-gray;
margin: 20px;
}
.nothing-here-block {
text-align: center;
padding: 20px;
- color: #666;
+ color: $gl-gray;
font-weight: normal;
font-size: 16px;
line-height: 36px;
}
+
+.gray-content-block {
+ margin: -$gl-padding;
+ background-color: #f8fafc;
+ padding: $gl-padding;
+ margin-bottom: 0px;
+ border-top: 1px solid #e7e9ed;
+ border-bottom: 1px solid #e7e9ed;
+ color: $gl-gray;
+
+ &.second-block {
+ margin-top: -1px;
+ margin-bottom: 0;
+ }
+
+ &.footer-block {
+ margin-top: 0;
+ margin-bottom: -$gl-padding;
+ }
+
+ .title {
+ color: $gl-text-color;
+ }
+
+ .oneline {
+ line-height: 44px;
+ }
+}
diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss
index cd6bf64c0ae..e8237509092 100644
--- a/app/assets/stylesheets/generic/buttons.scss
+++ b/app/assets/stylesheets/generic/buttons.scss
@@ -72,3 +72,19 @@
}
}
}
+
+.btn-group-next {
+ .btn {
+ padding: 9px 0px;
+ font-size: 15px;
+ color: #7f8fa4;
+ border-color: #e7e9ed;
+ width: 140px;
+
+ &.active {
+ border-color: $gl-info;
+ background: $gl-info;
+ color: #fff;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index bf5c7a8d75e..b995486588f 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -1,5 +1,5 @@
/** COLORS **/
-.cgray { color: gray }
+.cgray { color: $gl-gray; }
.clgray { color: #BBB }
.cred { color: #D12F19 }
.cgreen { color: #4a2 }
@@ -7,6 +7,7 @@
/** COMMON CLASSES **/
.prepend-top-10 { margin-top:10px }
+.prepend-top-default { margin-top: $gl-padding; }
.prepend-top-20 { margin-top:20px }
.prepend-left-10 { margin-left:10px }
.prepend-left-20 { margin-left:20px }
@@ -20,10 +21,10 @@
.underlined-link { text-decoration: underline; }
.hint { font-style: italic; color: #999; }
-.light { color: #888 }
+.light { color: $gl-gray; }
.slead {
- color: #666;
+ color: $gl-gray;
font-size: 15px;
margin-bottom: 12px;
font-weight: normal;
@@ -74,8 +75,6 @@ pre {
color: $gl-link-color;
}
-.help li { color:$style_color; }
-
.back-link {
font-size: 14px;
}
@@ -132,10 +131,6 @@ p.time {
text-shadow: none;
}
-.highlight_word {
- background: #fafe3d;
-}
-
.thin_area{
height: 150px;
}
@@ -307,7 +302,7 @@ table {
}
.btn-sign-in {
- margin-top: 7px;
+ margin-top: 15px;
text-shadow: none;
}
@@ -359,14 +354,14 @@ table {
}
.description {
- font-size: 16px;
+ font-size: $gl-font-size;
color: #666;
margin-top: 8px;
}
}
.profiler-results {
- top: 50px !important;
+ top: 73px !important;
.profiler-button,
.profiler-controls {
@@ -375,21 +370,41 @@ table {
}
.center-top-menu {
- border-bottom: 1px solid #EEE;
+ padding: 0;
+ margin: 0;
list-style: none;
text-align: center;
- padding-bottom: 15px;
- margin-bottom: 15px;
+ margin-top: 5px;
+ margin-bottom: $gl-padding;
+ height: 56px;
+ margin-top: -$gl-padding;
+ padding-top: $gl-padding;
li {
display: inline-block;
a {
- padding: 10px;
+ padding: 14px;
+ font-size: 17px;
+ line-height: 28px;
+ color: #7f8fa4;
+ border-bottom: 2px solid transparent;
+
+ &:hover, &:active, &:focus {
+ text-decoration: none;
+ }
}
&.active a {
- color: #666;
+ color: #4c4e54;
+ border-bottom: 2px solid #1cacfc;
+ }
+
+ .badge {
+ font-weight: normal;
+ background-color: #fff;
+ background-color: #eee;
+ color: #78a;
}
}
}
diff --git a/app/assets/stylesheets/generic/filters.scss b/app/assets/stylesheets/generic/filters.scss
index bd93a79722d..8e6922c9231 100644
--- a/app/assets/stylesheets/generic/filters.scss
+++ b/app/assets/stylesheets/generic/filters.scss
@@ -2,31 +2,6 @@
margin-right: 15px;
}
-.issues-state-filters {
- li.active a {
- border-color: #DDD !important;
-
- &, &:hover, &:active, &.active {
- background: #f5f5f5 !important;
- border-bottom: 1px solid #f5f5f5 !important;
- }
- }
-}
-
-.issues-details-filters {
- font-size: 13px;
- background: #f5f5f5;
- margin: -10px 0;
- padding: 10px 15px;
- margin-top: -15px;
- border-left: 1px solid #DDD;
- border-right: 1px solid #DDD;
-
- .btn {
- font-size: 13px;
- }
-}
-
@media (min-width: 800px) {
.issues-filters,
.issues_bulk_update {
diff --git a/app/assets/stylesheets/generic/header.scss b/app/assets/stylesheets/generic/header.scss
index 31e2ad86691..b758a526fbb 100644
--- a/app/assets/stylesheets/generic/header.scss
+++ b/app/assets/stylesheets/generic/header.scss
@@ -20,33 +20,32 @@ header {
}
&.navbar-gitlab {
+ padding: 0 20px;
z-index: 100;
margin-bottom: 0;
min-height: $header-height;
+ background-color: #fff;
border: none;
- width: 100%;
+ border-bottom: 1px solid #EEE;
- .container {
- background: #FFF;
+ .container-fluid {
width: 100% !important;
- padding: 0;
filter: none;
+ padding: 0;
.nav > li > a {
- color: #888;
- font-size: 14px;
+ color: #7f8fa4;
+ font-size: 18px;
padding: 0;
- background-color: #f5f5f5;
margin: ($header-height - 28) / 2 0;
margin-left: 10px;
- border-radius: 40px;
height: 28px;
width: 28px;
line-height: 28px;
text-align: center;
&:hover, &:focus, &:active {
- background-color: #EEE;
+ background-color: #FFF;
}
}
@@ -56,6 +55,7 @@ header {
border-radius: 0;
position: absolute;
right: 2px;
+ top: 15px;
&:hover {
background-color: #EEE;
@@ -64,66 +64,22 @@ header {
}
}
- .header-logo {
- border-bottom: 1px solid transparent;
- float: left;
- height: $header-height;
- width: $sidebar_width;
- overflow: hidden;
- transition-duration: .3s;
-
- a {
- float: left;
- height: $header-height;
- width: 100%;
- padding: ($header-height - 36 ) / 2 8px;
- overflow: hidden;
-
- img {
- width: 36px;
- height: 36px;
- float: left;
- }
-
- .gitlab-text-container {
- width: 230px;
-
- h3 {
- width: 158px;
- float: left;
- margin: 0;
- margin-left: 14px;
- font-size: 18px;
- line-height: $header-height - 14;
- font-weight: normal;
- }
- }
- }
-
- &:hover {
- background-color: #EEE;
- }
- }
-
.header-content {
- border-bottom: 1px solid #EEE;
- padding-right: 35px;
height: $header-height;
.title {
margin: 0;
- padding: 0 15px 0 35px;
overflow: hidden;
- font-size: 18px;
+ font-size: 19px;
line-height: $header-height;
- font-weight: bold;
- color: #444;
+ font-weight: normal;
+ color: #4c4e54;
text-overflow: ellipsis;
vertical-align: top;
white-space: nowrap;
a {
- color: #444;
+ color: #4c4e54;
&:hover {
text-decoration: underline;
}
@@ -138,7 +94,7 @@ header {
.search {
margin-right: 10px;
margin-left: 10px;
- margin-top: ($header-height - 28) / 2;
+ margin-top: ($header-height - 36) / 2;
form {
margin: 0;
@@ -149,13 +105,8 @@ header {
width: 220px;
background-image: image-url("icon-search.png");
background-repeat: no-repeat;
- background-position: 10px;
- height: inherit;
- padding: 4px 6px;
- padding-left: 25px;
- font-size: 13px;
- background-color: #f5f5f5;
- border-color: #f5f5f5;
+ background-position: 195px;
+ @include input-big;
&:focus {
@include box-shadow(none);
@@ -168,15 +119,7 @@ header {
}
@mixin collapsed-header {
- .header-logo {
- width: $sidebar_collapsed_width;
- }
-
- .header-content {
- .title {
- margin-left: 30px;
- }
- }
+ margin-left: $sidebar_collapsed_width;
}
@media (max-width: $screen-md-max) {
@@ -191,16 +134,14 @@ header {
}
.header-expanded {
+ margin-left: $sidebar_width;
}
}
@media (max-width: $screen-xs-max) {
- header .container {
+ header .container-fluid {
font-size: 18px;
- .title {
- }
-
.navbar-nav {
margin: 0px;
float: none !important;
diff --git a/app/assets/stylesheets/generic/lists.scss b/app/assets/stylesheets/generic/lists.scss
index c502d953c75..3bfed8de772 100644
--- a/app/assets/stylesheets/generic/lists.scss
+++ b/app/assets/stylesheets/generic/lists.scss
@@ -49,8 +49,6 @@
}
}
- .author { color: #999; }
-
.list-item-name {
float: left;
position: relative;
@@ -71,15 +69,6 @@
font-size: $list-font-size;
line-height: 18px;
}
-
- .row_title {
- color: $gray-dark;
-
- &:hover {
- color: $text-color;
- text-decoration: underline;
- }
- }
}
}
@@ -93,28 +82,12 @@ ol, ul {
/** light list with border-bottom between li **/
ul.bordered-list {
- margin: 5px 0px;
- padding: 0px;
- li {
- padding: 5px 0;
- border-bottom: 1px solid #EEE;
- overflow: hidden;
- display: block;
- margin: 0px;
- &:last-child { border:none }
- &.active {
- background: #f9f9f9;
- a { font-weight: bold; }
- }
-
- &.light {
- a { color: #777; }
- }
- }
+ @include basic-list;
&.top-list {
li:first-child {
padding-top: 0;
+
h4, h5 {
margin-top: 0;
}
@@ -125,3 +98,28 @@ ul.bordered-list {
li.task-list-item {
list-style-type: none;
}
+
+ul.content-list {
+ @include basic-list;
+
+ margin: 0;
+ padding: 0;
+
+ > li {
+ padding: $gl-padding;
+ border-color: #f1f2f4;
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+ color: $gl-gray;
+
+ .avatar {
+ margin-right: 15px;
+ }
+
+ .controls {
+ padding-top: 10px;
+ float: right;
+ }
+ }
+}
+
diff --git a/app/assets/stylesheets/generic/mobile.scss b/app/assets/stylesheets/generic/mobile.scss
index bb7b9356c70..36ae126f865 100644
--- a/app/assets/stylesheets/generic/mobile.scss
+++ b/app/assets/stylesheets/generic/mobile.scss
@@ -80,6 +80,23 @@
%ul.notes .note-role, .note-actions {
display: none;
}
+
+ .center-top-menu {
+ height: 45px;
+
+ li a {
+ font-size: 14px;
+ padding: 19px 10px;
+ }
+ }
+
+ .projects-search-form {
+ margin: 0 -5px !important;
+
+ .btn {
+ display: none;
+ }
+ }
}
@media (max-width: $screen-sm-max) {
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index d8e0dc028d1..f0860de1c49 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -3,9 +3,9 @@
.select2-choice {
background: #FFF;
border-color: #DDD;
- height: 34px;
- padding: 6px 14px;
- font-size: 14px;
+ height: 42px;
+ padding: 8px $gl-padding;
+ font-size: $gl-font-size;
line-height: 1.42857143;
@include border-radius(4px);
@@ -13,7 +13,7 @@
.select2-arrow {
background: #FFF;
border-left: none;
- padding-top: 3px;
+ padding-top: 5px;
}
}
}
diff --git a/app/assets/stylesheets/generic/sidebar.scss b/app/assets/stylesheets/generic/sidebar.scss
index b96664d30db..22720c2e1d5 100644
--- a/app/assets/stylesheets/generic/sidebar.scss
+++ b/app/assets/stylesheets/generic/sidebar.scss
@@ -18,13 +18,21 @@
}
.content-wrapper {
+ min-height: 100vh;
width: 100%;
padding: 20px;
- background: #FFF;
+ background: #f1f4f8;
+
+ .container-fluid {
+ background: #FFF;
+ padding: $gl-padding;
+ border: 1px solid #e7e9ed;
+ min-height: 90vh;
+ }
}
.nav-sidebar {
- margin-top: 29 + $header-height;
+ margin-top: 14 + $header-height;
margin-bottom: 50px;
transition-duration: .3s;
list-style: none;
@@ -43,13 +51,14 @@
}
a {
- padding: 8px 15px;
- font-size: 13px;
- line-height: 18px;
+ padding: 7px 15px;
+ font-size: $gl-font-size;
+ line-height: 24px;
color: $gray;
display: block;
text-decoration: none;
- padding-left: 16px;
+ padding-left: 22px;
+ font-weight: normal;
&:hover {
text-decoration: none;
@@ -60,9 +69,9 @@
}
i {
- width: 20px;
+ width: 16px;
color: $gray-light;
- margin-right: 23px;
+ margin-right: 13px;
}
.count {
@@ -108,17 +117,31 @@
}
@mixin folded-sidebar {
- padding-left: 50px;
+ padding-left: 60px;
transition-duration: .3s;
.sidebar-wrapper {
width: $sidebar_collapsed_width;
+ .header-logo {
+ width: $sidebar_collapsed_width;
+
+ a {
+ padding-left: 12px;
+
+ .gitlab-text-container {
+ display: none;
+ }
+ }
+ }
+
.nav-sidebar {
width: $sidebar_collapsed_width;
li a {
- padding-left: 16px;
+ span {
+ display: none;
+ }
}
}
@@ -128,21 +151,25 @@
}
.sidebar-user {
+ padding-left: 12px;
width: $sidebar_collapsed_width;
+
+ .username {
+ display: none;
+ }
}
}
}
.collapse-nav a {
+ width: $sidebar_width;
position: fixed;
- top: $header-height;
- left: 198px;
+ bottom: 0;
font-size: 13px;
background: transparent;
- width: 32px;
- height: 28px;
+ height: 40px;
text-align: center;
- line-height: 28px;
+ line-height: 40px;
transition-duration: .3s;
}
@@ -176,15 +203,60 @@
}
.sidebar-user {
+ padding: 9px 22px;
position: fixed;
- bottom: 0;
+ bottom: 40px;
width: $sidebar_width;
- padding: 10px;
overflow: hidden;
transition-duration: .3s;
.username {
- margin-top: 5px;
+ margin-left: 10px;
width: $sidebar_width - 2 * 10px;
+ font-size: 16px;
+ line-height: 34px;
+ }
+}
+
+.sidebar-wrapper {
+ .header-logo {
+ border-bottom: 1px solid transparent;
+ float: left;
+ height: $header-height;
+ width: $sidebar_width;
+ overflow: hidden;
+ transition-duration: .3s;
+
+ a {
+ float: left;
+ height: $header-height;
+ width: 100%;
+ padding: 10px 22px;
+ overflow: hidden;
+
+ img {
+ width: 36px;
+ height: 36px;
+ float: left;
+ }
+
+ .gitlab-text-container {
+ width: 230px;
+
+ h3 {
+ width: 158px;
+ float: left;
+ margin: 0;
+ margin-left: 14px;
+ font-size: 19px;
+ line-height: 41px;
+ font-weight: normal;
+ }
+ }
+ }
+
+ &:hover {
+ background-color: #EEE;
+ }
}
}
diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss
index 34b4ee3e17e..73034c84f9a 100644
--- a/app/assets/stylesheets/generic/typography.scss
+++ b/app/assets/stylesheets/generic/typography.scss
@@ -9,6 +9,11 @@
margin-bottom: 5px;
}
+h1, h2, h3, h4, h5, h6 {
+ color: $gl-header-color;
+ font-weight: 500;
+}
+
/** CODE **/
pre {
font-family: $monospace_font;
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index c8cb18ec35f..8323a8598ec 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -21,6 +21,12 @@ pre.code.highlight.dark,
background-color: #557 !important;
}
+ // Search result highlight
+ span.highlight_word {
+ background: #ffe792;
+ color: #000000;
+ }
+
.hll { background-color: #373b41 }
.c { color: #969896 } /* Comment */
.err { color: #cc6666 } /* Error */
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index 001e8b31020..e8381674336 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -21,6 +21,12 @@ pre.code.monokai,
background-color: #49483e !important;
}
+ // Search result highlight
+ span.highlight_word {
+ background: #ffe792;
+ color: #000000;
+ }
+
.hll { background-color: #49483e }
.c { color: #75715e } /* Comment */
.err { color: #960050; background-color: #1e0010 } /* Error */
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index f5b827e7c02..bd41480aefb 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -21,6 +21,11 @@ pre.code.highlight.solarized-dark,
background-color: #174652 !important;
}
+ // Search result highlight
+ span.highlight_word {
+ background: #094554;
+ }
+
/* Solarized Dark
For use with Jekyll and Pygments
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 6b44c00c305..4cc62863870 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -21,6 +21,11 @@ pre.code.highlight.solarized-light,
background-color: #ddd8c5 !important;
}
+ // Search result highlight
+ span.highlight_word {
+ background: #eee8d5;
+ }
+
/* Solarized Light
For use with Jekyll and Pygments
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index a52ffc971d1..e0edfb80b42 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -21,6 +21,11 @@ pre.code.highlight.white,
background-color: #f8eec7 !important;
}
+ // Search result highlight
+ span.highlight_word {
+ background: #fafe3d;
+ }
+
.hll { background-color: #f8f8f8 }
.c { color: #999988; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; }
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index e7125c03993..5436c6dad97 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -61,10 +61,6 @@
}
}
-.file-stats a {
- color: $style_color;
-}
-
.file-stats {
.new-file {
a {
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 359f4073e87..de2ae93df37 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -52,7 +52,7 @@ li.commit {
}
.commit-row-message {
- color: #444;
+ color: $gl-link-color;
&:hover {
text-decoration: underline;
@@ -88,12 +88,12 @@ li.commit {
}
.commit-row-info {
- color: #777;
+ color: $gl-gray;
line-height: 24px;
font-size: 13px;
a {
- color: #777;
+ color: $gl-gray;
}
.committed_ago {
diff --git a/app/assets/stylesheets/pages/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss
index 9a3b543ad10..25a86cd0f94 100644
--- a/app/assets/stylesheets/pages/dashboard.scss
+++ b/app/assets/stylesheets/pages/dashboard.scss
@@ -2,7 +2,7 @@
.side {
.panel {
.panel-heading {
- background: #EEE;
+ background: $background-color;
border-top-left-radius: 0;
}
border-top-left-radius: 0;
@@ -23,41 +23,6 @@
}
}
-.project-row, .group-row {
- padding: 0 !important;
- font-size: 14px;
- line-height: 24px;
-
- a {
- display: block;
- padding: 8px 15px;
- }
-
- .project-name, .group-name {
- font-weight: 500;
- }
-
- .arrow {
- float: right;
- margin: 0;
- font-size: 20px;
- }
-
- .last-activity {
- float: right;
- font-size: 12px;
- color: #AAA;
- display: block;
- .date {
- color: #777;
- }
- }
-}
-
-.project-description {
- overflow: hidden;
-}
-
.project-access-icon {
margin-left: 10px;
float: left;
@@ -73,12 +38,11 @@
float: left;
.avatar {
- margin-top: -8px;
- margin-left: -15px;
- @include border-radius(0px);
+ @include border-radius(50%);
}
+
.identicon {
- line-height: 40px;
+ line-height: 46px;
}
}
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index d4af7506d5b..ca2ee455423 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -1,70 +1,58 @@
/**
- * Events labels
- *
- */
-.event_label {
- &.pushed {
- padding: 0 2px;
- }
-
- &.opened {
- padding: 0 2px;
- }
-
- &.closed {
- padding: 0 2px;
- }
-
- &.merged {
- padding: 0 2px;
- }
-
- &.left,
- &.joined {
- padding: 0 2px;
- float: none;
- }
-}
-
-/**
* Dashboard events feed
*
*/
.event-item {
- &:first-child {
- padding-top: 0;
- }
+ font-size: $gl-font-size;
+ padding: $gl-padding;
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+ border-bottom: 1px solid #f1f2f4;
+ color: #7f8fa4;
&.event-inline {
.avatar {
position: relative;
top: -2px;
}
+
+ .event-title {
+ line-height: 44px;
+ }
+
+ .event-item-timestamp {
+ line-height: 44px;
+ }
+ }
+
+ a {
+ color: #4c4e54;
+ }
+
+ .avatar {
+ margin-right: 15px;
}
- padding: 12px 0px;
- border-bottom: 1px solid #eee;
.event-title {
- max-width: 70%;
@include str-truncated(calc(100% - 174px));
- font-weight: 500;
- font-size: 14px;
+ font-weight: 600;
+
.author_name {
color: #333;
}
}
+
.event-body {
- font-size: 13px;
- margin-left: 35px;
+ margin-left: 63px;
margin-right: 80px;
- color: #777;
.event-note {
margin-top: 5px;
word-wrap: break-word;
.md {
- font-size: 13px;
+ color: #7f8fa4;
+ font-size: $gl-font-size;
iframe.twitter-share-button {
vertical-align: bottom;
@@ -94,7 +82,7 @@
.event-note-icon {
color: #777;
float: left;
- font-size: 16px;
+ font-size: $gl-font-size;
line-height: 16px;
margin-right: 5px;
}
@@ -116,7 +104,7 @@
&:last-child { border:none }
.event_commits {
- margin-top: 5px;
+ margin-top: 9px;
li {
&.commit {
@@ -125,10 +113,12 @@
padding-left: 0;
border: none;
.commit-row-title {
- font-size: 12px;
+ font-size: $gl-font-size;
}
}
+
&.commits-stat {
+ margin-top: 3px;
display: block;
padding: 3px;
padding-left: 0;
@@ -142,7 +132,6 @@
.event-item-timestamp {
float: right;
- color: #999;
line-height: 22px;
}
}
@@ -186,12 +175,3 @@
}
}
}
-
-.event_filter {
- li a {
- font-size: 13px;
- padding: 5px 10px;
- background: $background-color;
- margin-left: 4px;
- }
-}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 3f617e72b02..2d32d82e107 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -46,8 +46,13 @@
.btn { font-size: 13px; }
}
-.issuable-details {
- .description {
- max-width: $readable-width;
+.project-issuable-filter {
+ .controls {
+ float: right;
+ margin-top: 7px;
+ }
+
+ .center-top-menu {
+ text-align: left;
}
}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 3572f33e91f..7928b6220fc 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -10,7 +10,7 @@
}
.issue-info {
- color: #999;
+ color: $gl-gray;
font-size: 13px;
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 10fce5b3daa..f0fb68d3422 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -136,7 +136,7 @@
}
.merge-request-info {
- color: #999;
+ color: $gl-gray;
font-size: 13px;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 29d3dbc25eb..361fd63bc79 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -16,6 +16,10 @@
.project-home-panel {
text-align: center;
+ background: #f7f8fa;
+ margin: -$gl-padding;
+ padding: $gl-padding;
+ padding-top: 40px;
.project-identicon-holder {
margin-bottom: 15px;
@@ -30,14 +34,20 @@
}
}
+ .project-home-dropdown {
+ margin: 11px 3px 0;
+ }
+
.project-home-desc {
h1 {
margin: 0;
margin-bottom: 10px;
- font-size: 26px;
+ font-size: 23px;
+ font-weight: normal;
}
p {
+ color: #7f8fa4;
display: inline;
}
}
@@ -45,6 +55,10 @@
.git-clone-holder {
max-width: 600px;
margin: 20px auto;
+
+ .form-control {
+ background: #FFF;
+ }
}
.visibility-level-label {
@@ -55,17 +69,18 @@
}
.project-repo-buttons {
- margin-top: 25px;
+ margin-top: $gl-padding;
margin-bottom: 25px;
.btn {
@extend .btn-info;
+ text-transform: uppercase;
+ font-size: 15px;
+ line-height: 20px;
+ padding: 8px 14px;
+ border-radius: 3px;
margin-left: 10px;
- font-weight: bold;
- font-size: 14px;
- line-height: 16px;
- padding: 8px 12px;
.count {
padding-left: 7px;
@@ -155,78 +170,6 @@ ul.nav.nav-projects-tabs {
margin: 0px;
}
-.my-projects,
-.public-projects {
- li {
- .project-info {
- margin-bottom: 10px;
- overflow: hidden;
- }
-
- .access-icon {
- color: #AAA;
- margin-left: 10px;
- i {
- color: #AAA;
- }
- }
- }
-}
-
-.public-clone {
- background: #EEE;
- color: #777;
- padding: 6px 10px;
- margin: 1px;
- font-weight: normal;
-}
-
-.public-projects .repo-info {
- color: #777;
-
- a {
- color: #777;
- }
-}
-
-.project-side {
- .project-fork-icon {
- float: left;
- font-size: 26px;
- margin-right: 10px;
- line-height: 1.5;
- }
-
- .panel {
- @include border-radius(3px);
-
- .panel-heading, .panel-footer {
- font-weight: normal;
- background-color: transparent;
- color: #666;
- border-color: #EEE;
- }
-
- .actions {
- margin-top: 10px;
- }
-
- .nav-pills a {
- padding: 10px;
- font-weight: bold;
- color: $gl-link-color;
- }
-
- .nav {
- margin-bottom: 15px;
- }
- }
-
- .ci-status-image {
- max-height: 22px;
- }
-}
-
.transfer-project .select2-container {
min-width: 200px;
}
@@ -249,10 +192,10 @@ ul.nav.nav-projects-tabs {
.breadcrumb.repo-breadcrumb {
padding: 0;
- line-height: 34px;
- background: white;
+ line-height: 42px;
+ background: transparent;
border: none;
- font-size: 16px;
+ margin: 0;
> li + li:before {
padding: 0 3px;
@@ -298,10 +241,23 @@ table.table.protected-branches-list tr.no-border {
.project-stats {
text-align: center;
+ margin-top: 0;
+ margin-bottom: 0;
+ padding-top: 5px;
+ padding-bottom: 0;
+
+ ul.nav-pills {
+ display:inline-block;
+ }
+
+ li {
+ display:inline;
+ }
- ul.nav-pills { display:inline-block; }
- li { display:inline; }
- a { float:left; }
+ a {
+ float:left;
+ font-size: 17px;
+ }
li.missing a {
color: #bbb;
@@ -316,3 +272,69 @@ table.table.protected-branches-list tr.no-border {
pre.light-well {
border-color: #f1f1f1;
}
+
+.projects-search-form {
+ margin: -$gl-padding;
+ background-color: #f8fafc;
+ padding: $gl-padding;
+ margin-bottom: 0px;
+ border-top: 1px solid #e7e9ed;
+ border-bottom: 1px solid #e7e9ed;
+}
+
+/*
+ * Projects list rendered on dashboard and user page
+ */
+.projects-list {
+ @include basic-list;
+
+ .project-row {
+ padding: $gl-padding;
+ border-color: #f1f2f4;
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+
+ &.no-description {
+ .project {
+ line-height: 44px;
+ }
+ }
+
+ .project-full-name {
+ @include str-truncated;
+ font-weight: 600;
+ color: #4c4e54;
+ }
+
+ .pull-right.light {
+ line-height: 45px;
+ color: #7f8fa4;
+ }
+
+ .project-description {
+ color: #7f8fa4;
+
+ p {
+ @include str-truncated;
+ margin-bottom: 0;
+ color: #7f8fa4;
+ }
+ }
+ }
+
+ .bottom {
+ padding-top: $gl-padding;
+ padding-bottom: 0;
+ }
+}
+
+.panel .projects-list li {
+ padding: 10px 15px;
+ margin: 0;
+}
+
+.project-show-activity {
+ .activity-filter-block {
+ margin-top: -1px;
+ }
+}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index bdaa17ac339..3aaa96da609 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -1,7 +1,19 @@
.search-results {
.search-result-row {
- border-bottom: 1px solid #EEE;
- padding-bottom: 10px;
- margin-bottom: 10px;
+ border-bottom: 1px solid #DDD;
+ padding-bottom: 15px;
+ margin-bottom: 15px;
}
}
+
+.search-holder {
+ max-width: 600px;
+ margin: 0 auto;
+ margin-bottom: 20px;
+
+ input {
+ border-color: #BBB;
+ font-weight: bold;
+ }
+}
+
diff --git a/app/assets/stylesheets/pages/snippets.scss b/app/assets/stylesheets/pages/snippets.scss
index d79591d9915..a3d7aba054d 100644
--- a/app/assets/stylesheets/pages/snippets.scss
+++ b/app/assets/stylesheets/pages/snippets.scss
@@ -6,3 +6,27 @@
.snippet-form-holder .file-holder .file-title {
padding: 2px;
}
+
+
+.snippet-row {
+ .snippet-title {
+ font-size: 15px;
+ font-weight: bold;
+ line-height: 20px;
+ margin-bottom: 2px;
+
+ .monospace {
+ font-weight: normal;
+ }
+ }
+
+ .snippet-info {
+ color: #888;
+ font-size: 13px;
+ line-height: 24px;
+
+ a {
+ color: #888;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index 5f1a3db4fb6..587d09a04a5 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -63,15 +63,15 @@
padding-right: 8px;
.commit-author-name {
- color: gray;
+ color: $gl-gray;
}
}
.tree_commit {
- color: gray;
+ color: $gl-gray;
.tree-commit-link {
- color: gray;
+ color: $gl-gray;
&:hover {
text-decoration: underline;
@@ -117,7 +117,6 @@
.readme-holder {
margin: 0 auto;
- max-width: $readable-width;
.readme-file-title {
font-size: 14px;
diff --git a/app/assets/stylesheets/themes/gitlab-theme.scss b/app/assets/stylesheets/themes/gitlab-theme.scss
index 3589cb88d03..8d9a0aae568 100644
--- a/app/assets/stylesheets/themes/gitlab-theme.scss
+++ b/app/assets/stylesheets/themes/gitlab-theme.scss
@@ -7,27 +7,27 @@
* $color-dark -
*/
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
- header {
- &.navbar-gitlab {
- .header-logo {
- background-color: $color-darker;
- border-color: $color-darker;
+ .page-with-sidebar {
+ .header-logo {
+ background-color: $color;
+ border-color: $color;
- a {
+ a {
+ color: $color-light;
+
+ h3 {
color: $color-light;
}
+ }
- &:hover {
- background-color: $color-dark;
- a {
- color: #FFF;
- }
+ &:hover {
+ background-color: $color-darker;
+ a {
+ color: #FFF;
}
}
}
- }
- .page-with-sidebar {
.collapse-nav a {
color: #FFF;
background: $color;
@@ -87,7 +87,7 @@
}
$theme-blue: #2980B9;
-$theme-charcoal: #474D57;
+$theme-charcoal: #333c47;
$theme-graphite: #888888;
$theme-gray: #373737;
$theme-green: #019875;
@@ -99,7 +99,7 @@ body {
}
&.ui_charcoal {
- @include gitlab-theme(#979DA7, $theme-charcoal, #373D47, #24272D);
+ @include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272D);
}
&.ui_graphite {
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index 34f37bca4ad..38a5a9fca08 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -4,8 +4,13 @@ class Admin::AbuseReportsController < Admin::ApplicationController
end
def destroy
- AbuseReport.find(params[:id]).destroy
+ abuse_report = AbuseReport.find(params[:id])
- redirect_to admin_abuse_reports_path, notice: 'Report was removed'
+ if params[:remove_user]
+ abuse_report.user.destroy
+ end
+
+ abuse_report.destroy
+ render nothing: true
end
end
diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb
index 690096bdbcf..d670386f8c6 100644
--- a/app/controllers/admin/hooks_controller.rb
+++ b/app/controllers/admin/hooks_controller.rb
@@ -39,6 +39,6 @@ class Admin::HooksController < Admin::ApplicationController
end
def hook_params
- params.require(:hook).permit(:url)
+ params.require(:hook).permit(:url, :enable_ssl_verification)
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 12d439b0b31..cb1cf13d34d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -55,7 +55,9 @@ class ApplicationController < ActionController::Base
def authenticate_user!(*args)
# If user is not signed-in and tries to access root_path - redirect him to landing page
- if current_application_settings.home_page_url.present?
+ # Don't redirect to the default URL to prevent endless redirections
+ if current_application_settings.home_page_url.present? &&
+ current_application_settings.home_page_url.chomp('/') != Gitlab.config.gitlab['url'].chomp('/')
if current_user.nil? && root_path == request.path
redirect_to current_application_settings.home_page_url and return
end
@@ -190,11 +192,12 @@ class ApplicationController < ActionController::Base
end
def add_gon_variables
+ gon.api_version = API::API.version
+ gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s
gon.default_issues_tracker = Project.new.default_issue_tracker.to_param
- gon.api_version = API::API.version
- gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
- gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s
- gon.max_file_size = current_application_settings.max_attachment_size;
+ gon.max_file_size = current_application_settings.max_attachment_size
+ gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
+ gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
if current_user
gon.current_user_id = current_user.id
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index d2f0c43929f..2bc2e5e58f5 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -1,6 +1,6 @@
class DashboardController < Dashboard::ApplicationController
- before_action :load_projects
- before_action :event_filter, only: :show
+ before_action :load_projects, except: :activity
+ before_action :event_filter, only: :activity
respond_to :html
@@ -10,13 +10,8 @@ class DashboardController < Dashboard::ApplicationController
respond_to do |format|
format.html
-
- format.json do
- load_events
- pager_json("events/_events", @events.count)
- end
-
format.atom do
+ event_filter
load_events
render layout: false
end
@@ -40,6 +35,19 @@ class DashboardController < Dashboard::ApplicationController
end
end
+ def activity
+ @last_push = current_user.recent_push
+
+ respond_to do |format|
+ format.html
+
+ format.json do
+ load_events
+ pager_json("events/_events", @events.count)
+ end
+ end
+ end
+
protected
def load_projects
@@ -47,7 +55,14 @@ class DashboardController < Dashboard::ApplicationController
end
def load_events
- @events = Event.in_projects(current_user.authorized_projects.pluck(:id))
+ project_ids =
+ if params[:filter] == "starred"
+ current_user.starred_projects
+ else
+ current_user.authorized_projects
+ end.pluck(:id)
+
+ @events = Event.in_projects(project_ids)
@events = @event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0)
end
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 76062446c92..4e5b4125f5a 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -53,6 +53,7 @@ class Projects::HooksController < Projects::ApplicationController
end
def hook_params
- params.require(:hook).permit(:url, :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events)
+ params.require(:hook).permit(:url, :push_events, :issues_events,
+ :merge_requests_events, :tag_push_events, :note_events, :enable_ssl_verification)
end
end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 647c1454078..5f6fbce795e 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -17,8 +17,7 @@ class Projects::RawController < Projects::ApplicationController
send_data(
@blob.data,
type: type,
- disposition: 'inline',
- filename: @blob.name
+ disposition: 'inline'
)
else
not_found!
@@ -30,6 +29,8 @@ class Projects::RawController < Projects::ApplicationController
def get_blob_type
if @blob.text?
'text/plain; charset=utf-8'
+ elsif @blob.image?
+ @blob.content_type
else
'application/octet-stream'
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 01105532479..3a22ed832ac 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -2,13 +2,13 @@ class Projects::ServicesController < Projects::ApplicationController
ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_version, :subdomain,
:room, :recipients, :project_url, :webhook,
:user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
- :build_key, :server, :teamcity_url, :build_type,
+ :build_key, :server, :teamcity_url, :drone_url, :build_type,
:description, :issues_url, :new_issue_url, :restrict_to_branch, :channel,
:colorize_messages, :channels,
:push_events, :issues_events, :merge_requests_events, :tag_push_events,
:note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url,
:notify, :color,
- :server_host, :server_port, :default_irc_uri]
+ :server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
# Authorize
before_action :authorize_admin_project!
before_action :service, only: [:edit, :update, :test]
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 64306637423..b07a2a8db2f 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -30,9 +30,14 @@ class Projects::SnippetsController < Projects::ApplicationController
def create
@snippet = CreateSnippetService.new(@project, current_user,
snippet_params).execute
- respond_with(@snippet,
- location: namespace_project_snippet_path(@project.namespace,
- @project, @snippet))
+
+ if @snippet.valid?
+ respond_with(@snippet,
+ location: namespace_project_snippet_path(@project.namespace,
+ @project, @snippet))
+ else
+ render :new
+ end
end
def edit
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 50512cb6dc3..51c26a6a465 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -5,7 +5,6 @@ class Projects::WikisController < Projects::ApplicationController
before_action :authorize_create_wiki!, only: [:edit, :create, :history]
before_action :authorize_admin_wiki!, only: :destroy
before_action :load_project_wiki
- include WikiHelper
def pages
@wiki_pages = Kaminari.paginate_array(@project_wiki.pages).page(params[:page]).per(PER_PAGE)
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 8389f07a3bd..cfa565cd03e 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -8,6 +8,8 @@ class SessionsController < Devise::SessionsController
def new
if Gitlab.config.ldap.enabled
@ldap_servers = Gitlab::LDAP::Config.servers
+ else
+ @ldap_servers = []
end
super
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 2bb5c338cf6..1484356a7f4 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -51,10 +51,6 @@ class UsersController < ApplicationController
def set_user
@user = User.find_by_username!(params[:username])
-
- unless current_user || @user.public_profile?
- return authenticate_user!
- end
end
def authorized_projects_ids
diff --git a/app/finders/trending_projects_finder.rb b/app/finders/trending_projects_finder.rb
index a79bd47d986..f3f4d461efa 100644
--- a/app/finders/trending_projects_finder.rb
+++ b/app/finders/trending_projects_finder.rb
@@ -2,13 +2,21 @@ class TrendingProjectsFinder
def execute(current_user, start_date = nil)
start_date ||= Date.today - 1.month
- projects = projects_for(current_user)
-
# Determine trending projects based on comments count
# for period of time - ex. month
- projects.joins(:notes).where('notes.created_at > ?', start_date).
- select("projects.*, count(notes.id) as ncount").
- group("projects.id").reorder("ncount DESC")
+ trending_project_ids = Note.
+ select("notes.project_id, count(notes.project_id) as pcount").
+ where('notes.created_at > ?', start_date).
+ group("project_id").
+ reorder("pcount DESC").
+ map(&:project_id)
+
+ sql_order_ids = trending_project_ids.reverse.
+ map { |project_id| "id = #{project_id}" }.join(", ")
+
+ # Get list of projects that user allowed to see
+ projects = projects_for(current_user)
+ projects.where(id: trending_project_ids).reorder(sql_order_ids)
end
private
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index 0e7a37b4cc6..d9502181c4f 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -1,6 +1,6 @@
module AuthHelper
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
- FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos'].freeze
+ FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos', 'crowd'].freeze
def ldap_enabled?
Gitlab.config.ldap.enabled
@@ -26,6 +26,10 @@ module AuthHelper
auth_providers.select { |provider| form_based_provider?(provider) }
end
+ def crowd_enabled?
+ auth_providers.include? :crowd
+ end
+
def button_based_providers
auth_providers.reject { |provider| form_based_provider?(provider) }
end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 1bd3ec5e0e0..6ffa1a7121d 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -137,7 +137,7 @@ module DiffHelper
# Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format)
- link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] != 'parallel' ? 'btn btn-sm active' : 'btn btn-sm') do
+ link_to url_for(params_copy), id: "inline-diff-btn", class: (params[:view] != 'parallel' ? 'btn btn-sm active' : 'btn btn-sm') do
'Inline'
end
end
@@ -148,7 +148,7 @@ module DiffHelper
# Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format)
- link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] == 'parallel' ? 'btn active btn-sm' : 'btn btn-sm') do
+ link_to url_for(params_copy), id: "parallel-diff-btn", class: (params[:view] == 'parallel' ? 'btn active btn-sm' : 'btn btn-sm') do
'Side-by-side'
end
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 8428281f8f6..76602614bcd 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -27,16 +27,13 @@ module EventsHelper
key = key.to_s
active = 'active' if @event_filter.active?(key)
link_opts = {
- class: 'event_filter_link',
+ class: "event-filter-link btn btn-default #{active}",
id: "#{key}_event_filter",
title: "Filter by #{tooltip.downcase}",
- data: { toggle: 'tooltip', placement: 'top' }
}
- content_tag :li, class: "filter_icon #{active}" do
- link_to request.path, link_opts do
- icon(icon_for_event[key]) + content_tag(:span, ' ' + tooltip)
- end
+ link_to request.path, link_opts do
+ content_tag(:span, ' ' + tooltip)
end
end
@@ -66,7 +63,7 @@ module EventsHelper
end
words << "at"
elsif event.target
- words << "##{event.target_iid}:"
+ words << "##{event.target_iid}:"
words << event.target.title if event.target.respond_to?(:title)
words << "at"
end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index eb3f72a307d..1ebfd92f119 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -1,9 +1,6 @@
require 'nokogiri'
module GitlabMarkdownHelper
- include Gitlab::Markdown
- include PreferencesHelper
-
# Use this in places where you would normally use link_to(gfm(...), ...).
#
# It solves a problem occurring with nested links (i.e.
@@ -22,7 +19,7 @@ module GitlabMarkdownHelper
escape_once(body)
end
- gfm_body = gfm(escaped_body, {}, html_options)
+ gfm_body = Gitlab::Markdown.gfm(escaped_body, project: @project, current_user: current_user)
fragment = Nokogiri::XML::DocumentFragment.parse(gfm_body)
if fragment.children.size == 1 && fragment.children[0].name == 'a'
@@ -39,32 +36,38 @@ module GitlabMarkdownHelper
end
end
+ # Add any custom CSS classes to the GFM-generated reference links
+ if html_options[:class]
+ fragment.css('a.gfm').add_class(html_options[:class])
+ end
+
fragment.to_html.html_safe
end
- MARKDOWN_OPTIONS = {
- no_intra_emphasis: true,
- tables: true,
- fenced_code_blocks: true,
- strikethrough: true,
- lax_spacing: true,
- space_after_headers: true,
- superscript: true,
- footnotes: true
- }.freeze
-
- def markdown(text, options={})
- unless @markdown && options == @options
- @options = options
-
- # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch
- rend = Redcarpet::Render::GitlabHTML.new(self, user_color_scheme_class, options)
-
- # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
- @markdown = Redcarpet::Markdown.new(rend, MARKDOWN_OPTIONS)
- end
+ def markdown(text, context = {})
+ context.merge!(
+ current_user: current_user,
+ path: @path,
+ project: @project,
+ project_wiki: @project_wiki,
+ ref: @ref
+ )
+
+ Gitlab::Markdown.render(text, context)
+ end
+
+ # TODO (rspeicher): Remove all usages of this helper and just call `markdown`
+ # with a custom pipeline depending on the content being rendered
+ def gfm(text, options = {})
+ options.merge!(
+ current_user: current_user,
+ path: @path,
+ project: @project,
+ project_wiki: @project_wiki,
+ ref: @ref
+ )
- @markdown.render(text).html_safe
+ Gitlab::Markdown.gfm(text, options)
end
def asciidoc(text)
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index b067cb54a43..82eebf4245b 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -30,4 +30,13 @@ module GroupsHelper
image_path('no_group_avatar.png')
end
end
+
+ def group_title(group, name, url)
+ content_tag :span do
+ link_to(
+ simple_sanitize(group.name), group_path(group)
+ ) + ' &middot; '.html_safe +
+ link_to(simple_sanitize(name), url)
+ end
+ end
end
diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb
index 01b6a63552c..8473d6d75d0 100644
--- a/app/helpers/page_layout_helper.rb
+++ b/app/helpers/page_layout_helper.rb
@@ -23,4 +23,12 @@ module PageLayoutHelper
@sidebar
end
end
+
+ def fluid_layout(enabled = false)
+ if @fluid_layout.nil?
+ @fluid_layout = enabled
+ else
+ @fluid_layout
+ end
+ end
end
diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb
index ea774e28ecf..7f1b6a69926 100644
--- a/app/helpers/preferences_helper.rb
+++ b/app/helpers/preferences_helper.rb
@@ -1,25 +1,5 @@
# Helper methods for per-User preferences
module PreferencesHelper
- COLOR_SCHEMES = {
- 1 => 'white',
- 2 => 'dark',
- 3 => 'solarized-light',
- 4 => 'solarized-dark',
- 5 => 'monokai',
- }
- COLOR_SCHEMES.default = 'white'
-
- # Helper method to access the COLOR_SCHEMES
- #
- # The keys are the `color_scheme_ids`
- # The values are the `name` of the scheme.
- #
- # The preview images are `name-scheme-preview.png`
- # The stylesheets should use the css class `.name`
- def color_schemes
- COLOR_SCHEMES.freeze
- end
-
# Maps `dashboard` values to more user-friendly option text
DASHBOARD_CHOICES = {
projects: 'Your Projects (default)',
@@ -50,12 +30,11 @@ module PreferencesHelper
end
def user_application_theme
- theme = Gitlab::Themes.by_id(current_user.try(:theme_id))
- theme.css_class
+ Gitlab::Themes.for_user(current_user).css_class
end
- def user_color_scheme_class
- COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user)
+ def user_color_scheme
+ Gitlab::ColorSchemes.for_user(current_user).css_class
end
def prefer_readme?
diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb
deleted file mode 100644
index f8a96516e61..00000000000
--- a/app/helpers/wiki_helper.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-module WikiHelper
- # Rails v4.1.9+ escapes all model IDs, converting slashes into %2F. The
- # only way around this is to implement our own path generators.
- def namespace_project_wiki_path(namespace, project, wiki_page, *args)
- slug =
- case wiki_page
- when Symbol
- wiki_page
- when String
- wiki_page
- else
- wiki_page.slug
- end
- namespace_project_path(namespace, project) + "/wikis/#{slug}"
- end
-
- def edit_namespace_project_wiki_path(namespace, project, wiki_page, *args)
- namespace_project_wiki_path(namespace, project, wiki_page) + '/edit'
- end
-
- def history_namespace_project_wiki_path(namespace, project, wiki_page, *args)
- namespace_project_wiki_path(namespace, project, wiki_page) + '/history'
- end
-end
diff --git a/app/mailers/email_rejection_mailer.rb b/app/mailers/email_rejection_mailer.rb
index 89aceda82d1..883f1c73ad4 100644
--- a/app/mailers/email_rejection_mailer.rb
+++ b/app/mailers/email_rejection_mailer.rb
@@ -3,6 +3,8 @@ class EmailRejectionMailer < BaseMailer
@reason = reason
@original_message = Mail::Message.new(original_raw)
+ return unless @original_message.from
+
headers = {
to: @original_message.from,
subject: "[Rejected] #{@original_message.subject}"
diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb
index c8c39db11bc..07c87a7fe87 100644
--- a/app/models/abuse_report.rb
+++ b/app/models/abuse_report.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: abuse_reports
+#
+# id :integer not null, primary key
+# reporter_id :integer
+# user_id :integer
+# message :text
+# created_at :datetime
+# updated_at :datetime
+#
+
class AbuseReport < ActiveRecord::Base
belongs_to :reporter, class_name: "User"
belongs_to :user
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 46fb85336e5..9a8251bdad5 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -25,6 +25,7 @@ class WebHook < ActiveRecord::Base
default_value_for :note_events, false
default_value_for :merge_requests_events, false
default_value_for :tag_push_events, false
+ default_value_for :enable_ssl_verification, false
# HTTParty timeout
default_timeout Gitlab.config.gitlab.webhook_timeout
@@ -41,7 +42,7 @@ class WebHook < ActiveRecord::Base
"Content-Type" => "application/json",
"X-Gitlab-Event" => hook_name.singularize.titleize
},
- verify: false)
+ verify: enable_ssl_verification)
else
post_url = url.gsub("#{parsed_url.userinfo}@", "")
auth = {
@@ -54,7 +55,7 @@ class WebHook < ActiveRecord::Base
"Content-Type" => "application/json",
"X-Gitlab-Event" => hook_name.singularize.titleize
},
- verify: false,
+ verify: enable_ssl_verification,
basic_auth: auth)
end
rescue SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 2456b7d0dc1..fc7e9abe29e 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -2,19 +2,20 @@
#
# Table name: issues
#
-# id :integer not null, primary key
-# title :string(255)
-# assignee_id :integer
-# author_id :integer
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# position :integer default(0)
-# branch_name :string(255)
-# description :text
-# milestone_id :integer
-# state :string(255)
-# iid :integer
+# id :integer not null, primary key
+# title :string(255)
+# assignee_id :integer
+# author_id :integer
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# position :integer default(0)
+# branch_name :string(255)
+# description :text
+# milestone_id :integer
+# state :string(255)
+# iid :integer
+# updated_by_id :integer
#
require 'carrierwave/orm/activerecord'
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 467b90861f9..93faa133875 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -19,6 +19,7 @@
# description :text
# position :integer default(0)
# locked_at :datetime
+# updated_by_id :integer
#
require Rails.root.join("app/models/commit")
diff --git a/app/models/note.rb b/app/models/note.rb
index 36cad8f583d..89d81ab1de2 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -15,6 +15,7 @@
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
+# updated_by_id :integer
#
require 'carrierwave/orm/activerecord'
diff --git a/app/models/project.rb b/app/models/project.rb
index 69f9af91c51..8e33a4b2f0f 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -73,6 +73,7 @@ class Project < ActiveRecord::Base
has_many :services
has_one :gitlab_ci_service, dependent: :destroy
has_one :campfire_service, dependent: :destroy
+ has_one :drone_ci_service, dependent: :destroy
has_one :emails_on_push_service, dependent: :destroy
has_one :irker_service, dependent: :destroy
has_one :pivotaltracker_service, dependent: :destroy
@@ -613,6 +614,7 @@ class Project < ActiveRecord::Base
name: name,
ssh_url: ssh_url_to_repo,
http_url: http_url_to_repo,
+ web_url: web_url,
namespace: namespace.name,
visibility_level: visibility_level
}
diff --git a/app/models/project_services/buildkite_service.rb b/app/models/project_services/buildkite_service.rb
index a714bc82246..9e5da6f45d2 100644
--- a/app/models/project_services/buildkite_service.rb
+++ b/app/models/project_services/buildkite_service.rb
@@ -23,7 +23,7 @@ require "addressable/uri"
class BuildkiteService < CiService
ENDPOINT = "https://buildkite.com"
- prop_accessor :project_url, :token
+ prop_accessor :project_url, :token, :enable_ssl_verification
validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
@@ -37,6 +37,7 @@ class BuildkiteService < CiService
def compose_service_hook
hook = service_hook || build_service_hook
hook.url = webhook_url
+ hook.enable_ssl_verification = enable_ssl_verification
hook.save
end
@@ -96,7 +97,11 @@ class BuildkiteService < CiService
{ type: 'text',
name: 'project_url',
- placeholder: "#{ENDPOINT}/example/project" }
+ placeholder: "#{ENDPOINT}/example/project" },
+
+ { type: 'checkbox',
+ name: 'enable_ssl_verification',
+ title: "Enable SSL verification" }
]
end
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index 803402c83ee..88186113c68 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -25,12 +25,24 @@ class CiService < Service
def category
:ci
end
-
+
+ def valid_token?(token)
+ self.respond_to?(:token) && self.token.present? && self.token == token
+ end
+
def supported_events
%w(push)
end
- # Return complete url to build page
+ def merge_request_page(iid, sha, ref)
+ commit_page(sha, ref)
+ end
+
+ def commit_page(sha, ref)
+ build_page(sha, ref)
+ end
+
+ # Return complete url to merge_request page
#
# Ex.
# http://jenkins.example.com:8888/job/test1/scm/bySHA1/12d65c
@@ -45,10 +57,27 @@ class CiService < Service
#
#
# Ex.
- # @service.commit_status('13be4ac')
+ # @service.merge_request_status(9, '13be4ac', 'dev')
+ # # => 'success'
+ #
+ # @service.merge_request_status(10, '2abe4ac', 'dev)
+ # # => 'running'
+ #
+ #
+ def merge_request_status(iid, sha, ref)
+ commit_status(sha, ref)
+ end
+
+ # Return string with build status or :error symbol
+ #
+ # Allowed states: 'success', 'failed', 'running', 'pending', 'skipped'
+ #
+ #
+ # Ex.
+ # @service.commit_status('13be4ac', 'master')
# # => 'success'
#
- # @service.commit_status('2abe4ac')
+ # @service.commit_status('2abe4ac', 'dev')
# # => 'running'
#
#
diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb
new file mode 100644
index 00000000000..3e2b7faecdb
--- /dev/null
+++ b/app/models/project_services/drone_ci_service.rb
@@ -0,0 +1,190 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
+#
+
+class DroneCiService < CiService
+
+ prop_accessor :drone_url, :token, :enable_ssl_verification
+ validates :drone_url,
+ presence: true,
+ format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }, if: :activated?
+ validates :token,
+ presence: true,
+ format: { with: /\A([A-Za-z0-9]+)\z/ }, if: :activated?
+
+ after_save :compose_service_hook, if: :activated?
+
+ def compose_service_hook
+ hook = service_hook || build_service_hook
+ hook.url = [drone_url, "/api/hook", "?owner=#{project.namespace.path}", "&name=#{project.path}", "&access_token=#{token}"].join
+ hook.enable_ssl_verification = enable_ssl_verification
+ hook.save
+ end
+
+ def execute(data)
+ case data[:object_kind]
+ when 'push'
+ service_hook.execute(data) if push_valid?(data)
+ when 'merge_request'
+ service_hook.execute(data) if merge_request_valid?(data)
+ when 'tag_push'
+ service_hook.execute(data) if tag_push_valid?(data)
+ end
+ end
+
+ def allow_target_ci?
+ true
+ end
+
+ def supported_events
+ %w(push merge_request tag_push)
+ end
+
+ def merge_request_status_path(iid, sha = nil, ref = nil)
+ url = [drone_url,
+ "gitlab/#{project.namespace.path}/#{project.path}/pulls/#{iid}",
+ "?access_token=#{token}"]
+
+ URI.join(*url).to_s
+ end
+
+ def commit_status_path(sha, ref)
+ url = [drone_url,
+ "gitlab/#{project.namespace.path}/#{project.path}/commits/#{sha}",
+ "?branch=#{URI::encode(ref.to_s)}&access_token=#{token}"]
+
+ URI.join(*url).to_s
+ end
+
+ def merge_request_status(iid, sha, ref)
+ response = HTTParty.get(merge_request_status_path(iid), verify: enable_ssl_verification)
+
+ if response.code == 200 and response['status']
+ case response['status']
+ when 'killed'
+ :canceled
+ when 'failure', 'error'
+ # Because drone return error if some test env failed
+ :failed
+ else
+ response["status"]
+ end
+ else
+ :error
+ end
+ rescue Errno::ECONNREFUSED
+ :error
+ end
+
+ def commit_status(sha, ref)
+ response = HTTParty.get(commit_status_path(sha, ref), verify: enable_ssl_verification)
+
+ if response.code == 200 and response['status']
+ case response['status']
+ when 'killed'
+ :canceled
+ when 'failure', 'error'
+ # Because drone return error if some test env failed
+ :failed
+ else
+ response["status"]
+ end
+ else
+ :error
+ end
+ rescue Errno::ECONNREFUSED
+ :error
+ end
+
+ def merge_request_page(iid, sha, ref)
+ url = [drone_url,
+ "gitlab/#{project.namespace.path}/#{project.path}/redirect/pulls/#{iid}"]
+
+ URI.join(*url).to_s
+ end
+
+ def commit_page(sha, ref)
+ url = [drone_url,
+ "gitlab/#{project.namespace.path}/#{project.path}/redirect/commits/#{sha}",
+ "?branch=#{URI::encode(ref.to_s)}"]
+
+ URI.join(*url).to_s
+ end
+
+ def commit_coverage(sha, ref)
+ nil
+ end
+
+ def build_page(sha, ref)
+ commit_page(sha, ref)
+ end
+
+ def builds_path
+ url = [drone_url, "#{project.namespace.path}/#{project.path}"]
+
+ URI.join(*url).to_s
+ end
+
+ def status_img_path
+ url = [drone_url,
+ "api/badges/#{project.namespace.path}/#{project.path}/status.svg",
+ "?branch=#{URI::encode(project.default_branch)}"]
+
+ URI.join(*url).to_s
+ end
+
+ def title
+ 'Drone CI'
+ end
+
+ def description
+ 'Drone is a Continuous Integration platform built on Docker, written in Go'
+ end
+
+ def to_param
+ 'drone_ci'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'token', placeholder: 'Drone CI project specific token' },
+ { type: 'text', name: 'drone_url', placeholder: 'http://drone.example.com' },
+ { type: 'checkbox', name: 'enable_ssl_verification', title: "Enable SSL verification" }
+ ]
+ end
+
+ private
+
+ def tag_push_valid?(data)
+ data[:total_commits_count] > 0 && !Gitlab::Git.blank_ref?(data[:after])
+ end
+
+ def push_valid?(data)
+ opened_merge_requests = project.merge_requests.opened.where(source_project_id: project.id,
+ source_branch: Gitlab::Git.ref_name(data[:ref]))
+
+ opened_merge_requests.empty? && data[:total_commits_count] > 0 &&
+ !Gitlab::Git.blank_ref?(data[:after])
+ end
+
+ def merge_request_valid?(data)
+ ['opened', 'reopened'].include?(data[:object_attributes][:state]) &&
+ data[:object_attributes][:merge_status] == 'unchecked'
+ end
+end
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index ecdcd48ae60..acbbc9935b6 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -21,7 +21,7 @@
class GitlabCiService < CiService
API_PREFIX = "api/v1"
- prop_accessor :project_url, :token
+ prop_accessor :project_url, :token, :enable_ssl_verification
validates :project_url,
presence: true,
format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }, if: :activated?
@@ -34,6 +34,7 @@ class GitlabCiService < CiService
def compose_service_hook
hook = service_hook || build_service_hook
hook.url = [project_url, "/build", "?token=#{token}"].join("")
+ hook.enable_ssl_verification = enable_ssl_verification
hook.save
end
@@ -136,7 +137,8 @@ class GitlabCiService < CiService
def fields
[
{ type: 'text', name: 'token', placeholder: 'GitLab CI project specific token' },
- { type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3' }
+ { type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3' },
+ { type: 'checkbox', name: 'enable_ssl_verification', title: "Enable SSL verification" }
]
end
diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb
index 460ca40be3f..33b113a2a27 100644
--- a/app/models/sent_notification.rb
+++ b/app/models/sent_notification.rb
@@ -1,3 +1,16 @@
+# == Schema Information
+#
+# Table name: sent_notifications
+#
+# id :integer not null, primary key
+# project_id :integer
+# noteable_id :integer
+# noteable_type :string(255)
+# recipient_id :integer
+# commit_id :string(255)
+# reply_key :string(255) not null
+#
+
class SentNotification < ActiveRecord::Base
belongs_to :project
belongs_to :noteable, polymorphic: true
diff --git a/app/models/service.rb b/app/models/service.rb
index dcef2866c3b..60fcc9d2857 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -135,6 +135,7 @@ class Service < ActiveRecord::Base
buildkite
campfire
custom_issue_tracker
+ drone_ci
emails_on_push
external_wiki
flowdock
diff --git a/app/models/user.rb b/app/models/user.rb
index f70761074c5..bff8eeed96d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -2,62 +2,58 @@
#
# 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)
-# 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)
-# created_at :datetime
-# updated_at :datetime
-# name :string(255)
-# 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)
-# theme_id :integer default(1), not null
-# bio :string(255)
-# failed_attempts :integer default(0)
-# locked_at :datetime
-# username :string(255)
-# can_create_group :boolean default(TRUE), not null
-# can_create_team :boolean default(TRUE), not null
-# state :string(255)
-# 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)
-# confirmed_at :datetime
-# confirmation_sent_at :datetime
-# unconfirmed_email :string(255)
-# hide_no_ssh_key :boolean default(FALSE)
-# website_url :string(255) default(""), not null
-# github_access_token :string(255)
-# gitlab_access_token :string(255)
-# notification_email :string(255)
-# hide_no_password :boolean default(FALSE)
-# password_automatically_set :boolean default(FALSE)
-# bitbucket_access_token :string(255)
-# bitbucket_access_token_secret :string(255)
-# location :string(255)
-# encrypted_otp_secret :string(255)
-# encrypted_otp_secret_iv :string(255)
-# encrypted_otp_secret_salt :string(255)
-# otp_required_for_login :boolean default(FALSE), not null
-# otp_backup_codes :text
-# public_email :string(255) default(""), not null
-# dashboard :integer default(0)
-# project_view :integer default(0)
+# id :integer not null, primary key
+# email :string(255) default(""), not null
+# encrypted_password :string(255) default(""), not null
+# reset_password_token :string(255)
+# 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)
+# created_at :datetime
+# updated_at :datetime
+# name :string(255)
+# 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)
+# theme_id :integer default(1), not null
+# bio :string(255)
+# failed_attempts :integer default(0)
+# locked_at :datetime
+# username :string(255)
+# can_create_group :boolean default(TRUE), not null
+# can_create_team :boolean default(TRUE), not null
+# state :string(255)
+# 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)
+# confirmed_at :datetime
+# confirmation_sent_at :datetime
+# unconfirmed_email :string(255)
+# hide_no_ssh_key :boolean default(FALSE)
+# website_url :string(255) default(""), not null
+# notification_email :string(255)
+# 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)
+# otp_required_for_login :boolean default(FALSE), not null
+# otp_backup_codes :text
+# public_email :string(255) default(""), not null
+# dashboard :integer default(0)
+# project_view :integer default(0)
#
require 'carrierwave/orm/activerecord'
@@ -104,7 +100,7 @@ class User < ActiveRecord::Base
# Profile
has_many :keys, dependent: :destroy
has_many :emails, dependent: :destroy
- has_many :identities, dependent: :destroy
+ has_many :identities, dependent: :destroy, autosave: true
# Groups
has_many :members, dependent: :destroy
@@ -637,10 +633,6 @@ class User < ActiveRecord::Base
email.start_with?('temp-email-for-oauth')
end
- def public_profile?
- authorized_projects.public_only.any?
- end
-
def avatar_url(size = nil)
if avatar.present?
[gitlab_config.url, avatar.url].join
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 3735a136365..e294b23bc23 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -107,12 +107,17 @@ class NotificationService
recipients = []
+ mentioned_users = note.mentioned_users
+ mentioned_users.select! do |user|
+ user.can?(:read_project, note.project)
+ end
+
# Add all users participating in the thread (author, assignee, comment authors)
participants =
if target.respond_to?(:participants)
target.participants(note.author)
else
- note.mentioned_users
+ mentioned_users
end
recipients = recipients.concat(participants)
@@ -120,8 +125,8 @@ class NotificationService
recipients = add_project_watchers(recipients, note.project)
# Reject users with Mention notification level, except those mentioned in _this_ note.
- recipients = reject_mention_users(recipients - note.mentioned_users, note.project)
- recipients = recipients + note.mentioned_users
+ recipients = reject_mention_users(recipients - mentioned_users, note.project)
+ recipients = recipients + mentioned_users
recipients = reject_muted_users(recipients, note.project)
diff --git a/app/views/admin/abuse_reports/_abuse_report.html.haml b/app/views/admin/abuse_reports/_abuse_report.html.haml
index 4449721ae38..d3afc658cd6 100644
--- a/app/views/admin/abuse_reports/_abuse_report.html.haml
+++ b/app/views/admin/abuse_reports/_abuse_report.html.haml
@@ -3,7 +3,7 @@
%tr
%td
- if reporter
- = link_to reporter.name, [:admin, reporter]
+ = link_to reporter.name, reporter
- else
(removed)
%td
@@ -12,12 +12,15 @@
= abuse_report.message
%td
- if user
- = link_to user.name, [:admin, user]
+ = link_to user.name, user
- else
(removed)
%td
- if user
- = link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs btn-warning"
- = link_to 'Remove user', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-xs btn-remove"
+ = link_to 'Remove user & report', admin_abuse_report_path(abuse_report, remove_user: true),
+ data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, remote: true, method: :delete, class: "btn btn-xs btn-remove js-remove-tr"
+
%td
- = link_to 'Remove report', [:admin, abuse_report], method: :delete, class: "btn btn-xs btn-close"
+ - if user
+ = link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs"
+ = link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr"
diff --git a/app/views/admin/abuse_reports/index.html.haml b/app/views/admin/abuse_reports/index.html.haml
index 4a25848f156..2e8746146d1 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -9,7 +9,7 @@
%th Reported at
%th Message
%th User
- %th
+ %th Primary action
%th
= render @abuse_reports
= paginate @abuse_reports
diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index e74e1e85f41..b120f4dea67 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -18,6 +18,13 @@
= f.label :url, "URL:", class: 'control-label'
.col-sm-10
= f.text_field :url, class: "form-control"
+ .form-group
+ = f.label :enable_ssl_verification, "SSL verification", class: 'control-label checkbox'
+ .col-sm-10
+ .checkbox
+ = f.label :enable_ssl_verification do
+ = f.check_box :enable_ssl_verification
+ %strong Enable SSL verification
.form-actions
= f.submit "Add System Hook", class: "btn btn-create"
%hr
@@ -32,6 +39,7 @@
.list-item-name
= link_to admin_hook_path(hook) do
%strong= hook.url
+ %p SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"}
.pull-right
= link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-sm"
diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml
index 213b5d65b3c..1db56542afd 100644
--- a/app/views/dashboard/_activities.html.haml
+++ b/app/views/dashboard/_activities.html.haml
@@ -1,13 +1,13 @@
.hidden-xs
= render "events/event_last_push", event: @last_push
+.gray-content-block
- if current_user
%ul.nav.nav-pills.event_filter.pull-right
%li.pull-right
= link_to dashboard_path(:atom, { private_token: current_user.private_token }), class: 'rss-btn' do
%i.fa.fa-rss
-
= render 'shared/event_filter'
- %hr
+
.content_list
= spinner
diff --git a/app/views/dashboard/_activity_head.html.haml b/app/views/dashboard/_activity_head.html.haml
new file mode 100644
index 00000000000..9f4be025bf2
--- /dev/null
+++ b/app/views/dashboard/_activity_head.html.haml
@@ -0,0 +1,7 @@
+%ul.center-top-menu
+ %li{ class: ("active" unless params[:filter]) }
+ = link_to activity_dashboard_path, class: 'shortcuts-activity', data: {placement: 'right'} do
+ Your Projects
+ %li{ class: ("active" if params[:filter] == 'starred') }
+ = link_to activity_dashboard_path(filter: 'starred'), data: {placement: 'right'} do
+ Starred Projects
diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml
index 8a397a84e0e..dcd6c97d44d 100644
--- a/app/views/dashboard/_groups_head.html.haml
+++ b/app/views/dashboard/_groups_head.html.haml
@@ -3,5 +3,5 @@
= link_to dashboard_groups_path, title: 'Your groups', data: {placement: 'right'} do
Your Groups
= nav_link(page: [explore_groups_path]) do
- = link_to explore_groups_path, title: 'Explore groups', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = link_to explore_groups_path, title: 'Explore groups', data: {placement: 'bottom'} do
Explore Groups
diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml
index d676576067c..ef9b9ce756a 100644
--- a/app/views/dashboard/_projects.html.haml
+++ b/app/views/dashboard/_projects.html.haml
@@ -1,5 +1,5 @@
-.panel.panel-default
- .panel-heading.clearfix
+.projects-list-holder
+ .projects-search-form
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
- if current_user.can_create_project?
@@ -7,4 +7,4 @@
= link_to new_project_path, class: 'btn btn-success' do
New project
- = render 'shared/projects_list', projects: @projects, projects_limit: 20
+ = render 'shared/projects/list', projects: @projects
diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml
index f7be194c696..13a5eae3cdc 100644
--- a/app/views/dashboard/_projects_head.html.haml
+++ b/app/views/dashboard/_projects_head.html.haml
@@ -5,6 +5,6 @@
= nav_link(page: starred_dashboard_projects_path) do
= link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
Starred Projects
- = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path]) do
- = link_to explore_root_path, title: 'Explore', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path], html_options: { class: 'hidden-xs' }) do
+ = link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
Explore Projects
diff --git a/app/views/dashboard/activity.html.haml b/app/views/dashboard/activity.html.haml
new file mode 100644
index 00000000000..3e24338af64
--- /dev/null
+++ b/app/views/dashboard/activity.html.haml
@@ -0,0 +1,9 @@
+= content_for :meta_tags do
+ - if current_user
+ = auto_discovery_link_tag(:atom, dashboard_url(format: :atom, private_token: current_user.private_token), title: "All activity")
+
+- header_title "Activity", activity_dashboard_path
+= render 'dashboard/activity_head'
+
+%section.activities
+ = render 'activities'
diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml
index 0860fe3c761..c249f5cacec 100644
--- a/app/views/dashboard/groups/index.html.haml
+++ b/app/views/dashboard/groups/index.html.haml
@@ -1,39 +1,19 @@
- page_title "Groups"
+- header_title "Groups", dashboard_groups_path
= render 'dashboard/groups_head'
-.slead
- Group members have access to all group projects.
+.gray-content-block
- if current_user.can_create_group?
%span.pull-right.hidden-xs
- = link_to new_group_path, class: "btn btn-new btn-sm" do
+ = link_to new_group_path, class: "btn btn-new" do
%i.fa.fa-plus
New Group
-.panel.panel-default
- .panel-heading
- %strong Groups
- (#{@group_members.count})
- %ul.well-list
- - @group_members.each do |group_member|
- - group = group_member.group
- %li
- .pull-right.hidden-xs
- - if can?(current_user, :admin_group, group)
- = link_to edit_group_path(group), class: "btn-sm btn btn-grouped" do
- %i.fa.fa-cogs
- Settings
-
- = link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Leave this group' do
- %i.fa.fa-sign-out
- Leave
-
- = image_tag group_icon(group), class: "avatar s40 avatar-tile hidden-xs"
- = link_to group, class: 'group-name' do
- %strong= group.name
-
- as
- %strong #{group_member.human_access}
+ .title Welcome to the groups!
+ Group members have access to all group projects.
- %div.light
- #{pluralize(group.projects.count, "project")}, #{pluralize(group.users.count, "user")}
+%ul.content-list
+ - @group_members.each do |group_member|
+ - group = group_member.group
+ = render 'shared/groups/group', group: group, group_member: group_member
= paginate @group_members
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 94318d1bcf5..cd602e897b7 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -1,21 +1,17 @@
- page_title "Issues"
+- header_title "Issues", issues_dashboard_path(assignee_id: current_user.id)
= content_for :meta_tags do
- if current_user
= auto_discovery_link_tag(:atom, issues_dashboard_url(format: :atom, private_token: current_user.private_token), title: "#{current_user.name} issues")
-%h3.page-title
- Issues
-
-%p.light
- List all issues from all projects you have access to.
-%hr
.append-bottom-20
.pull-right
- if current_user
- .hidden-xs.pull-left
- = link_to issues_dashboard_url(format: :atom, private_token: current_user.private_token), class: 'btn' do
+ .hidden-xs.pull-left.prepend-top-20
+ = link_to issues_dashboard_url(format: :atom, private_token: current_user.private_token), class: '' do
%i.fa.fa-rss
= render 'shared/issuable/filter', type: :issues
+
= render 'shared/issues'
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index 90611d562b0..d1f332fa0d3 100644
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -1,11 +1,6 @@
- page_title "Merge Requests"
-%h3.page-title
- Merge Requests
+- header_title "Merge Requests", merge_requests_dashboard_path(assignee_id: current_user.id)
-
-%p.light
- List all merge requests from all projects you have access to.
-%hr
.append-bottom-20
= render 'shared/issuable/filter', type: :merge_requests
= render 'shared/merge_requests'
diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml
index 9a9a5e139a4..21b25c3986e 100644
--- a/app/views/dashboard/milestones/index.html.haml
+++ b/app/views/dashboard/milestones/index.html.haml
@@ -1,21 +1,19 @@
- page_title "Milestones"
-%h3.page-title
- Milestones
- %span.pull-right #{@dashboard_milestones.count} milestones
+- header_title "Milestones", dashboard_milestones_path
-%p.light
- List all milestones from all projects you have access to.
-
-%hr
= render 'shared/milestones_filter'
+
+.gray-content-block
+ .oneline
+ List all milestones from all projects you have access to.
+
.milestones
- .panel.panel-default
- %ul.well-list
- - if @dashboard_milestones.blank?
- %li
- .nothing-here-block No milestones to show
- - else
- - @dashboard_milestones.each do |milestone|
- = render 'milestone', milestone: milestone
+ %ul.content-list
+ - if @dashboard_milestones.blank?
+ %li
+ .nothing-here-block No milestones to show
+ - else
+ - @dashboard_milestones.each do |milestone|
+ = render 'milestone', milestone: milestone
= paginate @dashboard_milestones, theme: "gitlab"
diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml
index 98b8cde4766..2fd7a1cf16c 100644
--- a/app/views/dashboard/projects/starred.html.haml
+++ b/app/views/dashboard/projects/starred.html.haml
@@ -1,25 +1,9 @@
- page_title "Starred Projects"
+- header_title "Projects", (current_user ? root_path : explore_root_path)
= render 'dashboard/projects_head'
- if @projects.any?
- = render 'shared/show_aside'
-
- .dashboard.row
- %section.activities.col-md-8
- = render 'dashboard/activities'
- %aside.col-md-4
- .panel.panel-default
- .panel-heading.clearfix
- .input-group
- = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
- - if current_user.can_create_project?
- %span.input-group-btn
- = link_to new_project_path, class: 'btn btn-success' do
- New project
-
- = render 'shared/projects_list', projects: @projects,
- projects_limit: 20, stars: true, avatar: false
-
+ = render 'dashboard/projects'
- else
%h3 You don't have starred projects yet
%p.slead Visit project page and press on star icon and it will appear on this page.
diff --git a/app/views/dashboard/show.html.haml b/app/views/dashboard/show.html.haml
index a3a32b6932f..1d5324e0d72 100644
--- a/app/views/dashboard/show.html.haml
+++ b/app/views/dashboard/show.html.haml
@@ -2,16 +2,13 @@
- if current_user
= auto_discovery_link_tag(:atom, dashboard_url(format: :atom, private_token: current_user.private_token), title: "All activity")
+- header_title "Projects", (current_user ? root_path : explore_root_path)
= render 'dashboard/projects_head'
-- if @projects.any?
- = render 'shared/show_aside'
-
- .dashboard.row
- %section.activities.col-md-8
- = render 'activities'
- %aside.col-md-4
- = render 'sidebar'
+- if @last_push
+ = render "events/event_last_push", event: @last_push
+- if @projects.any?
+ = render 'projects'
- else
= render "zero_authorized_projects"
diff --git a/app/views/devise/sessions/_new_crowd.html.haml b/app/views/devise/sessions/_new_crowd.html.haml
new file mode 100644
index 00000000000..4974bb7f7fb
--- /dev/null
+++ b/app/views/devise/sessions/_new_crowd.html.haml
@@ -0,0 +1,9 @@
+= form_tag(user_omniauth_authorize_path("crowd"), id: 'new_crowd_user' ) do
+ = text_field_tag :username, nil, {class: "form-control top", placeholder: "Username", autofocus: "autofocus"}
+ = password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
+ - if devise_mapping.rememberable?
+ .remember-me.checkbox
+ %label{for: "remember_me"}
+ = check_box_tag :remember_me, '1', false, id: 'remember_me'
+ %span Remember me
+ = button_tag "Sign in", class: "btn-save btn" \ No newline at end of file
diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml
index bb5e479697d..41ad2c231d4 100644
--- a/app/views/devise/shared/_signin_box.html.haml
+++ b/app/views/devise/shared/_signin_box.html.haml
@@ -8,15 +8,21 @@
.login-body
- if form_based_providers.any?
%ul.nav.nav-tabs
+ - if crowd_enabled?
+ %li.active
+ = link_to "Crowd", "#tab-crowd", 'data-toggle' => 'tab'
- @ldap_servers.each_with_index do |server, i|
- %li{class: (:active if i.zero?)}
+ %li{class: (:active if i.zero? && !crowd_enabled?)}
= link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab'
- if signin_enabled?
%li
= link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
.tab-content
+ - if crowd_enabled?
+ %div.tab-pane.active{id: "tab-crowd"}
+ = render 'devise/sessions/new_crowd'
- @ldap_servers.each_with_index do |server, i|
- %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero?)}
+ %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero? && !crowd_enabled?)}
= render 'devise/sessions/new_ldap', server: server
- if signin_enabled?
%div#tab-signin.tab-pane
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index 742b74a67c7..ad63841ccf3 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -1,5 +1,5 @@
%li.commit
.commit-row-title
= link_to truncate_sha(commit[:id]), namespace_project_commit_path(project.namespace, project, commit[:id]), class: "commit_short_id", alt: ''
- &nbsp;
+ &middot;
= gfm event_commit_title(commit[:message]), project: project
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 0faab4458e9..9aacc79d686 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -3,8 +3,8 @@
.event-item-timestamp
#{time_ago_with_tooltip(event.created_at)}
- = cache [event, "v1"] do
- = image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
+ = cache [event, "v2.1"] do
+ = image_tag avatar_icon(event.author_email, 46), class: "avatar s46", alt:''
- if event.created_project?
= render "events/event/created_project", event: event
- elsif event.push?
diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml
index 501412642db..6a0c6cba41b 100644
--- a/app/views/events/_event_last_push.html.haml
+++ b/app/views/events/_event_last_push.html.haml
@@ -9,6 +9,6 @@
#{time_ago_with_tooltip(event.created_at)}
.pull-right
- = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-create btn-sm" do
+ = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-info btn-sm" do
Create Merge Request
%hr
diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml
index 07bec1697f5..830fec0b4ab 100644
--- a/app/views/events/event/_note.html.haml
+++ b/app/views/events/event/_note.html.haml
@@ -4,7 +4,7 @@
= event.action_name
= event_note_title_html(event)
at
-
+
- if event.project
= link_to_project event.project
- else
@@ -13,7 +13,6 @@
.event-body
.event-note
.md
- %i.fa.fa-comment-o.event-note-icon
= event_note(event.target.note, project: event.project)
- note = event.target
- if note.attachment.url
diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml
index 7dcefd330a1..e8a6752de8c 100644
--- a/app/views/explore/groups/index.html.haml
+++ b/app/views/explore/groups/index.html.haml
@@ -1,14 +1,15 @@
- page_title "Groups"
+- header_title "Groups", (current_user ? dashboard_groups_path : explore_groups_path)
- if current_user
= render 'dashboard/groups_head'
-.clearfix.append-bottom-10
+.gray-content-block.clearfix
.pull-left
= form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f|
= hidden_field_tag :sort, @sort
.form-group
= search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "groups_search"
.form-group
- = button_tag 'Search', class: "btn btn-primary wide"
+ = button_tag 'Search', class: "btn btn-default"
.pull-right
.dropdown.inline
@@ -30,19 +31,9 @@
= link_to explore_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
-%ul.bordered-list
+%ul.content-list
- @groups.each do |group|
- %li
- .clearfix
- %h4
- = link_to group_path(id: group.path) do
- = group.name
- .clearfix
- %p
- = truncate group.description, length: 150
- .clearfix
- %p.light
- #{pluralize(group.members.size, 'member')}, #{pluralize(group.projects.count, 'project')}
+ = render 'shared/groups/group', group: group
- unless @groups.present?
.nothing-here-block No public groups
diff --git a/app/views/explore/projects/_filter.html.haml b/app/views/explore/projects/_filter.html.haml
index 4b91291caf4..5a3d689d1e5 100644
--- a/app/views/explore/projects/_filter.html.haml
+++ b/app/views/explore/projects/_filter.html.haml
@@ -3,7 +3,7 @@
.form-group
= search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "projects_search"
.form-group
- = button_tag 'Search', class: "btn btn-primary wide"
+ = button_tag 'Search', class: "btn btn-success"
.pull-right.hidden-sm.hidden-xs
- if current_user
diff --git a/app/views/explore/projects/_project.html.haml b/app/views/explore/projects/_project.html.haml
deleted file mode 100644
index 1e8a89e3661..00000000000
--- a/app/views/explore/projects/_project.html.haml
+++ /dev/null
@@ -1,24 +0,0 @@
-%li
- %h4.project-title
- .project-access-icon
- = visibility_level_icon(project.visibility_level)
- = link_to project.name_with_namespace, [project.namespace.becomes(Namespace), project]
- %span.pull-right
- %i.fa.fa-star
- = project.star_count
-
- .project-info
- - if project.description.present?
- .project-description.str-truncated
- = markdown(project.description, pipeline: :description)
-
- .repo-info
- - unless project.empty_repo?
- = link_to pluralize(round_commit_count(project), 'commit'), namespace_project_commits_path(project.namespace, project, project.default_branch)
- &middot;
- = link_to pluralize(project.repository.branch_names.count, 'branch'), namespace_project_branches_path(project.namespace, project)
- &middot;
- = link_to pluralize(project.repository.tag_names.count, 'tag'), namespace_project_tags_path(project.namespace, project)
- - else
- %i.fa.fa-exclamation-triangle
- Empty repository
diff --git a/app/views/explore/projects/_projects.html.haml b/app/views/explore/projects/_projects.html.haml
new file mode 100644
index 00000000000..669079e9521
--- /dev/null
+++ b/app/views/explore/projects/_projects.html.haml
@@ -0,0 +1,6 @@
+- if projects.any?
+ .public-projects
+ = render 'shared/projects/list', projects: projects
+- else
+ .nothing-here-block
+ No such projects
diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml
index 4956081e1ed..9df5b3830a8 100644
--- a/app/views/explore/projects/index.html.haml
+++ b/app/views/explore/projects/index.html.haml
@@ -1,13 +1,7 @@
- page_title "Projects"
- if current_user
= render 'dashboard/projects_head'
-.clearfix
+.gray-content-block.clearfix
= render 'filter'
-%br
-.public-projects
- %ul.bordered-list.top-list
- = render @projects
- - unless @projects.present?
- .nothing-here-block No public projects
-
- = paginate @projects, theme: "gitlab"
+= render 'projects', projects: @projects
+= paginate @projects, theme: "gitlab"
diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml
index fdccbe5692f..a9df32f3d7d 100644
--- a/app/views/explore/projects/starred.html.haml
+++ b/app/views/explore/projects/starred.html.haml
@@ -1,14 +1,13 @@
- page_title "Starred Projects"
- if current_user
= render 'dashboard/projects_head'
+
.explore-trending-block
- .lead
- %i.fa.fa-star
- See most starred projects
+ .gray-content-block
.pull-right
= render 'explore/projects/dropdown'
- .public-projects
- %ul.bordered-list
- = render @starred_projects
-
+ .oneline
+ %i.fa.fa-star
+ See most starred projects
+ = render 'projects', projects: @starred_projects
= paginate @starred_projects, theme: 'gitlab'
diff --git a/app/views/explore/projects/trending.html.haml b/app/views/explore/projects/trending.html.haml
index 98a4174b426..c1ef06f6cdb 100644
--- a/app/views/explore/projects/trending.html.haml
+++ b/app/views/explore/projects/trending.html.haml
@@ -1,18 +1,18 @@
- page_title "Trending Projects"
- if current_user
= render 'dashboard/projects_head'
-.explore-title
- %h3
- Explore GitLab
- %p.lead
- Discover projects and groups. Share your projects with others
-%hr
+- else
+ .explore-title
+ %h3
+ Explore GitLab
+ %p.lead
+ Discover projects and groups. Share your projects with others
+ %br
.explore-trending-block
- .lead
- %i.fa.fa-comments-o
- See most discussed projects for last month
+ .gray-content-block
.pull-right
= render 'explore/projects/dropdown'
- .public-projects
- %ul.bordered-list
- = render @trending_projects
+ .oneline
+ %i.fa.fa-comments-o
+ See most discussed projects for last month
+ = render 'projects', projects: @trending_projects
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index 4f8aec1c67e..9ac56b1e5fe 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -1,4 +1,4 @@
-.panel.panel-default
+.panel.panel-default.projects-list-holder
.panel-heading.clearfix
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
@@ -7,4 +7,4 @@
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-success' do
New project
- = render 'shared/projects_list', projects: @projects, projects_limit: 20
+ = render 'shared/projects/list', projects: @projects, projects_limit: 20, stars: false
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index f0d90782556..08d97e418a3 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -1,25 +1,24 @@
- 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")
-%h3.page-title
- Issues
-%p.light
- Only issues from
- %strong #{@group.name}
- group are listed here.
- - if current_user
- To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
-%hr
-.append-bottom-20
+= render 'shared/issuable/filter', type: :issues
+.gray-content-block.second-block
.pull-right
- if current_user
.hidden-xs.pull-left
- = link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token), class: 'btn' do
+ = link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token) do
%i.fa.fa-rss
+ %div
+ Only issues from
+ %strong #{@group.name}
+ group are listed here.
+ - if current_user
+ To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
- = render 'shared/issuable/filter', type: :issues
-= render 'shared/issues'
+.prepend-top-default
+ = render 'shared/issues'
diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml
index ca85a158707..425ad8331bf 100644
--- a/app/views/groups/merge_requests.html.haml
+++ b/app/views/groups/merge_requests.html.haml
@@ -1,14 +1,13 @@
- page_title "Merge Requests"
-%h3.page-title
- Merge Requests
+- header_title group_title(@group, "Merge Requests", merge_requests_group_path(@group))
-%p.light
- Only merge requests from
- %strong #{@group.name}
- group are listed here.
- - if current_user
- To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
-%hr
-.append-bottom-20
- = render 'shared/issuable/filter', type: :merge_requests
-= render 'shared/merge_requests'
+= render 'shared/issuable/filter', type: :merge_requests
+.gray-content-block.second-block
+ %div
+ Only merge requests from
+ %strong #{@group.name}
+ group are listed here.
+ - if current_user
+ To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
+.prepend-top-default
+ = render 'shared/merge_requests'
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index 385222fa5b7..2bbcad5fdfb 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -1,23 +1,17 @@
- page_title "Milestones"
-%h3.page-title
- Milestones
- %span.pull-right #{@group_milestones.count} milestones
+- header_title group_title(@group, "Milestones", group_milestones_path(@group))
-%p.light
+= render 'shared/milestones_filter'
+.gray-content-block
Only milestones from
%strong #{@group.name}
group are listed here.
-
-%hr
-
-= render 'shared/milestones_filter'
.milestones
- .panel.panel-default
- %ul.well-list
- - if @group_milestones.blank?
- %li
- .nothing-here-block No milestones to show
- - else
- - @group_milestones.each do |milestone|
- = render 'milestone', milestone: milestone
+ %ul.content-list
+ - if @group_milestones.blank?
+ %li
+ .nothing-here-block No milestones to show
+ - else
+ - @group_milestones.each do |milestone|
+ = render 'milestone', milestone: milestone
= paginate @group_milestones, theme: "gitlab"
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index d31dae7d648..0577f4ec142 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -17,7 +17,7 @@
= render 'shared/show_aside'
.row
- %section.activities.col-md-8
+ %section.activities.col-md-7
.hidden-xs
- if current_user
= render "events/event_last_push", event: @last_push
@@ -33,5 +33,5 @@
.content_list
= spinner
- %aside.side.col-md-4
+ %aside.side.col-md-5
= render "projects", projects: @projects
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 96e15783a36..c1746676ae2 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -1,6 +1,11 @@
.page-with-sidebar{ class: nav_sidebar_class }
= render "layouts/broadcast"
.sidebar-wrapper.nicescroll
+ .header-logo
+ = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = brand_header_logo
+ .gitlab-text-container
+ %h3 GitLab
- if defined?(sidebar) && sidebar
= render "layouts/nav/#{sidebar}"
- elsif current_user
@@ -9,12 +14,12 @@
= render partial: 'layouts/collapse_button'
- if current_user
= link_to current_user, class: 'sidebar-user' do
- = image_tag avatar_icon(current_user.email, 60), alt: 'User activity', class: 'avatar avatar s32'
+ = image_tag avatar_icon(current_user.email, 60), alt: 'User activity', class: 'avatar avatar s36'
.username
= current_user.username
.content-wrapper
- .container-fluid
+ = render "layouts/flash"
+ %div{ class: fluid_layout ? "container-fluid" : "container-fluid container-limited" }
.content
- = render "layouts/flash"
.clearfix
= yield
diff --git a/app/views/layouts/dashboard.html.haml b/app/views/layouts/dashboard.html.haml
index c72eca10bf4..fad7de69432 100644
--- a/app/views/layouts/dashboard.html.haml
+++ b/app/views/layouts/dashboard.html.haml
@@ -1,5 +1,6 @@
- page_title "Dashboard"
-- header_title "Dashboard", root_path
+- unless @header_title
+ - header_title "Dashboard", root_path
- sidebar "dashboard"
= render template: "layouts/application"
diff --git a/app/views/layouts/explore.html.haml b/app/views/layouts/explore.html.haml
index 17fee9c510d..9098554e6f0 100644
--- a/app/views/layouts/explore.html.haml
+++ b/app/views/layouts/explore.html.haml
@@ -1,6 +1,7 @@
- page_title "Explore"
- if current_user
- - header_title "Dashboard", root_path
+ - unless @header_title
+ - header_title "Projects", (current_user ? root_path : explore_root_path)
- else
- header_title "Explore GitLab", explore_root_path
- sidebar "dashboard"
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index db7dbf9bfe3..4f00d01d4cd 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,5 +1,6 @@
- page_title @group.name
-- header_title @group.name, group_path(@group)
+- unless @header_title
+ - header_title @group.name, group_path(@group)
- sidebar "group" unless sidebar
= render template: "layouts/application"
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 12ddbe6f1b7..3892f71c0e3 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -1,10 +1,5 @@
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class }
- .container
- .header-logo
- = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do
- = brand_header_logo
- .gitlab-text-container
- %h3 GitLab
+ %div{ class: fluid_layout ? "container-fluid" : "container-fluid" }
.header-content
%button.navbar-toggle{type: 'button'}
%span.sr-only Toggle navigation
@@ -17,26 +12,14 @@
%li.visible-sm.visible-xs
= link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('search')
- -#%li.hidden-xs
- = link_to help_path, title: 'Help', data: {toggle: 'tooltip', placement: 'bottom'} do
- = icon('question-circle fw')
- -#%li
- = link_to explore_root_path, title: 'Explore', data: {toggle: 'tooltip', placement: 'bottom'} do
- = icon('globe fw')
- -#%li
- = link_to user_snippets_path(current_user), title: 'Your snippets', data: {toggle: 'tooltip', placement: 'bottom'} do
- = icon('clipboard fw')
- if current_user.is_admin?
%li
= link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('wrench fw')
- if current_user.can_create_project?
- %li.hidden-xs
+ %li
= link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('plus fw')
- -#%li
- = link_to profile_path, title: 'Profile settings', data: {toggle: 'tooltip', placement: 'bottom'} do
- = icon('cog fw')
%li
= link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('sign-out')
diff --git a/app/views/layouts/header/_public.html.haml b/app/views/layouts/header/_public.html.haml
index 15c2e292be3..a6a26518a0e 100644
--- a/app/views/layouts/header/_public.html.haml
+++ b/app/views/layouts/header/_public.html.haml
@@ -1,14 +1,9 @@
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class }
- .container
- .header-logo
- = link_to explore_root_path, class: "home" do
- = brand_header_logo
- .gitlab-text-container
- %h3 GitLab
+ %div{ class: fluid_layout ? "container-fluid" : "container-fluid" }
.header-content
- unless current_controller?('sessions')
.pull-right
- = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success btn-sm'
+ = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success'
%h1.title= title
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 8f010196d1a..0cf1c3d5d27 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -1,9 +1,14 @@
%ul.nav.nav-sidebar
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to (current_user ? root_path : explore_root_path), title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
- = icon('dashboard fw')
+ = icon('home fw')
%span
Projects
+ = nav_link(path: 'dashboard#activity') do
+ = link_to activity_dashboard_path, title: 'Activity', data: {placement: 'right'} do
+ = icon('dashboard fw')
+ %span
+ Activity
= nav_link(controller: :groups) do
= link_to (current_user ? dashboard_groups_path : explore_groups_path), title: 'Groups', data: {placement: 'right'} do
= icon('group fw')
@@ -29,7 +34,7 @@
%span.count= current_user.assigned_merge_requests.opened.count
= nav_link(controller: :snippets) do
= link_to (current_user ? user_snippets_path(current_user) : snippets_path), title: 'Your snippets', data: {placement: 'right'} do
- = icon('dashboard fw')
+ = icon('clipboard fw')
%span
Snippets
- if current_user
@@ -37,7 +42,7 @@
= link_to profile_path, title: 'Profile settings', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('user fw')
%span
- Profile
+ Profile Settings
= nav_link(controller: :help) do
= link_to help_path, title: 'Help', data: {placement: 'right'} do
= icon('question-circle fw')
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index d17d1c5fbd4..5e7b902622b 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -100,7 +100,7 @@
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets', data: {placement: 'right'} do
- = icon('file-text-o fw')
+ = icon('clipboard fw')
%span
Snippets
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index 3193206fe12..77d2ccbf762 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -1,5 +1,5 @@
-- page_title "Settings"
-- header_title "Settings", profile_path
+- page_title "Profile Settings"
+- header_title "Profile Settings", profile_path
- sidebar "profile"
= render template: "layouts/application"
diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml
index b77fe09fc2a..d9c90d4fcef 100644
--- a/app/views/layouts/snippets.html.haml
+++ b/app/views/layouts/snippets.html.haml
@@ -1,6 +1,6 @@
- page_title 'Snippets'
- if current_user
- - header_title "Dashboard", root_path
+ - header_title "Snippets", user_snippets_path(current_user)
- else
- header_title 'Snippets', snippets_path
- sidebar "dashboard"
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 9480a19f5b2..db7fa2eabe3 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -48,7 +48,7 @@
= f.radio_button :notification_level, Notification::N_WATCH
.level-title
Watch
- %p You will receive all notifications from projects in which you participate
+ %p You will receive notifications for any activity
.form-actions
= f.submit 'Save changes', class: "btn btn-create"
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index 1134317ee06..aa0361a0a1b 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -22,11 +22,11 @@
.panel-heading
Syntax highlighting theme
.panel-body
- - color_schemes.each do |color_scheme_id, color_scheme|
+ - Gitlab::ColorSchemes.each do |scheme|
= label_tag do
- .preview= image_tag "#{color_scheme}-scheme-preview.png"
- = f.radio_button :color_scheme_id, color_scheme_id
- = color_scheme.tr('-_', ' ').titleize
+ .preview= image_tag "#{scheme.css_class}-scheme-preview.png"
+ = f.radio_button :color_scheme_id, scheme.id
+ = scheme.name
.panel.panel-default
.panel-heading
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 9fdeddfcc7a..c519e52e596 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -100,11 +100,6 @@
%hr
= link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
- - if @user.public_profile?
- .alert.alert-info
- %h4 Public profile
- %p Your profile is publicly visible because you joined public project(s)
-
.row
.col-md-7
diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml
index ee02b7f6a6c..1261f6254d7 100644
--- a/app/views/projects/_activity.html.haml
+++ b/app/views/projects/_activity.html.haml
@@ -1,5 +1,5 @@
= render 'projects/last_push'
-.hidden-xs
+.gray-content-block.activity-filter-block
- if current_user
%ul.nav.nav-pills.event_filter.pull-right
%li
@@ -7,7 +7,6 @@
%i.fa.fa-rss
= render 'shared/event_filter'
- %hr
.content_list{:"data-href" => activity_project_path(@project)}
= spinner
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index bec40ec27a5..b93036e78e6 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -2,7 +2,7 @@
.project-home-panel.clearfix{:class => ("empty-project" if empty_repo)}
.project-identicon-holder
= project_icon(@project, alt: '', class: 'project-avatar avatar s90')
- .project-home-desc.lead
+ .project-home-desc
%h1= @project.name
- if @project.description.present?
= markdown(@project.description, pipeline: :description)
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index a3ff7ce2f1f..c1ec42aefca 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -27,7 +27,7 @@
.light
= commit_author_link(commit, avatar: false)
authored
- #{time_ago_with_tooltip(commit.committed_date)}
+ #{time_ago_with_tooltip(commit.committed_date, skip_js: true)}
%td.lines.blame-numbers
%pre
- line_count = blame_group[:lines].count
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index a693c4b282f..cc0ec9483d2 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -1,20 +1,20 @@
- commit = @repository.commit(branch.target)
%li(class="js-branch-#{branch.name}")
- %h4
+ %div
= link_to namespace_project_tree_path(@project.namespace, @project, branch.name) do
%strong.str-truncated= branch.name
+ &nbsp;
- if branch.name == @repository.root_ref
- %span.label.label-info default
+ %span.label.label-primary default
- elsif @repository.merged_to_root_ref? branch.name
- %span.label.label-primary.has_tooltip(title="Merged into #{@repository.root_ref}")
- %i.fa.fa-check
+ %span.label.label-info.has_tooltip(title="Merged into #{@repository.root_ref}")
merged
- if @project.protected_branch? branch.name
%span.label.label-success
%i.fa.fa-lock
protected
- .pull-right
+ .controls.hidden-xs
- if create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-grouped btn-xs' do
= icon('plus')
@@ -30,8 +30,7 @@
= icon("trash-o")
- if commit
- %ul.list-unstyled
- = render 'projects/commits/inline_commit', commit: commit, project: @project
+ = render 'projects/branches/commit', commit: commit, project: @project
- else
%p
Cant find HEAD commit for this branch
diff --git a/app/views/projects/branches/_commit.html.haml b/app/views/projects/branches/_commit.html.haml
new file mode 100644
index 00000000000..68326e65d85
--- /dev/null
+++ b/app/views/projects/branches/_commit.html.haml
@@ -0,0 +1,7 @@
+.branch-commit.light
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
+ &middot;
+ %span.str-truncated
+ = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
+ &middot;
+ #{time_ago_with_tooltip(commit.committed_date)}
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 80acc937908..6e2dc2d2710 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -1,7 +1,6 @@
- page_title "Branches"
= render "projects/commits/head"
-%h3.page-title
- Branches
+.gray-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
@@ -24,9 +23,10 @@
= sort_title_recently_updated
= link_to namespace_project_branches_path(sort: 'last_updated') do
= sort_title_oldest_updated
-%hr
+ .oneline
+ Protected branches can be managed in project settings
- unless @branches.empty?
- %ul.bordered-list.top-list.all-branches
+ %ul.content-list.all-branches
- @branches.each do |branch|
= render "projects/branches/branch", branch: branch
= paginate @branches, theme: 'gitlab'
diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml
index cade930c8cc..bc7625e8989 100644
--- a/app/views/projects/buttons/_dropdown.html.haml
+++ b/app/views/projects/buttons/_dropdown.html.haml
@@ -2,7 +2,7 @@
%span.dropdown
%a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"}
= icon('plus')
- %ul.dropdown-menu
+ %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
- if can?(current_user, :create_issue, @project)
%li
= link_to url_for_new_issue do
diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml
index e3d8cd0fdd5..50c0fd6803d 100644
--- a/app/views/projects/commits/_head.html.haml
+++ b/app/views/projects/commits/_head.html.haml
@@ -1,22 +1,18 @@
-%ul.nav.nav-tabs
+%ul.center-top-menu
= nav_link(controller: [:commit, :commits]) do
= link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref) do
- = icon("history")
Commits
%span.badge= number_with_delimiter(@repository.commit_count)
= nav_link(controller: :compare) do
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: @ref || @repository.root_ref) do
- = icon("exchange")
Compare
= nav_link(html_options: {class: branches_tab_class}) do
= link_to namespace_project_branches_path(@project.namespace, @project) do
- = icon("code-fork")
Branches
%span.badge.js-totalbranch-count= @repository.branches.size
= nav_link(controller: :tags) do
= link_to namespace_project_tags_path(@project.namespace, @project) do
- = icon("tags")
Tags
%span.badge.js-totaltags-count= @repository.tags.length
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 55054a31977..a01a99458a0 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -5,22 +5,23 @@
= render "head"
-.tree-ref-holder
- = render 'shared/ref_switcher', destination: 'commits'
+.gray-content-block
+ .tree-ref-holder
+ = render 'shared/ref_switcher', destination: 'commits'
-.commits-feed-holder.hidden-xs.hidden-sm
- - if create_mr_button?(@repository.root_ref, @ref)
- = link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
- = icon('plus')
- Create Merge Request
+ .commits-feed-holder.hidden-xs.hidden-sm
+ - if create_mr_button?(@repository.root_ref, @ref)
+ = link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
+ = icon('plus')
+ Create Merge Request
- - if current_user && current_user.private_token
- = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'prepend-left-10 btn' do
- = icon("rss")
+ - if current_user && current_user.private_token
+ = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'prepend-left-10 btn' do
+ = icon("rss")
-%ul.breadcrumb.repo-breadcrumb
- = commits_breadcrumbs
+ %ul.breadcrumb.repo-breadcrumb
+ = commits_breadcrumbs
%div{id: dom_id(@project)}
#commits-list= render "commits", project: @project
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index 3019893d12c..efc25eda26b 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -1,5 +1,5 @@
= form_tag namespace_project_compare_index_path(@project.namespace, @project), method: :post, class: 'form-inline js-requires-input' do
- .clearfix.append-bottom-20
+ .clearfix
- if params[:to] && params[:from]
= link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has_tooltip', title: 'Switch base of comparison'}
.form-group
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index d1e579a2ede..43d00726c48 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,9 +1,7 @@
- page_title "Compare"
= render "projects/commits/head"
-%h3.page-title
- Compare View
-%p.slead
+.gray-content-block
Compare branches, tags or commit ranges.
%br
Fill input field with commit id like
@@ -14,4 +12,5 @@
%br
Changes are shown <b>from</b> the version in the first field <b>to</b> the version in the second field.
-= render "form"
+.prepend-top-20
+ = render "form"
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 3670dd5c13b..8800ffdf482 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -1,16 +1,16 @@
- page_title "#{params[:from]}...#{params[:to]}"
= render "projects/commits/head"
-%h3.page-title
- Compare View
-= render "form"
+.gray-content-block
+ = render "form"
- if @commits.present?
- = render "projects/commits/commit_list"
- = render "projects/diffs/diffs", diffs: @diffs, project: @project
+ .prepend-top-20
+ = render "projects/commits/commit_list"
+ = render "projects/diffs/diffs", diffs: @diffs, project: @project
- else
- .light-well
+ .light-well.prepend-top-20
.center
%h4
There isn't anything to compare.
diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml
index 2e9c5dc08c8..8e24c778b7c 100644
--- a/app/views/projects/deploy_keys/index.html.haml
+++ b/app/views/projects/deploy_keys/index.html.haml
@@ -1,4 +1,5 @@
- page_title "Deploy Keys"
+
%h3.page-title
Deploy keys allow read-only access to the repository
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 52c1e03040c..30943f49bba 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -1,3 +1,6 @@
+- if params[:view] == 'parallel'
+ - fluid_layout true
+
.prepend-top-20.append-bottom-20
.pull-right
.btn-group
diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml
index caed0e69dc8..f99bc9a85eb 100644
--- a/app/views/projects/diffs/_warning.html.haml
+++ b/app/views/projects/diffs/_warning.html.haml
@@ -3,7 +3,7 @@
Too many changes to show.
.pull-right
- unless diff_hard_limit_enabled?
- = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: :html)), class: "btn btn-sm btn-warning"
+ = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm btn-warning"
- if current_controller?(:commit) or current_controller?(:merge_requests)
- if current_controller?(:commit)
diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml
index 141acbdcf72..a357736bf52 100644
--- a/app/views/projects/graphs/commits.html.haml
+++ b/app/views/projects/graphs/commits.html.haml
@@ -50,39 +50,42 @@
datasets : [{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)",
- pointColor : "rgba(220,220,220,1)",
- pointStrokeColor : "#EEE",
+ barStrokeWidth: 1,
+ barValueSpacing: 1,
+ barDatasetSpacing: 1,
data : #{@commits_per_time.values.to_json}
}]
}
ctx = $("#hour-chart").get(0).getContext("2d");
- new Chart(ctx).Line(data,{"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
+ new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
data = {
labels : #{@commits_per_week_days.keys.to_json},
datasets : [{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)",
- pointColor : "rgba(220,220,220,1)",
- pointStrokeColor : "#EEE",
+ barStrokeWidth: 1,
+ barValueSpacing: 1,
+ barDatasetSpacing: 1,
data : #{@commits_per_week_days.values.to_json}
}]
}
ctx = $("#weekday-chart").get(0).getContext("2d");
- new Chart(ctx).Line(data,{"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
+ new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
data = {
labels : #{@commits_per_month.keys.to_json},
datasets : [{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)",
- pointColor : "rgba(220,220,220,1)",
- pointStrokeColor : "#EEE",
+ barStrokeWidth: 1,
+ barValueSpacing: 1,
+ barDatasetSpacing: 1,
data : #{@commits_per_month.values.to_json}
}]
}
ctx = $("#month-chart").get(0).getContext("2d");
- new Chart(ctx).Line(data, {"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
+ new Chart(ctx).Bar(data, {"scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2})
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index eadbf61fdd4..85dbfd67862 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -55,6 +55,13 @@
%strong Merge Request events
%p.light
This url will be triggered when a merge request is created
+ .form-group
+ = f.label :enable_ssl_verification, "SSL verification", class: 'control-label checkbox'
+ .col-sm-10
+ .checkbox
+ = f.label :enable_ssl_verification do
+ = f.check_box :enable_ssl_verification
+ %strong Enable SSL verification
.form-actions
= f.submit "Add Web Hook", class: "btn btn-create"
@@ -74,3 +81,4 @@
- %w(push_events tag_push_events issues_events note_events merge_requests_events).each do |trigger|
- if hook.send(trigger)
%span.label.label-gray= trigger.titleize
+ SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"}
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index 5d243adb5fe..a3399c57aa2 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -1,9 +1,8 @@
-.panel.panel-default
- %ul.well-list.issues-list
- = render @issues
- - if @issues.blank?
- %li
- .nothing-here-block No issues to show
+%ul.content-list.issues-list
+ = render @issues
+ - if @issues.blank?
+ %li
+ .nothing-here-block No issues to show
- if @issues.present?
.pull-right
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index d06225f5488..24314d11404 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -3,8 +3,8 @@
- if current_user
= auto_discovery_link_tag(:atom, namespace_project_issues_url(@project.namespace, @project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
-.append-bottom-10
- .pull-right
+.project-issuable-filter
+ .controls
.pull-left
- if current_user
.hidden-xs.pull-left
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 0bcd543fee7..4295c828dad 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -14,11 +14,6 @@
%span
%i.fa.fa-ban
CLOSED
- - else
- %span.hidden-xs.hidden-sm
- %span.label-branch<
- %i.fa.fa-code-fork
- %span= merge_request.target_branch
- note_count = merge_request.mr_and_commit_notes.user.count
- if merge_request.assignee
&nbsp;
diff --git a/app/views/projects/merge_requests/_merge_requests.html.haml b/app/views/projects/merge_requests/_merge_requests.html.haml
index b8a0ca9a42f..d86707b3d97 100644
--- a/app/views/projects/merge_requests/_merge_requests.html.haml
+++ b/app/views/projects/merge_requests/_merge_requests.html.haml
@@ -1,9 +1,8 @@
-.panel.panel-default
- %ul.well-list.mr-list
- = render @merge_requests
- - if @merge_requests.blank?
- %li
- .nothing-here-block No merge requests to show
+%ul.content-list.mr-list
+ = render @merge_requests
+ - if @merge_requests.blank?
+ %li
+ .nothing-here-block No merge requests to show
- if @merge_requests.present?
.pull-right
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 007f6c6a787..ec1838eb489 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -1,4 +1,7 @@
- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests"
+- if params[:view] == 'parallel'
+ - fluid_layout true
+
.merge-request{'data-url' => merge_request_path(@merge_request)}
.merge-request-details.issuable-details
= render "projects/merge_requests/show/mr_title"
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 72fbe2e27a7..d3a576977c2 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -1,7 +1,7 @@
- page_title "Merge Requests"
= render 'projects/last_push'
-.append-bottom-10
- .pull-right
+.project-issuable-filter
+ .controls
= render 'shared/issuable/search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
- if can? current_user, :create_merge_request, @project
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 995eecd7830..2b8fd671587 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -1,18 +1,21 @@
- page_title "Milestones"
-.pull-right
- - if can? current_user, :admin_milestone, @project
- = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do
- %i.fa.fa-plus
- New Milestone
= render 'shared/milestones_filter'
+.gray-content-block
+ .pull-right
+ - if can? current_user, :admin_milestone, @project
+ = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do
+ %i.fa.fa-plus
+ New Milestone
+ .oneline
+ Milestone allows you to group issues and set due date for it
+
.milestones
- .panel.panel-default
- %ul.well-list
- = render @milestones
+ %ul.content-list
+ = render @milestones
- - if @milestones.blank?
- %li
- .nothing-here-block No milestones to show
+ - if @milestones.blank?
+ %li
+ .nothing-here-block No milestones to show
= paginate @milestones, theme: "gitlab"
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 507f2c7beb0..d5c4ee71978 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -11,7 +11,7 @@
= render "home_panel"
-.project-stats
+.project-stats.gray-content-block
%ul.nav.nav-pills
%li
= link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref) do
@@ -63,21 +63,22 @@
= icon("exclamation-triangle fw")
Archived project! Repository is read-only
-%hr
%section
- if prefer_readme?
- = render 'projects/readme'
+ .project-show-readme
+ = render 'projects/readme'
- else
- = render 'projects/activity'
+ .project-show-activity
+ = render 'projects/activity'
- if current_user
- access = user_max_access_in_project(current_user, @project)
- if access
- %hr
- %p.light
- You have #{access} access to this project.
- - if @project.project_member_by_id(current_user)
- = link_to leave_namespace_project_project_members_path(@project.namespace, @project),
- data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project', class: 'cred' do
- Leave this project \ No newline at end of file
+ .prepend-top-20
+ .gray-content-block.footer-block.center
+ You have #{access} access to this project.
+ - if @project.project_member_by_id(current_user)
+ = link_to leave_namespace_project_project_members_path(@project.namespace, @project),
+ data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project', class: 'cred' do
+ Leave this project
diff --git a/app/views/projects/snippets/_snippet.html.haml b/app/views/projects/snippets/_snippet.html.haml
deleted file mode 100644
index b2c35edc44c..00000000000
--- a/app/views/projects/snippets/_snippet.html.haml
+++ /dev/null
@@ -1,15 +0,0 @@
-%li
- %h4.snippet-title
- = link_to reliable_snippet_path(snippet) do
- = truncate(snippet.title, length: 60)
- %span.cgray.monospace.tiny.pull-right
- = snippet.file_name
-
- .snippet-info
- = "##{snippet.id}"
- %span
- by
- = image_tag avatar_icon(snippet.author_email), class: "avatar avatar-inline s16"
- = snippet.author_name
- %span.light
- #{time_ago_with_tooltip(snippet.created_at)}
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index 30081673ffc..45d4de6a385 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -8,9 +8,8 @@
%p.light
Share code pastes with others out of git repository
-%hr
%ul.bordered-list
- = render partial: "projects/snippets/snippet", collection: @snippets
+ = render partial: "shared/snippets/snippet", collection: @snippets
- if @snippets.empty?
%li
.nothing-here-block Nothing here.
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index 28ad272322f..2ca295fc5f3 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -1,13 +1,14 @@
- commit = @repository.commit(tag.target)
%li
- %h4
+ %div
= link_to namespace_project_commits_path(@project.namespace, @project, tag.name), class: "" do
- %i.fa.fa-tag
- = tag.name
+ %strong
+ %i.fa.fa-tag
+ = tag.name
- if tag.message.present?
&nbsp;
= strip_gpg_signature(tag.message)
- .pull-right
+ .controls
- if can? current_user, :download_code, @project
= render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-xs'
- if can?(current_user, :admin_project, @project)
@@ -15,8 +16,7 @@
%i.fa.fa-trash-o
- if commit
- %ul.list-unstyled
- = render 'projects/commits/inline_commit', commit: commit, project: @project
+ = render 'projects/branches/commit', commit: commit, project: @project
- else
%p
Cant find HEAD commit for this tag
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index d4652a47cba..1503a4330f4 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -1,21 +1,18 @@
- page_title "Tags"
= render "projects/commits/head"
-%h3.page-title
- Git Tags
+.gray-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
%i.fa.fa-add-sign
New tag
-
-%p.light
- Tags give the ability to mark specific points in history as being important
-%hr
+ .oneline
+ Tags give the ability to mark specific points in history as being important
.tags
- unless @tags.empty?
- %ul.bordered-list
+ %ul.content-list
- @tags.each do |tag|
= render 'tag', tag: @repository.find_tag(tag)
diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree.html.haml
index 5048154cb2f..367a87927d7 100644
--- a/app/views/projects/tree/_tree.html.haml
+++ b/app/views/projects/tree/_tree.html.haml
@@ -14,7 +14,7 @@
%small
%i.fa.fa-plus
-%div#tree-content-holder.tree-content-holder
+%div#tree-content-holder.tree-content-holder.prepend-top-20
%table#tree-slider{class: "table_#{@hex_path} tree-table" }
%thead
%tr
diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 788bb8cf1e2..acc2c8b2f7f 100644
--- a/app/views/projects/wikis/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -1,8 +1,8 @@
%span.pull-right
- if (@page && @page.persisted?)
- = link_to history_namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
+ = link_to namespace_project_wiki_history_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
Page History
- if can?(current_user, :create_wiki, @project)
- = link_to edit_namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
+ = link_to namespace_project_wiki_edit_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml
index 804a1b52dbe..ec87c3c765a 100644
--- a/app/views/projects/wikis/_nav.html.haml
+++ b/app/views/projects/wikis/_nav.html.haml
@@ -3,10 +3,10 @@
= link_to 'Home', namespace_project_wiki_path(@project.namespace, @project, :home)
= nav_link(path: 'wikis#pages') do
- = link_to 'Pages', pages_namespace_project_wikis_path(@project.namespace, @project)
+ = link_to 'Pages', namespace_project_wiki_pages_path(@project.namespace, @project)
= nav_link(path: 'wikis#git_access') do
- = link_to git_access_namespace_project_wikis_path(@project.namespace, @project) do
+ = link_to namespace_project_wikis_git_access_path(@project.namespace, @project) do
%i.fa.fa-download
Git Access
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index 5c4dd7f91ae..90c4b83cf37 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -10,7 +10,7 @@
- if @page.historical?
.warning_message
This is an old version of this page.
- You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", history_namespace_project_wiki_path(@project.namespace, @project, @page)}.
+ You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", namespace_project_wiki_history_path(@project.namespace, @project, @page)}.
%hr
diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml
index a75cd7bd809..d637abfa76b 100644
--- a/app/views/search/_category.html.haml
+++ b/app/views/search/_category.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-pills.search-filter
+%ul.nav.nav-tabs.search-filter
- if @project
%li{class: ("active" if @scope == 'blobs')}
= link_to search_filter_path(scope: 'blobs') do
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index e2d0cab9e79..ec478a5963d 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -1,6 +1,5 @@
.dropdown.inline
- %button.dropdown-toggle.btn.btn{type: 'button', 'data-toggle' => 'dropdown'}
- %i.fa.fa-tags
+ %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
%span.light Group:
- if @group.present?
%strong= @group.name
@@ -17,8 +16,7 @@
= group.name
.dropdown.inline.prepend-left-10.project-filter
- %button.dropdown-toggle.btn.btn{type: 'button', 'data-toggle' => 'dropdown'}
- %i.fa.fa-tags
+ %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
%span.light Project:
- if @project.present?
%strong= @project.name_with_namespace
diff --git a/app/views/search/_form.html.haml b/app/views/search/_form.html.haml
index 5ee70be1ad6..3938c545cad 100644
--- a/app/views/search/_form.html.haml
+++ b/app/views/search/_form.html.haml
@@ -1,12 +1,14 @@
-= form_tag search_path, method: :get, class: 'form-inline' do |f|
+= form_tag search_path, method: :get do |f|
= hidden_field_tag :project_id, params[:project_id]
= hidden_field_tag :group_id, params[:group_id]
= hidden_field_tag :snippets, params[:snippets]
= hidden_field_tag :scope, params[:scope]
+
.search-holder.clearfix
- .form-group
+ .input-group
= search_field_tag :search, params[:search], placeholder: "Search for projects, issues etc", class: "form-control search-text-input", id: "dashboard_search", autofocus: true
- = button_tag 'Search', class: "btn btn-primary"
+ %span.input-group-btn
+ = button_tag 'Search', class: "btn btn-primary"
- unless params[:snippets].eql? 'true'
- .pull-right
- = render 'filter'
+ %br
+ = render 'filter'
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 741c780ad96..2a38c98dcfc 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,7 +1,7 @@
- if @search_results.empty?
= render partial: "search/results/empty"
- else
- .light
+ %p.light
Search results for
%code
= @search_term
@@ -11,10 +11,13 @@
- elsif @group
in group #{link_to @group.name, @group}
- %br
.results.prepend-top-10
.search-results
- = render partial: "search/results/#{@scope.singularize}", collection: @objects
+ - if @scope == 'projects'
+ .term
+ = render 'shared/projects/list', projects: @objects
+ - else
+ = render partial: "search/results/#{@scope.singularize}", collection: @objects
= paginate @objects, theme: 'gitlab'
:javascript
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index 58f58eff54d..0fe8a3b490a 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -7,4 +7,4 @@
%strong
= blob.filename
.file-content.code.term
- = render 'shared/file_highlight', blob: blob, first_line_number: blob.startline, user_color_scheme_class: 'white'
+ = render 'shared/file_highlight', blob: blob, first_line_number: blob.startline
diff --git a/app/views/search/results/_project.html.haml b/app/views/search/results/_project.html.haml
deleted file mode 100644
index 195cf06c8ea..00000000000
--- a/app/views/search/results/_project.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-.search-result-row
- %h4
- = link_to [project.namespace.becomes(Namespace), project] do
- %span.term= project.name_with_namespace
- - if project.description.present?
- %span.light.term= project.description
diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml
index 95099853918..9a4f9fb9485 100644
--- a/app/views/search/results/_snippet_blob.html.haml
+++ b/app/views/search/results/_snippet_blob.html.haml
@@ -23,7 +23,7 @@
.nothing-here-block Empty file
- else
.file-content.code
- %div.highlighted-data{class: user_color_scheme_class}
+ %div.highlighted-data{ class: user_color_scheme }
.line-numbers
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
diff --git a/app/views/search/results/_wiki_blob.html.haml b/app/views/search/results/_wiki_blob.html.haml
index c03438eb952..f5859481d46 100644
--- a/app/views/search/results/_wiki_blob.html.haml
+++ b/app/views/search/results/_wiki_blob.html.haml
@@ -7,4 +7,4 @@
%strong
= wiki_blob.filename
.file-content.code.term
- = render 'shared/file_highlight', blob: wiki_blob, first_line_number: wiki_blob.startline, user_color_scheme_class: 'white'
+ = render 'shared/file_highlight', blob: wiki_blob, first_line_number: wiki_blob.startline
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 60f9e9ac9de..f4f3dcfc29f 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -1,7 +1,5 @@
- page_title @search_term
= render 'search/form'
-%hr
- if @search_term
= render 'search/category'
- %hr
= render 'search/results'
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 07672359dba..2cd422e772a 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -4,7 +4,7 @@
.input-group-btn
%button{ |
type: 'button', |
- class: "btn btn-sm #{ 'active' if default_clone_protocol == 'ssh' }#{ ' has_tooltip' if current_user && current_user.require_ssh_key? }", |
+ class: "btn #{ 'active' if default_clone_protocol == 'ssh' }#{ ' has_tooltip' if current_user && current_user.require_ssh_key? }", |
:"data-clone" => project.ssh_url_to_repo, |
:"data-title" => "Add an SSH key to your profile<br> to pull or push via SSH",
:"data-html" => "true",
@@ -13,13 +13,13 @@
.input-group-btn
%button{ |
type: 'button', |
- class: "btn btn-sm #{ 'active' if default_clone_protocol == 'http' }#{ ' has_tooltip' if current_user && current_user.require_password? }", |
+ class: "btn #{ 'active' if default_clone_protocol == 'http' }#{ ' has_tooltip' if current_user && current_user.require_password? }", |
:"data-clone" => project.http_url_to_repo, |
:"data-title" => "Set a password on your account<br> to pull or push via #{gitlab_config.protocol.upcase}",
:"data-html" => "true",
:"data-container" => "body"}
= gitlab_config.protocol.upcase
- = text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control input-sm", readonly: true
+ = text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true
- if project.kind_of?(Project)
.input-group-addon
.visibility-level-label.has_tooltip{'data-title' => "#{visibility_level_label(project.visibility_level)} project" }
diff --git a/app/views/shared/_event_filter.html.haml b/app/views/shared/_event_filter.html.haml
index 334db60690d..8495774accc 100644
--- a/app/views/shared/_event_filter.html.haml
+++ b/app/views/shared/_event_filter.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-pills.event_filter
+.btn-group.btn-group-next.event-filter
= event_filter_link EventFilter.push, 'Push events'
= event_filter_link EventFilter.merged, 'Merge events'
= event_filter_link EventFilter.comments, 'Comments'
diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml
index d6a2e177da1..57c3aff3e18 100644
--- a/app/views/shared/_file_highlight.html.haml
+++ b/app/views/shared/_file_highlight.html.haml
@@ -1,4 +1,4 @@
-.file-content.code{class: user_color_scheme_class}
+.file-content.code.js-syntax-highlight{ class: user_color_scheme }
.line-numbers
- if blob.data.present?
- blob.data.lines.each_index do |index|
diff --git a/app/views/shared/_milestones_filter.html.haml b/app/views/shared/_milestones_filter.html.haml
index f685ae7726c..cbdecda4fff 100644
--- a/app/views/shared/_milestones_filter.html.haml
+++ b/app/views/shared/_milestones_filter.html.haml
@@ -1,14 +1,11 @@
-.milestones-filters.append-bottom-10
- %ul.nav.nav-tabs
+.milestones-filters
+ %ul.center-top-menu
%li{class: ("active" if params[:state].blank? || params[:state] == 'opened')}
= link_to milestones_filter_path(state: 'opened') do
- %i.fa.fa-exclamation-circle
Open
%li{class: ("active" if params[:state] == 'closed')}
= link_to milestones_filter_path(state: 'closed') do
- %i.fa.fa-check-circle
Closed
%li{class: ("active" if params[:state] == 'all')}
= link_to milestones_filter_path(state: 'all') do
- %i.fa.fa-compass
All
diff --git a/app/views/shared/_project.html.haml b/app/views/shared/_project.html.haml
deleted file mode 100644
index 6bd61455d21..00000000000
--- a/app/views/shared/_project.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-= cache [project.namespace, project, controller.controller_name, controller.action_name] do
- = link_to project_path(project), class: dom_class(project) do
- - if avatar
- .dash-project-avatar
- = project_icon(project, alt: '', class: 'avatar project-avatar s40')
- %span.str-truncated
- %span.namespace-name
- - if project.namespace
- = project.namespace.human_name
- \/
- %span.project-name.filter-title
- = project.name
- - if stars
- %span.pull-right.light
- %i.fa.fa-star
- = project.star_count
diff --git a/app/views/shared/_projects_list.html.haml b/app/views/shared/_projects_list.html.haml
deleted file mode 100644
index 4c58092af44..00000000000
--- a/app/views/shared/_projects_list.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- projects_limit = 20 unless local_assigns[:projects_limit]
-- avatar = true unless local_assigns[:avatar] == false
-- stars = false unless local_assigns[:stars] == true
-%ul.well-list.projects-list
- - projects.each_with_index do |project, i|
- %li{class: (i >= projects_limit) ? 'project-row hide' : 'project-row'}
- = render "shared/project", project: project, avatar: avatar, stars: stars
- - if projects.blank?
- %li
- .nothing-here-block There are no projects here.
- - if projects.count > projects_limit
- %li.bottom
- %span.light
- #{projects_limit} of #{pluralize(projects.count, 'project')} displayed.
- %span
- = link_to '#', class: 'js-expand' do
- Show all
diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml
new file mode 100644
index 00000000000..a54c5fa8c33
--- /dev/null
+++ b/app/views/shared/groups/_group.html.haml
@@ -0,0 +1,22 @@
+- group_member = local_assigns[:group_member]
+%li
+ - if group_member
+ .controls.hidden-xs
+ - if can?(current_user, :admin_group, group)
+ = link_to edit_group_path(group), class: "btn-sm btn btn-grouped" do
+ %i.fa.fa-cogs
+
+ = link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Leave this group' do
+ %i.fa.fa-sign-out
+
+ = image_tag group_icon(group), class: "avatar s46 hidden-xs"
+ = link_to group, class: 'group-name' do
+ %strong= group.name
+
+ - if group_member
+ as
+ %span #{group_member.human_access}
+
+ %div.light
+ #{pluralize(group.projects.count, "project")}, #{pluralize(group.users.count, "user")}
+
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index bcaa48c7a12..8f16773077e 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -1,33 +1,28 @@
.issues-filters
.issues-state-filters
- %ul.nav.nav-tabs
+ %ul.center-top-menu
%li{class: ("active" if params[:state] == 'opened')}
= link_to page_filter_path(state: 'opened') do
- = icon('exclamation-circle')
#{state_filters_text_for(:opened, @project)}
- if defined?(type) && type == :merge_requests
%li{class: ("active" if params[:state] == 'merged')}
= link_to page_filter_path(state: 'merged') do
- = icon('check-circle')
#{state_filters_text_for(:merged, @project)}
%li{class: ("active" if params[:state] == 'closed')}
= link_to page_filter_path(state: 'closed') do
- = icon('ban')
#{state_filters_text_for(:closed, @project)}
- else
%li{class: ("active" if params[:state] == 'closed')}
= link_to page_filter_path(state: 'closed') do
- = icon('check-circle')
#{state_filters_text_for(:closed, @project)}
%li{class: ("active" if params[:state] == 'all')}
= link_to page_filter_path(state: 'all') do
- = icon('compass')
#{state_filters_text_for(:all, @project)}
- .issues-details-filters
+ .issues-details-filters.gray-content-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
diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml
new file mode 100644
index 00000000000..021e3b689a1
--- /dev/null
+++ b/app/views/shared/projects/_list.html.haml
@@ -0,0 +1,19 @@
+- projects_limit = 20 unless local_assigns[:projects_limit]
+- avatar = true unless local_assigns[:avatar] == false
+- stars = true unless local_assigns[:stars] == false
+
+%ul.projects-list
+ - projects.each_with_index do |project, i|
+ - css_class = (i >= projects_limit) ? 'hide' : nil
+ = render "shared/projects/project", project: project,
+ avatar: avatar, stars: stars, css_class: css_class
+
+ - if projects.count > projects_limit
+ %li.bottom.center
+ .light
+ #{projects_limit} of #{pluralize(projects.count, 'project')} displayed.
+ = link_to '#', class: 'js-expand' do
+ Show all
+
+:coffeescript
+ new ProjectsList()
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
new file mode 100644
index 00000000000..5318c6011f4
--- /dev/null
+++ b/app/views/shared/projects/_project.html.haml
@@ -0,0 +1,24 @@
+- avatar = true unless local_assigns[:avatar] == false
+- stars = true unless local_assigns[:stars] == false
+- css_class = '' unless local_assigns[:css_class]
+- css_class += " no-description" unless project.description.present?
+%li.project-row{ class: css_class }
+ = cache [project.namespace, project, controller.controller_name, controller.action_name, 'v2.1'] do
+ = link_to project_path(project), class: dom_class(project) do
+ - if avatar
+ .dash-project-avatar
+ = project_icon(project, alt: '', class: 'avatar project-avatar s46')
+ %span.project-full-name
+ %span.namespace-name
+ - if project.namespace
+ = project.namespace.human_name
+ \/
+ %span.project-name.filter-title
+ = project.name
+ - if stars
+ %span.pull-right.light
+ %i.fa.fa-star
+ = project.star_count
+ - if project.description.present?
+ .project-description
+ = markdown(project.description, pipeline: :description)
diff --git a/app/views/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index 5bb28664349..69a713ad9aa 100644
--- a/app/views/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -1,12 +1,12 @@
-%li
- %h4.snippet-title
+%li.snippet-row
+ .snippet-title
= link_to reliable_snippet_path(snippet) do
= truncate(snippet.title, length: 60)
- if snippet.private?
%span.label.label-gray
%i.fa.fa-lock
private
- %span.cgray.monospace.tiny.pull-right
+ %span.monospace.pull-right
= snippet.file_name
%small.pull-right.cgray
@@ -14,10 +14,8 @@
= link_to snippet.project.name_with_namespace, namespace_project_path(snippet.project.namespace, snippet.project)
.snippet-info
- = "##{snippet.id}"
- %span
- by
- = link_to user_snippets_path(snippet.author) do
- = image_tag avatar_icon(snippet.author_email), class: "avatar avatar-inline s16", alt: ''
- = snippet.author_name
- %span.light #{time_ago_with_tooltip(snippet.created_at)}
+ = link_to user_snippets_path(snippet.author) do
+ = image_tag avatar_icon(snippet.author_email), class: "avatar s24", alt: ''
+ = snippet.author_name
+ authored #{time_ago_with_tooltip(snippet.created_at)}
+
diff --git a/app/views/snippets/_snippets.html.haml b/app/views/snippets/_snippets.html.haml
index 40df42b6cf5..d9aa4dd1d2e 100644
--- a/app/views/snippets/_snippets.html.haml
+++ b/app/views/snippets/_snippets.html.haml
@@ -1,5 +1,5 @@
%ul.bordered-list
- = render partial: 'snippet', collection: @snippets
+ = render partial: 'shared/snippets/snippet', collection: @snippets
- if @snippets.empty?
%li
.nothing-here-block Nothing here.
diff --git a/app/views/snippets/current_user_index.html.haml b/app/views/snippets/current_user_index.html.haml
index 62a967a2e06..d704407c4dd 100644
--- a/app/views/snippets/current_user_index.html.haml
+++ b/app/views/snippets/current_user_index.html.haml
@@ -1,14 +1,15 @@
- page_title "Your Snippets"
= render 'head'
-.slead
- Share code pastes with others out of git repository
-
+.gray-content-block
.pull-right
- = link_to new_snippet_path, class: "btn btn-new btn-sm", title: "New Snippet" do
+ = link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do
Add new snippet
-%ul.nav.nav-tabs
+ .oneline
+ Share code pastes with others out of git repository
+
+%ul.nav.nav-tabs.prepend-top-20
= nav_tab :scope, nil do
= link_to user_snippets_path(@user) do
All
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index 8608815e0a6..3b62dd2a6e1 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -2,8 +2,14 @@
- if current_user
= render 'head'
-.slead
- Public snippets created by you and other users are listed here
+.gray-content-block
+ - if current_user
+ .pull-right
+ = link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do
+ Add new snippet
+
+ .oneline
+ Public snippets created by you and other users are listed here
= render 'snippets'
diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml
index 297fa537394..a126a858ea8 100644
--- a/app/views/users/_projects.html.haml
+++ b/app/views/users/_projects.html.haml
@@ -1,13 +1,13 @@
- if local_assigns.has_key?(:contributed_projects) && contributed_projects.present?
.panel.panel-default.contributed-projects
.panel-heading Projects contributed to
- = render 'shared/projects_list',
+ = render 'shared/projects/list',
projects: contributed_projects.sort_by(&:star_count).reverse,
projects_limit: 5, stars: true, avatar: false
- if local_assigns.has_key?(:projects) && projects.present?
.panel.panel-default
.panel-heading Personal projects
- = render 'shared/projects_list',
+ = render 'shared/projects/list',
projects: projects.sort_by(&:star_count).reverse,
projects_limit: 10, stars: true, avatar: false
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 64b7f25ad37..aa4e8722fb1 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -7,7 +7,7 @@
= render 'shared/show_aside'
.row
- %section.col-md-8
+ %section.col-md-7
.header-with-avatar
= link_to avatar_icon(@user.email, 400), target: '_blank' do
= image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
@@ -59,7 +59,7 @@
.content_list
= spinner
- %aside.col-md-4
+ %aside.col-md-5
= render 'profile', user: @user
= render 'projects', projects: @projects, contributed_projects: @contributed_projects
diff --git a/app/workers/email_receiver_worker.rb b/app/workers/email_receiver_worker.rb
index a588a1f45ee..8cfb96ef376 100644
--- a/app/workers/email_receiver_worker.rb
+++ b/app/workers/email_receiver_worker.rb
@@ -18,6 +18,8 @@ class EmailReceiverWorker
def handle_failure(raw, e)
Rails.logger.warn("Email can not be processed: #{e}\n\n#{raw}")
+ return unless raw.present?
+
can_retry = false
reason = nil
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 1d21addece6..916a99bb273 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -4,7 +4,7 @@ class EmailsOnPushWorker
def perform(project_id, recipients, push_data, options = {})
options.symbolize_keys!
options.reverse_merge!(
- send_from_committer_email: false,
+ send_from_committer_email: false,
disable_diffs: false
)
send_from_committer_email = options[:send_from_committer_email]
@@ -16,9 +16,9 @@ class EmailsOnPushWorker
ref = push_data["ref"]
author_id = push_data["user_id"]
- action =
+ action =
if Gitlab::Git.blank_ref?(before_sha)
- :create
+ :create
elsif Gitlab::Git.blank_ref?(after_sha)
:delete
else
@@ -42,17 +42,22 @@ class EmailsOnPushWorker
end
recipients.split(" ").each do |recipient|
- Notify.repository_push_email(
- project_id,
- recipient,
- author_id: author_id,
- ref: ref,
- action: action,
- compare: compare,
- reverse_compare: reverse_compare,
- send_from_committer_email: send_from_committer_email,
- disable_diffs: disable_diffs
- ).deliver
+ begin
+ Notify.repository_push_email(
+ project_id,
+ recipient,
+ author_id: author_id,
+ ref: ref,
+ action: action,
+ compare: compare,
+ reverse_compare: reverse_compare,
+ send_from_committer_email: send_from_committer_email,
+ disable_diffs: disable_diffs
+ ).deliver
+ # These are input errors and won't be corrected even if Sidekiq retries
+ rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
+ logger.info("Failed to send e-mail for project '#{project.name_with_namespace}' to #{recipient}: #{e}")
+ end
end
ensure
compare = nil
diff --git a/app/workers/merge_worker.rb b/app/workers/merge_worker.rb
index 6a8665c179a..5d1a8555b7d 100644
--- a/app/workers/merge_worker.rb
+++ b/app/workers/merge_worker.rb
@@ -14,6 +14,10 @@ class MergeWorker
if result[:status] == :success && params[:should_remove_source_branch].present?
DeleteBranchService.new(merge_request.source_project, current_user).
execute(merge_request.source_branch)
+
+ merge_request.source_project.repository.expire_branch_names
end
+
+ result
end
end
diff --git a/bin/daemon_with_pidfile b/bin/daemon_with_pidfile
new file mode 100755
index 00000000000..f138c27a0e2
--- /dev/null
+++ b/bin/daemon_with_pidfile
@@ -0,0 +1,33 @@
+#!/usr/bin/env ruby
+# daemon_with_pidfile
+#
+# Daemonize, write a pidfile, and exec the remainder of the command line.
+
+def main(pidfile, cmd)
+ if middle_pid = Process.fork
+ # outer process
+ # Do not exit the outer process before the middle process finishes
+ Process.waitpid(middle_pid)
+ exit $?.exitstatus
+ end
+
+ if final_pid = Process.fork
+ # middle process
+ open(pidfile, 'w') { |f| f.puts final_pid }
+ exit
+ end
+
+ # Standard daemon things: become session leader, ignore SIGHUP, close stdin.
+ Signal.trap("HUP", "IGNORE")
+ Process.setsid
+ IO.new(0).close
+
+ exec(*cmd)
+end
+
+if ARGV.count < 2
+ abort "Usage: #$0 pidfile command [args...]"
+end
+
+pidfile = ARGV.shift
+main(pidfile, ARGV)
diff --git a/bin/mail_room b/bin/mail_room
index f4f1a170c04..74a84f5b2b4 100755
--- a/bin/mail_room
+++ b/bin/mail_room
@@ -19,9 +19,7 @@ get_mail_room_pid()
start()
{
- bundle exec mail_room -q -c $mail_room_config >> $mail_room_logfile 2>&1 &
- PID=$!
- echo $PID > $mail_room_pidfile
+ bin/daemon_with_pidfile $mail_room_pidfile bundle exec mail_room -q -c $mail_room_config >> $mail_room_logfile 2>&1
}
stop()
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index c7b60a1d4b1..9eb99dae456 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -246,6 +246,11 @@ production: &base
# issuer: 'https://gitlab.example.com',
# name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
# } }
+ # - { name: 'crowd',
+ # args: {
+ # crowd_server_url: 'CROWD SERVER URL',
+ # application_name: 'YOUR_APP_NAME',
+ # application_password: 'YOUR_APP_PASSWORD' } }
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index bd26ac1da20..c47e5dab27c 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -8,7 +8,7 @@ class Settings < Settingslogic
def gitlab_on_standard_port?
gitlab.port.to_i == (gitlab.https ? 443 : 80)
end
-
+
# get host without www, thanks to http://stackoverflow.com/a/6674363/1233435
def get_host_without_www(url)
url = URI.encode(url)
@@ -32,14 +32,12 @@ class Settings < Settingslogic
end
end
+ def build_base_gitlab_url
+ base_gitlab_url.join('')
+ end
+
def build_gitlab_url
- custom_port = gitlab_on_standard_port? ? nil : ":#{gitlab.port}"
- [ gitlab.protocol,
- "://",
- gitlab.host,
- custom_port,
- gitlab.relative_url_root
- ].join('')
+ (base_gitlab_url + [gitlab.relative_url_root]).join('')
end
# check that values in `current` (string or integer) is a contant in `modul`.
@@ -64,6 +62,17 @@ class Settings < Settingslogic
end
value
end
+
+ private
+
+ def base_gitlab_url
+ custom_port = gitlab_on_standard_port? ? nil : ":#{gitlab.port}"
+ [ gitlab.protocol,
+ "://",
+ gitlab.host,
+ custom_port
+ ]
+ end
end
end
@@ -123,6 +132,7 @@ Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].ni
Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}"
Settings.gitlab['email_display_name'] ||= "GitLab"
Settings.gitlab['email_reply_to'] ||= "noreply@#{Settings.gitlab.host}"
+Settings.gitlab['base_url'] ||= Settings.send(:build_base_gitlab_url)
Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url)
Settings.gitlab['user'] ||= 'git'
Settings.gitlab['user_home'] ||= begin
diff --git a/config/initializers/7_omniauth.rb b/config/initializers/7_omniauth.rb
index 7f73546ac89..70ed10e8275 100644
--- a/config/initializers/7_omniauth.rb
+++ b/config/initializers/7_omniauth.rb
@@ -11,7 +11,7 @@ if Gitlab::LDAP::Config.enabled?
end
end
-OmniAuth.config.full_host = Settings.gitlab['url']
+OmniAuth.config.full_host = Settings.gitlab['base_url']
OmniAuth.config.allowed_request_methods = [:post]
#In case of auto sign-in, the GET method is used (users don't get to click on a button)
OmniAuth.config.allowed_request_methods << :get if Gitlab.config.omniauth.auto_sign_in_with_provider.present?
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 091548348b1..2ce24592f8b 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -238,7 +238,7 @@ Devise.setup do |config|
provider_arguments.concat provider['args']
when Hash
# A Hash from the configuration will be passed as is.
- provider_arguments << provider['args']
+ provider_arguments << provider['args'].symbolize_keys
end
config.omniauth provider['name'].to_sym, *provider_arguments
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index 6139ddbe6cd..66ac88e9f4a 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -12,8 +12,7 @@ Doorkeeper.configure do
end
resource_owner_from_credentials do |routes|
- u = User.find_by(email: params[:username]) || User.find_by(username: params[:username])
- u if u && u.valid_password?(params[:password])
+ Gitlab::Auth.new.find(params[:username], params[:password])
end
# If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
diff --git a/config/mail_room.yml.example b/config/mail_room.yml.example
index 28366eb7394..dd8edfc42eb 100644
--- a/config/mail_room.yml.example
+++ b/config/mail_room.yml.example
@@ -14,6 +14,8 @@
# :name: "inbox"
# # Always "sidekiq".
# :delivery_method: sidekiq
+ # # Always true.
+ # :delete_after_delivery: true
# :delivery_options:
# # The URL to the Redis server used by Sidekiq. Should match the URL in config/resque.yml.
# :redis_url: redis://localhost:6379
diff --git a/config/routes.rb b/config/routes.rb
index d7307a61ede..25c286b3083 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -30,12 +30,7 @@ Gitlab::Application.routes.draw do
end
# Enable Grack support
- mount Grack::Bundle.new({
- git_path: Gitlab.config.git.bin_path,
- project_root: Gitlab.config.gitlab_shell.repos_path,
- upload_pack: Gitlab.config.gitlab_shell.upload_pack,
- receive_pack: Gitlab.config.gitlab_shell.receive_pack
- }), at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) }, via: [:get, :post]
+ mount Grack::AuthSpawner, at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) }, via: [:get, :post]
# Help
get 'help' => 'help#index'
@@ -261,6 +256,7 @@ Gitlab::Application.routes.draw do
member do
get :issues
get :merge_requests
+ get :activity
end
scope module: :dashboard do
@@ -410,16 +406,20 @@ Gitlab::Application.routes.draw do
end
end
- resources :wikis, only: [:show, :edit, :destroy, :create], constraints: { id: /[a-zA-Z.0-9_\-\/]+/ } do
- collection do
- get :pages
- put ':id' => 'wikis#update'
- get :git_access
- end
+ WIKI_SLUG_ID = { id: /[a-zA-Z.0-9_\-\/]+/ } unless defined? WIKI_SLUG_ID
- member do
- get 'history'
- end
+ scope do
+ # Order matters to give priority to these matches
+ get '/wikis/git_access', to: 'wikis#git_access'
+ get '/wikis/pages', to: 'wikis#pages', as: 'wiki_pages'
+ post '/wikis', to: 'wikis#create'
+
+ get '/wikis/*id/history', to: 'wikis#history', as: 'wiki_history', constraints: WIKI_SLUG_ID
+ get '/wikis/*id/edit', to: 'wikis#edit', as: 'wiki_edit', constraints: WIKI_SLUG_ID
+
+ get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID
+ delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID
+ put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID
end
resource :repository, only: [:show, :create] do
diff --git a/db/migrate/20150817163600_deduplicate_user_identities.rb b/db/migrate/20150817163600_deduplicate_user_identities.rb
new file mode 100644
index 00000000000..fab669c2905
--- /dev/null
+++ b/db/migrate/20150817163600_deduplicate_user_identities.rb
@@ -0,0 +1,14 @@
+class DeduplicateUserIdentities < ActiveRecord::Migration
+ def change
+ execute 'DROP TABLE IF EXISTS tt_migration_DeduplicateUserIdentities;'
+ execute 'CREATE TEMPORARY TABLE tt_migration_DeduplicateUserIdentities AS SELECT id,provider,user_id FROM identities;'
+ execute 'DELETE FROM identities WHERE id NOT IN ( SELECT MIN(id) FROM tt_migration_DeduplicateUserIdentities GROUP BY user_id, provider);'
+ execute 'DROP TABLE IF EXISTS tt_migration_DeduplicateUserIdentities;'
+ end
+
+ def down
+ # This is an irreversible migration;
+ # If someone is trying to rollback for other reasons, we should not throw an Exception.
+ # raise ActiveRecord::IrreversibleMigration
+ end
+end
diff --git a/db/migrate/20150824002011_add_enable_ssl_verification.rb b/db/migrate/20150824002011_add_enable_ssl_verification.rb
new file mode 100644
index 00000000000..093c068fbde
--- /dev/null
+++ b/db/migrate/20150824002011_add_enable_ssl_verification.rb
@@ -0,0 +1,5 @@
+class AddEnableSslVerification < ActiveRecord::Migration
+ def change
+ add_column :web_hooks, :enable_ssl_verification, :boolean, default: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 108c48bf321..36568dd4edd 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: 20150818213832) do
+ActiveRecord::Schema.define(version: 20150824002011) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -487,12 +487,12 @@ ActiveRecord::Schema.define(version: 20150818213832) do
add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree
create_table "users", force: true do |t|
- t.string "email", default: "", null: false
- t.string "encrypted_password", default: "", null: false
+ t.string "email", default: "", null: false
+ t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
- t.integer "sign_in_count", default: 0
+ t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
@@ -500,22 +500,22 @@ ActiveRecord::Schema.define(version: 20150818213832) do
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
- t.boolean "admin", default: false, null: false
- t.integer "projects_limit", default: 10
- t.string "skype", default: "", null: false
- t.string "linkedin", default: "", null: false
- t.string "twitter", default: "", null: false
+ t.boolean "admin", default: false, null: false
+ t.integer "projects_limit", default: 10
+ t.string "skype", default: "", null: false
+ t.string "linkedin", default: "", null: false
+ t.string "twitter", default: "", null: false
t.string "authentication_token"
- t.integer "theme_id", default: 1, null: false
+ t.integer "theme_id", default: 1, null: false
t.string "bio"
- t.integer "failed_attempts", default: 0
+ t.integer "failed_attempts", default: 0
t.datetime "locked_at"
t.string "username"
- t.boolean "can_create_group", default: true, null: false
- t.boolean "can_create_team", default: true, null: false
+ t.boolean "can_create_group", default: true, null: false
+ t.boolean "can_create_team", default: true, null: false
t.string "state"
- t.integer "color_scheme_id", default: 1, null: false
- t.integer "notification_level", default: 1, null: false
+ t.integer "color_scheme_id", default: 1, null: false
+ t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at"
t.integer "created_by_id"
t.datetime "last_credential_check_at"
@@ -524,20 +524,20 @@ ActiveRecord::Schema.define(version: 20150818213832) do
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
- t.boolean "hide_no_ssh_key", default: false
- t.string "website_url", default: "", null: false
+ t.boolean "hide_no_ssh_key", default: false
+ t.string "website_url", default: "", null: false
t.string "notification_email"
- t.boolean "hide_no_password", default: false
- t.boolean "password_automatically_set", default: false
+ t.boolean "hide_no_password", default: false
+ t.boolean "password_automatically_set", default: false
t.string "location"
t.string "encrypted_otp_secret"
t.string "encrypted_otp_secret_iv"
t.string "encrypted_otp_secret_salt"
- t.boolean "otp_required_for_login", default: false, null: false
+ t.boolean "otp_required_for_login", default: false, null: false
t.text "otp_backup_codes"
- t.string "public_email", default: "", null: false
- t.integer "dashboard", default: 0
- t.integer "project_view", default: 0
+ t.string "public_email", default: "", null: false
+ t.integer "dashboard", default: 0
+ t.integer "project_view", default: 0
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
@@ -566,13 +566,14 @@ ActiveRecord::Schema.define(version: 20150818213832) do
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
- t.string "type", default: "ProjectHook"
+ t.string "type", default: "ProjectHook"
t.integer "service_id"
- t.boolean "push_events", default: true, null: false
- t.boolean "issues_events", default: false, null: false
- t.boolean "merge_requests_events", default: false, null: false
- t.boolean "tag_push_events", default: false
- t.boolean "note_events", default: false, null: false
+ t.boolean "push_events", default: true, null: false
+ t.boolean "issues_events", default: false, null: false
+ t.boolean "merge_requests_events", default: false, null: false
+ t.boolean "tag_push_events", default: false
+ t.boolean "note_events", default: false, null: false
+ t.boolean "enable_ssl_verification", default: false
end
add_index "web_hooks", ["created_at", "id"], name: "index_web_hooks_on_created_at_and_id", using: :btree
diff --git a/doc/api/README.md b/doc/api/README.md
index f369c3fd978..6b8528de50c 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -21,6 +21,7 @@
- [Groups](groups.md)
- [Namespaces](namespaces.md)
- [Settings](settings.md)
+- [Keys](keys.md)
## Clients
diff --git a/doc/api/keys.md b/doc/api/keys.md
new file mode 100644
index 00000000000..faa6f212b43
--- /dev/null
+++ b/doc/api/keys.md
@@ -0,0 +1,46 @@
+# Keys
+
+## Get SSH key with user by ID of an SSH key
+
+Get SSH key with user by ID of an SSH key. Note only administrators can lookup SSH key with user by ID of an SSH key.
+
+```
+GET /keys/:id
+```
+
+Parameters:
+
+- `id` (required) - The ID of an SSH key
+
+```json
+{
+ "id": 1,
+ "title": "Sample key 25",
+ "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt1256k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
+ "created_at": "2015-09-03T07:24:44.627Z",
+ "user": {
+ "name": "John Smith",
+ "username": "john_smith",
+ "id": 25,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/cfa35b8cd2ec278026357769582fa563?s=40\u0026d=identicon",
+ "web_url": "http://localhost:3000/u/john_smith",
+ "created_at": "2015-09-03T07:24:01.670Z",
+ "is_admin": false,
+ "bio": null,
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "email": "john@example.com",
+ "theme_id": 2,
+ "color_scheme_id": 1,
+ "projects_limit": 10,
+ "current_sign_in_at": null,
+ "identities": [],
+ "can_create_group": true,
+ "can_create_project": true,
+ "two_factor_enabled": false
+ }
+}
+```
diff --git a/doc/api/services.md b/doc/api/services.md
index cbf767d1b25..bc5049dd302 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -1,8 +1,296 @@
# Services
+## Asana
+
+Asana - Teamwork without email
+
+### Create/Edit Asana service
+
+Set Asana service for a project.
+
+> This service adds commit messages as comments to Asana tasks. Once enabled, commit messages are checked for Asana task URLs (for example, `https://app.asana.com/0/123456/987654`) or task IDs starting with # (for example, `#987654`). Every task ID found will get the commit comment added to it. You can also close a task with a message containing: `fix #123456`. You can find your Api Keys here: http://developer.asana.com/documentation/#api_keys
+
+```
+PUT /projects/:id/services/asana
+```
+
+Parameters:
+
+- `api_key` (**required**) - User API token. User must have access to task,all comments will be attributed to this user.
+- `restrict_to_branch` (optional) - Comma-separated list of branches which will beautomatically inspected. Leave blank to include all branches.
+
+### Delete Asana service
+
+Delete Asana service for a project.
+
+```
+DELETE /projects/:id/services/asana
+```
+
+## Assembla
+
+Project Management Software (Source Commits Endpoint)
+
+### Create/Edit Assembla service
+
+Set Assembla service for a project.
+
+```
+PUT /projects/:id/services/assembla
+```
+
+Parameters:
+
+- `token` (**required**)
+- `subdomain` (optional)
+
+### Delete Assembla service
+
+Delete Assembla service for a project.
+
+```
+DELETE /projects/:id/services/assembla
+```
+
+## Atlassian Bamboo CI
+
+A continuous integration and build server
+
+### Create/Edit Atlassian Bamboo CI service
+
+Set Atlassian Bamboo CI service for a project.
+
+> You must set up automatic revision labeling and a repository trigger in Bamboo.
+
+```
+PUT /projects/:id/services/bamboo
+```
+
+Parameters:
+
+- `bamboo_url` (**required**) - Bamboo root URL like https://bamboo.example.com
+- `build_key` (**required**) - Bamboo build plan key like KEY
+- `username` (**required**) - A user with API access, if applicable
+- `password` (**required**)
+
+### Delete Atlassian Bamboo CI service
+
+Delete Atlassian Bamboo CI service for a project.
+
+```
+DELETE /projects/:id/services/bamboo
+```
+
+## Buildkite
+
+Continuous integration and deployments
+
+### Create/Edit Buildkite service
+
+Set Buildkite service for a project.
+
+```
+PUT /projects/:id/services/buildkite
+```
+
+Parameters:
+
+- `token` (**required**) - Buildkite project GitLab token
+- `project_url` (**required**) - https://buildkite.com/example/project
+- `enable_ssl_verification` (optional) - Enable SSL verification
+
+### Delete Buildkite service
+
+Delete Buildkite service for a project.
+
+```
+DELETE /projects/:id/services/buildkite
+```
+
+## Campfire
+
+Simple web-based real-time group chat
+
+### Create/Edit Campfire service
+
+Set Campfire service for a project.
+
+```
+PUT /projects/:id/services/campfire
+```
+
+Parameters:
+
+- `token` (**required**)
+- `subdomain` (optional)
+- `room` (optional)
+
+### Delete Campfire service
+
+Delete Campfire service for a project.
+
+```
+DELETE /projects/:id/services/campfire
+```
+
+## Custom Issue Tracker
+
+Custom issue tracker
+
+### Create/Edit Custom Issue Tracker service
+
+Set Custom Issue Tracker service for a project.
+
+```
+PUT /projects/:id/services/custom-issue-tracker
+```
+
+Parameters:
+
+- `new_issue_url` (**required**) - New Issue url
+- `issues_url` (**required**) - Issue url
+- `project_url` (**required**) - Project url
+- `description` (optional) - Custom issue tracker
+- `title` (optional) - Custom Issue Tracker
+
+### Delete Custom Issue Tracker service
+
+Delete Custom Issue Tracker service for a project.
+
+```
+DELETE /projects/:id/services/custom-issue-tracker
+```
+
+## Drone CI
+
+Drone is a Continuous Integration platform built on Docker, written in Go
+
+### Create/Edit Drone CI service
+
+Set Drone CI service for a project.
+
+```
+PUT /projects/:id/services/drone-ci
+```
+
+Parameters:
+
+- `token` (**required**) - Drone CI project specific token
+- `drone_url` (**required**) - http://drone.example.com
+- `enable_ssl_verification` (optional) - Enable SSL verification
+
+### Delete Drone CI service
+
+Delete Drone CI service for a project.
+
+```
+DELETE /projects/:id/services/drone-ci
+```
+
+## Emails on push
+
+Email the commits and diff of each push to a list of recipients.
+
+### Create/Edit Emails on push service
+
+Set Emails on push service for a project.
+
+```
+PUT /projects/:id/services/emails-on-push
+```
+
+Parameters:
+
+- `recipients` (**required**) - Emails separated by whitespace
+- `disable_diffs` (optional) - Disable code diffs
+- `send_from_committer_email` (optional) - Send from committer
+
+### Delete Emails on push service
+
+Delete Emails on push service for a project.
+
+```
+DELETE /projects/:id/services/emails-on-push
+```
+
+## External Wiki
+
+Replaces the link to the internal wiki with a link to an external wiki.
+
+### Create/Edit External Wiki service
+
+Set External Wiki service for a project.
+
+```
+PUT /projects/:id/services/external-wiki
+```
+
+Parameters:
+
+- `external_wiki_url` (**required**) - The URL of the external Wiki
+
+### Delete External Wiki service
+
+Delete External Wiki service for a project.
+
+```
+DELETE /projects/:id/services/external-wiki
+```
+
+## Flowdock
+
+Flowdock is a collaboration web app for technical teams.
+
+### Create/Edit Flowdock service
+
+Set Flowdock service for a project.
+
+```
+PUT /projects/:id/services/flowdock
+```
+
+Parameters:
+
+- `token` (**required**) - Flowdock Git source token
+
+### Delete Flowdock service
+
+Delete Flowdock service for a project.
+
+```
+DELETE /projects/:id/services/flowdock
+```
+
+## Gemnasium
+
+Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities.
+
+### Create/Edit Gemnasium service
+
+Set Gemnasium service for a project.
+
+```
+PUT /projects/:id/services/gemnasium
+```
+
+Parameters:
+
+- `api_key` (**required**) - Your personal API KEY on gemnasium.com
+- `token` (**required**) - The project's slug on gemnasium.com
+
+### Delete Gemnasium service
+
+Delete Gemnasium service for a project.
+
+```
+DELETE /projects/:id/services/gemnasium
+```
+
## GitLab CI
-### Edit GitLab CI service
+Continuous integration server from GitLab
+
+### Create/Edit GitLab CI service
Set GitLab CI service for a project.
@@ -12,12 +300,13 @@ PUT /projects/:id/services/gitlab-ci
Parameters:
-- `token` (required) - CI project token
-- `project_url` (required) - CI project URL
+- `token` (**required**) - GitLab CI project specific token
+- `project_url` (**required**) - http://ci.gitlabhq.com/projects/3
+- `enable_ssl_verification` (optional) - Enable SSL verification
### Delete GitLab CI service
-Delete GitLab CI service settings for a project.
+Delete GitLab CI service for a project.
```
DELETE /projects/:id/services/gitlab-ci
@@ -25,17 +314,24 @@ DELETE /projects/:id/services/gitlab-ci
## HipChat
-### Edit HipChat service
+Private group chat and IM
+
+### Create/Edit HipChat service
-Set HipChat service for project.
+Set HipChat service for a project.
```
PUT /projects/:id/services/hipchat
```
+
Parameters:
-- `token` (required) - HipChat token
-- `room` (required) - HipChat room name
+- `token` (**required**) - Room token
+- `color` (optional)
+- `notify` (optional)
+- `room` (optional) - Room name or ID
+- `api_version` (optional) - Leave blank for default (v2)
+- `server` (optional) - Leave blank for default. https://hipchat.example.com
### Delete HipChat service
@@ -44,3 +340,197 @@ Delete HipChat service for a project.
```
DELETE /projects/:id/services/hipchat
```
+
+## Irker (IRC gateway)
+
+Send IRC messages, on update, to a list of recipients through an Irker gateway.
+
+### Create/Edit Irker (IRC gateway) service
+
+Set Irker (IRC gateway) service for a project.
+
+> NOTE: Irker does NOT have built-in authentication, which makes it vulnerable to spamming IRC channels if it is hosted outside of a firewall. Please make sure you run the daemon within a secured network to prevent abuse. For more details, read: http://www.catb.org/~esr/irker/security.html.
+
+```
+PUT /projects/:id/services/irker
+```
+
+Parameters:
+
+- `recipients` (**required**) - Recipients/channels separated by whitespaces
+- `default_irc_uri` (optional) - irc://irc.network.net:6697/
+- `server_port` (optional) - 6659
+- `server_host` (optional) - localhost
+- `colorize_messages` (optional)
+
+### Delete Irker (IRC gateway) service
+
+Delete Irker (IRC gateway) service for a project.
+
+```
+DELETE /projects/:id/services/irker
+```
+
+## JIRA
+
+Jira issue tracker
+
+### Create/Edit JIRA service
+
+Set JIRA service for a project.
+
+> Setting `project_url`, `issues_url` and `new_issue_url` will allow a user to easily navigate to the Jira issue tracker. See the [integration doc](http://doc.gitlab.com/ce/integration/external-issue-tracker.html) for details. Support for referencing commits and automatic closing of Jira issues directly from GitLab is [available in GitLab EE.](http://doc.gitlab.com/ee/integration/jira.html)
+
+```
+PUT /projects/:id/services/jira
+```
+
+Parameters:
+
+- `new_issue_url` (**required**) - New Issue url
+- `project_url` (**required**) - Project url
+- `issues_url` (**required**) - Issue url
+- `description` (optional) - Jira issue tracker
+
+### Delete JIRA service
+
+Delete JIRA service for a project.
+
+```
+DELETE /projects/:id/services/jira
+```
+
+## PivotalTracker
+
+Project Management Software (Source Commits Endpoint)
+
+### Create/Edit PivotalTracker service
+
+Set PivotalTracker service for a project.
+
+```
+PUT /projects/:id/services/pivotaltracker
+```
+
+Parameters:
+
+- `token` (**required**)
+
+### Delete PivotalTracker service
+
+Delete PivotalTracker service for a project.
+
+```
+DELETE /projects/:id/services/pivotaltracker
+```
+
+## Pushover
+
+Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.
+
+### Create/Edit Pushover service
+
+Set Pushover service for a project.
+
+```
+PUT /projects/:id/services/pushover
+```
+
+Parameters:
+
+- `api_key` (**required**) - Your application key
+- `user_key` (**required**) - Your user key
+- `priority` (**required**)
+- `device` (optional) - Leave blank for all active devices
+- `sound` (optional)
+
+### Delete Pushover service
+
+Delete Pushover service for a project.
+
+```
+DELETE /projects/:id/services/pushover
+```
+
+## Redmine
+
+Redmine issue tracker
+
+### Create/Edit Redmine service
+
+Set Redmine service for a project.
+
+```
+PUT /projects/:id/services/redmine
+```
+
+Parameters:
+
+- `new_issue_url` (**required**) - New Issue url
+- `project_url` (**required**) - Project url
+- `issues_url` (**required**) - Issue url
+- `description` (optional) - Redmine issue tracker
+
+### Delete Redmine service
+
+Delete Redmine service for a project.
+
+```
+DELETE /projects/:id/services/redmine
+```
+
+## Slack
+
+A team communication tool for the 21st century
+
+### Create/Edit Slack service
+
+Set Slack service for a project.
+
+```
+PUT /projects/:id/services/slack
+```
+
+Parameters:
+
+- `webhook` (**required**) - https://hooks.slack.com/services/...
+- `username` (optional) - username
+- `channel` (optional) - #channel
+
+### Delete Slack service
+
+Delete Slack service for a project.
+
+```
+DELETE /projects/:id/services/slack
+```
+
+## JetBrains TeamCity CI
+
+A continuous integration and build server
+
+### Create/Edit JetBrains TeamCity CI service
+
+Set JetBrains TeamCity CI service for a project.
+
+> The build configuration in Teamcity must use the build format number %build.vcs.number% you will also want to configure monitoring of all branches so merge requests build, that setting is in the vsc root advanced settings.
+
+```
+PUT /projects/:id/services/teamcity
+```
+
+Parameters:
+
+- `teamcity_url` (**required**) - TeamCity root URL like https://teamcity.example.com
+- `build_type` (**required**) - Build configuration ID
+- `username` (**required**) - A user with permissions to trigger a manual build
+- `password` (**required**)
+
+### Delete JetBrains TeamCity CI service
+
+Delete JetBrains TeamCity CI service for a project.
+
+```
+DELETE /projects/:id/services/teamcity
+```
+
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index 53f8095cb13..a4a980cf0e0 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -27,3 +27,9 @@ You can find results under the `doc/code` directory.
```
bundle exec rake gitlab:generate_docs
```
+
+## Generate API documentation for project services (e.g. Slack)
+
+```
+bundle exec rake services:doc
+```
diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md
index b03cca4029c..addd3b6b6eb 100644
--- a/doc/gitlab-basics/command-line-commands.md
+++ b/doc/gitlab-basics/command-line-commands.md
@@ -72,3 +72,8 @@ You will be asked for an administrator’s password.
```
sudo
```
+
+### Tell where you are
+```
+pwd
+```
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 73e36fa7e51..52031e9b9a1 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -125,13 +125,25 @@ Install the Bundler Gem:
sudo gem install bundler --no-ri --no-rdoc
-## 3. System Users
+## 3. Go
+
+Since GitLab 8.0, Git HTTP requests are handled by gitlab-git-http-server.
+This is a small daemon written in Go.
+To install gitlab-git-http-server we need a Go compiler.
+
+ curl -O --progress https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz
+ echo '5817fa4b2252afdb02e11e8b9dc1d9173ef3bd5a go1.5.linux-amd64.tar.gz' | shasum -c - && \
+ sudo tar -C /usr/local -xzf go1.5.linux-amd64.tar.gz
+ sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/
+ rm go1.5.linux-amd64.tar.gz
+
+## 4. System Users
Create a `git` user for GitLab:
sudo adduser --disabled-login --gecos 'GitLab' git
-## 4. Database
+## 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.
@@ -157,7 +169,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
# Quit the database session
gitlabhq_production> \q
-## 5. Redis
+## 6. Redis
sudo apt-get install redis-server
@@ -187,7 +199,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
# Add git to the redis group
sudo usermod -aG redis git
-## 6. GitLab
+## 7. GitLab
# We'll install GitLab into home directory of the user "git"
cd /home/git
@@ -297,6 +309,13 @@ GitLab Shell is an SSH access and repository management software developed speci
**Note:** Make sure your hostname can be resolved on the machine itself by either a proper DNS record or an additional line in /etc/hosts ("127.0.0.1 hostname"). This might be necessary for example if you set up gitlab behind a reverse proxy. If the hostname cannot be resolved, the final installation check will fail with "Check GitLab API access: FAILED. code: 401" and pushing commits will be rejected with "[remote rejected] master -> master (hook declined)".
+### Install gitlab-git-http-server
+
+ cd /home/git
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-git-http-server.git
+ cd gitlab-git-http-server
+ sudo -u git -H make
+
### Initialize Database and Activate Advanced Features
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
@@ -345,7 +364,7 @@ Check if GitLab and its environment are configured correctly:
# or
sudo /etc/init.d/gitlab restart
-## 7. Nginx
+## 8. Nginx
**Note:** Nginx is the officially supported web server for GitLab. If you cannot or do not want to use Nginx as your web server, have a look at the [GitLab recipes](https://gitlab.com/gitlab-org/gitlab-recipes/).
diff --git a/doc/integration/crowd.md b/doc/integration/crowd.md
new file mode 100644
index 00000000000..2ecc8795ac1
--- /dev/null
+++ b/doc/integration/crowd.md
@@ -0,0 +1,58 @@
+# Crowd OmniAuth Provider
+
+To enable the Crowd OmniAuth provider you must register your application with Crowd. To configure Crowd integration you need an application name and password.
+
+1. On your GitLab server, open the configuration file.
+
+ For omnibus package:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For instalations from source:
+
+ ```sh
+ cd /home/git/gitlab
+
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "crowd",
+ "args" => {
+ "crowd_server_url" => "CROWD",
+ "application_name" => "YOUR_APP_NAME",
+ "application_password" => "YOUR_APP_PASSWORD"
+ }
+ }
+ ]
+ ```
+
+ For installations from source:
+
+ ```
+ - { name: 'crowd',
+ args: {
+ crowd_server_url: 'CROWD SERVER URL',
+ application_name: 'YOUR_APP_NAME',
+ application_password: 'YOUR_APP_PASSWORD' } }
+ ```
+
+1. Change 'YOUR_APP_NAME' to the application name from Crowd applications page.
+
+1. Change 'YOUR_APP_PASSWORD' to the application password you've set.
+
+1. Save the configuration file.
+
+1. Restart GitLab for the changes to take effect.
+
+On the sign in page there should now be a Crowd tab in the sign in form. \ No newline at end of file
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 2010cb9b8a1..c5cecbc2f2d 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -76,6 +76,7 @@ Now we can choose one or more of the Supported Providers below to continue confi
- [Shibboleth](shibboleth.md)
- [Twitter](twitter.md)
- [SAML](saml.md)
+- [Crowd](crowd.md)
## Enable OmniAuth for an Existing User
diff --git a/doc/reply_by_email/README.md b/doc/reply_by_email/README.md
index f1dcef5de2d..1f704e65bcf 100644
--- a/doc/reply_by_email/README.md
+++ b/doc/reply_by_email/README.md
@@ -65,6 +65,8 @@ In this example, we'll use the Gmail address `gitlab-replies@gmail.com`.
:name: "inbox"
# Always "sidekiq".
:delivery_method: sidekiq
+ # Always true.
+ :delete_after_delivery: true
:delivery_options:
# The URL to the Redis server used by Sidekiq. Should match the URL in config/resque.yml.
:redis_url: redis://localhost:6379
@@ -163,6 +165,8 @@ sudo gitlab-ctl restart mailroom
:name: "inbox"
# Always "sidekiq".
:delivery_method: sidekiq
+ # Always true.
+ :delete_after_delivery: true
:delivery_options:
# The URL to the Redis server used by Sidekiq. Should match the URL in config/resque.yml.
:redis_url: redis://localhost:6379
diff --git a/doc/update/7.14-to-8.0.md b/doc/update/7.14-to-8.0.md
new file mode 100644
index 00000000000..29a38d07b3d
--- /dev/null
+++ b/doc/update/7.14-to-8.0.md
@@ -0,0 +1,159 @@
+# From 7.14 to 8.0
+
+### 0. Double-check your Git version
+
+**This notice applies only to /usr/local/bin/git**
+
+If you compiled Git from source on your GitLab server then please double-check
+that you are using a version that protects against CVE-2014-9390. For six
+months after this vulnerability became known the GitLab installation guide
+still contained instructions that would install the outdated, 'vulnerable' Git
+version 2.1.2.
+
+Run the following command to get your current Git version.
+
+```
+/usr/local/bin/git --version
+```
+
+If you see 'No such file or directory' then you did not install Git according
+to the outdated instructions from the GitLab installation guide and you can go
+to the next step 'Stop server' below.
+
+If you see a version string then it should be v1.8.5.6, v1.9.5, v2.0.5, v2.1.4,
+v2.2.1 or newer. You can use the [instructions in the GitLab source
+installation
+guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
+to install a newer version of Git.
+
+### 1. Stop server
+
+ sudo service gitlab stop
+
+### 2. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 3. Get latest code
+
+```bash
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+```
+
+For GitLab Community Edition:
+
+```bash
+sudo -u git -H git checkout 8-0-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 8-0-stable-ee
+```
+
+### 4. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch
+sudo -u git -H git checkout v2.6.4
+```
+
+### 5. Install gitlab-git-http-server
+
+First we download Go 1.5 and install it into /usr/local/go.
+
+ curl -O --progress https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz
+ echo '5817fa4b2252afdb02e11e8b9dc1d9173ef3bd5a go1.5.linux-amd64.tar.gz' | shasum -c - && \
+ sudo tar -C /usr/local -xzf go1.5.linux-amd64.tar.gz
+ sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/
+ rm go1.5.linux-amd64.tar.gz
+
+Now we download gitlab-git-http-server and install it in /home/git/gitlab-git-http-server.
+
+ cd /home/git
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-git-http-server.git
+ cd gitlab-git-http-server
+ sudo -u git -H make
+
+If you put your Git repositories in a directory different from /home/git/repositories, you need to tell gitlab-git-http-server about it via /etc/gitlab/default.
+See lib/support/init.d/gitlab.default.example for the options.
+
+### 6. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without ... postgres')
+sudo -u git -H bundle install --without development test postgres --deployment
+
+# PostgreSQL installations (note: the line below states '--without ... mysql')
+sudo -u git -H bundle install --without development test mysql --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+### 7. Update config files
+
+#### New configuration options for `gitlab.yml`
+
+There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them to your current `gitlab.yml`.
+
+```
+git diff origin/7-14-stable:config/gitlab.yml.example origin/8-0-stable:config/gitlab.yml.example
+``````
+
+#### New NGINX configuration
+
+Because of the new gitlab-git-http-server you need to update your NGINX configuration.
+If you skip this step 'git clone' and 'git push' over HTTP(S) will stop working.
+
+```
+# Remove '-ssl' twice in the diff command below if you use HTTP instead of HTTPS
+git diff origin/7-14-stable:lib/support/nginx/gitlab-ssl origin/8-0-stable:lib/support/nginx/gitlab-ssl
+```
+
+### 8. Start application
+
+ sudo service gitlab start
+ sudo service nginx restart
+
+### 9. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations, the upgrade is complete!
+
+## Things went south? Revert to previous version (7.14)
+
+### 1. Revert the code to the previous version
+Follow the [upgrade guide from 7.13 to 7.14](7.13-to-7.14.md), except for the database migration
+(The backup is already migrated to the previous version)
+
+### 2. Restore from the backup:
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index 73717ffc7d6..09400d9b163 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -279,6 +279,7 @@ X-Gitlab-Event: Note Hook
"name": "Gitlab Test",
"ssh_url": "git@example.com:gitlab-org/gitlab-test.git",
"http_url": "http://example.com/gitlab-org/gitlab-test.git",
+ "web_url": "http://example.com/gitlab-org/gitlab-test",
"namespace": "Gitlab Org",
"visibility_level": 10
},
@@ -286,6 +287,7 @@ X-Gitlab-Event: Note Hook
"name": "Gitlab Test",
"ssh_url": "git@example.com:gitlab-org/gitlab-test.git",
"http_url": "http://example.com/gitlab-org/gitlab-test.git",
+ "web_url": "http://example.com/gitlab-org/gitlab-test",
"namespace": "Gitlab Org",
"visibility_level": 10
},
@@ -462,6 +464,7 @@ X-Gitlab-Event: Merge Request Hook
"name": "awesome_project",
"ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git",
"http_url": "http://example.com/awesome_space/awesome_project.git",
+ "web_url": "http://example.com/awesome_space/awesome_project",
"visibility_level": 20,
"namespace": "awesome_space"
},
@@ -469,6 +472,7 @@ X-Gitlab-Event: Merge Request Hook
"name": "awesome_project",
"ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git",
"http_url": "http://example.com/awesome_space/awesome_project.git",
+ "web_url": "http://example.com/awesome_space/awesome_project",
"visibility_level": 20,
"namespace": "awesome_space"
},
diff --git a/doc/workflow/importing/README.md b/doc/workflow/importing/README.md
index cd98d1b9852..5cde90993d2 100644
--- a/doc/workflow/importing/README.md
+++ b/doc/workflow/importing/README.md
@@ -8,5 +8,5 @@
### Note
* If you'd like to migrate from a self-hosted GitLab instance to GitLab.com, you can copy your repos by changing the remote and pushing to the new server; but issues and merge requests can't be imported.
-* Repositories are imported to GitLab via HTTP.
-If the repository is too large, it can timeout. We have a soft limit of 10GB.
+* You can import any Git repository via HTTP from the New Project page.
+If the repository is too large, it can timeout.
diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md
index 3efa92cb868..2d77c6d1172 100644
--- a/doc/workflow/importing/import_projects_from_github.md
+++ b/doc/workflow/importing/import_projects_from_github.md
@@ -17,4 +17,4 @@ If you want to import from a GitHub Enterprise instance, you need to use GitLab
* To import a project, you can simple click "Add". The importer will import your repository and issues. Once the importer is done, a new GitLab project will be created with your imported data.
### Note
-When you import your projects from GitHub, it is not possible to keep your labels and milestones and issue numbers won't match. We are working on improving this in the near future.
+When you import your projects from GitHub, it is not possible to keep your labels and milestones. We are working on improving this in the near future.
diff --git a/features/admin/hooks.feature b/features/admin/hooks.feature
new file mode 100644
index 00000000000..5ca332d9f1c
--- /dev/null
+++ b/features/admin/hooks.feature
@@ -0,0 +1,9 @@
+@admin
+Feature: Admin Hooks
+ Background:
+ Given I sign in as an admin
+
+ Scenario: On Admin Hooks
+ Given I visit admin hooks page
+ Then I submit the form with enabled SSL verification
+ And I see new hook with enabled SSL verification \ No newline at end of file
diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature
index 1959d327082..392d4235eff 100644
--- a/features/dashboard/dashboard.feature
+++ b/features/dashboard/dashboard.feature
@@ -10,6 +10,10 @@ Feature: Dashboard
Scenario: I should see projects list
Then I should see "New Project" link
Then I should see "Shop" project link
+
+ @javascript
+ Scenario: I should see activity list
+ And I visit dashboard activity page
Then I should see project "Shop" activity feed
Scenario: I should see groups list
@@ -26,12 +30,12 @@ Feature: Dashboard
@javascript
Scenario: I should see User joined Project event
Given user with name "John Doe" joined project "Shop"
- When I visit dashboard page
+ When I visit dashboard activity page
Then I should see "John Doe joined project Shop" event
@javascript
Scenario: I should see User left Project event
Given user with name "John Doe" joined project "Shop"
And user with name "John Doe" left project "Shop"
- When I visit dashboard page
+ When I visit dashboard activity page
Then I should see "John Doe left project Shop" event
diff --git a/features/dashboard/event_filters.feature b/features/dashboard/event_filters.feature
index ec5680caba6..96399ea21a6 100644
--- a/features/dashboard/event_filters.feature
+++ b/features/dashboard/event_filters.feature
@@ -6,7 +6,7 @@ Feature: Event Filters
And this project has push event
And this project has new member event
And this project has merge request event
- And I visit dashboard page
+ And I visit dashboard activity page
@javascript
Scenario: I should see all events
@@ -16,7 +16,7 @@ Feature: Event Filters
@javascript
Scenario: I should see only pushed events
- When I click "push" event filter
+ When I click "push" event filter
Then I should see push event
And I should not see new member event
And I should not see merge request event
@@ -38,11 +38,11 @@ Feature: Event Filters
@javascript
Scenario: I should see only selected events while page reloaded
When I click "push" event filter
- And I visit dashboard page
+ And I visit dashboard activity page
Then I should see push event
And I should not see new member event
When I click "team" event filter
- And I visit dashboard page
+ And I visit dashboard activity page
Then I should see push event
And I should see new member event
And I should not see merge request event
diff --git a/features/login_form.feature b/features/login_form.feature
new file mode 100644
index 00000000000..b4d95754482
--- /dev/null
+++ b/features/login_form.feature
@@ -0,0 +1,5 @@
+Feature: Login form
+ Scenario: I see crowd form
+ Given Crowd integration enabled
+ When I visit sign in page
+ Then I should see Crowd login form \ No newline at end of file
diff --git a/features/project/commits/commits.feature b/features/project/commits/commits.feature
index c4b206edc95..3ebc8a39aae 100644
--- a/features/project/commits/commits.feature
+++ b/features/project/commits/commits.feature
@@ -41,6 +41,7 @@ Feature: Project Commits
Scenario: I browse big commit
Given I visit big commit page
Then I see big commit warning
+ And I see "Reload with full diff" link
Scenario: I browse a commit with an image
Given I visit a commit with an image that changed
diff --git a/features/project/hooks.feature b/features/project/hooks.feature
index 1a60846a23e..627738004c4 100644
--- a/features/project/hooks.feature
+++ b/features/project/hooks.feature
@@ -13,6 +13,11 @@ Feature: Project Hooks
When I submit new hook
Then I should see newly created hook
+ Scenario: I add new hook with SSL verification enabled
+ Given I visit project hooks page
+ When I submit new hook with SSL verification enabled
+ Then I should see newly created hook with SSL verification enabled
+
Scenario: I test hook
Given project has hook
And I visit project hooks page
diff --git a/features/project/wiki.feature b/features/project/wiki.feature
index 2ebfa3c1660..af970ecf2d0 100644
--- a/features/project/wiki.feature
+++ b/features/project/wiki.feature
@@ -91,3 +91,15 @@ Feature: Project Wiki
And I view the page history of a Wiki page that has a path
Then I should see a non-escaped path
And I should see the page history
+
+ @javascript
+ Scenario: View an old page version of a Wiki page
+ Given I create a New page with paths
+ And I click on the "Pages" button
+ And I edit the Wiki page with a path
+ Then I should see a non-escaped path
+ And I should see the Editing page
+ And I change the content
+ Then I click on Page History
+ And I should see the page history
+ And I should see a link with a version ID
diff --git a/features/steps/admin/hooks.rb b/features/steps/admin/hooks.rb
new file mode 100644
index 00000000000..541e25fcb70
--- /dev/null
+++ b/features/steps/admin/hooks.rb
@@ -0,0 +1,15 @@
+class Spinach::Features::AdminHooks < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedAdmin
+
+ step "I submit the form with enabled SSL verification" do
+ fill_in 'hook_url', with: 'http://google.com'
+ check "Enable SSL verification"
+ click_on "Add System Hook"
+ end
+
+ step "I see new hook with enabled SSL verification" do
+ expect(page).to have_content "SSL Verification: enabled"
+ end
+end
diff --git a/features/steps/dashboard/starred_projects.rb b/features/steps/dashboard/starred_projects.rb
index 59c73fe63f2..c33813e550b 100644
--- a/features/steps/dashboard/starred_projects.rb
+++ b/features/steps/dashboard/starred_projects.rb
@@ -8,7 +8,7 @@ class Spinach::Features::DashboardStarredProjects < Spinach::FeatureSteps
end
step 'I should not see project "Shop"' do
- page.within 'aside' do
+ page.within '.projects-list' do
expect(page).not_to have_content('Shop')
end
end
diff --git a/features/steps/login_form.rb b/features/steps/login_form.rb
new file mode 100644
index 00000000000..b9ff6ae67fd
--- /dev/null
+++ b/features/steps/login_form.rb
@@ -0,0 +1,25 @@
+class Spinach::Features::LoginForm < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedSnippet
+ include SharedUser
+ include SharedSearch
+
+ step 'Crowd integration enabled' do
+ @providers_orig = Gitlab::OAuth::Provider.providers
+ @omniauth_conf_orig = Gitlab.config.omniauth.enabled
+ expect(Gitlab::OAuth::Provider).to receive(:providers).and_return([:crowd])
+ allow_any_instance_of(ApplicationHelper).to receive(:user_omniauth_authorize_path).and_return(root_path)
+ expect(Gitlab.config.omniauth).to receive(:enabled).and_return(true)
+ end
+
+ step 'I should see Crowd login form' do
+ expect(page).to have_selector '#tab-crowd form'
+ Gitlab::OAuth::Provider.stub(:providers).and_return(@providers_orig)
+ Gitlab.config.omniauth.stub(:enabled).and_return(@omniauth_conf_orig)
+ end
+
+ step 'I visit sign in page' do
+ visit new_user_session_path
+ end
+end
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index e6330ec457e..23e67371f96 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -52,7 +52,6 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I see compared refs' do
- expect(page).to have_content "Compare View"
expect(page).to have_content "Commits (1)"
expect(page).to have_content "Showing 2 changed files"
end
@@ -79,6 +78,12 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
expect(page).to have_content "Too many changes"
end
+ step 'I see "Reload with full diff" link' do
+ link = find_link('Reload with full diff')
+ expect(link[:href]).to end_with('?force_show_diff=true')
+ expect(link[:href]).not_to include('.html')
+ end
+
step 'I visit a commit with an image that changed' do
visit namespace_project_commit_path(@project.namespace, @project, sample_image_commit.id)
end
@@ -92,4 +97,8 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
step 'I see inline diff button' do
expect(page).to have_content "Inline"
end
+
+ step 'I click side-by-side diff button' do
+ find('#parallel-diff-btn').click
+ end
end
diff --git a/features/steps/project/hooks.rb b/features/steps/project/hooks.rb
index 04e3bf78ede..df4a23a3716 100644
--- a/features/steps/project/hooks.rb
+++ b/features/steps/project/hooks.rb
@@ -28,11 +28,24 @@ class Spinach::Features::ProjectHooks < Spinach::FeatureSteps
expect { click_button "Add Web Hook" }.to change(ProjectHook, :count).by(1)
end
+ step 'I submit new hook with SSL verification enabled' do
+ @url = FFaker::Internet.uri("http")
+ fill_in "hook_url", with: @url
+ check "hook_enable_ssl_verification"
+ expect { click_button "Add Web Hook" }.to change(ProjectHook, :count).by(1)
+ end
+
step 'I should see newly created hook' do
expect(current_path).to eq namespace_project_hooks_path(current_project.namespace, current_project)
expect(page).to have_content(@url)
end
+ step 'I should see newly created hook with SSL verification enabled' do
+ expect(current_path).to eq namespace_project_hooks_path(current_project.namespace, current_project)
+ expect(page).to have_content(@url)
+ expect(page).to have_content("SSL Verification: enabled")
+ end
+
step 'I click test hook button' do
stub_request(:post, @hook.url).to_return(status: 200)
click_link 'Test Hook'
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 778dce06359..c92998631ff 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -128,7 +128,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see the proper Inline and Side-by-side links' do
- expect(page).to have_css('#commit-diff-viewtype', count: 2)
+ expect(page).to have_css('#parallel-diff-btn', count: 1)
+ expect(page).to have_css('#inline-diff-btn', count: 1)
end
step 'I switch to the merge request\'s comments tab' do
@@ -225,13 +226,13 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step 'I click link "Hide inline discussion" of the second file' do
page.within '.files [id^=diff]:nth-child(2)' do
- find('.js-toggle-diff-comments').click
+ find('.js-toggle-diff-comments').trigger('click')
end
end
step 'I click link "Show inline discussion" of the second file' do
page.within '.files [id^=diff]:nth-child(2)' do
- find('.js-toggle-diff-comments').click
+ find('.js-toggle-diff-comments').trigger('click')
end
end
diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb
index eebfaee1ede..02207dbffa6 100644
--- a/features/steps/project/wiki.rb
+++ b/features/steps/project/wiki.rb
@@ -3,7 +3,6 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
include SharedProject
include SharedNote
include SharedPaths
- include WikiHelper
step 'I click on the Cancel button' do
page.within(:css, ".form-actions") do
@@ -165,6 +164,10 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
click_on 'Page History'
end
+ step 'I click on Page History' do
+ click_on 'Page History'
+ end
+
step 'I should see the page history' do
expect(page).to have_content('History for')
end
@@ -174,6 +177,10 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
click_button "Search"
end
+ step 'I should see a link with a version ID' do
+ find('a[href*="?version_id"]')
+ end
+
def wiki
@project_wiki = ProjectWiki.new(project, current_user)
end
diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb
index 92e099315d8..eb2ccd9d01e 100644
--- a/features/steps/shared/active_tab.rb
+++ b/features/steps/shared/active_tab.rb
@@ -6,7 +6,7 @@ module SharedActiveTab
end
def ensure_active_sub_tab(content)
- expect(find('div.content ul.nav-tabs li.active')).to have_content(content)
+ expect(find('div.content ul.center-top-menu li.active')).to have_content(content)
end
def ensure_active_sub_nav(content)
@@ -18,7 +18,7 @@ module SharedActiveTab
end
step 'no other sub tabs should be active' do
- expect(page).to have_selector('div.content ul.nav-tabs li.active', count: 1)
+ expect(page).to have_selector('div.content ul.center-top-menu li.active', count: 1)
end
step 'no other sub navs should be active' do
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index 27a95aeb19a..72621911a37 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -198,7 +198,7 @@ module SharedDiffNote
end
step 'I click side-by-side diff button' do
- click_link "Side-by-side"
+ find('#parallel-diff-btn').trigger('click')
end
step 'I see side-by-side diff button' do
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index ca8fbb49101..b4deccb6520 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -71,6 +71,10 @@ module SharedPaths
visit dashboard_path
end
+ step 'I visit dashboard activity page' do
+ visit activity_dashboard_path
+ end
+
step 'I visit dashboard projects page' do
visit projects_dashboard_path
end
diff --git a/features/user.feature b/features/user.feature
index 69618e929c4..35eae842e77 100644
--- a/features/user.feature
+++ b/features/user.feature
@@ -14,11 +14,6 @@ Feature: User
And I should not see project "Internal"
And I should see project "Community"
- Scenario: I visit user "John Doe" page while not signed in when he is not authorized to a public project
- Given "John Doe" owns internal project "Internal"
- When I visit user "John Doe" page
- Then I should be redirected to sign in page
-
# Signed in as someone else
Scenario: I visit user "John Doe" page while signed in as someone else when he owns a public project
diff --git a/lib/api/api.rb b/lib/api/api.rb
index eebd44ea5b6..c09488d3547 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -50,5 +50,6 @@ module API
mount Branches
mount Labels
mount Settings
+ mount Keys
end
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 1f9dd6bc152..8dddcd7ccc3 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -199,6 +199,10 @@ module API
expose :id, :title, :key, :created_at
end
+ class SSHKeyWithUser < SSHKey
+ expose :user, using: Entities::UserFull
+ end
+
class Note < Grape::Entity
expose :id
expose :note, as: :body
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 1ebf9a1f022..76c9cc2e3a4 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -55,6 +55,32 @@ module API
end
end
+ def project_service
+ @project_service ||= begin
+ underscored_service = params[:service_slug].underscore
+
+ if Service.available_services_names.include?(underscored_service)
+ user_project.build_missing_services
+
+ service_method = "#{underscored_service}_service"
+
+ send_service(service_method)
+ end
+ end
+
+ @project_service || not_found!("Service")
+ end
+
+ def send_service(service_method)
+ user_project.send(service_method)
+ end
+
+ def service_attributes
+ @service_attributes ||= project_service.fields.inject([]) do |arr, hash|
+ arr << hash[:name].to_sym
+ end
+ end
+
def find_group(id)
begin
group = Group.find(id)
diff --git a/lib/api/keys.rb b/lib/api/keys.rb
new file mode 100644
index 00000000000..2b723b79504
--- /dev/null
+++ b/lib/api/keys.rb
@@ -0,0 +1,20 @@
+module API
+ # Keys API
+ class Keys < Grape::API
+ before { authenticate! }
+
+ resource :keys do
+ # Get single ssh key by id. Only available to admin users.
+ #
+ # Example Request:
+ # GET /keys/:id
+ get ":id" do
+ authenticated_as_admin!
+
+ key = Key.find(params[:id])
+
+ present key, with: Entities::SSHKeyWithUser
+ end
+ end
+ end
+end
diff --git a/lib/api/services.rb b/lib/api/services.rb
index 3ad59cf3adf..73645cedea4 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -4,73 +4,49 @@ module API
before { authenticate! }
before { authorize_admin_project }
+
resource :projects do
- # Set GitLab CI service for project
- #
- # Parameters:
- # token (required) - CI project token
- # project_url (required) - CI project url
+ # Set <service_slug> service for project
#
# Example Request:
+ #
# PUT /projects/:id/services/gitlab-ci
- put ":id/services/gitlab-ci" do
- required_attributes! [:token, :project_url]
- attrs = attributes_for_keys [:token, :project_url]
- user_project.build_missing_services
-
- if user_project.gitlab_ci_service.update_attributes(attrs.merge(active: true))
- true
- else
- not_found!
- end
- end
-
- # Delete GitLab CI service settings
#
- # Example Request:
- # DELETE /projects/:id/services/gitlab-ci
- delete ":id/services/gitlab-ci" do
- if user_project.gitlab_ci_service
- user_project.gitlab_ci_service.update_attributes(
- active: false,
- token: nil,
- project_url: nil
- )
- end
- end
+ put ':id/services/:service_slug' do
+ if project_service
+ validators = project_service.class.validators.select do |s|
+ s.class == ActiveRecord::Validations::PresenceValidator &&
+ s.attributes != [:project_id]
+ end
- # Set Hipchat service for project
- #
- # Parameters:
- # token (required) - Hipchat token
- # room (required) - Hipchat room name
- #
- # Example Request:
- # PUT /projects/:id/services/hipchat
- put ':id/services/hipchat' do
- required_attributes! [:token, :room]
- attrs = attributes_for_keys [:token, :room]
- user_project.build_missing_services
+ required_attributes! validators.map(&:attributes).flatten.uniq
+ attrs = attributes_for_keys service_attributes
- if user_project.hipchat_service.update_attributes(
- attrs.merge(active: true))
- true
- else
- not_found!
+ if project_service.update_attributes(attrs.merge(active: true))
+ true
+ else
+ not_found!
+ end
end
end
- # Delete Hipchat service settings
+ # Delete <service_slug> service for project
#
# Example Request:
- # DELETE /projects/:id/services/hipchat
- delete ':id/services/hipchat' do
- if user_project.hipchat_service
- user_project.hipchat_service.update_attributes(
- active: false,
- token: nil,
- room: nil
- )
+ #
+ # DELETE /project/:id/services/gitlab-ci
+ #
+ delete ':id/services/:service_slug' do
+ if project_service
+ attrs = service_attributes.inject({}) do |hash, key|
+ hash.merge!(key => nil)
+ end
+
+ if project_service.update_attributes(attrs.merge(active: false))
+ true
+ else
+ not_found!
+ end
end
end
end
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 12292f614e9..0353b3b7ed3 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -1,6 +1,14 @@
require_relative 'shell_env'
module Grack
+ class AuthSpawner
+ def self.call(env)
+ # Avoid issues with instance variables in Grack::Auth persisting across
+ # requests by creating a new instance for each request.
+ Auth.new({}).call(env)
+ end
+ end
+
class Auth < Rack::Auth::Basic
attr_accessor :user, :project, :env
@@ -10,7 +18,7 @@ module Grack
@request = Rack::Request.new(env)
@auth = Request.new(env)
- @gitlab_ci = false
+ @ci = false
# Need this patch due to the rails mount
# Need this if under RELATIVE_URL_ROOT
@@ -26,13 +34,9 @@ module Grack
auth!
if project && authorized_request?
- if ENV['GITLAB_GRACK_AUTH_ONLY'] == '1'
- # Tell gitlab-git-http-server the request is OK, and what the GL_ID is
- render_grack_auth_ok
- else
- @app.call(env)
- end
- elsif @user.nil? && !@gitlab_ci
+ # Tell gitlab-git-http-server the request is OK, and what the GL_ID is
+ render_grack_auth_ok
+ elsif @user.nil? && !@ci
unauthorized
else
render_not_found
@@ -51,8 +55,8 @@ module Grack
# Allow authentication for GitLab CI service
# if valid token passed
- if gitlab_ci_request?(login, password)
- @gitlab_ci = true
+ if ci_request?(login, password)
+ @ci = true
return
end
@@ -64,12 +68,17 @@ module Grack
end
end
- def gitlab_ci_request?(login, password)
- if login == "gitlab-ci-token" && project && project.gitlab_ci?
- token = project.gitlab_ci_service.token
+ def ci_request?(login, password)
+ matched_login = /(?<s>^[a-zA-Z]*-ci)-token$/.match(login)
+
+ if project && matched_login.present? && git_cmd == 'git-upload-pack'
+ underscored_service = matched_login['s'].underscore
- if token.present? && token == password && git_cmd == 'git-upload-pack'
- return true
+ if Service.available_services_names.include?(underscored_service)
+ service_method = "#{underscored_service}_service"
+ service = project.send(service_method)
+
+ return service && service.activated? && service.valid_token?(password)
end
end
@@ -128,11 +137,13 @@ module Grack
end
def authorized_request?
- return true if @gitlab_ci
+ return true if @ci
case git_cmd
when *Gitlab::GitAccess::DOWNLOAD_COMMANDS
- if user
+ if !Gitlab.config.gitlab_shell.upload_pack
+ false
+ elsif user
Gitlab::GitAccess.new(user, project).download_access_check.allowed?
elsif project.public?
# Allow clone/fetch for public projects
@@ -141,7 +152,9 @@ module Grack
false
end
when *Gitlab::GitAccess::PUSH_COMMANDS
- if user
+ if !Gitlab.config.gitlab_shell.receive_pack
+ false
+ elsif user
# Skip user authorization on upload request.
# It will be done by the pre-receive hook in the repository.
true
diff --git a/lib/gitlab/bitbucket_import/client.rb b/lib/gitlab/bitbucket_import/client.rb
index aec44b8c87b..d88a6eaac6b 100644
--- a/lib/gitlab/bitbucket_import/client.rb
+++ b/lib/gitlab/bitbucket_import/client.rb
@@ -52,11 +52,26 @@ module Gitlab
end
def issues(project_identifier)
- JSON.parse(get("/api/1.0/repositories/#{project_identifier}/issues").body)
+ all_issues = []
+ offset = 0
+ per_page = 50 # Maximum number allowed by Bitbucket
+ index = 0
+
+ begin
+ issues = JSON.parse(get(issue_api_endpoint(project_identifier, per_page, offset)).body)
+ # Find out how many total issues are present
+ total = issues["count"] if index == 0
+ all_issues.concat(issues["issues"])
+ offset += issues["issues"].count
+ index += 1
+ end while all_issues.count < total
+
+ all_issues
end
def issue_comments(project_identifier, issue_id)
- JSON.parse(get("/api/1.0/repositories/#{project_identifier}/issues/#{issue_id}/comments").body)
+ comments = JSON.parse(get("/api/1.0/repositories/#{project_identifier}/issues/#{issue_id}/comments").body)
+ comments.sort_by { |comment| comment["utc_created_on"] }
end
def project(project_identifier)
@@ -100,6 +115,10 @@ module Gitlab
response
end
+ def issue_api_endpoint(project_identifier, per_page, offset)
+ "/api/1.0/repositories/#{project_identifier}/issues?sort=utc_created_on&limit=#{per_page}&start=#{offset}"
+ end
+
def config
Gitlab.config.omniauth.providers.find { |provider| provider.name == "bitbucket"}
end
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index d8a7d29f1bf..2355b3c6ddc 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -20,8 +20,18 @@ module Gitlab
#Issues && Comments
issues = client.issues(project_identifier)
- issues["issues"].each do |issue|
- body = @formatter.author_line(issue["reported_by"]["username"], issue["content"])
+ issues.each do |issue|
+ body = ''
+ reporter = nil
+ author = 'Anonymous'
+
+ if issue["reported_by"] && issue["reported_by"]["username"]
+ reporter = issue["reported_by"]["username"]
+ author = reporter
+ end
+
+ body = @formatter.author_line(author)
+ body += issue["content"]
comments = client.issue_comments(project_identifier, issue["local_id"])
@@ -30,14 +40,20 @@ module Gitlab
end
comments.each do |comment|
- body += @formatter.comment(comment["author_info"]["username"], comment["utc_created_on"], comment["content"])
+ author = 'Anonymous'
+
+ if comment["author_info"] && comment["author_info"]["username"]
+ author = comment["author_info"]["username"]
+ end
+
+ body += @formatter.comment(author, comment["utc_created_on"], comment["content"])
end
project.issues.create!(
description: body,
title: issue["title"],
state: %w(resolved invalid duplicate wontfix).include?(issue["status"]) ? 'closed' : 'opened',
- author_id: gl_user_id(project, issue["reported_by"]["username"])
+ author_id: gl_user_id(project, reporter)
)
end
@@ -47,9 +63,13 @@ module Gitlab
private
def gl_user_id(project, bitbucket_id)
- user = User.joins(:identities).find_by("identities.extern_uid = ? AND identities.provider = 'bitbucket'", bitbucket_id.to_s)
- (user && user.id) || project.creator_id
- end
+ if bitbucket_id
+ user = User.joins(:identities).find_by("identities.extern_uid = ? AND identities.provider = 'bitbucket'", bitbucket_id.to_s)
+ (user && user.id) || project.creator_id
+ else
+ project.creator_id
+ end
+ end
end
end
end
diff --git a/lib/gitlab/color_schemes.rb b/lib/gitlab/color_schemes.rb
new file mode 100644
index 00000000000..9c4664df903
--- /dev/null
+++ b/lib/gitlab/color_schemes.rb
@@ -0,0 +1,67 @@
+module Gitlab
+ # Module containing GitLab's syntax color scheme definitions and helper
+ # methods for accessing them.
+ module ColorSchemes
+ # Struct class representing a single Scheme
+ Scheme = Struct.new(:id, :name, :css_class)
+
+ SCHEMES = [
+ Scheme.new(1, 'White', 'white'),
+ Scheme.new(2, 'Dark', 'dark'),
+ Scheme.new(3, 'Solarized Light', 'solarized-light'),
+ Scheme.new(4, 'Solarized Dark', 'solarized-dark'),
+ Scheme.new(5, 'Monokai', 'monokai')
+ ].freeze
+
+ # Convenience method to get a space-separated String of all the color scheme
+ # classes that might be applied to a code block.
+ #
+ # Returns a String
+ def self.body_classes
+ SCHEMES.collect(&:css_class).uniq.join(' ')
+ end
+
+ # Get a Scheme by its ID
+ #
+ # If the ID is invalid, returns the default Scheme.
+ #
+ # id - Integer ID
+ #
+ # Returns a Scheme
+ def self.by_id(id)
+ SCHEMES.detect { |s| s.id == id } || default
+ end
+
+ # Returns the number of defined Schemes
+ def self.count
+ SCHEMES.size
+ end
+
+ # Get the default Scheme
+ #
+ # Returns a Scheme
+ def self.default
+ by_id(1)
+ end
+
+ # Iterate through each Scheme
+ #
+ # Yields the Scheme object
+ def self.each(&block)
+ SCHEMES.each(&block)
+ end
+
+ # Get the Scheme for the specified user, or the default
+ #
+ # user - User record
+ #
+ # Returns a Scheme
+ def self.for_user(user)
+ if user
+ by_id(user.color_scheme_id)
+ else
+ default
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 1a2a50a14d0..0ea1b6a2f6f 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -4,7 +4,7 @@ module Gitlab
key = :current_application_settings
RequestStore.store[key] ||= begin
- if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings')
+ if connect_to_db?
ApplicationSetting.current || ApplicationSetting.create_from_defaults
else
fake_application_settings
@@ -26,5 +26,17 @@ module Gitlab
import_sources: Settings.gitlab['import_sources']
)
end
+
+ private
+
+ def connect_to_db?
+ use_db = if ENV['USE_DB'] == "false"
+ false
+ else
+ true
+ end
+
+ use_db && ActiveRecord::Base.connection.active? && ActiveRecord::Base.connection.table_exists?('application_settings')
+ end
end
end
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index 8c106a61735..bd7340a80f1 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -18,7 +18,8 @@ module Gitlab
direction: :asc).each do |issue|
if issue.pull_request.nil?
- body = @formatter.author_line(issue.user.login, issue.body)
+ body = @formatter.author_line(issue.user.login)
+ body += issue.body
if issue.comments > 0
body += @formatter.comments_header
diff --git a/lib/gitlab/gitlab_import/importer.rb b/lib/gitlab/gitlab_import/importer.rb
index 50594d2b24f..e24b94d6159 100644
--- a/lib/gitlab/gitlab_import/importer.rb
+++ b/lib/gitlab/gitlab_import/importer.rb
@@ -18,7 +18,8 @@ module Gitlab
issues = client.issues(project_identifier)
issues.each do |issue|
- body = @formatter.author_line(issue["author"]["name"], issue["description"])
+ body = @formatter.author_line(issue["author"]["name"])
+ body += issue["description"]
comments = client.issue_comments(project_identifier, issue["id"])
diff --git a/lib/gitlab/import_formatter.rb b/lib/gitlab/import_formatter.rb
index 72e041a90b1..3e54456e936 100644
--- a/lib/gitlab/import_formatter.rb
+++ b/lib/gitlab/import_formatter.rb
@@ -8,8 +8,8 @@ module Gitlab
"\n\n\n**Imported comments:**\n"
end
- def author_line(author, body)
- "*Created by: #{author}*\n\n#{body}"
+ def author_line(author)
+ "*Created by: #{author}*\n\n"
end
end
end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index f7f3ba9ad7d..04a22237478 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -44,9 +44,14 @@ module Gitlab
gl_user.skip_reconfirmation!
gl_user.email = auth_hash.email
- # Build new identity only if we dont have have same one
- gl_user.identities.find_or_initialize_by(provider: auth_hash.provider,
- extern_uid: auth_hash.uid)
+ # find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved.
+ identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider }
+ identity ||= gl_user.identities.build(provider: auth_hash.provider)
+
+ # For a new user set extern_uid to the LDAP DN
+ # For an existing user with matching email but changed DN, update the DN.
+ # For an existing user with no change in DN, this line changes nothing.
+ identity.extern_uid = auth_hash.uid
gl_user
end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 9f6e19a09fd..097caf67a65 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -5,6 +5,32 @@ module Gitlab
#
# See the files in `lib/gitlab/markdown/` for specific processing information.
module Markdown
+ # Convert a Markdown String into an HTML-safe String of HTML
+ #
+ # markdown - Markdown String
+ # context - Hash of context options passed to our HTML Pipeline
+ #
+ # Returns an HTML-safe String
+ def self.render(markdown, context = {})
+ html = renderer.render(markdown)
+ html = gfm(html, context)
+
+ html.html_safe
+ end
+
+ # Convert a Markdown String into HTML without going through the HTML
+ # Pipeline.
+ #
+ # Note that because the pipeline is skipped, SanitizationFilter is as well.
+ # Do not output the result of this method to the user.
+ #
+ # markdown - Markdown String
+ #
+ # Returns a String
+ def self.render_without_gfm(markdown)
+ renderer.render(markdown)
+ end
+
# Provide autoload paths for filters to prevent a circular dependency error
autoload :AutolinkFilter, 'gitlab/markdown/autolink_filter'
autoload :CommitRangeReferenceFilter, 'gitlab/markdown/commit_range_reference_filter'
@@ -18,6 +44,7 @@ module Gitlab
autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter'
autoload :SanitizationFilter, 'gitlab/markdown/sanitization_filter'
autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter'
+ autoload :SyntaxHighlightFilter, 'gitlab/markdown/syntax_highlight_filter'
autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter'
autoload :TaskListFilter, 'gitlab/markdown/task_list_filter'
autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter'
@@ -28,8 +55,7 @@ module Gitlab
# options - A Hash of options used to customize output (default: {}):
# :xhtml - output XHTML instead of HTML
# :reference_only_path - Use relative path for reference links
- # html_options - extra options for the reference links as given to link_to
- def gfm(text, options = {}, html_options = {})
+ def self.gfm(text, options = {})
return text if text.nil?
# Duplicate the string so we don't alter the original, then call to_str
@@ -40,8 +66,8 @@ module Gitlab
options.reverse_merge!(
xhtml: false,
reference_only_path: true,
- project: @project,
- current_user: current_user
+ project: options[:project],
+ current_user: options[:current_user]
)
@pipeline ||= HTML::Pipeline.new(filters)
@@ -61,12 +87,11 @@ module Gitlab
current_user: options[:current_user],
only_path: options[:reference_only_path],
project: options[:project],
- reference_class: html_options[:class],
# RelativeLinkFilter
- ref: @ref,
- requested_path: @path,
- project_wiki: @project_wiki
+ ref: options[:ref],
+ requested_path: options[:path],
+ project_wiki: options[:project_wiki]
}
result = @pipeline.call(text, context)
@@ -83,14 +108,36 @@ module Gitlab
private
+ def self.renderer
+ @markdown ||= begin
+ renderer = Redcarpet::Render::HTML.new
+ Redcarpet::Markdown.new(renderer, redcarpet_options)
+ end
+ end
+
+ def self.redcarpet_options
+ # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
+ @redcarpet_options ||= {
+ fenced_code_blocks: true,
+ footnotes: true,
+ lax_spacing: true,
+ no_intra_emphasis: true,
+ space_after_headers: true,
+ strikethrough: true,
+ superscript: true,
+ tables: true
+ }.freeze
+ end
+
# Filters used in our pipeline
#
# SanitizationFilter should come first so that all generated reference HTML
# goes through untouched.
#
# See https://github.com/jch/html-pipeline#filters for more filters.
- def filters
+ def self.filters
[
+ Gitlab::Markdown::SyntaxHighlightFilter,
Gitlab::Markdown::SanitizationFilter,
Gitlab::Markdown::RelativeLinkFilter,
diff --git a/lib/gitlab/markdown/autolink_filter.rb b/lib/gitlab/markdown/autolink_filter.rb
index 541f1d88ffc..c37c3bc55bf 100644
--- a/lib/gitlab/markdown/autolink_filter.rb
+++ b/lib/gitlab/markdown/autolink_filter.rb
@@ -1,3 +1,4 @@
+require 'gitlab/markdown'
require 'html/pipeline/filter'
require 'uri'
diff --git a/lib/gitlab/markdown/commit_range_reference_filter.rb b/lib/gitlab/markdown/commit_range_reference_filter.rb
index a9f1ee9c161..8613150894b 100644
--- a/lib/gitlab/markdown/commit_range_reference_filter.rb
+++ b/lib/gitlab/markdown/commit_range_reference_filter.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# HTML filter that replaces commit range references with links.
diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb
index eacdf8a6d37..5696b4fa585 100644
--- a/lib/gitlab/markdown/commit_reference_filter.rb
+++ b/lib/gitlab/markdown/commit_reference_filter.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# HTML filter that replaces commit references with links.
diff --git a/lib/gitlab/markdown/cross_project_reference.rb b/lib/gitlab/markdown/cross_project_reference.rb
index 66c256c5104..855748fdccc 100644
--- a/lib/gitlab/markdown/cross_project_reference.rb
+++ b/lib/gitlab/markdown/cross_project_reference.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# Common methods for ReferenceFilters that support an optional cross-project
diff --git a/lib/gitlab/markdown/emoji_filter.rb b/lib/gitlab/markdown/emoji_filter.rb
index 6794ab9c897..da10e4d3760 100644
--- a/lib/gitlab/markdown/emoji_filter.rb
+++ b/lib/gitlab/markdown/emoji_filter.rb
@@ -1,6 +1,7 @@
+require 'action_controller'
+require 'gitlab/markdown'
require 'gitlab_emoji'
require 'html/pipeline/filter'
-require 'action_controller'
module Gitlab
module Markdown
diff --git a/lib/gitlab/markdown/external_issue_reference_filter.rb b/lib/gitlab/markdown/external_issue_reference_filter.rb
index afd28dd8cf3..f7c43e1ca89 100644
--- a/lib/gitlab/markdown/external_issue_reference_filter.rb
+++ b/lib/gitlab/markdown/external_issue_reference_filter.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# HTML filter that replaces external issue tracker references with links.
diff --git a/lib/gitlab/markdown/external_link_filter.rb b/lib/gitlab/markdown/external_link_filter.rb
index c539e0fb823..29e51b6ade6 100644
--- a/lib/gitlab/markdown/external_link_filter.rb
+++ b/lib/gitlab/markdown/external_link_filter.rb
@@ -1,3 +1,4 @@
+require 'gitlab/markdown'
require 'html/pipeline/filter'
module Gitlab
diff --git a/lib/gitlab/markdown/issue_reference_filter.rb b/lib/gitlab/markdown/issue_reference_filter.rb
index ab6f6bc1cf7..01320f80796 100644
--- a/lib/gitlab/markdown/issue_reference_filter.rb
+++ b/lib/gitlab/markdown/issue_reference_filter.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# HTML filter that replaces issue references with links. References to
diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb
index 2186f36f854..3d7445a27f1 100644
--- a/lib/gitlab/markdown/label_reference_filter.rb
+++ b/lib/gitlab/markdown/label_reference_filter.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# HTML filter that replaces label references with links.
diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb
index 884f60f9d53..48248f5219d 100644
--- a/lib/gitlab/markdown/merge_request_reference_filter.rb
+++ b/lib/gitlab/markdown/merge_request_reference_filter.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# HTML filter that replaces merge request references with links. References
diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb
index 47ee1d99da3..9b293c957d6 100644
--- a/lib/gitlab/markdown/reference_filter.rb
+++ b/lib/gitlab/markdown/reference_filter.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/string/output_safety'
+require 'gitlab/markdown'
require 'html/pipeline/filter'
module Gitlab
@@ -9,7 +10,6 @@ module Gitlab
#
# Context options:
# :project (required) - Current project, ignored if reference is cross-project.
- # :reference_class - Custom CSS class added to reference links.
# :only_path - Generate path-only links.
#
# Results:
@@ -70,7 +70,7 @@ module Gitlab
end
def reference_class(type)
- "gfm gfm-#{type} #{context[:reference_class]}".strip
+ "gfm gfm-#{type}"
end
# Iterate through the document's text nodes, yielding the current node's
diff --git a/lib/gitlab/markdown/relative_link_filter.rb b/lib/gitlab/markdown/relative_link_filter.rb
index 30f50b82996..8c5cf51bfe1 100644
--- a/lib/gitlab/markdown/relative_link_filter.rb
+++ b/lib/gitlab/markdown/relative_link_filter.rb
@@ -1,3 +1,4 @@
+require 'gitlab/markdown'
require 'html/pipeline/filter'
require 'uri'
diff --git a/lib/gitlab/markdown/sanitization_filter.rb b/lib/gitlab/markdown/sanitization_filter.rb
index 74b3a8d274f..68ed57f6257 100644
--- a/lib/gitlab/markdown/sanitization_filter.rb
+++ b/lib/gitlab/markdown/sanitization_filter.rb
@@ -1,3 +1,4 @@
+require 'gitlab/markdown'
require 'html/pipeline/filter'
require 'html/pipeline/sanitization_filter'
diff --git a/lib/gitlab/markdown/snippet_reference_filter.rb b/lib/gitlab/markdown/snippet_reference_filter.rb
index 92979a356dc..9e1aab936cb 100644
--- a/lib/gitlab/markdown/snippet_reference_filter.rb
+++ b/lib/gitlab/markdown/snippet_reference_filter.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# HTML filter that replaces snippet references with links. References to
diff --git a/lib/gitlab/markdown/syntax_highlight_filter.rb b/lib/gitlab/markdown/syntax_highlight_filter.rb
new file mode 100644
index 00000000000..86f4385753a
--- /dev/null
+++ b/lib/gitlab/markdown/syntax_highlight_filter.rb
@@ -0,0 +1,39 @@
+require 'gitlab/markdown'
+require 'html/pipeline/filter'
+require 'rouge/plugins/redcarpet'
+
+module Gitlab
+ module Markdown
+ # HTML Filter to highlight fenced code blocks
+ #
+ class SyntaxHighlightFilter < HTML::Pipeline::Filter
+ include Rouge::Plugins::Redcarpet
+
+ def call
+ doc.search('pre > code').each do |node|
+ highlight_node(node)
+ end
+
+ doc
+ end
+
+ def highlight_node(node)
+ language = node.attr('class')
+ code = node.text
+
+ highlighted = block_code(code, language)
+
+ # Replace the parent `pre` element with the entire highlighted block
+ node.parent.replace(highlighted)
+ end
+
+ private
+
+ # Override Rouge::Plugins::Redcarpet#rouge_formatter
+ def rouge_formatter(lexer)
+ Rouge::Formatters::HTMLGitlab.new(
+ cssclass: "code highlight js-syntax-highlight #{lexer.tag}")
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/markdown/table_of_contents_filter.rb b/lib/gitlab/markdown/table_of_contents_filter.rb
index 38887c9778c..bbb3bf7fc8b 100644
--- a/lib/gitlab/markdown/table_of_contents_filter.rb
+++ b/lib/gitlab/markdown/table_of_contents_filter.rb
@@ -1,3 +1,4 @@
+require 'gitlab/markdown'
require 'html/pipeline/filter'
module Gitlab
diff --git a/lib/gitlab/markdown/task_list_filter.rb b/lib/gitlab/markdown/task_list_filter.rb
index c6eb2e2bf6d..2f133ae8500 100644
--- a/lib/gitlab/markdown/task_list_filter.rb
+++ b/lib/gitlab/markdown/task_list_filter.rb
@@ -1,3 +1,4 @@
+require 'gitlab/markdown'
require 'task_list/filter'
module Gitlab
diff --git a/lib/gitlab/markdown/user_reference_filter.rb b/lib/gitlab/markdown/user_reference_filter.rb
index a4aec7a05d1..1871e52df0e 100644
--- a/lib/gitlab/markdown/user_reference_filter.rb
+++ b/lib/gitlab/markdown/user_reference_filter.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
module Markdown
# HTML filter that replaces user or group references with links.
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index e836b05ff25..0961bd80421 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -1,3 +1,5 @@
+require 'gitlab/markdown'
+
module Gitlab
# Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor
@@ -10,7 +12,7 @@ module Gitlab
def analyze(text)
references.clear
- @text = markdown.render(text.dup)
+ @text = Gitlab::Markdown.render_without_gfm(text)
end
%i(user label issue merge_request snippet commit commit_range).each do |type|
@@ -21,10 +23,6 @@ module Gitlab
private
- def markdown
- @markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, GitlabMarkdownHelper::MARKDOWN_OPTIONS)
- end
-
def references
@references ||= Hash.new do |references, type|
type = type.to_sym
@@ -42,7 +40,7 @@ module Gitlab
# Returns the results Array for the requested filter type
def pipeline_result(filter_type)
klass = filter_type.to_s.camelize + 'ReferenceFilter'
- filter = "Gitlab::Markdown::#{klass}".constantize
+ filter = Gitlab::Markdown.const_get(klass)
context = {
project: project,
diff --git a/lib/gitlab/themes.rb b/lib/gitlab/themes.rb
index 5209df92795..83f91de810c 100644
--- a/lib/gitlab/themes.rb
+++ b/lib/gitlab/themes.rb
@@ -37,6 +37,11 @@ module Gitlab
THEMES.detect { |t| t.id == id } || default
end
+ # Returns the number of defined Themes
+ def self.count
+ THEMES.size
+ end
+
# Get the default Theme
#
# Returns a Theme
@@ -51,6 +56,19 @@ module Gitlab
THEMES.each(&block)
end
+ # Get the Theme for the specified user, or the default
+ #
+ # user - User record
+ #
+ # Returns a Theme
+ def self.for_user(user)
+ if user
+ by_id(user.theme_id)
+ else
+ default
+ end
+ end
+
private
def self.default_id
diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb
index 11b0d44f340..779819bc2bf 100644
--- a/lib/gitlab/url_builder.rb
+++ b/lib/gitlab/url_builder.rb
@@ -23,12 +23,12 @@ module Gitlab
def build_issue_url(id)
issue = Issue.find(id)
- issue_url(issue, host: Gitlab.config.gitlab['url'])
+ issue_url(issue)
end
def build_merge_request_url(id)
merge_request = MergeRequest.find(id)
- merge_request_url(merge_request, host: Gitlab.config.gitlab['url'])
+ merge_request_url(merge_request)
end
def build_note_url(id)
@@ -37,22 +37,18 @@ module Gitlab
namespace_project_commit_url(namespace_id: note.project.namespace,
id: note.commit_id,
project_id: note.project,
- host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
elsif note.for_issue?
issue = Issue.find(note.noteable_id)
issue_url(issue,
- host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
elsif note.for_merge_request?
merge_request = MergeRequest.find(note.noteable_id)
merge_request_url(merge_request,
- host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
elsif note.for_project_snippet?
snippet = Snippet.find(note.noteable_id)
project_snippet_url(snippet,
- host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
end
end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
deleted file mode 100644
index f57b56cbdf0..00000000000
--- a/lib/redcarpet/render/gitlab_html.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require 'active_support/core_ext/string/output_safety'
-
-class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
- attr_reader :template
- alias_method :h, :template
-
- def initialize(template, color_scheme, options = {})
- @template = template
- @color_scheme = color_scheme
- @options = options.dup
-
- @options.reverse_merge!(
- # Handled further down the line by Gitlab::Markdown::SanitizationFilter
- escape_html: false,
- project: @template.instance_variable_get("@project")
- )
-
- super(options)
- end
-
- def normal_text(text)
- ERB::Util.html_escape_once(text)
- end
-
- # Stolen from Rouge::Plugins::Redcarpet as this module is not required
- # from Rouge's gem root.
- def block_code(code, language)
- lexer = Rouge::Lexer.find_fancy(language, code) || Rouge::Lexers::PlainText
-
- # XXX HACK: Redcarpet strips hard tabs out of code blocks,
- # so we assume you're not using leading spaces that aren't tabs,
- # and just replace them here.
- if lexer.tag == 'make'
- code.gsub!(/^ /, "\t")
- end
-
- formatter = Rouge::Formatters::HTMLGitlab.new(
- cssclass: "code highlight #{@color_scheme} #{lexer.tag}"
- )
- formatter.format(lexer.lex(code))
- end
-
- def postprocess(full_document)
- h.gfm(full_document, @options)
- end
-end
diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab
index 41a2f254db6..a80e7e77430 100755
--- a/lib/support/init.d/gitlab
+++ b/lib/support/init.d/gitlab
@@ -37,6 +37,10 @@ web_server_pid_path="$pid_path/unicorn.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
mail_room_enabled=false
mail_room_pid_path="$pid_path/mail_room.pid"
+gitlab_git_http_server_pid_path="$pid_path/gitlab-git-http-server.pid"
+gitlab_git_http_server_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-git-http-server.socket -authBackend http://127.0.0.1:8080"
+gitlab_git_http_server_repo_root='/home/git/repositories'
+gitlab_git_http_server_log="$app_root/log/gitlab-git-http-server.log"
shell_path="/bin/bash"
# Read configuration variable file if it is present
@@ -72,6 +76,11 @@ check_pids(){
else
spid=0
fi
+ if [ -f "$gitlab_git_http_server_pid_path" ]; then
+ hpid=$(cat "$gitlab_git_http_server_pid_path")
+ else
+ hpid=0
+ fi
if [ "$mail_room_enabled" = true ]; then
if [ -f "$mail_room_pid_path" ]; then
mpid=$(cat "$mail_room_pid_path")
@@ -85,7 +94,7 @@ check_pids(){
wait_for_pids(){
# We are sleeping a bit here mostly because sidekiq is slow at writing it's pid
i=0;
- while [ ! -f $web_server_pid_path ] || [ ! -f $sidekiq_pid_path ] || { [ "$mail_room_enabled" = true ] && [ ! -f $mail_room_pid_path ]; }; do
+ while [ ! -f $web_server_pid_path ] || [ ! -f $sidekiq_pid_path ] || [ ! -f $gitlab_git_http_server_pid_path ] || { [ "$mail_room_enabled" = true ] && [ ! -f $mail_room_pid_path ]; }; do
sleep 0.1;
i=$((i+1))
if [ $((i%10)) = 0 ]; then
@@ -120,6 +129,12 @@ check_status(){
else
sidekiq_status="-1"
fi
+ if [ $hpid -ne 0 ]; then
+ kill -0 "$hpid" 2>/dev/null
+ gitlab_git_http_server_status="$?"
+ else
+ gitlab_git_http_server_status="-1"
+ fi
if [ "$mail_room_enabled" = true ]; then
if [ $mpid -ne 0 ]; then
kill -0 "$mpid" 2>/dev/null
@@ -128,7 +143,7 @@ check_status(){
mail_room_status="-1"
fi
fi
- if [ $web_status = 0 ] && [ $sidekiq_status = 0 ] && { [ "$mail_room_enabled" != true ] || [ $mail_room_status = 0 ]; }; then
+ if [ $web_status = 0 ] && [ $sidekiq_status = 0 ] && [ $gitlab_git_http_server_status = 0 ] && { [ "$mail_room_enabled" != true ] || [ $mail_room_status = 0 ]; }; then
gitlab_status=0
else
# http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
@@ -156,6 +171,13 @@ check_stale_pids(){
exit 1
fi
fi
+ if [ "$hpid" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ]; then
+ echo "Removing stale gitlab-git-http-server pid. This is most likely caused by gitlab-git-http-server crashing the last time it ran."
+ if ! rm "$gitlab_git_http_server_pid_path"; then
+ echo "Unable to remove stale pid, exiting"
+ exit 1
+ fi
+ fi
if [ "$mail_room_enabled" = true ] && [ "$mpid" != "0" ] && [ "$mail_room_status" != "0" ]; then
echo "Removing stale MailRoom job dispatcher pid. This is most likely caused by MailRoom crashing the last time it ran."
if ! rm "$mail_room_pid_path"; then
@@ -168,7 +190,7 @@ check_stale_pids(){
## If no parts of the service is running, bail out.
exit_if_not_running(){
check_stale_pids
- if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
echo "GitLab is not running."
exit
fi
@@ -184,6 +206,9 @@ start_gitlab() {
if [ "$sidekiq_status" != "0" ]; then
echo "Starting GitLab Sidekiq"
fi
+ if [ "$gitlab_git_http_server_status" != "0" ]; then
+ echo "Starting gitlab-git-http-server"
+ fi
if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" != "0" ]; then
echo "Starting GitLab MailRoom"
fi
@@ -205,6 +230,17 @@ start_gitlab() {
RAILS_ENV=$RAILS_ENV bin/background_jobs start &
fi
+ if [ "$gitlab_git_http_server_status" = "0" ]; then
+ echo "The gitlab-git-http-server is already running with pid $spid, not restarting"
+ else
+ # No need to remove a socket, gitlab-git-http-server does this itself
+ $app_root/bin/daemon_with_pidfile $gitlab_git_http_server_pid_path \
+ $app_root/../gitlab-git-http-server/gitlab-git-http-server \
+ $gitlab_git_http_server_options \
+ $gitlab_git_http_server_repo_root \
+ >> $gitlab_git_http_server_log 2>&1 &
+ fi
+
if [ "$mail_room_enabled" = true ]; then
# If MailRoom is already running, don't start it again.
if [ "$mail_room_status" = "0" ]; then
@@ -226,33 +262,27 @@ stop_gitlab() {
if [ "$web_status" = "0" ]; then
echo "Shutting down GitLab Unicorn"
+ RAILS_ENV=$RAILS_ENV bin/web stop
fi
if [ "$sidekiq_status" = "0" ]; then
echo "Shutting down GitLab Sidekiq"
- fi
- if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; then
- echo "Shutting down GitLab MailRoom"
- fi
-
- # If the Unicorn web server is running, tell it to stop;
- if [ "$web_status" = "0" ]; then
- RAILS_ENV=$RAILS_ENV bin/web stop
- fi
- # And do the same thing for the Sidekiq.
- if [ "$sidekiq_status" = "0" ]; then
RAILS_ENV=$RAILS_ENV bin/background_jobs stop
fi
- # And do the same thing for the MailRoom.
+ if [ "$gitlab_git_http_server_status" = "0" ]; then
+ echo "Shutting down gitlab-git-http-server"
+ kill -- $(cat $gitlab_git_http_server_pid_path)
+ fi
if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; then
+ echo "Shutting down GitLab MailRoom"
RAILS_ENV=$RAILS_ENV bin/mail_room stop
fi
# If something needs to be stopped, lets wait for it to stop. Never use SIGKILL in a script.
- while [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; do
+ while [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_git_http_server_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; do
sleep 1
check_status
printf "."
- if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
printf "\n"
break
fi
@@ -262,6 +292,7 @@ stop_gitlab() {
# Cleaning up unused pids
rm "$web_server_pid_path" 2>/dev/null
# rm "$sidekiq_pid_path" 2>/dev/null # Sidekiq seems to be cleaning up it's own pid.
+ rm -f "$gitlab_git_http_server_pid_path"
if [ "$mail_room_enabled" = true ]; then
rm "$mail_room_pid_path" 2>/dev/null
fi
@@ -272,7 +303,7 @@ stop_gitlab() {
## Prints the status of GitLab and it's components.
print_status() {
check_status
- if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
echo "GitLab is not running."
return
fi
@@ -286,9 +317,14 @@ print_status() {
else
printf "The GitLab Sidekiq job dispatcher is \033[31mnot running\033[0m.\n"
fi
+ if [ "$gitlab_git_http_server_status" = "0" ]; then
+ echo "The gitlab-git-http-server with pid $hpid is running."
+ else
+ printf "The gitlab-git-http-server is \033[31mnot running\033[0m.\n"
+ fi
if [ "$mail_room_enabled" = true ]; then
if [ "$mail_room_status" = "0" ]; then
- echo "The GitLab MailRoom email processor with pid $spid is running."
+ echo "The GitLab MailRoom email processor with pid $mpid is running."
else
printf "The GitLab MailRoom email processor is \033[31mnot running\033[0m.\n"
fi
@@ -324,7 +360,7 @@ reload_gitlab(){
## Restarts Sidekiq and Unicorn.
restart_gitlab(){
check_status
- if [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; then
+ if [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_git_http_server" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; then
stop_gitlab
fi
start_gitlab
diff --git a/lib/support/init.d/gitlab.default.example b/lib/support/init.d/gitlab.default.example
index fd70cb7cc74..aab5acaa72c 100755
--- a/lib/support/init.d/gitlab.default.example
+++ b/lib/support/init.d/gitlab.default.example
@@ -30,6 +30,16 @@ web_server_pid_path="$pid_path/unicorn.pid"
# The default is "$pid_path/sidekiq.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
+gitlab_git_http_server_pid_path="$pid_path/gitlab-git-http-server.pid"
+# The -listenXxx settings determine where gitlab-git-http-server
+# listens for connections from NGINX. To listen on localhost:8181, write
+# '-listenNetwork tcp -listenAddr localhost:8181'.
+# The -authBackend setting tells gitlab-git-http-server where it can reach
+# Unicorn.
+gitlab_git_http_server_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-git-http-server.socket -authBackend http://127.0.0.1:8080"
+gitlab_git_http_server_repo_root="/home/git/repositories"
+gitlab_git_http_server_log="$app_root/log/gitlab-git-http-server.log"
+
# mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled.
# This is required for the Reply by email feature.
# The default is "false"
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index efa0898900f..17f89c8beb6 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -38,10 +38,9 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
-## Experimental: gitlab-git-http-server
-# upstream gitlab-git-http-server {
-# server localhost:8181;
-# }
+upstream gitlab-git-http-server {
+ server unix:/home/git/gitlab/tmp/sockets/gitlab-git-http-server.socket fail_timeout=0;
+}
## Normal HTTP host
server {
@@ -114,25 +113,24 @@ server {
proxy_pass http://gitlab;
}
- ## Experimental: send Git HTTP traffic to gitlab-git-http-server instead of Unicorn
- # location ~ [-\/\w\.]+\.git\/ {
- # ## If you use HTTPS make sure you disable gzip compression
- # ## to be safe against BREACH attack.
- # # gzip off;
-
- # ## https://github.com/gitlabhq/gitlabhq/issues/694
- # ## Some requests take more than 30 seconds.
- # proxy_read_timeout 300;
- # proxy_connect_timeout 300;
- # proxy_redirect off;
-
- # proxy_set_header Host $http_host;
- # proxy_set_header X-Real-IP $remote_addr;
- # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- # proxy_set_header X-Forwarded-Proto $scheme;
-
- # proxy_pass http://gitlab-git-http-server;
- # }
+ location ~ [-\/\w\.]+\.git\/ {
+ ## If you use HTTPS make sure you disable gzip compression
+ ## to be safe against BREACH attack.
+ # gzip off;
+
+ ## https://github.com/gitlabhq/gitlabhq/issues/694
+ ## Some requests take more than 30 seconds.
+ proxy_read_timeout 300;
+ proxy_connect_timeout 300;
+ proxy_redirect off;
+
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ proxy_pass http://gitlab-git-http-server;
+ }
## Enable gzip compression as per rails guide:
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 314525518f1..5ba39fc41a4 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -42,10 +42,9 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
-## Experimental: gitlab-git-http-server
-# upstream gitlab-git-http-server {
-# server localhost:8181;
-# }
+upstream gitlab-git-http-server {
+ server unix:/home/git/gitlab/tmp/sockets/gitlab-git-http-server.socket fail_timeout=0;
+}
## Redirects all HTTP traffic to the HTTPS host
server {
@@ -161,25 +160,24 @@ server {
proxy_pass http://gitlab;
}
- ## Experimental: send Git HTTP traffic to gitlab-git-http-server instead of Unicorn
- # location ~ [-\/\w\.]+\.git\/ {
- # ## If you use HTTPS make sure you disable gzip compression
- # ## to be safe against BREACH attack.
- # gzip off;
-
- # ## https://github.com/gitlabhq/gitlabhq/issues/694
- # ## Some requests take more than 30 seconds.
- # proxy_read_timeout 300;
- # proxy_connect_timeout 300;
- # proxy_redirect off;
-
- # proxy_set_header Host $http_host;
- # proxy_set_header X-Real-IP $remote_addr;
- # proxy_set_header X-Forwarded-Ssl on;
- # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- # proxy_set_header X-Forwarded-Proto $scheme;
- # proxy_pass http://gitlab-git-http-server;
- # }
+ location ~ [-\/\w\.]+\.git\/ {
+ ## If you use HTTPS make sure you disable gzip compression
+ ## to be safe against BREACH attack.
+ gzip off;
+
+ ## https://github.com/gitlabhq/gitlabhq/issues/694
+ ## Some requests take more than 30 seconds.
+ proxy_read_timeout 300;
+ proxy_connect_timeout 300;
+ proxy_redirect off;
+
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-Ssl on;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass http://gitlab-git-http-server;
+ }
## Enable gzip compression as per rails guide:
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 9815582d02d..bcd25ccbaf3 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -278,7 +278,7 @@ namespace :gitlab do
fix_and_rerun
end
end
-
+
def check_uploads
print "Uploads directory setup correctly? ... "
@@ -331,15 +331,18 @@ namespace :gitlab do
end
def check_redis_version
- print "Redis version >= 2.0.0? ... "
+ min_redis_version = "2.4.0"
+ print "Redis version >= #{min_redis_version}? ... "
redis_version = run(%W(redis-cli --version))
- if redis_version.try(:match, /redis-cli 2.\d.\d/) || redis_version.try(:match, /redis-cli 3.\d.\d/)
+ redis_version = redis_version.try(:match, /redis-cli (.*)/)
+ if redis_version &&
+ (Gem::Version.new(redis_version[1]) > Gem::Version.new(min_redis_version))
puts "yes".green
else
puts "no".red
try_fixing_it(
- "Update your redis server to a version >= 2.0.0"
+ "Update your redis server to a version >= #{min_redis_version}"
)
for_more_information(
"gitlab-public-wiki/wiki/Trouble-Shooting-Guide in section sidekiq"
@@ -488,7 +491,7 @@ namespace :gitlab do
else
puts "wrong or missing hooks".red
try_fixing_it(
- sudo_gitlab("#{gitlab_shell_path}/bin/create-hooks"),
+ sudo_gitlab("#{File.join(gitlab_shell_path, 'bin/create-hooks')}"),
'Check the hooks_path in config/gitlab.yml',
'Check your gitlab-shell installation'
)
diff --git a/lib/tasks/services.rake b/lib/tasks/services.rake
new file mode 100644
index 00000000000..3f276a5e12e
--- /dev/null
+++ b/lib/tasks/services.rake
@@ -0,0 +1,89 @@
+services_template = <<-ERB
+# Services
+
+<% services.each do |service| %>
+## <%= service[:title] %>
+
+
+<% unless service[:description].blank? %>
+<%= service[:description] %>
+<% end %>
+
+
+### Create/Edit <%= service[:title] %> service
+
+Set <%= service[:title] %> service for a project.
+<% unless service[:help].blank? %>
+
+> <%= service[:help].gsub("\n", ' ') %>
+
+<% end %>
+
+```
+PUT /projects/:id/services/<%= service[:dashed_name] %>
+
+```
+
+Parameters:
+
+<% service[:params].each do |param| %>
+- `<%= param[:name] %>` <%= param[:required] ? "(**required**)" : "(optional)" %><%= [" -", param[:description]].join(" ").gsub("\n", '') unless param[:description].blank? %>
+
+<% end %>
+
+### Delete <%= service[:title] %> service
+
+Delete <%= service[:title] %> service for a project.
+
+```
+DELETE /projects/:id/services/<%= service[:dashed_name] %>
+
+```
+
+<% end %>
+ERB
+
+namespace :services do
+ task doc: :environment do
+ services = Service.available_services_names.map do |s|
+ service_start = Time.now
+ klass = "#{s}_service".classify.constantize
+
+ service = klass.new
+
+ service_hash = {}
+
+ service_hash[:title] = service.title
+ service_hash[:dashed_name] = s.dasherize
+ service_hash[:description] = service.description
+ service_hash[:help] = service.help
+ service_hash[:params] = service.fields.map do |p|
+ param_hash = {}
+
+ param_hash[:name] = p[:name]
+ param_hash[:description] = p[:placeholder] || p[:title]
+ param_hash[:required] = klass.validators_on(p[:name].to_sym).any? do |v|
+ v.class == ActiveRecord::Validations::PresenceValidator
+ end
+
+ param_hash
+ end.sort_by { |p| p[:required] ? 0 : 1 }
+
+ puts "Collected data for: #{service.title}, #{Time.now-service_start}"
+ service_hash
+ end
+
+ doc_start = Time.now
+ doc_path = File.join(Rails.root, 'doc', 'api', 'services.md')
+
+ result = ERB.new(services_template, 0 , '>')
+ .result(OpenStruct.new(services: services).instance_eval { binding })
+
+ File.open(doc_path, 'w') do |f|
+ f.write result
+ end
+
+ puts "write a new service.md to: #{doc_path.to_s}, #{Time.now-doc_start}"
+
+ end
+end
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
new file mode 100644
index 00000000000..c114f342021
--- /dev/null
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe Projects::RawController do
+ let(:public_project) { create(:project, :public) }
+
+ describe "#show" do
+ context 'regular filename' do
+ let(:id) { 'master/README.md' }
+
+ it 'delivers ASCII file' do
+ get(:show,
+ namespace_id: public_project.namespace.to_param,
+ project_id: public_project.to_param,
+ id: id)
+
+ expect(response.status).to eq(200)
+ expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
+ expect(response.header['Content-Disposition']).
+ to eq("inline")
+ end
+ end
+
+ context 'image header' do
+ let(:id) { 'master/files/images/6049019_460s.jpg' }
+
+ it 'set image content type header' do
+ get(:show,
+ namespace_id: public_project.namespace.to_param,
+ project_id: public_project.to_param,
+ id: id)
+
+ expect(response.status).to eq(200)
+ expect(response.header['Content-Type']).to eq('image/jpeg')
+ end
+ end
+ end
+end
diff --git a/spec/factories/abuse_reports.rb b/spec/factories/abuse_reports.rb
index 29fcbc5e197..8d287ded292 100644
--- a/spec/factories/abuse_reports.rb
+++ b/spec/factories/abuse_reports.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: abuse_reports
+#
+# id :integer not null, primary key
+# reporter_id :integer
+# user_id :integer
+# message :text
+# created_at :datetime
+# updated_at :datetime
+#
+
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 3b7adfe4398..6080d0ccdef 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -19,6 +19,7 @@
# description :text
# position :integer default(0)
# locked_at :datetime
+# updated_by_id :integer
#
FactoryGirl.define do
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index e1009d5916e..9d777ddfccd 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -15,6 +15,7 @@
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
+# updated_by_id :integer
#
require_relative '../support/repo_helpers'
diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb
index 0c1bc53cdb5..7852c39fee2 100644
--- a/spec/features/gitlab_flavored_markdown_spec.rb
+++ b/spec/features/gitlab_flavored_markdown_spec.rb
@@ -77,7 +77,7 @@ describe "GitLab Flavored Markdown", feature: true do
it "should render details in issues#show" do
visit namespace_project_issue_path(project.namespace, project, @issue)
- expect(page).to have_link("@#{fred.username}")
+ expect(page).to have_link(fred.to_reference)
end
end
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index 3da4dfc2b23..c557a1061af 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -64,8 +64,8 @@ describe 'GitLab Markdown', feature: true do
it 'parses fenced code blocks' do
aggregate_failures do
- expect(doc).to have_selector('pre.code.highlight.white.c')
- expect(doc).to have_selector('pre.code.highlight.white.python')
+ expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.c')
+ expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.python')
end
end
@@ -179,7 +179,7 @@ describe 'GitLab Markdown', feature: true do
before(:all) do
@feat = MarkdownFeature.new
- # `gfm` helper depends on a `@project` variable
+ # `markdown` helper expects a `@project` variable
@project = @feat.project
@html = markdown(@feat.raw_markdown)
@@ -224,8 +224,4 @@ describe 'GitLab Markdown', feature: true do
def current_user
@feat.user
end
-
- def user_color_scheme_class
- :white
- end
end
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index da58ab98462..e68a5ec29ab 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -28,8 +28,7 @@ describe EventsHelper do
it 'should display the first line of a code block' do
input = "```\nCode block\nwith two lines\n```"
- expected = '<pre class="code highlight white plaintext"><code>' \
- 'Code block...</code></pre>'
+ expected = %r{<pre.+><code>Code block\.\.\.</code></pre>}
expect(event_note(input)).to match(expected)
end
@@ -55,7 +54,7 @@ describe EventsHelper do
it 'should preserve code color scheme' do
input = "```ruby\ndef test\n 'hello world'\nend\n```"
- expected = '<pre class="code highlight white ruby">' \
+ expected = '<pre class="code highlight js-syntax-highlight ruby">' \
"<code><span class=\"k\">def</span> <span class=\"nf\">test</span>\n" \
" <span class=\"s1\">\'hello world\'</span>\n" \
"<span class=\"k\">end</span>" \
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index a42ccb9b501..5639b3db913 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -19,28 +19,23 @@ describe GitlabMarkdownHelper do
@project = project
end
- describe "#gfm" do
- it "should forward HTML options to links" do
- expect(gfm("Fixed in #{commit.id}", { project: @project }, class: 'foo')).
- to have_selector('a.gfm.foo')
- end
-
+ describe "#markdown" do
describe "referencing multiple objects" do
let(:actual) { "#{merge_request.to_reference} -> #{commit.to_reference} -> #{issue.to_reference}" }
it "should link to the merge request" do
expected = namespace_project_merge_request_path(project.namespace, project, merge_request)
- expect(gfm(actual)).to match(expected)
+ expect(markdown(actual)).to match(expected)
end
it "should link to the commit" do
expected = namespace_project_commit_path(project.namespace, project, commit)
- expect(gfm(actual)).to match(expected)
+ expect(markdown(actual)).to match(expected)
end
it "should link to the issue" do
expected = namespace_project_issue_path(project.namespace, project, issue)
- expect(gfm(actual)).to match(expected)
+ expect(markdown(actual)).to match(expected)
end
end
end
diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb
index d814b562113..06f69262b71 100644
--- a/spec/helpers/preferences_helper_spec.rb
+++ b/spec/helpers/preferences_helper_spec.rb
@@ -1,72 +1,82 @@
require 'spec_helper'
describe PreferencesHelper do
+ describe 'dashboard_choices' do
+ it 'raises an exception when defined choices may be missing' do
+ expect(User).to receive(:dashboards).and_return(foo: 'foo')
+ expect { helper.dashboard_choices }.to raise_error(RuntimeError)
+ end
+
+ it 'raises an exception when defined choices may be using the wrong key' do
+ expect(User).to receive(:dashboards).and_return(foo: 'foo', bar: 'bar')
+ expect { helper.dashboard_choices }.to raise_error(KeyError)
+ end
+
+ it 'provides better option descriptions' do
+ expect(helper.dashboard_choices).to match_array [
+ ['Your Projects (default)', 'projects'],
+ ['Starred Projects', 'stars']
+ ]
+ end
+ end
+
describe 'user_application_theme' do
context 'with a user' do
it "returns user's theme's css_class" do
- user = double('user', theme_id: 3)
- allow(self).to receive(:current_user).and_return(user)
- expect(user_application_theme).to eq 'ui_green'
+ stub_user(theme_id: 3)
+
+ expect(helper.user_application_theme).to eq 'ui_green'
end
it 'returns the default when id is invalid' do
- user = double('user', theme_id: Gitlab::Themes::THEMES.size + 5)
+ stub_user(theme_id: Gitlab::Themes.count + 5)
allow(Gitlab.config.gitlab).to receive(:default_theme).and_return(2)
- allow(self).to receive(:current_user).and_return(user)
- expect(user_application_theme).to eq 'ui_charcoal'
+ expect(helper.user_application_theme).to eq 'ui_charcoal'
end
end
context 'without a user' do
- before do
- allow(self).to receive(:current_user).and_return(nil)
- end
-
it 'returns the default theme' do
- expect(user_application_theme).to eq Gitlab::Themes.default.css_class
+ stub_user
+
+ expect(helper.user_application_theme).to eq Gitlab::Themes.default.css_class
end
end
end
- describe 'dashboard_choices' do
- it 'raises an exception when defined choices may be missing' do
- expect(User).to receive(:dashboards).and_return(foo: 'foo')
- expect { dashboard_choices }.to raise_error(RuntimeError)
- end
+ describe 'user_color_scheme' do
+ context 'with a user' do
+ it "returns user's scheme's css_class" do
+ allow(helper).to receive(:current_user).
+ and_return(double(color_scheme_id: 3))
- it 'raises an exception when defined choices may be using the wrong key' do
- expect(User).to receive(:dashboards).and_return(foo: 'foo', bar: 'bar')
- expect { dashboard_choices }.to raise_error(KeyError)
- end
+ expect(helper.user_color_scheme).to eq 'solarized-light'
+ end
- it 'provides better option descriptions' do
- expect(dashboard_choices).to match_array [
- ['Your Projects (default)', 'projects'],
- ['Starred Projects', 'stars']
- ]
+ it 'returns the default when id is invalid' do
+ allow(helper).to receive(:current_user).
+ and_return(double(color_scheme_id: Gitlab::ColorSchemes.count + 5))
+ end
end
- end
- describe 'user_color_scheme_class' do
- context 'with current_user is nil' do
- it 'should return a string' do
- allow(self).to receive(:current_user).and_return(nil)
- expect(user_color_scheme_class).to be_kind_of(String)
+ context 'without a user' do
+ it 'returns the default theme' do
+ stub_user
+
+ expect(helper.user_color_scheme).
+ to eq Gitlab::ColorSchemes.default.css_class
end
end
+ end
- context 'with a current_user' do
- (1..5).each do |color_scheme_id|
- context "with color_scheme_id == #{color_scheme_id}" do
- it 'should return a string' do
- current_user = double(color_scheme_id: color_scheme_id)
- allow(self).to receive(:current_user).and_return(current_user)
- expect(user_color_scheme_class).to be_kind_of(String)
- end
- end
- end
+ def stub_user(messages = {})
+ if messages.empty?
+ allow(helper).to receive(:current_user).and_return(nil)
+ else
+ allow(helper).to receive(:current_user).
+ and_return(double('user', messages))
end
end
end
diff --git a/spec/javascripts/zen_mode_spec.js.coffee b/spec/javascripts/zen_mode_spec.js.coffee
index 1f4ea58ad48..4cb3836755f 100644
--- a/spec/javascripts/zen_mode_spec.js.coffee
+++ b/spec/javascripts/zen_mode_spec.js.coffee
@@ -29,6 +29,11 @@ describe 'ZenMode', ->
enterZen()
expect(Mousetrap.pause).toHaveBeenCalled()
+ it 'removes textarea styling', ->
+ $('textarea').attr('style', 'height: 400px')
+ enterZen()
+ expect('textarea').not.toHaveAttr('style')
+
describe 'in use', ->
beforeEach ->
enterZen()
diff --git a/spec/lib/gitlab/bitbucket_import/client_spec.rb b/spec/lib/gitlab/bitbucket_import/client_spec.rb
index dd450e9967b..dfe58637eee 100644
--- a/spec/lib/gitlab/bitbucket_import/client_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/client_spec.rb
@@ -14,4 +14,38 @@ describe Gitlab::BitbucketImport::Client do
expect(key).to be_kind_of(Symbol)
end
end
+
+ context 'issues' do
+ let(:per_page) { 50 }
+ let(:count) { 95 }
+ let(:sample_issues) do
+ issues = []
+
+ count.times do |i|
+ issues << { local_id: i }
+ end
+
+ issues
+ end
+ let(:first_sample_data) { { count: count, issues: sample_issues[0..per_page - 1] } }
+ let(:second_sample_data) { { count: count, issues: sample_issues[per_page..count] } }
+ let(:project_id) { 'namespace/repo' }
+
+ 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: {})
+
+ 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: {})
+
+ issues = client.issues(project_id)
+ expect(issues.count).to eq(95)
+ end
+ end
end
diff --git a/spec/lib/gitlab/color_schemes_spec.rb b/spec/lib/gitlab/color_schemes_spec.rb
new file mode 100644
index 00000000000..c7be45dbcd3
--- /dev/null
+++ b/spec/lib/gitlab/color_schemes_spec.rb
@@ -0,0 +1,45 @@
+require 'spec_helper'
+
+describe Gitlab::ColorSchemes do
+ describe '.body_classes' do
+ it 'returns a space-separated list of class names' do
+ css = described_class.body_classes
+
+ expect(css).to include('white')
+ expect(css).to include(' solarized-light ')
+ expect(css).to include(' monokai')
+ end
+ end
+
+ describe '.by_id' do
+ it 'returns a scheme by its ID' do
+ expect(described_class.by_id(1).name).to eq 'White'
+ expect(described_class.by_id(4).name).to eq 'Solarized Dark'
+ end
+ end
+
+ describe '.default' do
+ it 'returns the default scheme' do
+ expect(described_class.default.id).to eq 1
+ end
+ end
+
+ describe '.each' do
+ it 'passes the block to the SCHEMES Array' do
+ ids = []
+ described_class.each { |scheme| ids << scheme.id }
+ expect(ids).not_to be_empty
+ end
+ end
+
+ describe '.for_user' do
+ it 'returns default when user is nil' do
+ expect(described_class.for_user(nil).id).to eq 1
+ end
+
+ it "returns user's preferred color scheme" do
+ user = double(color_scheme_id: 5)
+ expect(described_class.for_user(user).id).to eq 5
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index 7cfca96f4e0..84d9fb54b61 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -47,6 +47,28 @@ describe Gitlab::LDAP::User do
expect(existing_user.ldap_identity.provider).to eql 'ldapmain'
end
+ it 'connects to existing ldap user if the extern_uid changes' do
+ existing_user = create(:omniauth_user, email: 'john@example.com', extern_uid: 'old-uid', provider: 'ldapmain')
+ expect{ ldap_user.save }.not_to change{ User.count }
+
+ existing_user.reload
+ expect(existing_user.ldap_identity.extern_uid).to eql 'my-uid'
+ expect(existing_user.ldap_identity.provider).to eql 'ldapmain'
+ expect(existing_user.id).to eql ldap_user.gl_user.id
+ end
+
+ it 'maintains an identity per provider' do
+ existing_user = create(:omniauth_user, email: 'john@example.com', provider: 'twitter')
+ expect(existing_user.identities.count).to eql(1)
+
+ ldap_user.save
+ expect(ldap_user.gl_user.identities.count).to eql(2)
+
+ # Expect that find_by provider only returns a single instance of an identity and not an Enumerable
+ expect(ldap_user.gl_user.identities.find_by(provider: 'twitter')).to be_instance_of Identity
+ expect(ldap_user.gl_user.identities.find_by(provider: auth_hash.provider)).to be_instance_of Identity
+ end
+
it "creates a new user if not found" do
expect{ ldap_user.save }.to change{ User.count }.by(1)
end
diff --git a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
index 58155284486..3c6c84a0416 100644
--- a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
@@ -75,11 +75,6 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit_range'
end
- it 'includes an optional custom class' do
- doc = filter("See #{reference}", reference_class: 'custom')
- expect(doc.css('a').first.attr('class')).to include 'custom'
- end
-
it 'includes a data-project-id attribute' do
doc = filter("See #{reference}")
link = doc.css('a').first
diff --git a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
index 05a02de4669..9ed438252b3 100644
--- a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
@@ -71,11 +71,6 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit'
end
- it 'includes an optional custom class' do
- doc = filter("See #{reference}", reference_class: 'custom')
- expect(doc.css('a').first.attr('class')).to include 'custom'
- end
-
it 'includes a data-project-id attribute' do
doc = filter("See #{reference}")
link = doc.css('a').first
diff --git a/spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb b/spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb
index f16095bc2b2..d8c2970b6bd 100644
--- a/spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb
@@ -68,11 +68,6 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-issue'
end
- it 'includes an optional custom class' do
- doc = filter("Issue #{reference}", reference_class: 'custom')
- expect(doc.css('a').first.attr('class')).to include 'custom'
- end
-
it 'supports an :only_path context' do
doc = filter("Issue #{reference}", only_path: true)
link = doc.css('a').first.attr('href')
diff --git a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
index 35b1ba5f132..1dd54f58588 100644
--- a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
@@ -68,11 +68,6 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-issue'
end
- it 'includes an optional custom class' do
- doc = filter("Issue #{reference}", reference_class: 'custom')
- expect(doc.css('a').first.attr('class')).to include 'custom'
- end
-
it 'includes a data-project-id attribute' do
doc = filter("Issue #{reference}")
link = doc.css('a').first
diff --git a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
index fabe0411e46..e32089de376 100644
--- a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
@@ -25,11 +25,6 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-label'
end
- it 'includes an optional custom class' do
- doc = filter("Label #{reference}", reference_class: 'custom')
- expect(doc.css('a').first.attr('class')).to include 'custom'
- end
-
it 'includes a data-project-id attribute' do
doc = filter("Label #{reference}")
link = doc.css('a').first
diff --git a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
index 5cef52b1916..66616b93368 100644
--- a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
@@ -56,11 +56,6 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-merge_request'
end
- it 'includes an optional custom class' do
- doc = filter("Merge #{reference}", reference_class: 'custom')
- expect(doc.css('a').first.attr('class')).to include 'custom'
- end
-
it 'includes a data-project-id attribute' do
doc = filter("Merge #{reference}")
link = doc.css('a').first
diff --git a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
index 678b171e99e..fd3f0d20fad 100644
--- a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
@@ -55,11 +55,6 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-snippet'
end
- it 'includes an optional custom class' do
- doc = filter("Snippet #{reference}", reference_class: 'custom')
- expect(doc.css('a').first.attr('class')).to include 'custom'
- end
-
it 'includes a data-project-id attribute' do
doc = filter("Snippet #{reference}")
link = doc.css('a').first
diff --git a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
index a5405e14a73..b2155fab59b 100644
--- a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
@@ -121,7 +121,6 @@ module Gitlab::Markdown
end
it 'links with adjacent text' do
- skip "TODO (rspeicher): Re-enable when usernames can't end in periods."
doc = filter("Mention me (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{reference}<\/a>\.\)/)
end
@@ -131,11 +130,6 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-project_member'
end
- it 'includes an optional custom class' do
- doc = filter("Hey #{reference}", reference_class: 'custom')
- expect(doc.css('a').first.attr('class')).to include 'custom'
- end
-
it 'supports an :only_path context' do
doc = filter("Hey #{reference}", only_path: true)
link = doc.css('a').first.attr('href')
diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb
index 9c6c3fd8104..e554458e41c 100644
--- a/spec/lib/gitlab/themes_spec.rb
+++ b/spec/lib/gitlab/themes_spec.rb
@@ -43,9 +43,6 @@ describe Gitlab::Themes do
ids = []
described_class.each { |theme| ids << theme.id }
expect(ids).not_to be_empty
-
- # TODO (rspeicher): RSpec 3.x
- # expect(described_class.each).to yield_with_arg(described_class::Theme)
end
end
end
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index d83004a8388..635a6e2518c 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: abuse_reports
+#
+# id :integer not null, primary key
+# reporter_id :integer
+# user_id :integer
+# message :text
+# created_at :datetime
+# updated_at :datetime
+#
+
require 'rails_helper'
RSpec.describe AbuseReport, type: :model do
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index bc14ff98fd8..de0b2ef4cda 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -22,6 +22,7 @@
# user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
+# import_sources :text
#
require 'spec_helper'
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 9bac451c28c..cf336d82957 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -2,19 +2,20 @@
#
# Table name: issues
#
-# id :integer not null, primary key
-# title :string(255)
-# assignee_id :integer
-# author_id :integer
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# position :integer default(0)
-# branch_name :string(255)
-# description :text
-# milestone_id :integer
-# state :string(255)
-# iid :integer
+# id :integer not null, primary key
+# title :string(255)
+# assignee_id :integer
+# author_id :integer
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# position :integer default(0)
+# branch_name :string(255)
+# description :text
+# milestone_id :integer
+# state :string(255)
+# iid :integer
+# updated_by_id :integer
#
require 'spec_helper'
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index b91687bc09f..17a49013d25 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -19,6 +19,7 @@
# description :text
# position :integer default(0)
# locked_at :datetime
+# updated_by_id :integer
#
require 'spec_helper'
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 331505a01b3..3a0b194ba1e 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -15,6 +15,7 @@
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
+# updated_by_id :integer
#
require 'spec_helper'
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
new file mode 100644
index 00000000000..bad9a9e6e1a
--- /dev/null
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -0,0 +1,107 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
+#
+
+require 'spec_helper'
+
+describe DroneCiService do
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to have_one(:service_hook) }
+ end
+
+ describe 'validations' do
+ context 'active' do
+ before { allow(subject).to receive(:activated?).and_return(true) }
+
+ it { is_expected.to validate_presence_of(:token) }
+ it { is_expected.to validate_presence_of(:drone_url) }
+ it { is_expected.to allow_value('ewf9843kdnfdfs89234n').for(:token) }
+ it { is_expected.to allow_value('http://ci.example.com').for(:drone_url) }
+ it { is_expected.not_to allow_value('token with spaces').for(:token) }
+ it { is_expected.not_to allow_value('token/with%spaces').for(:token) }
+ it { is_expected.not_to allow_value('this is not url').for(:drone_url) }
+ it { is_expected.not_to allow_value('http//noturl').for(:drone_url) }
+ it { is_expected.not_to allow_value('ftp://ci.example.com').for(:drone_url) }
+ end
+
+ context 'inactive' do
+ before { allow(subject).to receive(:activated?).and_return(false) }
+
+ it { is_expected.not_to validate_presence_of(:token) }
+ it { is_expected.not_to validate_presence_of(:drone_url) }
+ it { is_expected.to allow_value('ewf9843kdnfdfs89234n').for(:token) }
+ it { is_expected.to allow_value('http://drone.example.com').for(:drone_url) }
+ it { is_expected.to allow_value('token with spaces').for(:token) }
+ it { is_expected.to allow_value('ftp://drone.example.com').for(:drone_url) }
+ end
+ end
+
+ shared_context :drone_ci_service do
+ let(:drone) { DroneCiService.new }
+ let(:project) { create(:project, name: 'project') }
+ let(:path) { "#{project.namespace.path}/#{project.path}" }
+ let(:drone_url) { 'http://drone.example.com' }
+ let(:sha) { '2ab7834c' }
+ let(:branch) { 'dev' }
+ let(:token) { 'secret' }
+ let(:iid) { rand(1..9999) }
+
+ before(:each) do
+ allow(drone).to receive_messages(
+ project_id: project.id,
+ project: project,
+ active: true,
+ drone_url: drone_url,
+ token: token
+ )
+ end
+ end
+
+ describe "service page/path methods" do
+ include_context :drone_ci_service
+
+ # URL's
+ let(:commit_page) { "#{drone_url}/gitlab/#{path}/redirect/commits/#{sha}?branch=#{branch}" }
+ let(:merge_request_page) { "#{drone_url}/gitlab/#{path}/redirect/pulls/#{iid}" }
+ let(:commit_status_path) { "#{drone_url}/gitlab/#{path}/commits/#{sha}?branch=#{branch}&access_token=#{token}" }
+ let(:merge_request_status_path) { "#{drone_url}/gitlab/#{path}/pulls/#{iid}?access_token=#{token}" }
+
+ it { expect(drone.build_page(sha, branch)).to eq(commit_page) }
+ it { expect(drone.commit_page(sha, branch)).to eq(commit_page) }
+ it { expect(drone.merge_request_page(iid, sha, branch)).to eq(merge_request_page) }
+ it { expect(drone.commit_status_path(sha, branch)).to eq(commit_status_path) }
+ it { expect(drone.merge_request_status_path(iid, sha, branch)).to eq(merge_request_status_path) }
+ end
+
+ describe "execute" do
+ include_context :drone_ci_service
+
+ let(:user) { create(:user, username: 'username') }
+ let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
+
+ it do
+ service_hook = double
+ expect(service_hook).to receive(:execute)
+ expect(drone).to receive(:service_hook).and_return(service_hook)
+
+ drone.execute(push_sample_data)
+ end
+ end
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index a46e789eab4..eeb9069aa17 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2,62 +2,58 @@
#
# 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)
-# 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)
-# created_at :datetime
-# updated_at :datetime
-# name :string(255)
-# 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)
-# theme_id :integer default(1), not null
-# bio :string(255)
-# failed_attempts :integer default(0)
-# locked_at :datetime
-# username :string(255)
-# can_create_group :boolean default(TRUE), not null
-# can_create_team :boolean default(TRUE), not null
-# state :string(255)
-# 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)
-# confirmed_at :datetime
-# confirmation_sent_at :datetime
-# unconfirmed_email :string(255)
-# hide_no_ssh_key :boolean default(FALSE)
-# website_url :string(255) default(""), not null
-# github_access_token :string(255)
-# gitlab_access_token :string(255)
-# notification_email :string(255)
-# hide_no_password :boolean default(FALSE)
-# password_automatically_set :boolean default(FALSE)
-# bitbucket_access_token :string(255)
-# bitbucket_access_token_secret :string(255)
-# location :string(255)
-# encrypted_otp_secret :string(255)
-# encrypted_otp_secret_iv :string(255)
-# encrypted_otp_secret_salt :string(255)
-# otp_required_for_login :boolean default(FALSE), not null
-# otp_backup_codes :text
-# public_email :string(255) default(""), not null
-# dashboard :integer default(0)
-# project_view :integer default(0)
+# id :integer not null, primary key
+# email :string(255) default(""), not null
+# encrypted_password :string(255) default(""), not null
+# reset_password_token :string(255)
+# 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)
+# created_at :datetime
+# updated_at :datetime
+# name :string(255)
+# 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)
+# theme_id :integer default(1), not null
+# bio :string(255)
+# failed_attempts :integer default(0)
+# locked_at :datetime
+# username :string(255)
+# can_create_group :boolean default(TRUE), not null
+# can_create_team :boolean default(TRUE), not null
+# state :string(255)
+# 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)
+# confirmed_at :datetime
+# confirmation_sent_at :datetime
+# unconfirmed_email :string(255)
+# hide_no_ssh_key :boolean default(FALSE)
+# website_url :string(255) default(""), not null
+# notification_email :string(255)
+# 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)
+# otp_required_for_login :boolean default(FALSE), not null
+# otp_backup_codes :text
+# public_email :string(255) default(""), not null
+# dashboard :integer default(0)
+# project_view :integer default(0)
#
require 'spec_helper'
diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb
new file mode 100644
index 00000000000..d2b87f88712
--- /dev/null
+++ b/spec/requests/api/keys_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe API::API, api: true do
+ include ApiHelpers
+
+ let(:user) { create(:user) }
+ let(:admin) { create(:admin) }
+ let(:key) { create(:key, user: user) }
+ let(:email) { create(:email, user: user) }
+
+ describe 'GET /keys/:uid' do
+ before { admin }
+
+ context 'when unauthenticated' do
+ it 'should return authentication error' do
+ get api("/keys/#{key.id}")
+ expect(response.status).to eq(401)
+ end
+ end
+
+ context 'when authenticated' do
+ it 'should return 404 for non-existing key' do
+ get api('/keys/999999', admin)
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Not found')
+ end
+
+ it 'should return single ssh key with user information' do
+ user.keys << key
+ user.save
+ get api("/keys/#{key.id}", admin)
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(key.title)
+ expect(json_response['user']['id']).to eq(user.id)
+ expect(json_response['user']['username']).to eq(user.username)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 6d29a28580a..c297904614a 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -5,64 +5,47 @@ describe API::API, api: true do
let(:user) { create(:user) }
let(:project) {create(:project, creator_id: user.id, namespace: user.namespace) }
- describe "POST /projects/:id/services/gitlab-ci" do
- it "should update gitlab-ci settings" do
- put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'secrettoken', project_url: "http://ci.example.com/projects/1"
-
- expect(response.status).to eq(200)
- end
-
- it "should return if required fields missing" do
- put api("/projects/#{project.id}/services/gitlab-ci", user), project_url: "http://ci.example.com/projects/1", active: true
-
- expect(response.status).to eq(400)
- end
-
- it "should return if the format of token is invalid" do
- put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'token-with dashes and spaces%', project_url: "http://ci.example.com/projects/1", active: true
-
- expect(response.status).to eq(404)
- end
-
- it "should return if the format of token is invalid" do
- put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'token-with dashes and spaces%', project_url: "ftp://ci.example/projects/1", active: true
-
- expect(response.status).to eq(404)
- end
- end
-
- describe "DELETE /projects/:id/services/gitlab-ci" do
- it "should update gitlab-ci settings" do
- delete api("/projects/#{project.id}/services/gitlab-ci", user)
-
- expect(response.status).to eq(200)
- expect(project.gitlab_ci_service).to be_nil
- end
- end
-
- describe 'PUT /projects/:id/services/hipchat' do
- it 'should update hipchat settings' do
- put api("/projects/#{project.id}/services/hipchat", user),
- token: 'secret-token', room: 'test'
-
- expect(response.status).to eq(200)
- expect(project.hipchat_service).not_to be_nil
- end
-
- it 'should return if required fields missing' do
- put api("/projects/#{project.id}/services/gitlab-ci", user),
- token: 'secret-token', active: true
-
- expect(response.status).to eq(400)
- end
- end
-
- describe 'DELETE /projects/:id/services/hipchat' do
- it 'should delete hipchat settings' do
- delete api("/projects/#{project.id}/services/hipchat", user)
-
- expect(response.status).to eq(200)
- expect(project.hipchat_service).to be_nil
+ Service.available_services_names.each do |service|
+ describe "PUT /projects/:id/services/#{service.dasherize}" do
+ include_context service
+
+ it "should update #{service} settings" do
+ put api("/projects/#{project.id}/services/#{dashed_service}", user), service_attrs
+
+ expect(response.status).to eq(200)
+ end
+
+ it "should return if required fields missing" do
+ attrs = service_attrs
+
+ required_attributes = service_attrs_list.select do |attr|
+ service_klass.validators_on(attr).any? do |v|
+ v.class == ActiveRecord::Validations::PresenceValidator
+ end
+ end
+
+ if required_attributes.empty?
+ expected_code = 200
+ else
+ attrs.delete(required_attributes.shuffle.first)
+ expected_code = 400
+ end
+
+ put api("/projects/#{project.id}/services/#{dashed_service}", user), attrs
+
+ expect(response.status).to eq(expected_code)
+ end
+ end
+
+ describe "DELETE /projects/:id/services/#{service.dasherize}" do
+ include_context service
+
+ it "should delete #{service}" do
+ delete api("/projects/#{project.id}/services/#{dashed_service}", user)
+
+ expect(response.status).to eq(200)
+ expect(project.send(service_method).activated?).to be_falsey
+ end
end
end
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 9da6c9dc949..8865335d0d1 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -31,13 +31,16 @@ describe NotificationService do
describe 'Notes' do
context 'issue note' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:empty_project, :private) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
- let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') }
+ let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced, @outsider also') }
before do
build_team(note.project)
+ project.team << [issue.author, :master]
+ project.team << [issue.assignee, :master]
+ project.team << [note.author, :master]
end
describe :new_note do
@@ -53,6 +56,7 @@ describe NotificationService do
should_not_email(@u_participating.id)
should_not_email(@u_disabled.id)
should_not_email(@unsubscriber.id)
+ should_not_email(@u_outsider_mentioned)
notification.new_note(note)
end
@@ -444,12 +448,15 @@ describe NotificationService do
@u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_MENTION)
@u_committer = create(:user, username: 'committer')
@u_not_mentioned = create(:user, username: 'regular', notification_level: Notification::N_PARTICIPATING)
+ @u_outsider_mentioned = create(:user, username: 'outsider')
project.team << [@u_watcher, :master]
project.team << [@u_participating, :master]
+ project.team << [@u_participant_mentioned, :master]
project.team << [@u_disabled, :master]
project.team << [@u_mentioned, :master]
project.team << [@u_committer, :master]
+ project.team << [@u_not_mentioned, :master]
end
def add_users_with_subscription(project, issuable)
diff --git a/spec/support/services_shared_context.rb b/spec/support/services_shared_context.rb
new file mode 100644
index 00000000000..4d007ae55ee
--- /dev/null
+++ b/spec/support/services_shared_context.rb
@@ -0,0 +1,21 @@
+Service.available_services_names.each do |service|
+ shared_context service do
+ let(:dashed_service) { service.dasherize }
+ let(:service_method) { "#{service}_service".to_sym }
+ let(:service_klass) { "#{service}_service".classify.constantize }
+ let(:service_attrs_list) { service_klass.new.fields.inject([]) {|arr, hash| arr << hash[:name].to_sym } }
+ let(:service_attrs) do
+ service_attrs_list.inject({}) do |hash, k|
+ if k =~ /^(token*|.*_token|.*_key)/
+ hash.merge!(k => 'secrettoken')
+ elsif k =~ /^(.*_url|url|webhook)/
+ hash.merge!(k => "http://example.com")
+ elsif service == 'irker' && k == :recipients
+ hash.merge!(k => 'irc://irc.network.net:666/#channel')
+ else
+ hash.merge!(k => "someword")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb
new file mode 100644
index 00000000000..3600c771075
--- /dev/null
+++ b/spec/workers/emails_on_push_worker_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe EmailsOnPushWorker do
+ include RepoHelpers
+
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:data) { Gitlab::PushDataBuilder.build_sample(project, user) }
+
+ subject { EmailsOnPushWorker.new }
+
+ before do
+ allow(Project).to receive(:find).and_return(project)
+ end
+
+ describe "#perform" do
+ it "sends mail" do
+ subject.perform(project.id, user.email, data.stringify_keys)
+
+ email = ActionMailer::Base.deliveries.last
+ expect(email.subject).to include('Change some files')
+ expect(email.to).to eq([user.email])
+ end
+
+ it "gracefully handles an input SMTP error" do
+ ActionMailer::Base.deliveries.clear
+ allow(Notify).to receive(:repository_push_email).and_raise(Net::SMTPFatalError)
+
+ subject.perform(project.id, user.email, data.stringify_keys)
+
+ expect(ActionMailer::Base.deliveries.count).to eq(0)
+ end
+ end
+end
diff --git a/spec/workers/merge_worker_spec.rb b/spec/workers/merge_worker_spec.rb
new file mode 100644
index 00000000000..b11c5de94e3
--- /dev/null
+++ b/spec/workers/merge_worker_spec.rb
@@ -0,0 +1,28 @@
+require 'spec_helper'
+
+describe MergeWorker do
+ describe "remove source branch" do
+ let!(:merge_request) { create(:merge_request, source_branch: "markdown") }
+ let!(:source_project) { merge_request.source_project }
+ let!(:project) { merge_request.project }
+ let!(:author) { merge_request.author }
+
+ before do
+ source_project.team << [author, :master]
+ source_project.repository.expire_branch_names
+ end
+
+ it 'clears cache of source repo after removing source branch' do
+ expect(source_project.repository.branch_names).to include('markdown')
+
+ MergeWorker.new.perform(
+ merge_request.id, merge_request.author_id,
+ commit_message: 'wow such merge',
+ should_remove_source_branch: true)
+
+ merge_request.reload
+ expect(merge_request).to be_merged
+ expect(source_project.repository.branch_names).not_to include('markdown')
+ end
+ end
+end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 46eae9ab081..e4151b9bb6a 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -4,7 +4,7 @@ describe PostReceive do
let(:changes) { "123456 789012 refs/heads/tést\n654321 210987 refs/tags/tag" }
let(:wrongly_encoded_changes) { changes.encode("ISO-8859-1").force_encoding("UTF-8") }
let(:base64_changes) { Base64.encode64(wrongly_encoded_changes) }
-
+
context "as a resque worker" do
it "reponds to #perform" do
expect(PostReceive.new).to respond_to(:perform)