summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAchilleas Pipinellis <axilleas@axilleas.me>2016-01-22 09:34:45 +0100
committerAchilleas Pipinellis <axilleas@axilleas.me>2016-01-22 09:34:45 +0100
commit831eb9468d5f82bd7d0c4e51e6ce87ca86aeca8c (patch)
tree739f342da21ad303605f997eb578ef5ce18d256d
parentb4d61ac46babc04f67bb191c477dddc88e10ad45 (diff)
parent8be4e545635f0f01993290b4577dbe38e74c6bbf (diff)
downloadgitlab-ce-831eb9468d5f82bd7d0c4e51e6ce87ca86aeca8c.tar.gz
Merge branch 'master' into doc_refactor_commits_api
-rw-r--r--CHANGELOG20
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock7
-rwxr-xr-x[-rw-r--r--]Rakefile0
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/OFL.txt0
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Black.ttf.woffbin113800 -> 113800 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Black.ttf.woff2bin82052 -> 82052 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-BlackIt.ttf.woffbin49704 -> 49704 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2bin34812 -> 34812 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Bold.ttf.woffbin117872 -> 117872 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Bold.ttf.woff2bin85604 -> 85604 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-BoldIt.ttf.woffbin50608 -> 50608 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2bin35864 -> 35864 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-ExtraLight.ttf.woffbin114336 -> 114336 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2bin82808 -> 82808 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woffbin49684 -> 49684 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2bin34560 -> 34560 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-It.ttf.woffbin51012 -> 51012 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-It.ttf.woff2bin36016 -> 36016 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Light.ttf.woffbin118284 -> 118284 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Light.ttf.woff2bin86336 -> 86336 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-LightIt.ttf.woffbin50992 -> 50992 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-LightIt.ttf.woff2bin35952 -> 35952 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Regular.ttf.woffbin119064 -> 119064 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Regular.ttf.woff2bin86844 -> 86844 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Semibold.ttf.woffbin118412 -> 118412 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Semibold.ttf.woff2bin86196 -> 86196 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woffbin50924 -> 50924 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2bin35984 -> 35984 bytes
-rw-r--r--app/assets/javascripts/awards_handler.coffee17
-rw-r--r--app/assets/javascripts/build_artifacts.js.coffee14
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee3
-rw-r--r--app/assets/javascripts/shortcuts.js.coffee1
-rw-r--r--app/assets/javascripts/shortcuts_tree.coffee4
-rw-r--r--app/assets/javascripts/star.js.coffee4
-rw-r--r--app/assets/stylesheets/framework/common.scss8
-rw-r--r--app/assets/stylesheets/framework/files.scss21
-rw-r--r--app/assets/stylesheets/framework/jquery.scss11
-rw-r--r--app/assets/stylesheets/framework/pagination.scss28
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap_variables.scss22
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/highlight/dark.scss36
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss36
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss36
-rw-r--r--app/assets/stylesheets/highlight/solarized_light.scss36
-rw-r--r--app/assets/stylesheets/highlight/white.scss60
-rw-r--r--app/assets/stylesheets/pages/diff.scss57
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss36
-rw-r--r--app/assets/stylesheets/pages/note_form.scss12
-rw-r--r--app/assets/stylesheets/pages/notes.scss3
-rw-r--r--app/assets/stylesheets/pages/projects.scss6
-rw-r--r--app/assets/stylesheets/pages/search.scss4
-rw-r--r--app/controllers/admin/application_settings_controller.rb4
-rw-r--r--app/controllers/application_controller.rb12
-rw-r--r--app/controllers/concerns/creates_commit.rb2
-rw-r--r--app/controllers/projects/blob_controller.rb9
-rw-r--r--app/controllers/projects/commit_controller.rb1
-rw-r--r--app/controllers/projects/compare_controller.rb3
-rw-r--r--app/controllers/projects/merge_requests_controller.rb8
-rw-r--r--app/controllers/registrations_controller.rb5
-rw-r--r--app/helpers/blob_helper.rb33
-rw-r--r--app/helpers/commits_helper.rb2
-rw-r--r--app/helpers/diff_helper.rb69
-rw-r--r--app/mailers/emails/builds.rb13
-rw-r--r--app/mailers/emails/projects.rb6
-rw-r--r--app/mailers/notify.rb15
-rw-r--r--app/models/application_setting.rb8
-rw-r--r--app/models/ci/build.rb8
-rw-r--r--app/models/member.rb7
-rw-r--r--app/models/members/project_member.rb6
-rw-r--r--app/models/merge_request.rb19
-rw-r--r--app/models/merge_request_diff.rb9
-rw-r--r--app/models/note.rb10
-rw-r--r--app/models/project.rb11
-rw-r--r--app/models/project_services/ci_service.rb8
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb4
-rw-r--r--app/models/project_services/issue_tracker_service.rb6
-rw-r--r--app/models/service.rb11
-rw-r--r--app/models/user.rb5
-rw-r--r--app/services/notification_service.rb21
-rw-r--r--app/views/admin/application_settings/_form.html.haml37
-rw-r--r--app/views/kaminari/gitlab/_next_page.html.haml8
-rw-r--r--app/views/kaminari/gitlab/_paginator.html.haml4
-rw-r--r--app/views/kaminari/gitlab/_prev_page.html.haml8
-rw-r--r--app/views/layouts/header/_default.html.haml3
-rw-r--r--app/views/profiles/show.html.haml4
-rw-r--r--app/views/projects/artifacts/_tree_directory.html.haml1
-rw-r--r--app/views/projects/artifacts/_tree_file.html.haml2
-rw-r--r--app/views/projects/artifacts/browse.html.haml8
-rw-r--r--app/views/projects/blame/show.html.haml22
-rw-r--r--app/views/projects/blob/diff.html.haml5
-rw-r--r--app/views/projects/blob/preview.html.haml12
-rw-r--r--app/views/projects/builds/index.html.haml7
-rw-r--r--app/views/projects/builds/show.html.haml2
-rw-r--r--app/views/projects/commit/show.html.haml3
-rw-r--r--app/views/projects/compare/show.html.haml2
-rw-r--r--app/views/projects/diffs/_diffs.html.haml2
-rw-r--r--app/views/projects/diffs/_file.html.haml40
-rw-r--r--app/views/projects/diffs/_match_line.html.haml2
-rw-r--r--app/views/projects/diffs/_match_line_parallel.html.haml8
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml52
-rw-r--r--app/views/projects/diffs/_text_file.html.haml20
-rw-r--r--app/views/projects/find_file/show.html.haml2
-rw-r--r--app/views/projects/issues/_issues.html.haml5
-rw-r--r--app/views/projects/merge_requests/_merge_requests.html.haml5
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_diffs.html.haml3
-rw-r--r--app/views/projects/notes/_notes_with_form.html.haml10
-rw-r--r--app/views/projects/notes/discussions/_diff.html.haml12
-rw-r--r--app/views/search/results/_snippet_blob.html.haml42
-rw-r--r--app/views/shared/_file_highlight.html.haml7
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml3
-rw-r--r--config.ru5
-rw-r--r--config/initializers/metrics.rb1
-rw-r--r--config/initializers/sentry.rb19
-rw-r--r--config/locales/en.yml4
-rw-r--r--db/migrate/20160118155830_add_sentry_to_application_settings.rb8
-rw-r--r--db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb6
-rw-r--r--db/migrate/20160119111158_add_services_category.rb39
-rw-r--r--db/migrate/20160119112418_add_services_default.rb20
-rw-r--r--db/migrate/20160119145451_add_ldap_email_to_users.rb30
-rw-r--r--db/migrate/20160120172143_add_base_commit_sha_to_merge_request_diffs.rb5
-rw-r--r--db/schema.rb22
-rw-r--r--doc/README.md4
-rw-r--r--doc/administration/environment_variables.md2
-rw-r--r--doc/administration/housekeeping.md22
-rw-r--r--doc/administration/img/housekeeping_settings.pngbin0 -> 23856 bytes
-rw-r--r--doc/administration/restart_gitlab.md145
-rw-r--r--doc/api/groups.md1
-rw-r--r--doc/api/projects.md4
-rw-r--r--doc/ci/README.md1
-rw-r--r--doc/ci/build_artifacts/README.md173
-rw-r--r--doc/ci/build_artifacts/img/build_artifacts_browser.pngbin0 -> 89132 bytes
-rw-r--r--doc/ci/build_artifacts/img/build_artifacts_browser_button.pngbin0 -> 11614 bytes
-rw-r--r--doc/ci/languages/php.md2
-rw-r--r--doc/ci/variables/README.md2
-rw-r--r--doc/ci/yaml/README.md60
-rw-r--r--doc/development/doc_styleguide.md18
-rw-r--r--doc/install/installation.md15
-rw-r--r--doc/install/requirements.md11
-rw-r--r--doc/monitoring/performance/gitlab_configuration.md39
-rw-r--r--doc/monitoring/performance/img/metrics_gitlab_configuration_settings.pngbin0 -> 45148 bytes
-rw-r--r--doc/monitoring/performance/influxdb_configuration.md192
-rw-r--r--doc/monitoring/performance/influxdb_schema.md87
-rw-r--r--doc/monitoring/performance/introduction.md64
-rw-r--r--doc/update/8.3-to-8.4.md7
-rw-r--r--doc/web_hooks/web_hooks.md2
-rw-r--r--doc/workflow/README.md1
-rw-r--r--doc/workflow/file_finder.md46
-rw-r--r--doc/workflow/img/file_finder_find_button.pngbin0 -> 30974 bytes
-rw-r--r--doc/workflow/img/file_finder_find_file.pngbin0 -> 42658 bytes
-rw-r--r--doc/workflow/protected_branches.md2
-rw-r--r--features/project/builds/artifacts.feature12
-rw-r--r--features/project/builds/summary.feature10
-rw-r--r--features/project/issues/issues.feature8
-rw-r--r--features/project/merge_requests.feature19
-rw-r--r--features/steps/project/builds/summary.rb9
-rw-r--r--features/steps/project/issues/issues.rb5
-rw-r--r--features/steps/project/merge_requests.rb10
-rw-r--r--features/steps/shared/builds.rb6
-rw-r--r--features/steps/shared/note.rb7
-rw-r--r--lib/api/helpers.rb4
-rw-r--r--lib/banzai/filter/reference_filter.rb2
-rw-r--r--lib/ci/gitlab_ci_yaml_processor.rb8
-rw-r--r--lib/dnsxl_check.rb105
-rw-r--r--lib/gitlab/ci/build/artifacts/metadata.rb8
-rw-r--r--lib/gitlab/ci/build/artifacts/metadata/entry.rb7
-rw-r--r--lib/gitlab/diff/file.rb21
-rw-r--r--lib/gitlab/diff/highlight.rb82
-rw-r--r--lib/gitlab/diff/inline_diff.rb73
-rw-r--r--lib/gitlab/diff/inline_diff_marker.rb109
-rw-r--r--lib/gitlab/diff/line.rb3
-rw-r--r--lib/gitlab/diff/parallel_diff.rb119
-rw-r--r--lib/gitlab/diff/parser.rb28
-rw-r--r--lib/gitlab/email/message/repository_push.rb1
-rw-r--r--lib/gitlab/github_import/importer.rb8
-rw-r--r--lib/gitlab/github_import/pull_request_formatter.rb6
-rw-r--r--lib/gitlab/highlight.rb38
-rw-r--r--lib/gitlab/inline_diff.rb104
-rw-r--r--lib/gitlab/ip_check.rb34
-rw-r--r--lib/gitlab/ldap/user.rb29
-rw-r--r--lib/gitlab/o_auth/auth_hash.rb8
-rw-r--r--lib/gitlab/o_auth/user.rb14
-rwxr-xr-xlib/support/init.d/gitlab9
-rwxr-xr-xlib/support/init.d/gitlab.default.example3
-rw-r--r--spec/fixtures/parallel_diff_result.yml324
-rw-r--r--spec/helpers/blob_helper_spec.rb63
-rw-r--r--spec/helpers/diff_helper_spec.rb68
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb25
-rw-r--r--spec/lib/dnsxl_check_spec.rb68
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb15
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb17
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/highlight_spec.rb41
-rw-r--r--spec/lib/gitlab/diff/inline_diff_marker_spec.rb15
-rw-r--r--spec/lib/gitlab/diff/inline_diff_spec.rb27
-rw-r--r--spec/lib/gitlab/diff/parallel_diff_spec.rb22
-rw-r--r--spec/lib/gitlab/diff/parser_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/pull_request_formatter_spec.rb27
-rw-r--r--spec/lib/gitlab/highlight_spec.rb21
-rw-r--r--spec/lib/gitlab/inline_diff_spec.rb39
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb28
-rw-r--r--spec/lib/gitlab/note_data_builder_spec.rb12
-rw-r--r--spec/mailers/notify_spec.rb57
-rw-r--r--spec/models/application_setting_spec.rb2
-rw-r--r--spec/models/build_spec.rb8
-rw-r--r--spec/requests/api/projects_spec.rb23
-rw-r--r--spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb2
-rw-r--r--spec/services/notification_service_spec.rb58
-rw-r--r--spec/services/projects/create_service_spec.rb1
211 files changed, 3254 insertions, 829 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5795395beeb..6985c1fa46e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,15 +1,22 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.5.0 (unreleased)
+ - Add "visibility" flag to GET /projects api endpoint
+ - Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push
+ - New UI for pagination
v 8.4.0 (unreleased)
+ - Allow LDAP users to change their email if it was not set by the LDAP server
- Ensure Gravatar host looks like an actual host
+ - Consider re-assign as a mention from a notification point of view
- Add pagination headers to already paginated API resources
- Properly generate diff of orphan commits, like the first commit in a repository
- Improve the consistency of commit titles, branch names, tag names, issue/MR titles, on their respective project pages
- - Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse)
- - Improved performance of finding issues for an entire group (Yorick Peterse)
- - Added custom application performance measuring system powered by InfluxDB (Yorick Peterse)
+ - Autocomplete data is now always loaded, instead of when focusing a comment text area
+ - Improved performance of finding issues for an entire group
+ - Added custom application performance measuring system powered by InfluxDB
+ - Add syntax highlighting to diffs
+ - Gracefully handle invalid UTF-8 sequences in Markdown links (Stan Hu)
- Bump fog to 1.36.0 (Stan Hu)
- Add user's last used IP addresses to admin page (Stan Hu)
- Add housekeeping function to project settings page
@@ -60,11 +67,16 @@ v 8.4.0 (unreleased)
- Autosize Markdown textareas
- Import GitHub wiki into GitLab
- Add reporters ability to download and browse build artifacts (Andrew Johnson)
- - Autofill referring url in message box when reporting user abuse. (Josh Frye)
+ - Autofill referring url in message box when reporting user abuse.
- Remove leading comma on award emoji when the user is the first to award the emoji (Zeger-Jan van de Weg)
- Add build artifacts browser
- Improve UX in builds artifacts browser
- Increase default size of `data` column in `events` table when using MySQL
+ - Expose button to CI Lint tool on project builds page
+ - Fix: Creator should be added as a master of the project on creation
+ - Added X-GitLab-... headers to emails from CI and Email On Push services (Anton Baklanov)
+ - Add IP check against DNSBLs at account sign-up
+ - Added cache:key to .gitlab-ci.yml allowing to fine tune the caching
v 8.3.4
- Use gitlab-workhorse 0.5.4 (fixes API routing bug)
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index a918a2aa18d..ee6cdce3c29 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-0.6.0
+0.6.1
diff --git a/Gemfile b/Gemfile
index 072f7a9fcc8..746d8e5d6de 100644
--- a/Gemfile
+++ b/Gemfile
@@ -49,7 +49,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 7.2.22'
+gem "gitlab_git", '~> 7.2.23'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
@@ -293,6 +293,9 @@ end
group :production do
gem "gitlab_meta", '7.0'
+
+ # Sentry integration
+ gem 'sentry-raven'
end
gem "newrelic_rpm", '~> 3.9.4.245'
diff --git a/Gemfile.lock b/Gemfile.lock
index a14fdbeed23..5e0718af70f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -356,7 +356,7 @@ GEM
posix-spawn (~> 0.3)
gitlab_emoji (0.2.0)
gemojione (~> 2.1)
- gitlab_git (7.2.22)
+ gitlab_git (7.2.23)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
@@ -725,6 +725,8 @@ GEM
activesupport (>= 3.1, < 4.3)
select2-rails (3.5.9.3)
thor (~> 0.14)
+ sentry-raven (0.15.3)
+ faraday (>= 0.7.6)
settingslogic (2.0.9)
sexp_processor (4.6.0)
sham_rack (1.3.6)
@@ -932,7 +934,7 @@ DEPENDENCIES
github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_emoji (~> 0.2.0)
- gitlab_git (~> 7.2.22)
+ gitlab_git (~> 7.2.23)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.1.0)
@@ -1008,6 +1010,7 @@ DEPENDENCIES
sdoc (~> 0.3.20)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
+ sentry-raven
settingslogic (~> 2.0.9)
sham_rack
shoulda-matchers (~> 2.8.0)
diff --git a/Rakefile b/Rakefile
index 35b2f05cbb4..35b2f05cbb4 100644..100755
--- a/Rakefile
+++ b/Rakefile
diff --git a/app/assets/fonts/OFL.txt b/app/assets/fonts/OFL.txt
index df187637e18..df187637e18 100755..100644
--- a/app/assets/fonts/OFL.txt
+++ b/app/assets/fonts/OFL.txt
diff --git a/app/assets/fonts/SourceSansPro-Black.ttf.woff b/app/assets/fonts/SourceSansPro-Black.ttf.woff
index b7e86200927..b7e86200927 100755..100644
--- a/app/assets/fonts/SourceSansPro-Black.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-Black.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Black.ttf.woff2 b/app/assets/fonts/SourceSansPro-Black.ttf.woff2
index c90d078406c..c90d078406c 100755..100644
--- a/app/assets/fonts/SourceSansPro-Black.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-Black.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff
index c3314b1ef06..c3314b1ef06 100755..100644
--- a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2
index b87e22c41b5..b87e22c41b5 100755..100644
--- a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf.woff b/app/assets/fonts/SourceSansPro-Bold.ttf.woff
index d1d40f840f8..d1d40f840f8 100755..100644
--- a/app/assets/fonts/SourceSansPro-Bold.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-Bold.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf.woff2 b/app/assets/fonts/SourceSansPro-Bold.ttf.woff2
index 0f46f3e833a..0f46f3e833a 100755..100644
--- a/app/assets/fonts/SourceSansPro-Bold.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-Bold.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff
index ef6ff514d3a..ef6ff514d3a 100755..100644
--- a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2
index 8007df6df32..8007df6df32 100755..100644
--- a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff
index 1e6c94d9eb3..1e6c94d9eb3 100755..100644
--- a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2 b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2
index b715f274082..b715f274082 100755..100644
--- a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff
index 7a408b1ec73..7a408b1ec73 100755..100644
--- a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2
index d8f9d29d4aa..d8f9d29d4aa 100755..100644
--- a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-It.ttf.woff b/app/assets/fonts/SourceSansPro-It.ttf.woff
index 4d54bc95718..4d54bc95718 100755..100644
--- a/app/assets/fonts/SourceSansPro-It.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-It.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-It.ttf.woff2 b/app/assets/fonts/SourceSansPro-It.ttf.woff2
index a00852641f8..a00852641f8 100755..100644
--- a/app/assets/fonts/SourceSansPro-It.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-It.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Light.ttf.woff b/app/assets/fonts/SourceSansPro-Light.ttf.woff
index 1706d57d3c5..1706d57d3c5 100755..100644
--- a/app/assets/fonts/SourceSansPro-Light.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-Light.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Light.ttf.woff2 b/app/assets/fonts/SourceSansPro-Light.ttf.woff2
index d8b610ad76e..d8b610ad76e 100755..100644
--- a/app/assets/fonts/SourceSansPro-Light.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-Light.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff
index 87378d6c609..87378d6c609 100755..100644
--- a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2
index e0eebac8273..e0eebac8273 100755..100644
--- a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf.woff b/app/assets/fonts/SourceSansPro-Regular.ttf.woff
index 460ab12a638..460ab12a638 100755..100644
--- a/app/assets/fonts/SourceSansPro-Regular.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-Regular.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf.woff2 b/app/assets/fonts/SourceSansPro-Regular.ttf.woff2
index 0dd3464c74b..0dd3464c74b 100755..100644
--- a/app/assets/fonts/SourceSansPro-Regular.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-Regular.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff
index 43379631b2d..43379631b2d 100755..100644
--- a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2 b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2
index 2526d2e1b60..2526d2e1b60 100755..100644
--- a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff
index 232c2048ae7..232c2048ae7 100755..100644
--- a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff
+++ b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2
index 606935af089..606935af089 100755..100644
--- a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2
+++ b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2
Binary files differ
diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee
index 9d5ae6c04e9..1ef31c7700e 100644
--- a/app/assets/javascripts/awards_handler.coffee
+++ b/app/assets/javascripts/awards_handler.coffee
@@ -44,7 +44,6 @@ class @AwardsHandler
decrementCounter: (emoji) ->
counter = @findEmojiIcon(emoji).siblings(".counter")
emojiIcon = counter.parent()
-
if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1)
emojiIcon.removeClass("active")
@@ -60,20 +59,18 @@ class @AwardsHandler
removeMeFromAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent()
authors = award_block.attr("data-original-title").split(", ")
- authors = _.without(authors, "me").join(", ")
- award_block.attr("title", authors)
+ authors.splice(authors.indexOf("me"),1)
+ award_block.closest(".award").attr("data-original-title", authors.join(", "))
@resetTooltip(award_block)
addMeToAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent()
- authors = _.compact(award_block.attr("data-original-title").split(", "))
+ origTitle = award_block.attr("data-original-title").trim()
+ authors = []
+ if origTitle
+ authors = origTitle.split(', ')
authors.push("me")
-
- if authors.length == 1
- award_block.attr("title", "me")
- else
- award_block.attr("title", authors.join(", "))
-
+ award_block.attr("title", authors.join(", "))
@resetTooltip(award_block)
resetTooltip: (award) ->
diff --git a/app/assets/javascripts/build_artifacts.js.coffee b/app/assets/javascripts/build_artifacts.js.coffee
new file mode 100644
index 00000000000..5ae6cba56c8
--- /dev/null
+++ b/app/assets/javascripts/build_artifacts.js.coffee
@@ -0,0 +1,14 @@
+class @BuildArtifacts
+ constructor: () ->
+ @disablePropagation()
+ @setupEntryClick()
+
+ disablePropagation: ->
+ $('.top-block').on 'click', '.download', (e) ->
+ e.stopPropagation()
+ $('.tree-holder').on 'click', 'tr[data-link] a', (e) ->
+ e.stopImmediatePropagation()
+
+ setupEntryClick: ->
+ $('.tree-holder').on 'click', 'tr[data-link]', (e) ->
+ window.location = @dataset.link
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 58d6b9d4060..2cdf01d874c 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -87,7 +87,6 @@ class Dispatcher
new GroupAvatar()
when 'projects:tree:show'
new TreeView()
- shortcut_handler = new ShortcutsTree()
when 'projects:find_file:show'
shortcut_handler = true
when 'projects:blob:show'
@@ -101,6 +100,8 @@ class Dispatcher
shortcut_handler = true
when 'projects:forks:new'
new ProjectFork()
+ when 'projects:artifacts:browse'
+ new BuildArtifacts()
when 'users:show'
new User()
new Activities()
diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee
index 4d915bfc8c5..f141fb69c3e 100644
--- a/app/assets/javascripts/shortcuts.js.coffee
+++ b/app/assets/javascripts/shortcuts.js.coffee
@@ -4,6 +4,7 @@ class @Shortcuts
Mousetrap.reset()
Mousetrap.bind('?', @selectiveHelp)
Mousetrap.bind('s', Shortcuts.focusSearch)
+ Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL?
selectiveHelp: (e) =>
Shortcuts.showHelp(e, @enabledHelp)
diff --git a/app/assets/javascripts/shortcuts_tree.coffee b/app/assets/javascripts/shortcuts_tree.coffee
deleted file mode 100644
index ba0839c9fc0..00000000000
--- a/app/assets/javascripts/shortcuts_tree.coffee
+++ /dev/null
@@ -1,4 +0,0 @@
-class @ShortcutsTree extends ShortcutsNavigation
- constructor: ->
- super()
- Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file'))
diff --git a/app/assets/javascripts/star.js.coffee b/app/assets/javascripts/star.js.coffee
index d849b2e7950..f27780dda93 100644
--- a/app/assets/javascripts/star.js.coffee
+++ b/app/assets/javascripts/star.js.coffee
@@ -6,7 +6,7 @@ class @Star
$starIcon = $this.find('i')
toggleStar = (isStarred) ->
- $this.parent().find('span.count').text data.star_count
+ $this.parent().find('.star-count').text data.star_count
if isStarred
$starSpan.removeClass('starred').text 'Star'
$starIcon.removeClass('fa-star').addClass 'fa-star-o'
@@ -19,4 +19,4 @@ class @Star
return
).on 'ajax:error', (e, xhr, status, error) ->
new Flash('Star toggle failed. Try again later.', 'alert')
- return \ No newline at end of file
+ return
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 585a9d83913..9bc814cfd2d 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -120,14 +120,6 @@ span.update-author {
display: inline;
}
-.line_holder {
- &:hover {
- td {
- background: #FFFFCF !important;
- }
- }
-}
-
p.time {
color: #999;
font-size: 90%;
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 6ee104ee31a..a4791cf6b34 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -92,15 +92,6 @@
&:last-child {
border-right: none;
}
- background: #fff;
- }
- .lines {
- pre {
- padding: 0;
- margin: 0;
- background: none;
- border: none;
- }
}
img.avatar {
border: 0 none;
@@ -116,18 +107,18 @@
color: #888;
}
}
- td.blame-numbers {
- pre {
- color: #AAA;
- white-space: pre;
- }
- background: #f1f1f1;
+ td.line-numbers {
+ float: none;
border-left: 1px solid #DDD;
}
td.lines {
+ padding: 0;
code {
font-family: $monospace_font;
}
+ pre {
+ margin: 0;
+ }
}
}
diff --git a/app/assets/stylesheets/framework/jquery.scss b/app/assets/stylesheets/framework/jquery.scss
index 871b808bad4..d6cd78813c0 100644
--- a/app/assets/stylesheets/framework/jquery.scss
+++ b/app/assets/stylesheets/framework/jquery.scss
@@ -53,3 +53,14 @@
color: #333;
}
}
+
+.ui-sortable-handle {
+ cursor: move;
+ cursor: -webkit-grab;
+ cursor: -moz-grab;
+
+ &:active {
+ cursor: -webkit-grabbing;
+ cursor: -moz-grabbing;
+ }
+}
diff --git a/app/assets/stylesheets/framework/pagination.scss b/app/assets/stylesheets/framework/pagination.scss
index 2cd30491bf5..b6f21fd8c91 100644
--- a/app/assets/stylesheets/framework/pagination.scss
+++ b/app/assets/stylesheets/framework/pagination.scss
@@ -1,35 +1,11 @@
.gl-pagination {
+ text-align: center;
border-top: 1px solid $border-color;
- background-color: $background-color;
- margin: -$gl-padding;
+ margin: 0;
margin-top: 0;
.pagination {
padding: 0;
- margin: 0;
- display: block;
-
- li.first,
- li.last,
- li.next,
- li.prev {
- > a {
- color: $link-color;
-
- &:hover {
- color: #fff;
- }
- }
- }
-
- li > a,
- li > span {
- border: none;
- margin: 0;
- @include border-radius(0 !important);
- padding: 13px 19px;
- border-right: 1px solid $border-color;
- }
}
}
diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
index cd0621cdbf3..798cd224ad0 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
@@ -66,20 +66,20 @@ $legend-color: $text-color;
//##
$pagination-color: $gl-gray;
-$pagination-bg: $background-color;
-$pagination-border: transparent;
+$pagination-bg: #fff;
+$pagination-border: $border-color;
-$pagination-hover-color: #fff;
-$pagination-hover-bg: $brand-info;
-$pagination-hover-border: transparent;
+$pagination-hover-color: $gl-gray;
+$pagination-hover-bg: $hover;
+$pagination-hover-border: $border-color;
-$pagination-active-color: #fff;
-$pagination-active-bg: $brand-info;
-$pagination-active-border: transparent;
+$pagination-active-color: $blue-dark;
+$pagination-active-bg: #fff;
+$pagination-active-border: $border-color;
-$pagination-disabled-color: #fff;
-$pagination-disabled-bg: lighten($brand-info, 15%);
-$pagination-disabled-border: transparent;
+$pagination-disabled-color: #cdcdcd;
+$pagination-disabled-bg: $background-color;
+$pagination-disabled-border: $border-color;
//== Form states and alerts
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 85ecdddda79..3ec48da9a41 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -26,6 +26,7 @@ $gl-vert-padding: 6px;
$gl-padding-top:10px;
$gl-avatar-size: 46px;
$secondary-text: #7f8fa4;
+$error-exclamation-point: #E62958;
/*
* Color schema
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 6a2b25ddc67..c7f7a5aaf07 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,20 +1,40 @@
/* https://github.com/MozMorris/tomorrow-pygments */
.code.dark {
+ // Line numbers
+ .line-numbers, .diff-line-num {
+ background-color: #1d1f21;
+ }
- background-color: #1d1f21 !important;
- color: #c5c8c6 !important;
-
- pre.highlight,
- .line-numbers,
- .line-numbers a {
- background-color: #1d1f21 !important;
- color: #c5c8c6 !important;
+ .diff-line-num, .diff-line-num a {
+ color: rgba(255, 255, 255, 0.3);
}
+ // Code itself
pre.code {
border-left: 1px solid #666;
}
+ &, pre.code, .line_holder .line_content {
+ background-color: #1d1f21;
+ color: #c5c8c6;
+ }
+
+ // Diff line
+ .line_holder {
+ .diff-line-num.new, .line_content.new {
+ @include diff_background(rgba(51, 255, 51, 0.1), rgba(51, 255, 51, 0.3), #808080);
+ }
+
+ .diff-line-num.old, .line_content.old {
+ @include diff_background(rgba(255, 51, 51, 0.2), rgba(255, 51, 51, 0.3), #808080);
+ }
+
+ .line_content.match {
+ color: rgba(255, 255, 255, 0.3);
+ background: rgba(255, 255, 255, 0.1);
+ }
+ }
+
// highlight line via anchor
pre .hll {
background-color: #557 !important;
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index 8560c3c490f..516d8aef960 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -1,20 +1,40 @@
/* https://github.com/richleland/pygments-css/blob/master/monokai.css */
.code.monokai {
+ // Line numbers
+ .line-numbers, .diff-line-num {
+ background-color: #272822;
+ }
- background-color: #272822 !important;
- color: #f8f8f2 !important;
-
- pre.highlight,
- .line-numbers,
- .line-numbers a {
- background-color :#272822 !important;
- color: #f8f8f2 !important;
+ .diff-line-num, .diff-line-num a {
+ color: rgba(255, 255, 255, 0.3);
}
+ // Code itself
pre.code {
border-left: 1px solid #555;
}
+ &, pre.code, .line_holder .line_content {
+ background-color: #272822;
+ color: #f8f8f2;
+ }
+
+ // Diff line
+ .line_holder {
+ .diff-line-num.new, .line_content.new {
+ @include diff_background(rgba(166, 226, 46, 0.2), rgba(166, 226, 46, 0.3), #808080);
+ }
+
+ .diff-line-num.old, .line_content.old {
+ @include diff_background(rgba(254, 147, 140, 0.2), rgba(254, 147, 140, 0.3), #808080);
+ }
+
+ .line_content.match {
+ color: rgba(255, 255, 255, 0.3);
+ background: rgba(255, 255, 255, 0.1);
+ }
+ }
+
// highlight line via anchor
pre .hll {
background-color: #49483e !important;
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index 7d489a9666b..ae7ecc65c39 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,20 +1,40 @@
/* https://gist.github.com/qguv/7936275 */
.code.solarized-dark {
+ // Line numbers
+ .line-numbers, .diff-line-num {
+ background-color: #002b36;
+ }
- background-color: #002b36 !important;
- color: #93a1a1 !important;
-
- pre.highlight,
- .line-numbers,
- .line-numbers a {
- background-color: #002b36 !important;
- color: #93a1a1 !important;
+ .diff-line-num, .diff-line-num a {
+ color: rgba(255, 255, 255, 0.3);
}
+ // Code itself
pre.code {
border-left: 1px solid #113b46;
}
+ &, pre.code, .line_holder .line_content {
+ background-color: #002b36;
+ color: #93a1a1;
+ }
+
+ // Diff line
+ .line_holder {
+ .diff-line-num.new, .line_content.new {
+ @include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #808080);
+ }
+
+ .diff-line-num.old, .line_content.old {
+ @include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #808080);
+ }
+
+ .line_content.match {
+ color: rgba(255, 255, 255, 0.3);
+ background: rgba(255, 255, 255, 0.1);
+ }
+ }
+
// highlight line via anchor
pre .hll {
background-color: #174652 !important;
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 200ed346446..1c138572145 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -1,20 +1,40 @@
/* https://gist.github.com/qguv/7936275 */
.code.solarized-light {
+ // Line numbers
+ .line-numbers, .diff-line-num {
+ background-color: #fdf6e3;
+ }
- background-color: #fdf6e3 !important;
- color: #586e75 !important;
-
- pre.highlight,
- .line-numbers,
- .line-numbers a {
- background-color: #fdf6e3 !important;
- color: #586e75 !important;
+ .diff-line-num, .diff-line-num a {
+ color: rgba(0, 0, 0, 0.3);
}
+ // Code itself
pre.code {
border-left: 1px solid #c5d0d4;
}
+ &, pre.code, .line_holder .line_content {
+ background-color: #fdf6e3;
+ color: #586e75;
+ }
+
+ // Diff line
+ .line_holder {
+ .diff-line-num.new, .line_content.new {
+ @include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #FAF3DD);
+ }
+
+ .diff-line-num.old, .line_content.old {
+ @include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #FAF3DD);
+ }
+
+ .line_content.match {
+ color: rgba(0, 0, 0, 0.3);
+ background: rgba(255, 255, 255, 0.4);
+ }
+ }
+
// highlight line via anchor
pre .hll {
background-color: #ddd8c5 !important;
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index e2626da7871..8a932e6540e 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,20 +1,60 @@
/* https://github.com/aahan/pygments-github-style */
.code.white {
+ // Line numbers
+ .line-numbers, .diff-line-num {
+ background-color: $background-color;
+ }
- background-color: #f8fafc !important;
- color: #5b6169 !important;
-
- pre.highlight,
- .line-numbers,
- .line-numbers a {
- background-color: $background-color !important;
- color: $gl-gray !important;
+ .diff-line-num, .diff-line-num a {
+ color: rgba(0, 0, 0, 0.3);
}
+ // Code itself
pre.code {
border-left: 1px solid $border-color;
- background-color: #fff !important;
- color: #333 !important;
+ }
+
+ &, pre.code, .line_holder .line_content {
+ background-color: #fff;
+ color: #333;
+ }
+
+ // Diff line
+ .line_holder {
+ .diff-line-num {
+ &.old {
+ background: #ffdddd;
+ border-color: #f1c0c0;
+ }
+
+ &.new {
+ background: #dbffdb;
+ border-color: #c1e9c1;
+ }
+ }
+
+ .line_content {
+ &.old {
+ background: #ffecec;
+
+ span.idiff {
+ background-color: #f8cbcb;
+ }
+ }
+
+ &.new {
+ background: #eaffea;
+
+ span.idiff {
+ background-color: #a6f3a6;
+ }
+ }
+
+ &.match {
+ color: rgba(0, 0, 0, 0.3);
+ background: #fafafa;
+ }
+ }
}
// highlight line via anchor
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 04e9a58e1cf..5215df04a6e 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -32,16 +32,6 @@
background: #FFF;
color: #333;
- .old {
- span.idiff {
- background-color: #f8cbcb;
- }
- }
- .new {
- span.idiff {
- background-color: #a6f3a6;
- }
- }
.unfold {
cursor: pointer;
}
@@ -76,7 +66,7 @@
}
tr.line_holder.parallel {
- .old_line, .new_line, .diff_line {
+ .old_line, .new_line {
min-width: 50px;
}
@@ -85,7 +75,7 @@
}
}
- .old_line, .new_line, .diff_line {
+ .old_line, .new_line {
margin: 0px;
padding: 0px;
border: none;
@@ -107,43 +97,12 @@
text-decoration: underline;
}
}
- &.new {
- background: #CFD;
- }
- &.old {
- background: #FDD;
- }
- }
- .diff_line {
- padding: 0;
- }
- .line_holder {
- &.old .old_line,
- &.old .new_line {
- background: #ffdddd;
- border-color: #f1c0c0;
- }
- &.new .old_line,
- &.new .new_line {
- background: #dbffdb;
- border-color: #c1e9c1;
- }
}
.line_content {
display: block;
margin: 0px;
padding: 0px 0.5em;
border: none;
- &.new {
- background: #eaffea;
- }
- &.old {
- background: #ffecec;
- }
- &.matched {
- color: $border-color;
- background: #fafafa;
- }
&.parallel {
display: table-cell;
}
@@ -393,3 +352,15 @@
right: 15px;
}
}
+
+@mixin diff_background($background, $idiff, $border) {
+ background: $background;
+
+ &.line_content span.idiff {
+ background: $idiff;
+ }
+
+ &.diff-line-num {
+ border-color: $border;
+ }
+}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 75f2ae80a92..f033ff15f88 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -201,3 +201,39 @@
.mr-source-target {
line-height: 31px;
}
+
+.disabled-comment-area {
+ padding: 16px 0;
+
+ .disabled-profile {
+ width: 40px;
+ height: 40px;
+ background: $border-gray-dark;
+ border-radius: 20px;
+ display: inline-block;
+ margin-right: 10px;
+ }
+
+ .disabled-comment {
+ background: $gray-light;
+ display: inline-block;
+ vertical-align: top;
+ height: 200px;
+ border-radius: 4px;
+ border: 1px solid $border-gray-normal;
+ padding-top: 90px;
+ text-align: center;
+ right: 20px;
+ position: absolute;
+ left: 70px;
+ margin-bottom: 20px;
+
+ span {
+ color: #B2B2B2;
+
+ a {
+ color: $md-link-color;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 2c9a42f9892..32ba1676333 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -10,18 +10,6 @@
margin: 10px $gl-padding;
}
.diff-file .diff-content {
- tr.line_holder:hover {
- &> td.line_content {
- background: $hover !important;
- border-color: darken($hover, 10%) !important;
- }
- &> td.new_line,
- &> td.old_line {
- background: darken($hover, 4%) !important;
- border-color: darken($hover, 10%) !important;
- }
- }
-
tr.line_holder:hover > td .line_note_link {
opacity: 1.0;
filter: alpha(opacity=100);
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 72b0ed29a69..f6343e6bb1e 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -242,11 +242,8 @@ ul.notes {
// "show" the icon also if we just hover somewhere over the line
&:hover > td {
- background: $hover !important;
-
.add-diff-note {
@include show-add-diff-note;
}
}
}
-
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 3a87b71078d..003a4c22f20 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -558,3 +558,9 @@ pre.light-well {
width: 101%;
}
}
+
+.cannot-be-merged,
+.cannot-be-merged:hover {
+ color: #E62958;
+ margin-top: 2px;
+}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index bdcf1897522..3aaa96da609 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -3,10 +3,6 @@
border-bottom: 1px solid #DDD;
padding-bottom: 15px;
margin-bottom: 15px;
-
- .term {
- height: 22px;
- }
}
}
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 91f7d78bd73..094eef28a43 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -74,9 +74,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:metrics_timeout,
:metrics_method_call_threshold,
:metrics_sample_interval,
+ :ip_blocking_enabled,
+ :dnsbl_servers_list,
:recaptcha_enabled,
:recaptcha_site_key,
:recaptcha_private_key,
+ :sentry_enabled,
+ :sentry_dsn,
restricted_visibility_levels: [],
import_sources: []
)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index bf99b2e777d..2d735b90597 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base
before_action :check_password_expiration
before_action :check_2fa_requirement
before_action :ldap_security_check
+ before_action :sentry_user_context
before_action :default_headers
before_action :add_gon_variables
before_action :configure_permitted_parameters, if: :devise_controller?
@@ -24,6 +25,7 @@ class ApplicationController < ActionController::Base
helper_method :abilities, :can?, :current_application_settings
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?
+ helper_method :repository
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
@@ -41,6 +43,16 @@ class ApplicationController < ActionController::Base
protected
+ def sentry_user_context
+ if Rails.env.production? && current_application_settings.sentry_enabled && current_user
+ Raven.user_context(
+ id: current_user.id,
+ email: current_user.email,
+ username: current_user.username,
+ )
+ end
+ end
+
# From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example
# https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
def authenticate_user_from_token!
diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb
index 62127a09081..b9eb0a22f88 100644
--- a/app/controllers/concerns/creates_commit.rb
+++ b/app/controllers/concerns/creates_commit.rb
@@ -97,7 +97,7 @@ module CreatesCommit
# Merge request from fork to this project
@mr_source_project = @tree_edit_project
@mr_target_project = @project
- @mr_target_branch = @mr_target_project.repository.root_ref
+ @mr_target_branch = @ref
end
end
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index c56a3497bb2..bb72232edd7 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -52,7 +52,9 @@ class Projects::BlobController < Projects::ApplicationController
def preview
@content = params[:content]
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
- @diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
+ diff_lines = diffy.diff.scan(/.*\n/)[2..-1]
+ diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines)
+ @diff_lines = Gitlab::Diff::Highlight.new(diff_lines).highlight
render layout: false
end
@@ -65,8 +67,9 @@ class Projects::BlobController < Projects::ApplicationController
end
def diff
- @form = UnfoldForm.new(params)
- @lines = @blob.data.lines[@form.since - 1..@form.to - 1]
+ @form = UnfoldForm.new(params)
+ @lines = Gitlab::Highlight.highlight_lines(repository, @ref, @path)
+ @lines = @lines[@form.since - 1..@form.to - 1]
if @form.bottom?
@match_line = ''
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 870f6795219..f5a169e5aa9 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -72,6 +72,7 @@ class Projects::CommitController < Projects::ApplicationController
@diffs = commit.diffs
end
+ @diff_refs = [commit.parent || commit, commit]
@notes_count = commit.notes.count
@statuses = ci_commit.statuses if ci_commit
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 5200d609cc9..f8ec76cd4e5 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -21,7 +21,8 @@ class Projects::CompareController < Projects::ApplicationController
@commits = Commit.decorate(compare_result.commits, @project)
@diffs = compare_result.diffs
@commit = @project.commit(head_ref)
- @first_commit = @project.commit(base_ref)
+ @base_commit = @project.commit(base_ref)
+ @diff_refs = [@base_commit, @commit]
@line_notes = []
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index a6284a24223..ed3050d59aa 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -58,7 +58,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def diffs
@commit = @merge_request.last_commit
- @first_commit = @merge_request.first_commit
+ @base_commit = @merge_request.diff_base_commit
+
+ # MRs created before 8.4 don't have a diff_base_commit,
+ # but we need it for the "View file @ ..." link by deleted files
+ @base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit
@comments_allowed = @reply_allowed = true
@comments_target = {
@@ -102,7 +106,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@source_project = merge_request.source_project
@commits = @merge_request.compare_commits.reverse
@commit = @merge_request.last_commit
- @first_commit = @merge_request.first_commit
+ @base_commit = @merge_request.diff_base_commit
@diffs = @merge_request.compare_diffs
@ci_commit = @merge_request.ci_commit
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index c48175a4c5a..5efdd613e79 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -8,6 +8,11 @@ class RegistrationsController < Devise::RegistrationsController
def create
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
+ if Gitlab::IpCheck.new(request.remote_ip).spam?
+ flash[:alert] = 'Could not create an account. This IP is listed for spam.'
+ return render action: 'new'
+ end
+
super
else
flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code."
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index d31d4cde08f..8b689b29a41 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -1,21 +1,10 @@
module BlobHelper
- def highlight(blob_name, blob_content, nowrap: false, continue: false)
- @formatter ||= Rouge::Formatters::HTMLGitlab.new(
- nowrap: nowrap,
- cssclass: 'code highlight',
- lineanchors: true,
- lineanchorsid: 'LC'
- )
-
- begin
- @lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new
- result = @formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe
- rescue
- @lexer = Rouge::Lexers::PlainText
- result = @formatter.format(@lexer.lex(blob_content)).html_safe
- end
+ def highlighter(blob_name, blob_content, nowrap: false)
+ Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap)
+ end
- result
+ def highlight(blob_name, blob_content, nowrap: false)
+ Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap)
end
def no_highlight_files
@@ -37,10 +26,10 @@ module BlobHelper
tree_join(ref, path),
link_opts)
- if !on_top_of_branch?
+ if !on_top_of_branch?(project, ref)
button_tag "Edit", class: "btn btn-default disabled has_tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' }
- elsif can_edit_blob?(blob)
- link_to "Edit", edit_path, class: 'btn btn-small'
+ elsif can_edit_blob?(blob, project, ref)
+ link_to "Edit", edit_path, class: 'btn'
elsif can?(current_user, :fork_project, project)
continue_params = {
to: edit_path,
@@ -50,7 +39,7 @@ module BlobHelper
fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id,
continue: continue_params)
- link_to "Edit", fork_path, class: 'btn btn-small', method: :post
+ link_to "Edit", fork_path, class: 'btn', method: :post
end
end
@@ -61,11 +50,11 @@ module BlobHelper
return unless blob
- if !on_top_of_branch?
+ if !on_top_of_branch?(project, ref)
button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "You can only #{action} files when you are on a branch", data: { container: 'body' }
elsif blob.lfs_pointer?
button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "It is not possible to #{action} files that are stored in LFS using the web interface", data: { container: 'body' }
- elsif can_edit_blob?(blob)
+ elsif can_edit_blob?(blob, project, ref)
button_tag label, class: "btn btn-#{btn_class}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal'
elsif can?(current_user, :fork_project, project)
continue_params = {
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 590d20ac7b3..d26f007c8e6 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -166,7 +166,7 @@ module CommitsHelper
link_to(
namespace_project_blob_path(project.namespace, project,
tree_join(commit_sha, diff.new_path)),
- class: 'btn btn-small view-file js-view-file'
+ class: 'btn view-file js-view-file'
) do
raw('View file @') + content_tag(:span, commit_sha[0..6],
class: 'commit-short-id')
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 24134310fc5..62971d1e14b 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -19,13 +19,13 @@ module DiffHelper
end
end
- def safe_diff_files(diffs)
+ def safe_diff_files(diffs, diff_refs)
lines = 0
safe_files = []
diffs.first(allowed_diff_size).each do |diff|
lines += diff.diff.lines.count
break if lines > allowed_diff_lines
- safe_files << Gitlab::Diff::File.new(diff)
+ safe_files << Gitlab::Diff::File.new(diff, diff_refs)
end
safe_files
end
@@ -43,64 +43,6 @@ module DiffHelper
Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
- def parallel_diff(diff_file, index)
- lines = []
- skip_next = false
-
- # Building array of lines
- #
- # [
- # left_type, left_line_number, left_line_content, left_line_code,
- # right_line_type, right_line_number, right_line_content, right_line_code
- # ]
- #
- diff_file.diff_lines.each do |line|
-
- full_line = line.text
- type = line.type
- line_code = generate_line_code(diff_file.file_path, line)
- line_new = line.new_pos
- line_old = line.old_pos
-
- next_line = diff_file.next_line(line.index)
-
- if next_line
- next_line_code = generate_line_code(diff_file.file_path, next_line)
- next_type = next_line.type
- next_line = next_line.text
- end
-
- if type == 'match' || type.nil?
- # line in the right panel is the same as in the left one
- line = [type, line_old, full_line, line_code, type, line_new, full_line, line_code]
- lines.push(line)
- elsif type == 'old'
- if next_type == 'new'
- # Left side has text removed, right side has text added
- line = [type, line_old, full_line, line_code, next_type, line_new, next_line, next_line_code]
- lines.push(line)
- skip_next = true
- elsif next_type == 'old' || next_type.nil?
- # Left side has text removed, right side doesn't have any change
- # No next line code, no new line number, no new line text
- line = [type, line_old, full_line, line_code, next_type, nil, "&nbsp;", nil]
- lines.push(line)
- end
- elsif type == 'new'
- if skip_next
- # Change has been already included in previous line so no need to do it again
- skip_next = false
- next
- else
- # Change is only on the right side, left side has no change
- line = [nil, nil, "&nbsp;", line_code, type, line_new, full_line, line_code]
- lines.push(line)
- end
- end
- end
- lines
- end
-
def unfold_bottom_class(bottom)
(bottom) ? 'js-unfold-bottom' : ''
end
@@ -111,9 +53,9 @@ module DiffHelper
def diff_line_content(line)
if line.blank?
- " &nbsp;"
+ " &nbsp;".html_safe
else
- line
+ line.html_safe
end
end
@@ -160,8 +102,7 @@ module DiffHelper
def commit_for_diff(diff)
if diff.deleted_file
- first_commit = @first_commit || @commit
- first_commit.parent || @first_commit
+ @base_commit || @commit.parent || @commit
else
@commit
end
diff --git a/app/mailers/emails/builds.rb b/app/mailers/emails/builds.rb
index d58609a2de5..64c1ce8cfab 100644
--- a/app/mailers/emails/builds.rb
+++ b/app/mailers/emails/builds.rb
@@ -3,13 +3,26 @@ module Emails
def build_fail_email(build_id, to)
@build = Ci::Build.find(build_id)
@project = @build.project
+ add_project_headers
+ add_build_headers
+ headers['X-GitLab-Build-Status'] = "failed"
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
end
def build_success_email(build_id, to)
@build = Ci::Build.find(build_id)
@project = @build.project
+ add_project_headers
+ add_build_headers
+ headers['X-GitLab-Build-Status'] = "success"
mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
end
+
+ private
+ def add_build_headers
+ headers['X-GitLab-Build-Id'] = @build.id
+ headers['X-GitLab-Build-Ref'] = @build.ref
+ end
+
end
end
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index b96418679bd..377c2999d6c 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -43,7 +43,7 @@ module Emails
@current_user = @created_by = User.find(created_by_id)
@access_level = access_level
@invite_email = invite_email
-
+
@target_url = namespace_project_url(@project.namespace, @project)
mail(to: @created_by.notification_email,
@@ -65,6 +65,10 @@ module Emails
# used in notify layout
@target_url = @message.target_url
+ @project = Project.find project_id
+
+ add_project_headers
+ headers['X-GitLab-Author'] = @message.author_username
mail(from: sender(@message.author_id, @message.send_from_committer_email?),
reply_to: @message.reply_to,
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index e1cd075a978..8cbc9eefc7b 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -100,12 +100,7 @@ class Notify < BaseMailer
end
def mail_thread(model, headers = {})
- if @project
- headers['X-GitLab-Project'] = @project.name
- headers['X-GitLab-Project-Id'] = @project.id
- headers['X-GitLab-Project-Path'] = @project.path_with_namespace
- end
-
+ add_project_headers
headers["X-GitLab-#{model.class.name}-ID"] = model.id
headers['X-GitLab-Reply-Key'] = reply_key
@@ -152,4 +147,12 @@ class Notify < BaseMailer
def reply_key
@reply_key ||= SentNotification.reply_key
end
+
+ def add_project_headers
+ return unless @project
+
+ headers['X-GitLab-Project'] = @project.name
+ headers['X-GitLab-Project-Id'] = @project.id
+ headers['X-GitLab-Project-Path'] = @project.path_with_namespace
+ end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 6c6c2468374..2f3487b53ac 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -41,6 +41,10 @@
# recaptcha_site_key :string
# recaptcha_private_key :string
# metrics_port :integer default(8089)
+# sentry_enabled :boolean default(FALSE)
+# sentry_dsn :string
+# ip_blocking_enabled :boolean default(FALSE)
+# dns_blacklist_threshold :float default(0.33)
#
class ApplicationSetting < ActiveRecord::Base
@@ -82,6 +86,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
if: :recaptcha_enabled
+ validates :sentry_dsn,
+ presence: true,
+ if: :sentry_enabled
+
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
value.each do |level|
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 16a5b03f591..623edd8bc57 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -346,17 +346,17 @@ module Ci
end
def artifacts_browse_url
- if artifacts_browser_supported?
+ if artifacts_metadata?
browse_namespace_project_build_artifacts_path(project.namespace, project, self)
end
end
- def artifacts_browser_supported?
+ def artifacts_metadata?
artifacts? && artifacts_metadata.exists?
end
- def artifacts_metadata_entry(path)
- Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path).to_entry
+ def artifacts_metadata_entry(path, **options)
+ Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path, **options).to_entry
end
private
diff --git a/app/models/member.rb b/app/models/member.rb
index 28aee2e3799..34efcd0088d 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -91,7 +91,7 @@ class Member < ActiveRecord::Base
member.invite_email = user
end
- if can_update_member?(current_user, member)
+ if can_update_member?(current_user, member) || project_creator?(member, access_level)
member.created_by ||= current_user
member.access_level = access_level
@@ -107,6 +107,11 @@ class Member < ActiveRecord::Base
current_user.can?(:update_group_member, member) ||
current_user.can?(:update_project_member, member)
end
+
+ def project_creator?(member, access_level)
+ member.new_record? && member.owner? &&
+ access_level.to_i == ProjectMember::MASTER
+ end
end
def invite?
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 1b0c76917aa..560d1690e14 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -84,7 +84,7 @@ class ProjectMember < Member
def truncate_teams(project_ids)
ProjectMember.transaction do
members = ProjectMember.where(source_id: project_ids)
-
+
members.each do |member|
member.destroy
end
@@ -133,13 +133,13 @@ class ProjectMember < Member
event_service.join_project(self.project, self.user)
notification_service.new_project_member(self)
end
-
+
super
end
def post_update_hook
if access_level_changed?
- notification_service.update_project_member(self)
+ notification_service.update_project_member(self)
end
super
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index c63d0c01653..41dd248d80a 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -180,6 +180,14 @@ class MergeRequest < ActiveRecord::Base
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
end
+ def diff_base_commit
+ if merge_request_diff
+ merge_request_diff.base_commit
+ else
+ self.target_project.commit(self.target_branch)
+ end
+ end
+
def last_commit_short_sha
last_commit.short_id
end
@@ -254,7 +262,7 @@ class MergeRequest < ActiveRecord::Base
end
def mergeable?
- return false unless open? && !work_in_progress?
+ return false unless open? && !work_in_progress? && !broken?
check_if_can_be_merged
@@ -477,8 +485,7 @@ class MergeRequest < ActiveRecord::Base
end
def target_sha
- @target_sha ||= target_project.
- repository.commit(target_branch).sha
+ @target_sha ||= target_project.repository.commit(target_branch).sha
end
def source_sha
@@ -517,4 +524,10 @@ class MergeRequest < ActiveRecord::Base
def ci_commit
@ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit && source_project
end
+
+ def diff_refs
+ return nil unless diff_base_commit
+
+ [diff_base_commit, last_commit]
+ end
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index c499a4b5b4c..ba0194cd0a6 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -73,6 +73,12 @@ class MergeRequestDiff < ActiveRecord::Base
commits.last
end
+ def base_commit
+ return nil unless self.base_commit_sha
+
+ merge_request.target_project.commit(self.base_commit_sha)
+ end
+
def last_commit_short_sha
@last_commit_short_sha ||= last_commit.short_id
end
@@ -156,6 +162,9 @@ class MergeRequestDiff < ActiveRecord::Base
end
self.st_diffs = new_diffs
+
+ self.base_commit_sha = merge_request.target_project.commit(target_branch).try(:sha)
+
self.save
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 3e1375e5ad6..55255d22c2f 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -33,7 +33,7 @@ class Note < ActiveRecord::Base
participant :author
belongs_to :project
- belongs_to :noteable, polymorphic: true
+ belongs_to :noteable, polymorphic: true, touch: true
belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User"
@@ -244,7 +244,7 @@ class Note < ActiveRecord::Base
prev_match_line = nil
prev_lines = []
- diff_lines.each do |line|
+ highlighted_diff_lines.each do |line|
if line.type == "match"
prev_lines.clear
prev_match_line = line
@@ -261,7 +261,11 @@ class Note < ActiveRecord::Base
end
def diff_lines
- @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines.to_a)
+ @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines)
+ end
+
+ def highlighted_diff_lines
+ Gitlab::Diff::Highlight.new(diff_lines).highlight
end
def discussion_id
diff --git a/app/models/project.rb b/app/models/project.rb
index 7e131151513..5579710a476 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -272,6 +272,10 @@ class Project < ActiveRecord::Base
query: "%#{query.try(:downcase)}%")
end
+ def search_by_visibility(level)
+ where(visibility_level: Gitlab::VisibilityLevel.const_get(level.upcase))
+ end
+
def search_by_title(query)
where('projects.archived = ?', false).where('LOWER(projects.name) LIKE :query', query: "%#{query.downcase}%")
end
@@ -468,12 +472,9 @@ class Project < ActiveRecord::Base
!external_issue_tracker
end
- def external_issues_trackers
- services.select(&:issue_tracker?).reject(&:default?)
- end
-
def external_issue_tracker
- @external_issues_tracker ||= external_issues_trackers.find(&:activated?)
+ @external_issue_tracker ||=
+ services.issue_trackers.active.without_defaults.first
end
def can_have_issues_tracker_id?
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index c3f70d1f972..e10b5529b42 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -23,14 +23,12 @@
# List methods you need to implement to get your CI service
# working with GitLab Merge Requests
class CiService < Service
- def category
- :ci
- end
-
+ default_value_for :category, 'ci'
+
def valid_token?(token)
self.respond_to?(:token) && self.token.present? && self.token == token
end
-
+
def supported_events
%w(push)
end
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index 7aa04309f54..05436cd0f79 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -24,9 +24,7 @@ class GitlabIssueTrackerService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
- def default?
- true
- end
+ default_value_for :default, true
def to_param
'gitlab'
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index ed201979d39..25045224ce5 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -23,12 +23,10 @@ class IssueTrackerService < Service
validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
- def category
- :issue_tracker
- end
+ default_value_for :category, 'issue_tracker'
def default?
- false
+ default
end
def issue_url(iid)
diff --git a/app/models/service.rb b/app/models/service.rb
index 24f4bf7646e..721273250ea 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -43,6 +43,9 @@ class Service < ActiveRecord::Base
validates :project_id, presence: true, unless: Proc.new { |service| service.template? }
scope :visible, -> { where.not(type: ['GitlabIssueTrackerService', 'GitlabCiService']) }
+ scope :issue_trackers, -> { where(category: 'issue_tracker') }
+ scope :active, -> { where(active: true) }
+ scope :without_defaults, -> { where(default: false) }
scope :push_hooks, -> { where(push_events: true, active: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
@@ -51,6 +54,8 @@ class Service < ActiveRecord::Base
scope :note_hooks, -> { where(note_events: true, active: true) }
scope :build_hooks, -> { where(build_events: true, active: true) }
+ default_value_for :category, 'common'
+
def activated?
active
end
@@ -60,7 +65,7 @@ class Service < ActiveRecord::Base
end
def category
- :common
+ read_attribute(:category).to_sym
end
def initialize_properties
@@ -153,7 +158,7 @@ class Service < ActiveRecord::Base
# Returns a hash of the properties that have been assigned a new value since last save,
# indicating their original values (attr => original value).
- # ActiveRecord does not provide a mechanism to track changes in serialized keys,
+ # ActiveRecord does not provide a mechanism to track changes in serialized keys,
# so we need a specific implementation for service properties.
# This allows to track changes to properties set with the accessor methods,
# but not direct manipulation of properties hash.
@@ -164,7 +169,7 @@ class Service < ActiveRecord::Base
def reset_updated_properties
@updated_properties = nil
end
-
+
def async_execute(data)
return unless supported_events.include?(data[:object_kind])
diff --git a/app/models/user.rb b/app/models/user.rb
index 592468933ed..4214f01f6a4 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -664,7 +664,10 @@ class User < ActiveRecord::Base
end
def all_emails
- [self.email, *self.emails.map(&:email)]
+ all_emails = []
+ all_emails << self.email unless self.temp_oauth_email?
+ all_emails.concat(self.emails.map(&:email))
+ all_emails
end
def hook_attrs
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index e4edc55bf69..ca8a41d93b8 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -376,10 +376,10 @@ class NotificationService
end
def reassign_resource_email(target, project, current_user, method)
- previous_assignee_id = previous_record(target, "assignee_id")
+ previous_assignee_id = previous_record(target, 'assignee_id')
previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
- recipients = build_recipients(target, project, current_user, [previous_assignee])
+ recipients = build_recipients(target, project, current_user, action: :reassign, previous_assignee: previous_assignee)
recipients.each do |recipient|
mailer.send(
@@ -400,22 +400,27 @@ class NotificationService
end
end
- def build_recipients(target, project, current_user, extra_recipients = nil)
+ def build_recipients(target, project, current_user, action: nil, previous_assignee: nil)
recipients = target.participants(current_user)
- recipients = recipients.concat(extra_recipients).compact.uniq if extra_recipients
-
recipients = add_project_watchers(recipients, project)
recipients = reject_mention_users(recipients, project)
- recipients = reject_muted_users(recipients, project)
+ # Re-assign is considered as a mention of the new assignee so we add the
+ # new assignee to the list of recipients after we rejected users with
+ # the "on mention" notification level
+ if action == :reassign
+ recipients << previous_assignee if previous_assignee
+ recipients << target.assignee
+ end
+
+ recipients = reject_muted_users(recipients, project)
recipients = add_subscribed_users(recipients, target)
recipients = reject_unsubscribed_users(recipients, target)
recipients.delete(current_user)
- recipients = recipients.uniq
- recipients
+ recipients.uniq
end
def mailer
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 83f6814d822..c4020c8273b 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -215,6 +215,22 @@
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
+ = f.label :ip_blocking_enabled do
+ = f.check_box :ip_blocking_enabled
+ Enable IP check against blacklist at sign-up
+ .help-block Helps preventing accounts creation from 'known spam sources'
+
+ .form-group
+ = f.label :dnsbl_servers_list, class: 'control-label col-sm-2' do
+ DNSBL servers list
+ .col-sm-10
+ = f.text_field :dnsbl_servers_list, class: 'form-control'
+ .help-block
+ Please enter DNSBL servers separated with comma
+
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
= f.label :recaptcha_enabled do
= f.check_box :recaptcha_enabled
Enable reCAPTCHA
@@ -226,11 +242,30 @@
= f.text_field :recaptcha_site_key, class: 'form-control'
.help-block
Generate site and private keys here:
- %a{ href: 'http://www.google.com/recaptcha', target: 'blank'} http://www.google.com/recaptcha
+ %a{ href: 'http://www.google.com/recaptcha', target: '_blank'} http://www.google.com/recaptcha
.form-group
= f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :recaptcha_private_key, class: 'form-control'
+ %fieldset
+ %legend Error Reporting and Logging
+ %p
+ These settings require a restart to take effect.
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :sentry_enabled do
+ = f.check_box :sentry_enabled
+ Enable Sentry
+ .help-block
+ Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here:
+ %a{ href: 'https://getsentry.com', target: '_blank' } https://getsentry.com
+
+ .form-group
+ = f.label :sentry_dsn, 'Sentry DSN', class: 'control-label col-sm-2'
+ .col-sm-10
+ = f.text_field :sentry_dsn, class: 'form-control'
+
.form-actions
= f.submit 'Save', class: 'btn btn-primary'
diff --git a/app/views/kaminari/gitlab/_next_page.html.haml b/app/views/kaminari/gitlab/_next_page.html.haml
index 00c5f0b6f4e..c805914fc3f 100644
--- a/app/views/kaminari/gitlab/_next_page.html.haml
+++ b/app/views/kaminari/gitlab/_next_page.html.haml
@@ -5,5 +5,9 @@
-# num_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%li.next
- = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote
+- if current_page.last?
+ %li{ class: "next disabled" }
+ %span= raw(t 'views.pagination.next')
+- else
+ %li{ class: "next" }
+ = link_to raw(t 'views.pagination.next'), url, rel: 'next', remote: remote
diff --git a/app/views/kaminari/gitlab/_paginator.html.haml b/app/views/kaminari/gitlab/_paginator.html.haml
index 2f645186921..a12c53bcfe7 100644
--- a/app/views/kaminari/gitlab/_paginator.html.haml
+++ b/app/views/kaminari/gitlab/_paginator.html.haml
@@ -10,13 +10,13 @@
%ul.pagination.clearfix
- unless current_page.first?
= first_page_tag unless num_pages < 5 # As kaminari will always show the first 5 pages
- = prev_page_tag
+ = prev_page_tag
- each_page do |page|
- if page.left_outer? || page.right_outer? || page.inside_window?
= page_tag page
- elsif !page.was_truncated?
= gap_tag
+ = next_page_tag
- unless current_page.last?
- = next_page_tag
= last_page_tag unless num_pages < 5
diff --git a/app/views/kaminari/gitlab/_prev_page.html.haml b/app/views/kaminari/gitlab/_prev_page.html.haml
index f673abdb3ae..afb20455e0a 100644
--- a/app/views/kaminari/gitlab/_prev_page.html.haml
+++ b/app/views/kaminari/gitlab/_prev_page.html.haml
@@ -5,5 +5,9 @@
-# num_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%li{class: "prev" }
- = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote
+- if current_page.first?
+ %li{ class: "prev disabled" }
+ %span= raw(t 'views.pagination.previous')
+- else
+ %li{ class: "prev" }
+ = link_to raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 3892ef8eefa..fcb6b835a7e 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -37,3 +37,6 @@
%h1.title= title
= render 'shared/outdated_browser'
+- if @project && !@project.empty_repo?
+ :javascript
+ var findFileURL = "#{namespace_project_find_file_path(@project.namespace, @project, @ref || @project.repository.root_ref)}"; \ No newline at end of file
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 9459d8a6295..add9a00138b 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -21,10 +21,10 @@
.form-group
= f.label :email, class: "control-label"
.col-sm-10
- - if @user.ldap_user?
+ - if @user.ldap_user? && @user.ldap_email?
= f.text_field :email, class: "form-control", required: true, readonly: true
%span.help-block.light
- Email is read-only for LDAP user
+ Your email address was automatically set based on the LDAP server.
- else
- if @user.temp_oauth_email?
= f.text_field :email, class: "form-control", required: true, value: nil
diff --git a/app/views/projects/artifacts/_tree_directory.html.haml b/app/views/projects/artifacts/_tree_directory.html.haml
index e4b7979949c..def493c56f5 100644
--- a/app/views/projects/artifacts/_tree_directory.html.haml
+++ b/app/views/projects/artifacts/_tree_directory.html.haml
@@ -6,4 +6,3 @@
%span.str-truncated
= link_to directory.name, path_to_directory
%td
- %td
diff --git a/app/views/projects/artifacts/_tree_file.html.haml b/app/views/projects/artifacts/_tree_file.html.haml
index 3dfc09cc495..36fb4c998c9 100644
--- a/app/views/projects/artifacts/_tree_file.html.haml
+++ b/app/views/projects/artifacts/_tree_file.html.haml
@@ -7,5 +7,3 @@
= link_to file.name, path_to_file
%td
= number_to_human_size(file.metadata[:size], precision: 2)
- %td
- = number_to_human_size(file.metadata[:zipped], precision: 2)
diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml
index 9dc7b2c2e1f..84034c8bf16 100644
--- a/app/views/projects/artifacts/browse.html.haml
+++ b/app/views/projects/artifacts/browse.html.haml
@@ -4,7 +4,7 @@
.top-block.gray-content-block.clearfix
.pull-right
= link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build),
- class: 'btn btn-default' do
+ class: 'btn btn-default download' do
= icon('download')
Download artifacts archive
@@ -15,14 +15,8 @@
%tr
%th Name
%th Size
- %th Compressed to
= render partial: 'tree_directory', collection: @entry.directories(parent: true), as: :directory
= render partial: 'tree_file', collection: @entry.files, as: :file
- if @entry.empty?
.center Empty
-
-:javascript
- $(document).on('click', 'tr[data-link]', function(e) {
- window.location = this.dataset.link;
- });
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index 8d9ec068a43..53dcac78a9f 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -12,9 +12,10 @@
%small= number_to_human_size @blob.size
.file-actions
= render "projects/blob/actions"
- .file-content.blame.highlight
+ .file-content.blame.code.js-syntax-highlight
%table
- current_line = 1
+ - blame_highlighter = highlighter(@blob.name, @blob.data, nowrap: true)
- @blame.each do |blame_group|
%tr
%td.blame-commit
@@ -30,16 +31,15 @@
= commit_author_link(commit, avatar: false)
authored
#{time_ago_with_tooltip(commit.committed_date, skip_js: true)}
- %td.lines.blame-numbers
- %pre
- - line_count = blame_group[:lines].count
- - (current_line...(current_line + line_count)).each do |i|
- = i
- \
- - current_line += line_count
+ %td.line-numbers
+ - line_count = blame_group[:lines].count
+ - (current_line...(current_line + line_count)).each do |i|
+ %a.diff-line-num= i
+ \
+ - current_line += line_count
%td.lines
- %pre{class: 'code highlight white'}
+ %pre{class: 'code highlight'}
%code
- blame_group[:lines].each do |line|
- :erb
- <%= highlight(@blob.name, line, nowrap: true, continue: true).html_safe %>
+ :preserve
+ #{blame_highlighter.highlight(line)}
diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml
index f3b01ff3288..abcfca4cd11 100644
--- a/app/views/projects/blob/diff.html.haml
+++ b/app/views/projects/blob/diff.html.haml
@@ -10,8 +10,9 @@
%tr.line_holder
%td.old_line.diff-line-num{data: {linenumber: line_old}}
= link_to raw(line_old), "#"
- %td.new_line= link_to raw(line_new) , "#"
- %td.line_content.noteable_line= ' ' * @form.indent + line
+ %td.new_line.diff-line-num
+ = link_to raw(line_new) , "#"
+ %td.line_content.noteable_line==#{' ' * @form.indent}#{line}
- if @form.unfold? && @form.bottom? && @form.to < @blob.loc
%tr.line_holder{ id: @form.to }
diff --git a/app/views/projects/blob/preview.html.haml b/app/views/projects/blob/preview.html.haml
index e7c3460ad78..c5a269f334c 100644
--- a/app/views/projects/blob/preview.html.haml
+++ b/app/views/projects/blob/preview.html.haml
@@ -14,12 +14,12 @@
- @diff_lines.each do |line|
%tr.line_holder{ class: "#{line.type}" }
- if line.type == "match"
- %td.old_line= "..."
- %td.new_line= "..."
- %td.line_content.matched= line.text
+ %td.old_line.diff-line-num= "..."
+ %td.new_line.diff-line-num= "..."
+ %td.line_content.match= line.text
- else
- %td.old_line
- %td.new_line
- %td.line_content{class: "#{line.type}"}= raw diff_line_content(line.text)
+ %td.old_line.diff-line-num
+ %td.new_line.diff-line-num
+ %td.line_content{class: "#{line.type}"}= diff_line_content(line.text)
- else
.nothing-here-block No changes.
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
index 5d18c0d803a..bbb6944a65a 100644
--- a/app/views/projects/builds/index.html.haml
+++ b/app/views/projects/builds/index.html.haml
@@ -6,7 +6,12 @@
- if can?(current_user, :manage_builds, @project)
.pull-left.hidden-xs
- if @all_builds.running_or_pending.any?
- = link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
+ = link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project),
+ data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
+
+ = link_to ci_lint_path, class: 'btn btn-default' do
+ = icon('wrench')
+ %span CI Lint
%ul.nav-links
%li{class: ('active' if @scope.nil?)}
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index 2be572d3b10..ba1fdc6f0e7 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -96,7 +96,7 @@
.center
.btn-group{ role: :group }
= link_to "Download", @build.artifacts_download_url, class: 'btn btn-sm btn-primary'
- - if @build.artifacts_browser_supported?
+ - if @build.artifacts_metadata?
= link_to "Browse", @build.artifacts_browse_url, class: 'btn btn-sm btn-primary'
.build-widget
diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml
index 02297158dec..05dbe5ebea4 100644
--- a/app/views/projects/commit/show.html.haml
+++ b/app/views/projects/commit/show.html.haml
@@ -9,5 +9,6 @@
= render "ci_menu"
- else
%div.block-connector
-= render "projects/diffs/diffs", diffs: @diffs, project: @project
+= render "projects/diffs/diffs", diffs: @diffs, project: @project,
+ diff_refs: @diff_refs
= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 51088a7dea8..da731f28bb6 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -9,7 +9,7 @@
- if @commits.present?
.prepend-top-default
= render "projects/commits/commit_list"
- = render "projects/diffs/diffs", diffs: @diffs, project: @project
+ = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @diff_refs
- else
.light-well.prepend-top-default
.center
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index f67058ae0ba..d668f483bcb 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -1,7 +1,7 @@
- if diff_view == 'parallel'
- fluid_layout true
-- diff_files = safe_diff_files(diffs)
+- diff_files = safe_diff_files(diffs, diff_refs)
.content-block.oneline-block
.inline-parallel-buttons
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 517f6aef7c5..fc0eaef2286 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -1,39 +1,37 @@
-.diff-file{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)}
- .diff-header{id: "file-path-#{hexdigest(diff_file.file_path)}"}
+.diff-file.file-holder{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)}
+ .file-title{id: "file-path-#{hexdigest(diff_file.file_path)}"}
- if diff_file.diff.submodule?
%span
= icon('archive fw')
%strong
= submodule_link(blob, @commit.id, project.repository)
- else
- %span
- = blob_icon blob.mode, blob.name
- = link_to "#diff-#{i}" do
- %strong
- = diff_file.new_path
+ = blob_icon blob.mode, blob.name
+ = link_to "#diff-#{i}" do
+ %strong
+ = diff_file.new_path
- - if diff_file.deleted_file
- deleted
- - elsif diff_file.renamed_file
- renamed from
- %strong
- = diff_file.old_path
+ - if diff_file.deleted_file
+ deleted
+ - elsif diff_file.renamed_file
+ renamed from
+ %strong
+ = diff_file.old_path
- - if diff_file.mode_changed?
- %small
- = "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}"
+ - if diff_file.mode_changed?
+ %small
+ = "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}"
- .diff-controls
+ .file-actions.hidden-xs
- if blob_text_viewable?(blob)
- = link_to '#', class: 'js-toggle-diff-comments btn btn-sm active has_tooltip', title: "Toggle comments for this file" do
- %i.fa.fa-comments
- &nbsp;
+ = link_to '#', class: 'js-toggle-diff-comments btn active has_tooltip', title: "Toggle comments for this file" do
+ = icon('comments')
+ \
- if editable_diff?(diff_file)
= edit_blob_link(@merge_request.source_project,
@merge_request.source_branch, diff_file.new_path,
from_merge_request_id: @merge_request.id)
- &nbsp;
= view_file_btn(diff_commit.id, diff_file, project)
diff --git a/app/views/projects/diffs/_match_line.html.haml b/app/views/projects/diffs/_match_line.html.haml
index d1f897b99f7..d6dddd97879 100644
--- a/app/views/projects/diffs/_match_line.html.haml
+++ b/app/views/projects/diffs/_match_line.html.haml
@@ -4,4 +4,4 @@
%td.new_line.diff-line-num{data: {linenumber: line_new},
class: [unfold_bottom_class(bottom), unfold_class(!new_file)]}
\...
-%td.line_content.matched= line
+%td.line_content.match= line
diff --git a/app/views/projects/diffs/_match_line_parallel.html.haml b/app/views/projects/diffs/_match_line_parallel.html.haml
index 815df16aa4a..0cd888876e0 100644
--- a/app/views/projects/diffs/_match_line_parallel.html.haml
+++ b/app/views/projects/diffs/_match_line_parallel.html.haml
@@ -1,4 +1,4 @@
-%td.old_line
- %td.line_content.parallel.matched= line
-%td.new_line
- %td.line_content.parallel.matched= line
+%td.old_line.diff-line-num
+%td.line_content.parallel.match= line
+%td.new_line.diff-line-num
+%td.line_content.parallel.match= line
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index 37fd1b1ec8a..d7c49068745 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -1,42 +1,40 @@
/ Side-by-side diff view
-%div.text-file.diff-wrap-lines
+%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight
%table
- - parallel_diff(diff_file, index).each do |line|
- - type_left = line[0]
- - line_number_left = line[1]
- - line_content_left = line[2]
- - line_code_left = line[3]
- - type_right = line[4]
- - line_number_right = line[5]
- - line_content_right = line[6]
- - line_code_right = line[7]
-
+ - diff_file.parallel_diff_lines.each do |line|
+ - left = line[:left]
+ - right = line[:right]
%tr.line_holder.parallel
- - if type_left == 'match'
- = render "projects/diffs/match_line_parallel", { line: line_content_left,
- line_old: line_number_left, line_new: line_number_right }
- - elsif type_left == 'old' || type_left.nil?
- %td.old_line{id: line_code_left, class: "#{type_left}"}
- = link_to raw(line_number_left), "##{line_code_left}", id: line_code_left
+ - if left[:type] == 'match'
+ = render "projects/diffs/match_line_parallel", { line: left[:text],
+ line_old: left[:number], line_new: right[:number] }
+ - elsif left[:type] == 'nonewline'
+ %td.old_line.diff-line-num
+ %td.line_content.parallel.match= left[:text]
+ %td.new_line.diff-line-num
+ %td.line_content.parallel.match= left[:text]
+ - else
+ %td.old_line.diff-line-num{id: left[:line_code], class: "#{left[:type]}"}
+ = link_to raw(left[:number]), "##{left[:line_code]}", id: left[:line_code]
- if @comments_allowed && can?(current_user, :create_note, @project)
- = link_to_new_diff_note(line_code_left, 'old')
- %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw line_content_left
+ = link_to_new_diff_note(left[:line_code], 'old')
+ %td.line_content{class: "parallel noteable_line #{left[:type]} #{left[:line_code]}", data: { line_code: left[:line_code] }}= diff_line_content(left[:text])
- - if type_right == 'new'
+ - if right[:type] == 'new'
- new_line_class = 'new'
- - new_line_code = line_code_right
+ - new_line_code = right[:line_code]
- else
- new_line_class = nil
- - new_line_code = line_code_left
+ - new_line_code = left[:line_code]
- %td.new_line{id: new_line_code, class: "#{new_line_class}", data: { linenumber: line_number_right }}
- = link_to raw(line_number_right), "##{new_line_code}", id: new_line_code
+ %td.new_line.diff-line-num{id: new_line_code, class: "#{new_line_class}", data: { linenumber: right[:number] }}
+ = link_to raw(right[:number]), "##{new_line_code}", id: new_line_code
- if @comments_allowed && can?(current_user, :create_note, @project)
- = link_to_new_diff_note(line_code_right, 'new')
- %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw line_content_right
+ = link_to_new_diff_note(right[:line_code], 'new')
+ %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", data: { line_code: new_line_code }}= diff_line_content(right[:text])
- if @reply_allowed
- - comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right)
+ - comments_left, comments_right = organize_comments(left[:type], right[:type], left[:line_code], right[:line_code])
- if comments_left.present? || comments_right.present?
= render "projects/notes/diff_notes_with_reply_parallel", notes_left: comments_left, notes_right: comments_right
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index 977ca423f75..5e835b10e1f 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -3,9 +3,11 @@
.suppressed-container
%a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show.
-%table.text-file{class: "#{'hide' if too_big}"}
+%table.text-file.code.js-syntax-highlight{ class: too_big ? 'hide' : '' }
+
- last_line = 0
- - diff_file.diff_lines.each_with_index do |line, index|
+ - raw_diff_lines = diff_file.diff_lines
+ - diff_file.highlighted_diff_lines.each_with_index do |line, index|
- type = line.type
- last_line = line.new_pos
- line_code = generate_line_code(diff_file.file_path, line)
@@ -14,19 +16,23 @@
- if type == "match"
= render "projects/diffs/match_line", {line: line.text,
line_old: line_old, line_new: line.new_pos, bottom: false, new_file: diff_file.new_file}
+ - elsif type == 'nonewline'
+ %td.old_line.diff-line-num
+ %td.new_line.diff-line-num
+ %td.line_content.match= line.text
- else
- %td.old_line
+ %td.old_line.diff-line-num{class: type}
= link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
- if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code)
- %td.new_line{data: {linenumber: line.new_pos}}
- = link_to raw(type == "old" ? "&nbsp;" : line.new_pos) , "##{line_code}", id: line_code
- %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text)
+ %td.new_line.diff-line-num{class: type, data: {linenumber: line.new_pos}}
+ = link_to raw(type == "old" ? "&nbsp;" : line.new_pos), "##{line_code}", id: line_code
+ %td.line_content{class: "noteable_line #{type} #{line_code}", data: { line_code: line_code }}= diff_line_content(line.text)
- if @reply_allowed
- comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at)
- unless comments.empty?
- = render "projects/notes/diff_notes_with_reply", notes: comments, line: line.text
+ = render "projects/notes/diff_notes_with_reply", notes: comments, line: raw_diff_lines[index].text
- if last_line > 0
= render "projects/diffs/match_line", {line: "",
diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml
index 40a2a61d8a1..905f6bbbd48 100644
--- a/app/views/projects/find_file/show.html.haml
+++ b/app/views/projects/find_file/show.html.haml
@@ -10,7 +10,7 @@
= link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path
%li.file-finder
- %input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path'}
+ %input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path', autocomplete: 'off'}
%div.tree-content-holder
.table-holder
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index e0e89b764d5..f34f3c05737 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -5,9 +5,4 @@
.nothing-here-block No issues to show
- if @issues.present?
- .issuable-filter-count
- %span.pull-right
- = number_with_delimiter(@issues.total_count)
- issues for this filter
-
= paginate @issues, theme: "gitlab"
diff --git a/app/views/projects/merge_requests/_merge_requests.html.haml b/app/views/projects/merge_requests/_merge_requests.html.haml
index 29d09d0a652..5473fa19166 100644
--- a/app/views/projects/merge_requests/_merge_requests.html.haml
+++ b/app/views/projects/merge_requests/_merge_requests.html.haml
@@ -5,10 +5,5 @@
.nothing-here-block No merge requests to show
- if @merge_requests.present?
- .issuable-filter-count
- %span.pull-right
- = number_with_delimiter(@merge_requests.total_count)
- merge requests for this filter
-
= paginate @merge_requests, theme: "gitlab"
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index dd2c59e112a..4c5a9818e3e 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -38,7 +38,7 @@
= render "projects/merge_requests/show/commits"
#diffs.diffs.tab-pane.active
- if @diffs.present?
- = render "projects/diffs/diffs", diffs: @diffs, project: @project
+ = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
.alert.alert-danger
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml
index d9cfc3d7ae9..64cd484193e 100644
--- a/app/views/projects/merge_requests/show/_diffs.html.haml
+++ b/app/views/projects/merge_requests/show/_diffs.html.haml
@@ -1,5 +1,6 @@
- if @merge_request_diff.collected?
- = render "projects/diffs/diffs", diffs: params[:w] == '1' ? @merge_request.diffs_no_whitespace : @merge_request.diffs, project: @merge_request.project
+ = render "projects/diffs/diffs", diffs: params[:w] == '1' ? @merge_request.diffs_no_whitespace : @merge_request.diffs,
+ project: @merge_request.project, diff_refs: @merge_request.diff_refs
- elsif @merge_request_diff.empty?
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
- else
diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml
index eb378b42603..910eb6cf66e 100644
--- a/app/views/projects/notes/_notes_with_form.html.haml
+++ b/app/views/projects/notes/_notes_with_form.html.haml
@@ -5,6 +5,16 @@
.js-main-target-form
- if can? current_user, :create_note, @project
= render "projects/notes/form", view: diff_view
+- else
+ .disabled-comment-area
+ .disabled-profile
+ .disabled-comment
+ %span
+ Please
+ = link_to "register",new_user_session_path
+ or
+ = link_to "login",new_user_session_path
+ to post a comment
:javascript
var notes = new Notes("#{namespace_project_notes_path(namespace_id: @project.namespace, target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}")
diff --git a/app/views/projects/notes/discussions/_diff.html.haml b/app/views/projects/notes/discussions/_diff.html.haml
index 0301445b5b2..92bbaf0961a 100644
--- a/app/views/projects/notes/discussions/_diff.html.haml
+++ b/app/views/projects/notes/discussions/_diff.html.haml
@@ -16,15 +16,15 @@
- line_code = generate_line_code(note.file_path, line)
%tr.line_holder{ id: line_code, class: "#{type}" }
- if type == "match"
- %td.old_line= "..."
- %td.new_line= "..."
- %td.line_content.matched= line.text
+ %td.old_line.diff-line-num= "..."
+ %td.new_line.diff-line-num= "..."
+ %td.line_content.match= line.text
- else
- %td.old_line
+ %td.old_line.diff-line-num
= raw(type == "new" ? "&nbsp;" : line.old_pos)
- %td.new_line
+ %td.new_line.diff-line-num
= raw(type == "old" ? "&nbsp;" : line.new_pos)
- %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text)
+ %td.line_content{class: "noteable_line #{type} #{line_code}", line_code: line_code}= diff_line_content(line.text)
- if line_code == note.line_code
= render "projects/notes/diff_notes_with_reply", notes: discussion_notes
diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml
index 9a4f9fb9485..dcd61199717 100644
--- a/app/views/search/results/_snippet_blob.html.haml
+++ b/app/views/search/results/_snippet_blob.html.haml
@@ -22,29 +22,27 @@
.file-content.code
.nothing-here-block Empty file
- else
- .file-content.code
- %div.highlighted-data{ class: user_color_scheme }
- .line-numbers
+ .file-content.code.js-syntax-highlight
+ .line-numbers
+ - snippet_blob[:snippet_chunks].each do |snippet|
+ - unless snippet[:data].empty?
+ - snippet[:data].lines.to_a.size.times do |index|
+ - offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1
+ - i = index + offset
+ = link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}", class: "diff-line-num" do
+ %i.fa.fa-link
+ = i
+ - unless snippet == snippet_blob[:snippet_chunks].last
+ %a.diff-line-num
+ = "."
+ %pre.code
+ %code
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
- - snippet[:data].lines.to_a.size.times do |index|
- - offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1
- - i = index + offset
- = link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}" do
- %i.fa.fa-link
- = i
+ = snippet[:data]
- unless snippet == snippet_blob[:snippet_chunks].last
%a
- = "."
- .highlight.term
- %pre
- %code
- - snippet_blob[:snippet_chunks].each do |snippet|
- - unless snippet[:data].empty?
- = snippet[:data]
- - unless snippet == snippet_blob[:snippet_chunks].last
- %a
- = "..."
- - else
- .file-content.code
- .nothing-here-block Empty file
+ = "..."
+ - else
+ .file-content.code
+ .nothing-here-block Empty file
diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml
index 2bc98983d67..ee242c94db8 100644
--- a/app/views/shared/_file_highlight.html.haml
+++ b/app/views/shared/_file_highlight.html.haml
@@ -1,13 +1,12 @@
-.file-content.code.js-syntax-highlight{ class: user_color_scheme }
+.file-content.code.js-syntax-highlight
.line-numbers
- if blob.data.present?
- blob.data.lines.each_index do |index|
- offset = defined?(first_line_number) ? first_line_number : 1
- i = index + offset
-# We're not using `link_to` because it is too slow once we get to thousands of lines.
- %a{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}
+ %a.diff-line-num{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}
%i.fa.fa-link
= i
.blob-content{data: {blob_id: blob.id}}
- :preserve
- #{highlight(blob.name, blob.data)}
+ = highlight(blob.name, blob.data)
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 9f4a7098ea2..3092ff54242 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -10,6 +10,9 @@
.value
- if issuable.assignee
%strong= link_to_member(@project, issuable.assignee, size: 24)
+ - if issuable.instance_of?(MergeRequest) && !issuable.can_be_merged_by?(issuable.assignee)
+ %a.pull-right.cannot-be-merged{href: '#', data: {toggle: 'tooltip'}, title: 'Not allowed to merge'}
+ = icon('exclamation-triangle')
- else
.light None
diff --git a/config.ru b/config.ru
index a2525c81361..065ce59932f 100644
--- a/config.ru
+++ b/config.ru
@@ -7,8 +7,11 @@ if defined?(Unicorn)
# Unicorn self-process killer
require 'unicorn/worker_killer'
+ min = (ENV['GITLAB_UNICORN_MEMORY_MIN'] || 300 * 1 << 20).to_i
+ max = (ENV['GITLAB_UNICORN_MEMORY_MAX'] || 350 * 1 << 20).to_i
+
# Max memory size (RSS) per worker
- use Unicorn::WorkerKiller::Oom, (200 * (1 << 20)), (250 * (1 << 20))
+ use Unicorn::WorkerKiller::Oom, min, max
end
end
diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb
index b1fe36dc21c..0945b93ed5d 100644
--- a/config/initializers/metrics.rb
+++ b/config/initializers/metrics.rb
@@ -49,6 +49,7 @@ if Gitlab::Metrics.enabled?
config.instrument_instance_methods(Gitlab::Shell)
config.instrument_methods(Gitlab::Git)
+ config.instrument_instance_methods(Gitlab::Git::Repository)
Gitlab::Git.constants.each do |name|
const = Gitlab::Git.const_get(name)
diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb
new file mode 100644
index 00000000000..d0630b9fa07
--- /dev/null
+++ b/config/initializers/sentry.rb
@@ -0,0 +1,19 @@
+# Be sure to restart your server when you modify this file.
+
+require 'gitlab/current_settings'
+include Gitlab::CurrentSettings
+
+if Rails.env.production?
+ # allow it to fail: it may do so when create_from_defaults is executed before migrations are actually done
+ begin
+ sentry_enabled = current_application_settings.sentry_enabled
+ rescue
+ sentry_enabled = false
+ end
+
+ if sentry_enabled
+ Raven.configure do |config|
+ config.dsn = current_application_settings.sentry_dsn
+ end
+ end
+end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index f6cfb5efd2a..cedb5e207bd 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -8,3 +8,7 @@ en:
wrong_size: "is the wrong size (should be %{file_size})"
size_too_small: "is too small (should be at least %{file_size})"
size_too_big: "is too big (should be at most %{file_size})"
+ views:
+ pagination:
+ previous: "Prev"
+ next: "Next"
diff --git a/db/migrate/20160118155830_add_sentry_to_application_settings.rb b/db/migrate/20160118155830_add_sentry_to_application_settings.rb
new file mode 100644
index 00000000000..fa7ff9d9228
--- /dev/null
+++ b/db/migrate/20160118155830_add_sentry_to_application_settings.rb
@@ -0,0 +1,8 @@
+class AddSentryToApplicationSettings < ActiveRecord::Migration
+ def change
+ change_table :application_settings do |t|
+ t.boolean :sentry_enabled, default: false
+ t.string :sentry_dsn
+ end
+ end
+end
diff --git a/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb b/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb
new file mode 100644
index 00000000000..26606b10b54
--- /dev/null
+++ b/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb
@@ -0,0 +1,6 @@
+class AddIpBlockingSettingsToApplicationSettings < ActiveRecord::Migration
+ def change
+ add_column :application_settings, :ip_blocking_enabled, :boolean, default: false
+ add_column :application_settings, :dnsbl_servers_list, :text
+ end
+end
diff --git a/db/migrate/20160119111158_add_services_category.rb b/db/migrate/20160119111158_add_services_category.rb
new file mode 100644
index 00000000000..a9110a8418b
--- /dev/null
+++ b/db/migrate/20160119111158_add_services_category.rb
@@ -0,0 +1,39 @@
+class AddServicesCategory < ActiveRecord::Migration
+ def up
+ add_column :services, :category, :string, default: 'common', null: false
+
+ category = quote_column_name('category')
+ type = quote_column_name('type')
+
+ execute <<-EOF
+UPDATE services
+SET #{category} = 'issue_tracker'
+WHERE #{type} IN (
+ 'CustomIssueTrackerService',
+ 'GitlabIssueTrackerService',
+ 'IssueTrackerService',
+ 'JiraService',
+ 'RedmineService'
+);
+EOF
+
+ execute <<-EOF
+UPDATE services
+SET #{category} = 'ci'
+WHERE #{type} IN (
+ 'BambooService',
+ 'BuildkiteService',
+ 'CiService',
+ 'DroneCiService',
+ 'GitlabCiService',
+ 'TeamcityService'
+);
+ EOF
+
+ add_index :services, :category
+ end
+
+ def down
+ remove_column :services, :category
+ end
+end
diff --git a/db/migrate/20160119112418_add_services_default.rb b/db/migrate/20160119112418_add_services_default.rb
new file mode 100644
index 00000000000..69a42d7b873
--- /dev/null
+++ b/db/migrate/20160119112418_add_services_default.rb
@@ -0,0 +1,20 @@
+class AddServicesDefault < ActiveRecord::Migration
+ def up
+ add_column :services, :default, :boolean, default: false
+
+ default = quote_column_name('default')
+ type = quote_column_name('type')
+
+ execute <<-EOF
+UPDATE services
+SET #{default} = true
+WHERE #{type} = 'GitlabIssueTrackerService'
+EOF
+
+ add_index :services, :default
+ end
+
+ def down
+ remove_column :services, :default
+ end
+end
diff --git a/db/migrate/20160119145451_add_ldap_email_to_users.rb b/db/migrate/20160119145451_add_ldap_email_to_users.rb
new file mode 100644
index 00000000000..654d31ab15a
--- /dev/null
+++ b/db/migrate/20160119145451_add_ldap_email_to_users.rb
@@ -0,0 +1,30 @@
+class AddLdapEmailToUsers < ActiveRecord::Migration
+ def up
+ add_column :users, :ldap_email, :boolean, default: false, null: false
+
+ if Gitlab::Database.mysql?
+ execute %{
+ UPDATE users, identities
+ SET users.ldap_email = TRUE
+ WHERE identities.user_id = users.id
+ AND users.email LIKE 'temp-email-for-oauth%'
+ AND identities.provider LIKE 'ldap%'
+ AND identities.extern_uid IS NOT NULL
+ }
+ else
+ execute %{
+ UPDATE users
+ SET ldap_email = TRUE
+ FROM identities
+ WHERE identities.user_id = users.id
+ AND users.email LIKE 'temp-email-for-oauth%'
+ AND identities.provider LIKE 'ldap%'
+ AND identities.extern_uid IS NOT NULL
+ }
+ end
+ end
+
+ def down
+ remove_column :users, :ldap_email
+ end
+end
diff --git a/db/migrate/20160120172143_add_base_commit_sha_to_merge_request_diffs.rb b/db/migrate/20160120172143_add_base_commit_sha_to_merge_request_diffs.rb
new file mode 100644
index 00000000000..d6c6aa4a4e8
--- /dev/null
+++ b/db/migrate/20160120172143_add_base_commit_sha_to_merge_request_diffs.rb
@@ -0,0 +1,5 @@
+class AddBaseCommitShaToMergeRequestDiffs < ActiveRecord::Migration
+ def change
+ add_column :merge_request_diffs, :base_commit_sha, :string
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 9045135dd9a..97594011a02 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: 20160113111034) do
+ActiveRecord::Schema.define(version: 20160120172143) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -62,6 +62,10 @@ ActiveRecord::Schema.define(version: 20160113111034) do
t.string "recaptcha_private_key"
t.integer "metrics_port", default: 8089
t.integer "metrics_sample_interval", default: 15
+ t.boolean "sentry_enabled", default: false
+ t.string "sentry_dsn"
+ t.boolean "ip_blocking_enabled", default: false
+ t.text "dnsbl_servers_list"
end
create_table "audit_events", force: :cascade do |t|
@@ -490,6 +494,7 @@ ActiveRecord::Schema.define(version: 20160113111034) do
t.integer "merge_request_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
+ t.string "base_commit_sha"
end
add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree
@@ -725,20 +730,24 @@ ActiveRecord::Schema.define(version: 20160113111034) do
t.string "type"
t.string "title"
t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.boolean "active", default: false, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.boolean "active", null: false
t.text "properties"
t.boolean "template", default: false
t.boolean "push_events", default: true
t.boolean "issues_events", default: true
t.boolean "merge_requests_events", default: true
t.boolean "tag_push_events", default: true
- t.boolean "note_events", default: true, null: false
- t.boolean "build_events", default: false, null: false
+ t.boolean "note_events", default: true, null: false
+ t.boolean "build_events", default: false, null: false
+ t.string "category", default: "common", null: false
+ t.boolean "default", default: false
end
+ add_index "services", ["category"], name: "index_services_on_category", using: :btree
add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree
+ add_index "services", ["default"], name: "index_services_on_default", using: :btree
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
add_index "services", ["template"], name: "index_services_on_template", using: :btree
@@ -850,6 +859,7 @@ ActiveRecord::Schema.define(version: 20160113111034) do
t.boolean "hide_project_limit", default: false
t.string "unlock_token"
t.datetime "otp_grace_period_started_at"
+ t.boolean "ldap_email", default: false, null: false
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
diff --git a/doc/README.md b/doc/README.md
index 7d4f84857e0..5089e1e70f6 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -30,6 +30,7 @@
- [User permissions](ci/permissions/README.md)
- [API](ci/api/README.md)
- [Triggering builds through the API](ci/triggers/README.md)
+- [Build artifacts](ci/build_artifacts/README.md)
### CI Languages
@@ -53,6 +54,7 @@
- [Custom git hooks](hooks/custom_hooks.md) Custom git hooks (on the filesystem) for when web hooks aren't enough.
- [Install](install/README.md) Requirements, directory structures and installation from source.
+- [Restart GitLab](administration/restart_gitlab.md) Learn how to restart GitLab and its components
- [Integration](integration/README.md) How to integrate with systems such as JIRA, Redmine, LDAP and Twitter.
- [Issue closing](customization/issue_closing.md) Customize how to close an issue from commit messages.
- [Libravatar](customization/libravatar.md) Use Libravatar for user avatars.
@@ -67,6 +69,8 @@
- [Reply by email](incoming_email/README.md) Allow users to comment on issues and merge requests by replying to notification emails.
- [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE.
- [Git LFS configuration](workflow/lfs/lfs_administration.md)
+- [Housekeeping](administration/housekeeping.md) Keep your Git repository tidy and fast.
+- [GitLab Performance Monitoring](monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics
## Contributor documentation
diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md
index 1eb3a74d304..42a27dcf6d6 100644
--- a/doc/administration/environment_variables.md
+++ b/doc/administration/environment_variables.md
@@ -17,6 +17,8 @@ DATABASE_URL | url | For example: postgresql://localhost/blog_development?pool=5
GITLAB_EMAIL_FROM | email | Email address used in the "From" field in mails sent by GitLab
GITLAB_EMAIL_DISPLAY_NAME | string | Name used in the "From" field in mails sent by GitLab
GITLAB_EMAIL_REPLY_TO | email | Email address used in the "Reply-To" field in mails sent by GitLab
+GITLAB_UNICORN_MEMORY_MIN | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer
+GITLAB_UNICORN_MEMORY_MAX | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer
## Complete database variables
diff --git a/doc/administration/housekeeping.md b/doc/administration/housekeeping.md
new file mode 100644
index 00000000000..c27cf1812dc
--- /dev/null
+++ b/doc/administration/housekeeping.md
@@ -0,0 +1,22 @@
+# Housekeeping
+
+_**Note:** This feature was [introduced][ce-2371] in GitLab 8.4_
+
+---
+
+The housekeeping function runs [`git gc`][man] on the current project Git
+repository.
+
+`git gc` runs a number of housekeeping tasks, such as compressing file
+revisions (to reduce disk space and increase performance) and removing
+unreachable objects which may have been created from prior invocations of
+`git add`.
+
+You can find this option under your **[Project] > Settings**.
+
+---
+
+![Housekeeping settings](img/housekeeping_settings.png)
+
+[ce-2371]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2371 "Housekeeping merge request"
+[man]: https://www.kernel.org/pub/software/scm/git/docs/git-gc.html "git gc man page"
diff --git a/doc/administration/img/housekeeping_settings.png b/doc/administration/img/housekeeping_settings.png
new file mode 100644
index 00000000000..f7c5bc44367
--- /dev/null
+++ b/doc/administration/img/housekeeping_settings.png
Binary files differ
diff --git a/doc/administration/restart_gitlab.md b/doc/administration/restart_gitlab.md
new file mode 100644
index 00000000000..483060395dd
--- /dev/null
+++ b/doc/administration/restart_gitlab.md
@@ -0,0 +1,145 @@
+# How to restart GitLab
+
+Depending on how you installed GitLab, there are different methods to restart
+its service(s).
+
+If you want the TL;DR versions, jump to:
+
+- [Omnibus GitLab restart](#omnibus-gitlab-restart)
+- [Omnibus GitLab reconfigure](#omnibus-gitlab-reconfigure)
+- [Source installation restart](#installations-from-source)
+
+## Omnibus installations
+
+If you have used the [Omnibus packages][omnibus-dl] to install GitLab, then
+you should already have `gitlab-ctl` in your `PATH`.
+
+`gitlab-ctl` interacts with the Omnibus packages and can be used to restart the
+GitLab Rails application (Unicorn) as well as the other components, like:
+
+- GitLab Workhorse
+- Sidekiq
+- PostgreSQL (if you are using the bundled one)
+- NGINX (if you are using the bundled one)
+- Redis (if you are using the bundled one)
+- [Mailroom][]
+- Logrotate
+
+### Omnibus GitLab restart
+
+There may be times in the documentation where you will be asked to _restart_
+GitLab. In that case, you need to run the following command:
+
+```bash
+sudo gitlab-ctl restart
+```
+
+The output should be similar to this:
+
+```
+ok: run: gitlab-workhorse: (pid 11291) 1s
+ok: run: logrotate: (pid 11299) 0s
+ok: run: mailroom: (pid 11306) 0s
+ok: run: nginx: (pid 11309) 0s
+ok: run: postgresql: (pid 11316) 1s
+ok: run: redis: (pid 11325) 0s
+ok: run: sidekiq: (pid 11331) 1s
+ok: run: unicorn: (pid 11338) 0s
+```
+
+To restart a component separately, you can append its service name to the
+`restart` command. For example, to restart **only** NGINX you would run:
+
+```bash
+sudo gitlab-ctl restart nginx
+```
+
+To check the status of GitLab services, run:
+
+```bash
+sudo gitlab-ctl status
+```
+
+Notice that all services say `ok: run`.
+
+Sometimes, components time out during the restart and sometimes they get stuck.
+In that case, you can use `gitlab-ctl kill <service>` to send the `SIGKILL`
+signal to the service, for example `sidekiq`. After that, a restart should
+perform fine.
+
+As a last resort, you can try to
+[reconfigure GitLab](#omnibus-gitlab-reconfigure) instead.
+
+### Omnibus GitLab reconfigure
+
+There may be times in the documentation where you will be asked to _reconfigure_
+GitLab. Remember that this method applies only for the Omnibus packages.
+
+Reconfigure Omnibus GitLab with:
+
+```bash
+sudo gitlab-ctl reconfigure
+```
+
+Reconfiguring GitLab should occur in the event that something in its
+configuration (`/etc/gitlab/gitlab.rb`) has changed.
+
+When you run this command, [Chef], the underlying configuration management
+application that powers Omnibus GitLab, will make sure that all directories,
+permissions, services, etc., are in place and in the same shape that they were
+initially shipped.
+
+It will also restart GitLab components where needed, if any of their
+configuration files have changed.
+
+If you manually edit any files in `/var/opt/gitlab` that are managed by Chef,
+running reconfigure will revert the changes AND restart the services that
+depend on those files.
+
+## Installations from source
+
+If you have followed the official installation guide to [install GitLab from
+source][install], run the following command to restart GitLab:
+
+```
+sudo service gitlab restart
+```
+
+The output should be similar to this:
+
+```
+Shutting down GitLab Unicorn
+Shutting down GitLab Sidekiq
+Shutting down GitLab Workhorse
+Shutting down GitLab MailRoom
+...
+GitLab is not running.
+Starting GitLab Unicorn
+Starting GitLab Sidekiq
+Starting GitLab Workhorse
+Starting GitLab MailRoom
+...
+The GitLab Unicorn web server with pid 28059 is running.
+The GitLab Sidekiq job dispatcher with pid 28176 is running.
+The GitLab Workhorse with pid 28122 is running.
+The GitLab MailRoom email processor with pid 28114 is running.
+GitLab and all its components are up and running.
+```
+
+This should restart Unicorn, Sidekiq, GitLab Workhorse and [Mailroom][]
+(if enabled). The init service file that does all the magic can be found on
+your server in `/etc/init.d/gitlab`.
+
+---
+
+If you are using other init systems, like systemd, you can check the
+[GitLab Recipes][gl-recipes] repository for some unofficial services. These are
+**not** officially supported so use them at your own risk.
+
+
+[omnibus-dl]: https://about.gitlab.com/downloads/ "Download the Omnibus packages"
+[install]: ../install/installation.md "Documentation to install GitLab from source"
+[mailroom]: ../incoming_email/README.md "Used for replying by email in GitLab issues and merge requests"
+[chef]: https://www.chef.io/chef/ "Chef official website"
+[src-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/support/init.d/gitlab "GitLab init service file"
+[gl-recipes]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/init "GitLab Recipes repository"
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 808675d8605..d47e79ba47f 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -33,6 +33,7 @@ GET /groups/:id/projects
Parameters:
- `archived` (optional) - if passed, limit by archived status
+- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 241229221db..3f372c955d2 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -29,6 +29,7 @@ GET /projects
Parameters:
- `archived` (optional) - if passed, limit by archived status
+- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
@@ -152,6 +153,7 @@ GET /projects/owned
Parameters:
- `archived` (optional) - if passed, limit by archived status
+- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
@@ -167,6 +169,7 @@ GET /projects/starred
Parameters:
- `archived` (optional) - if passed, limit by archived status
+- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
@@ -182,6 +185,7 @@ GET /projects/all
Parameters:
- `archived` (optional) - if passed, limit by archived status
+- `visibility` (optional) - if passed, limit by visibility `public`, `internal`, `private`
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 4cdd2e1ad33..5886829be51 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -12,6 +12,7 @@
* [Using Variables](variables/README.md)
* [Using SSH keys](ssh_keys/README.md)
* [Triggering builds through the API](triggers/README.md)
+* [Build artifacts](build_artifacts/README.md)
### Languages
diff --git a/doc/ci/build_artifacts/README.md b/doc/ci/build_artifacts/README.md
new file mode 100644
index 00000000000..b02caa9edff
--- /dev/null
+++ b/doc/ci/build_artifacts/README.md
@@ -0,0 +1,173 @@
+# Introduction to build artifacts
+
+Artifacts is a list of files and directories which are attached to a build
+after it completes successfully.
+
+Since GitLab 8.2 and [GitLab Runner] 0.7.0, build artifacts that are created by
+GitLab Runner are uploaded to GitLab and are downloadable as a single archive
+(`tar.gz`) using the GitLab UI.
+
+Starting from GitLab 8.4 and GitLab Runner 1.0, the artifacts archive format
+changed to `ZIP`, and it is now possible to browse its contents, with the added
+ability of downloading the files separately.
+
+## Enabling build artifacts
+
+If you are searching for ways to use the artifacts feature, jump to
+[Defining artifacts in `.gitlab-ci.yml`](#defining-artifacts-in-gitlab-ciyml).
+
+The artifacts feature is enabled by default in all GitLab installations.
+
+If by any chance you want to disable the artifacts feature on your GitLab
+instance, follow the steps below.
+
+---
+
+**In Omnibus installations:**
+
+1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
+
+ ```ruby
+ gitlab_rails['artifacts_enabled'] = false
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**In installations from source:**
+
+1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
+
+ ```yaml
+ artifacts:
+ enabled: false
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
+## Defining artifacts in `.gitlab-ci.yml`
+
+A simple example of using the artifacts definition in `.gitlab-ci.yml` would be
+the following:
+
+```yaml
+pdf:
+ script: xelatex mycv.tex
+ artifacts:
+ paths:
+ - mycv.pdf
+```
+
+A job named `pdf` calls the `xelatex` command in order to build a pdf file from
+the latex source file `mycv.tex`. We then define the `artifacts` paths which in
+turn are defined with the `paths` keyword. All paths to files and directories
+are relative to the repository that was cloned during the build.
+
+For more examples on artifacts, follow the
+[separate artifacts yaml documentation](../yaml/README.md#artifacts).
+
+## Storing build artifacts
+
+After a successful build, GitLab Runner uploads an archive containing the build
+artifacts to GitLab.
+
+To change the location where the artifacts are stored, follow the steps below.
+
+---
+
+**In Omnibus installations:**
+
+_The artifacts are stored by default in
+`/var/opt/gitlab/gitlab-rails/shared/artifacts`._
+
+1. To change the storage path for example to `/mnt/storage/artifacts`, edit
+ `/etc/gitlab/gitlab.rb` and add the following line:
+
+ ```ruby
+ gitlab_rails['artifacts_path'] = "/mnt/storage/artifacts"
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**In installations from source:**
+
+_The artifacts are stored by default in
+`/home/git/gitlab/shared/artifacts`._
+
+1. To change the storage path for example to `/mnt/storage/artifacts`, edit
+ `/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
+
+ ```yaml
+ artifacts:
+ enabled: true
+ path: /mnt/storage/artifacts
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
+## Browsing build artifacts
+
+When GitLab receives an artifacts archive, an archive metadata file is also
+generated. This metadata file describes all the entries that are located in the
+artifacts archive itself. The metadata file is in a binary format, with
+additional GZIP compression.
+
+GitLab does not extract the artifacts archive in order to save space, memory
+and disk I/O. It instead inspects the metadata file which contains all the
+relevant information. This is especially important when there is a lot of
+artifacts, or an archive is a very large file.
+
+---
+
+After a successful build, if you visit the build's specific page, you can see
+that there are two buttons.
+
+One is for downloading the artifacts archive and the other for browsing its
+contents.
+
+![Build artifacts browser button](img/build_artifacts_browser_button.png)
+
+---
+
+The archive browser shows the name and the actual file size of each file in the
+archive. If your artifacts contained directories, then you are also able to
+browse inside them.
+
+Below you can see an image of three different file formats, as well as two
+directories.
+
+![Build artifacts browser](img/build_artifacts_browser.png)
+
+---
+
+## Downloading build artifacts
+
+If you need to download the whole archive, there are buttons in various places
+inside GitLab that make that possible.
+
+1. While on the builds page, you can see the download icon for each build's
+ artifacts archive in the right corner
+
+1. While inside a specific build, you are presented with a download button
+ along with the one that browses the archive
+
+1. And finally, when browsing and archive you can see the download button at
+ the top right corner
+
+---
+
+Note that GitLab does not extract the entire artifacts archive to send just a
+single file to the user.
+
+When clicking on a specific file, [GitLab Workhorse] extracts it from the
+archive and the download begins.
+
+This implementation saves space, memory and disk I/O.
+
+[gitlab runner]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner "GitLab Runner repository"
+[reconfigure gitlab]: ../../administration/restart_gitlab.md "How to restart GitLab documentation"
+[restart gitlab]: ../../administration/restart_gitlab.md "How to restart GitLab documentation"
+[gitlab workhorse]: https://gitlab.com/gitlab-org/gitlab-workhorse "GitLab Workhorse repository"
diff --git a/doc/ci/build_artifacts/img/build_artifacts_browser.png b/doc/ci/build_artifacts/img/build_artifacts_browser.png
new file mode 100644
index 00000000000..73ed4eeb927
--- /dev/null
+++ b/doc/ci/build_artifacts/img/build_artifacts_browser.png
Binary files differ
diff --git a/doc/ci/build_artifacts/img/build_artifacts_browser_button.png b/doc/ci/build_artifacts/img/build_artifacts_browser_button.png
new file mode 100644
index 00000000000..f5d15bc3e7d
--- /dev/null
+++ b/doc/ci/build_artifacts/img/build_artifacts_browser_button.png
Binary files differ
diff --git a/doc/ci/languages/php.md b/doc/ci/languages/php.md
index dacb67fa3ff..77f9fae5bb6 100644
--- a/doc/ci/languages/php.md
+++ b/doc/ci/languages/php.md
@@ -12,7 +12,7 @@ configuration from the developer. To overcome this we will be using the
official [PHP docker image][php-hub] that can be found in Docker Hub.
This will allow us to test PHP projects against different versions of PHP.
-However, not everything is plug 'n' play, you still need to onfigure some
+However, not everything is plug 'n' play, you still need to configure some
things manually.
As with every build, you need to create a valid `.gitlab-ci.yml` describing the
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index b99ea25a3fe..862cacda586 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -56,7 +56,7 @@ export CI_SERVER_VERSION=""
```
### YAML-defined variables
-**This feature requires GitLab Runner 0.5.0 or higher**
+**This feature requires GitLab Runner 0.5.0 or higher and GitLab CI 7.14 or higher **
GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in build environment.
The variables are stored in repository and are meant to store non-sensitive project configuration, ie. RAILS_ENV or DATABASE_URL.
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index fd0d49de4e4..3b594df659d 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -135,10 +135,9 @@ thus allowing to fine tune them.
### cache
`cache` is used to specify a list of files and directories which should be
-cached between builds. Caches are stored according to the branch/ref and the
-job name. They are not currently shared between different job names or between
-branches/refs, which means that caching will benefit you if you push subsequent
-commits to an existing feature branch.
+cached between builds.
+
+**By default the caching is enabled per-job and per-branch.**
If `cache` is defined outside the scope of the jobs, it means it is set
globally and all jobs will use its definition.
@@ -152,6 +151,59 @@ cache:
- binaries/
```
+#### cache:key
+
+_**Note:** Introduced in GitLab Runner v1.0.0._
+
+The `key` directive allows you to define the affinity of caching
+between jobs, allowing to have a single cache for all jobs,
+cache per-job, cache per-branch or any other way you deem proper.
+
+This allows you to fine tune caching, allowing you to cache data between different jobs or even different branches.
+The `cache:key` variable can use any of the [predefined variables](../variables/README.md):
+
+Example configurations:
+
+To enable per-job caching:
+
+ ```yaml
+ cache:
+ key: "$CI_BUILD_NAME"
+ untracked: true
+ ```
+
+To enable per-branch caching:
+
+ ```yaml
+ cache:
+ key: "$CI_BUILD_REF_NAME"
+ untracked: true
+ ```
+
+To enable per-job and per-branch caching:
+
+ ```yaml
+ cache:
+ key: "$CI_BUILD_NAME/$CI_BUILD_REF_NAME"
+ untracked: true
+ ```
+
+To enable per-branch and per-stage caching:
+
+ ```yaml
+ cache:
+ key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME"
+ untracked: true
+ ```
+
+If you use **Windows Batch** to run your shell scripts you need to replace the `$` with `%`:
+
+ ```yaml
+ cache:
+ key: "%CI_BUILD_STAGE%/%CI_BUILD_REF_NAME%"
+ untracked: true
+ ```
+
## Jobs
`.gitlab-ci.yml` allows you to specify an unlimited number of jobs. Each job
diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md
index 0bd32b78201..caaa4032db2 100644
--- a/doc/development/doc_styleguide.md
+++ b/doc/development/doc_styleguide.md
@@ -103,6 +103,23 @@ Inside the document:
`_**Note:** This feature was introduced in GitLab EE 8.3_`. Otherwise, leave
this mention out
+## References
+
+- **GitLab Restart:**
+ There are many cases that a restart/reconfigure of GitLab is required. To
+ avoid duplication, link to the special document that can be found in
+ [`doc/administration/restart_gitlab.md`][doc-restart]. Usually the text will
+ read like:
+
+ ```
+ Save the file and [reconfigure GitLab](../administration/restart_gitlab.md)
+ for the changes to take effect.
+ ```
+ If the document you are editing resides in a place other than the GitLab CE/EE
+ `doc/` directory, instead of the relative link, use the full path:
+ `http://doc.gitlab.com/ce/administration/restart_gitlab.html`.
+ Replace `reconfigure` with `restart` where appropriate.
+
## API
Here is a list of must-have items. Use them in the exact order that appears
@@ -229,3 +246,4 @@ curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" -d "restricted_signup_domai
[cURL]: http://curl.haxx.se/ "cURL website"
[single spaces]: http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html
[gfm]: http://doc.gitlab.com/ce/markdown/markdown.html#newlines "GitLab flavored markdown documentation"
+[doc-restart]: ../administration/restart_gitlab.md "GitLab restart documentation"
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 00030729a4b..4772ed3c566 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -107,9 +107,16 @@ Then select 'Internet Site' and press enter to confirm the hostname.
## 2. Ruby
-The use of Ruby version managers such as [RVM](https://rvm.io/), [rbenv](https://github.com/sstephenson/rbenv) or [chruby](https://github.com/postmodern/chruby) with GitLab in production frequently leads to hard to diagnose problems. For example, GitLab Shell is called from OpenSSH and having a version manager can prevent pushing and pulling over SSH. Version managers are not supported and we strongly advise everyone to follow the instructions below to use a system Ruby.
+_**Note:** The current supported Ruby versions are 2.1.x. Ruby 2.2 and 2.3 are
+currently not supported._
-Remove the old Ruby 1.8 if present
+The use of Ruby version managers such as [RVM], [rbenv] or [chruby] with GitLab
+in production, frequently leads to hard to diagnose problems. For example,
+GitLab Shell is called from OpenSSH, and having a version manager can prevent
+pushing and pulling over SSH. Version managers are not supported and we strongly
+advise everyone to follow the instructions below to use a system Ruby.
+
+Remove the old Ruby 1.8 if present:
sudo apt-get remove ruby1.8
@@ -555,3 +562,7 @@ this is likely due to an outdated Nginx or Apache configuration, or a missing or
misconfigured gitlab-workhorse instance. Double-check that you've
[installed Go](#3-go), [installed gitlab-workhorse](#install-gitlab-workhorse),
and correctly [configured Nginx](#site-configuration).
+
+[RVM]: https://rvm.io/ "RVM Homepage"
+[rbenv]: https://github.com/sstephenson/rbenv "rbenv on GitHub"
+[chruby]: https://github.com/postmodern/chruby "chruby on GitHub"
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index c0ccdd37458..c0425f27ab1 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -32,15 +32,18 @@ Please consider using a virtual machine to run GitLab.
## Ruby versions
-GitLab requires Ruby (MRI) 2.1
+GitLab requires Ruby (MRI) 2.1.x and currently does not work with versions 2.2
+and 2.3.
+
You will have to use the standard MRI implementation of Ruby.
-We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/) but GitLab needs several Gems that have native extensions.
+We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/) but GitLab
+needs several Gems that have native extensions.
## Hardware requirements
### Storage
-The necessary hard drive space largely depends on the size of the repos you want to store in GitLab but as a *rule of thumb* you should have at least as much free space as all your repos combined take up.
+The necessary hard drive space largely depends on the size of the repos you want to store in GitLab but as a *rule of thumb* you should have at least as much free space as all your repos combined take up.
If you want to be flexible about growing your hard drive space in the future consider mounting it using LVM so you can add more hard drives when you need them.
@@ -109,4 +112,4 @@ On a very active server (10,000 active users) the Sidekiq process can use 1GB+ o
- Firefox (Latest released version and [latest ESR version](https://www.mozilla.org/en-US/firefox/organizations/))
- Safari 7+ (known problem: required fields in html5 do not work)
- Opera (Latest released version)
-- Internet Explorer (IE) 10+ but please make sure that you have the `Compatibility View` mode disabled. \ No newline at end of file
+- Internet Explorer (IE) 10+ but please make sure that you have the `Compatibility View` mode disabled.
diff --git a/doc/monitoring/performance/gitlab_configuration.md b/doc/monitoring/performance/gitlab_configuration.md
new file mode 100644
index 00000000000..b856e7935a3
--- /dev/null
+++ b/doc/monitoring/performance/gitlab_configuration.md
@@ -0,0 +1,39 @@
+# GitLab Configuration
+
+GitLab Performance Monitoring is disabled by default. To enable it and change any of its
+settings, navigate to the Admin area in **Settings > Metrics**
+(`/admin/application_settings`).
+
+The minimum required settings you need to set are the InfluxDB host and port.
+Make sure _Enable InfluxDB Metrics_ is checked and hit **Save** to save the
+changes.
+
+---
+
+![GitLab Performance Monitoring Admin Settings](img/metrics_gitlab_configuration_settings.png)
+
+---
+
+Finally, a restart of all GitLab processes is required for the changes to take
+effect:
+
+```bash
+# For Omnibus installations
+sudo gitlab-ctl restart
+
+# For installations from source
+sudo service gitlab restart
+```
+
+## Pending Migrations
+
+When any migrations are pending, the metrics are disabled until the migrations
+have been performed.
+
+---
+
+Read more on:
+
+- [Introduction to GitLab Performance Monitoring](introduction.md)
+- [InfluxDB Configuration](influxdb_configuration.md)
+- [InfluxDB Schema](influxdb_schema.md)
diff --git a/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png b/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png
new file mode 100644
index 00000000000..14d82b6ac98
--- /dev/null
+++ b/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png
Binary files differ
diff --git a/doc/monitoring/performance/influxdb_configuration.md b/doc/monitoring/performance/influxdb_configuration.md
new file mode 100644
index 00000000000..3a2b598b78f
--- /dev/null
+++ b/doc/monitoring/performance/influxdb_configuration.md
@@ -0,0 +1,192 @@
+# InfluxDB Configuration
+
+The default settings provided by [InfluxDB] are not sufficient for a high traffic
+GitLab environment. The settings discussed in this document are based on the
+settings GitLab uses for GitLab.com, depending on your own needs you may need to
+further adjust them.
+
+If you are intending to run InfluxDB on the same server as GitLab, make sure
+you have plenty of RAM since InfluxDB can use quite a bit depending on traffic.
+
+Unless you are going with a budget setup, it's advised to run it separately.
+
+## Requirements
+
+- InfluxDB 0.9.5 or newer
+- A fairly modern version of Linux
+- At least 4GB of RAM
+- At least 10GB of storage for InfluxDB data
+
+Note that the RAM and storage requirements can differ greatly depending on the
+amount of data received/stored. To limit the amount of stored data users can
+look into [InfluxDB Retention Policies][influxdb-retention].
+
+## Installation
+
+Installing InfluxDB is out of the scope of this document. Please refer to the
+[InfluxDB documentation].
+
+## InfluxDB Server Settings
+
+Since InfluxDB has many settings that users may wish to customize themselves
+(e.g. what port to run InfluxDB on), we'll only cover the essentials.
+
+The configuration file in question is usually located at
+`/etc/influxdb/influxdb.conf`. Whenever you make a change in this file,
+InfluxDB needs to be restarted.
+
+### Storage Engine
+
+InfluxDB comes with different storage engines and as of InfluxDB 0.9.5 a new
+storage engine is available, called [TSM Tree]. All users **must** use the new
+`tsm1` storage engine as this [will be the default engine][tsm1-commit] in
+upcoming InfluxDB releases.
+
+Make sure you have the following in your configuration file:
+
+```
+[data]
+ dir = "/var/lib/influxdb/data"
+ engine = "tsm1"
+```
+
+### Admin Panel
+
+Production environments should have the InfluxDB admin panel **disabled**. This
+feature can be disabled by adding the following to your InfluxDB configuration
+file:
+
+```
+[admin]
+ enabled = false
+```
+
+### HTTP
+
+HTTP is required when using the [InfluxDB CLI] or other tools such as Grafana,
+thus it should be enabled. When enabling make sure to _also_ enable
+authentication:
+
+```
+[http]
+ enabled = true
+ auth-enabled = true
+```
+
+_**Note:** Before you enable authentication, you might want to [create an
+admin user](#create-a-new-admin-user)._
+
+### UDP
+
+GitLab writes data to InfluxDB via UDP and thus this must be enabled. Enabling
+UDP can be done using the following settings:
+
+```
+[[udp]]
+ enabled = true
+ bind-address = ":8089"
+ database = "gitlab"
+ batch-size = 1000
+ batch-pending = 5
+ batch-timeout = "1s"
+ read-buffer = 209715200
+```
+
+This does the following:
+
+1. Enable UDP and bind it to port 8089 for all addresses.
+2. Store any data received in the "gitlab" database.
+3. Define a batch of points to be 1000 points in size and allow a maximum of
+ 5 batches _or_ flush them automatically after 1 second.
+4. Define a UDP read buffer size of 200 MB.
+
+One of the most important settings here is the UDP read buffer size as if this
+value is set too low, packets will be dropped. You must also make sure the OS
+buffer size is set to the same value, the default value is almost never enough.
+
+To set the OS buffer size to 200 MB, on Linux you can run the following command:
+
+```bash
+sysctl -w net.core.rmem_max=209715200
+```
+
+To make this permanent, add the following to `/etc/sysctl.conf` and restart the
+server:
+
+```bash
+net.core.rmem_max=209715200
+```
+
+It is **very important** to make sure the buffer sizes are large enough to
+handle all data sent to InfluxDB as otherwise you _will_ lose data. The above
+buffer sizes are based on the traffic for GitLab.com. Depending on the amount of
+traffic, users may be able to use a smaller buffer size, but we highly recommend
+using _at least_ 100 MB.
+
+When enabling UDP, users should take care to not expose the port to the public,
+as doing so will allow anybody to write data into your InfluxDB database (as
+[InfluxDB's UDP protocol][udp] doesn't support authentication). We recommend either
+whitelisting the allowed IP addresses/ranges, or setting up a VLAN and only
+allowing traffic from members of said VLAN.
+
+## Create a new admin user
+
+If you want to [enable authentication](#http), you might want to [create an
+admin user][influx-admin]:
+
+```
+influx -execute "CREATE USER jeff WITH PASSWORD '1234' WITH ALL PRIVILEGES"
+```
+
+## Create the `gitlab` database
+
+Once you get InfluxDB up and running, you need to create a database for GitLab.
+Make sure you have changed the [storage engine](#storage-engine) to `tsm1`
+before creating a database.
+
+_**Note:** If you [created an admin user](#create-a-new-admin-user) and enabled
+[HTTP authentication](#http), remember to append the username (`-username <username>`)
+and password (`-password <password>`) you set earlier to the commands below._
+
+Run the following command to create a database named `gitlab`:
+
+```bash
+influx -execute 'CREATE DATABASE gitlab'
+```
+
+The name **must** be `gitlab`, do not use any other name.
+
+Next, make sure that the database was successfully created:
+
+```bash
+influx -execute 'SHOW DATABASES'
+```
+
+The output should be similar to:
+
+```
+name: databases
+---------------
+name
+_internal
+gitlab
+```
+
+That's it! Now your GitLab instance should send data to InfluxDB.
+
+---
+
+Read more on:
+
+- [Introduction to GitLab Performance Monitoring](introduction.md)
+- [GitLab Configuration](gitlab_configuration.md)
+- [InfluxDB Schema](influxdb_schema.md)
+
+[influxdb-retention]: https://docs.influxdata.com/influxdb/v0.9/query_language/database_management/#retention-policy-management
+[influxdb documentation]: https://docs.influxdata.com/influxdb/v0.9/
+[influxdb cli]: https://docs.influxdata.com/influxdb/v0.9/tools/shell/
+[udp]: https://docs.influxdata.com/influxdb/v0.9/write_protocols/udp/
+[influxdb]: https://influxdata.com/time-series-platform/influxdb/
+[tsm tree]: https://influxdata.com/blog/new-storage-engine-time-structured-merge-tree/
+[tsm1-commit]: https://github.com/influxdata/influxdb/commit/15d723dc77651bac83e09e2b1c94be480966cb0d
+[influx-admin]: https://docs.influxdata.com/influxdb/v0.9/administration/authentication_and_authorization/#create-a-new-admin-user
diff --git a/doc/monitoring/performance/influxdb_schema.md b/doc/monitoring/performance/influxdb_schema.md
new file mode 100644
index 00000000000..a5a8aebd2d1
--- /dev/null
+++ b/doc/monitoring/performance/influxdb_schema.md
@@ -0,0 +1,87 @@
+# InfluxDB Schema
+
+The following measurements are currently stored in InfluxDB:
+
+- `PROCESS_file_descriptors`
+- `PROCESS_gc_statistics`
+- `PROCESS_memory_usage`
+- `PROCESS_method_calls`
+- `PROCESS_object_counts`
+- `PROCESS_transactions`
+- `PROCESS_views`
+
+Here, `PROCESS` is replaced with either `rails` or `sidekiq` depending on the
+process type. In all series, any form of duration is stored in milliseconds.
+
+## PROCESS_file_descriptors
+
+This measurement contains the number of open file descriptors over time. The
+value field `value` contains the number of descriptors.
+
+## PROCESS_gc_statistics
+
+This measurement contains Ruby garbage collection statistics such as the amount
+of minor/major GC runs (relative to the last sampling interval), the time spent
+in garbage collection cycles, and all fields/values returned by `GC.stat`.
+
+## PROCESS_memory_usage
+
+This measurement contains the process' memory usage (in bytes) over time. The
+value field `value` contains the number of bytes.
+
+## PROCESS_method_calls
+
+This measurement contains the methods called during a transaction along with
+their duration, and a name of the transaction action that invoked the method (if
+available). The method call duration is stored in the value field `duration`,
+while the method name is stored in the tag `method`. The tag `action` contains
+the full name of the transaction action. Both the `method` and `action` fields
+are in the following format:
+
+```
+ClassName#method_name
+```
+
+For example, a method called by the `show` method in the `UsersController` class
+would have `action` set to `UsersController#show`.
+
+## PROCESS_object_counts
+
+This measurement is used to store retained Ruby objects (per class) and the
+amount of retained objects. The number of objects is stored in the `count` value
+field while the class name is stored in the `type` tag.
+
+## PROCESS_transactions
+
+This measurement is used to store basic transaction details such as the time it
+took to complete a transaction, how much time was spent in SQL queries, etc. The
+following value fields are available:
+
+| Value | Description |
+| ----- | ----------- |
+| `duration` | The total duration of the transaction |
+| `allocated_memory` | The amount of bytes allocated while the transaction was running. This value is only reliable when using single-threaded application servers |
+| `method_duration` | The total time spent in method calls |
+| `sql_duration` | The total time spent in SQL queries |
+| `view_duration` | The total time spent in views |
+
+## PROCESS_views
+
+This measurement is used to store view rendering timings for a transaction. The
+following value fields are available:
+
+| Value | Description |
+| ----- | ----------- |
+| `duration` | The rendering time of the view |
+| `view` | The path of the view, relative to the application's root directory |
+
+The `action` tag contains the action name of the transaction that rendered the
+view.
+
+---
+
+Read more on:
+
+- [Introduction to GitLab Performance Monitoring](introduction.md)
+- [GitLab Configuration](gitlab_configuration.md)
+- [InfluxDB Configuration](influxdb_configuration.md)
diff --git a/doc/monitoring/performance/introduction.md b/doc/monitoring/performance/introduction.md
new file mode 100644
index 00000000000..f2460d31302
--- /dev/null
+++ b/doc/monitoring/performance/introduction.md
@@ -0,0 +1,64 @@
+# GitLab Performance Monitoring
+
+GitLab comes with its own application performance measuring system as of GitLab
+8.4, simply called "GitLab Performance Monitoring". GitLab Performance Monitoring is available in both the
+Community and Enterprise editions.
+
+Apart from this introduction, you are advised to read through the following
+documents in order to understand and properly configure GitLab Performance Monitoring:
+
+- [GitLab Configuration](gitlab_configuration.md)
+- [InfluxDB Configuration](influxdb_configuration.md)
+- [InfluxDB Schema](influxdb_schema.md)
+
+## Introduction to GitLab Performance Monitoring
+
+GitLab Performance Monitoring makes it possible to measure a wide variety of statistics
+including (but not limited to):
+
+- The time it took to complete a transaction (a web request or Sidekiq job).
+- The time spent in running SQL queries and rendering HAML views.
+- The time spent executing (instrumented) Ruby methods.
+- Ruby object allocations, and retained objects in particular.
+- System statistics such as the process' memory usage and open file descriptors.
+- Ruby garbage collection statistics.
+
+Metrics data is written to [InfluxDB][influxdb] over [UDP][influxdb-udp]. Stored
+data can be visualized using [Grafana][grafana] or any other application that
+supports reading data from InfluxDB. Alternatively data can be queried using the
+InfluxDB CLI.
+
+## Metric Types
+
+Two types of metrics are collected:
+
+1. Transaction specific metrics.
+1. Sampled metrics, collected at a certain interval in a separate thread.
+
+### Transaction Metrics
+
+Transaction metrics are metrics that can be associated with a single
+transaction. This includes statistics such as the transaction duration, timings
+of any executed SQL queries, time spent rendering HAML views, etc. These metrics
+are collected for every Rack request and Sidekiq job processed.
+
+### Sampled Metrics
+
+Sampled metrics are metrics that can't be associated with a single transaction.
+Examples include garbage collection statistics and retained Ruby objects. These
+metrics are collected at a regular interval. This interval is made up out of two
+parts:
+
+1. A user defined interval.
+1. A randomly generated offset added on top of the interval, the same offset
+ can't be used twice in a row.
+
+The actual interval can be anywhere between a half of the defined interval and a
+half above the interval. For example, for a user defined interval of 15 seconds
+the actual interval can be anywhere between 7.5 and 22.5. The interval is
+re-generated for every sampling run instead of being generated once and re-used
+for the duration of the process' lifetime.
+
+[influxdb]: https://influxdata.com/time-series-platform/influxdb/
+[influxdb-udp]: https://docs.influxdata.com/influxdb/v0.9/write_protocols/udp/
+[grafana]: http://grafana.org/
diff --git a/doc/update/8.3-to-8.4.md b/doc/update/8.3-to-8.4.md
index 604939cd733..bf80f66d004 100644
--- a/doc/update/8.3-to-8.4.md
+++ b/doc/update/8.3-to-8.4.md
@@ -48,7 +48,7 @@ which should already be on your system from GitLab 8.1.
```bash
cd /home/git/gitlab-workhorse
sudo -u git -H git fetch --all
-sudo -u git -H git checkout 0.6.0
+sudo -u git -H git checkout 0.6.1
sudo -u git -H make
```
@@ -104,10 +104,7 @@ via [/etc/default/gitlab].
#### Init script
-We updated the init script for GitLab in order to pass new
-configuration options to gitlab-workhorse. We let gitlab-workhorse
-connect to the Rails application via a Unix domain socket and we tell
-it where the 'public' directory of GitLab is.
+We updated the init script for GitLab in order to set a specific PATH for gitlab-workhorse.
```
cd /home/git/gitlab
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index 6420d65cf1b..c29037e89c2 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -56,7 +56,7 @@ X-Gitlab-Event: Push Hook
"author": {
"name": "Jordi Mallach",
"email": "jordi@softcatala.org"
- }
+ },
"added": ["CHANGELOG"],
"modified": ["app/controller/application.rb"],
"removed": []
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 3651b55f438..bf62ab41053 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -6,6 +6,7 @@
- [GitLab Flow](gitlab_flow.md)
- [Groups](groups.md)
- [Keyboard shortcuts](shortcuts.md)
+- [File finder](file_finder.md)
- [Labels](labels.md)
- [Notification emails](notifications.md)
- [Project Features](project_features.md)
diff --git a/doc/workflow/file_finder.md b/doc/workflow/file_finder.md
new file mode 100644
index 00000000000..b69ae663272
--- /dev/null
+++ b/doc/workflow/file_finder.md
@@ -0,0 +1,46 @@
+# File finder
+
+_**Note:** This feature was [introduced][gh-9889] in GitLab 8.4._
+
+---
+
+The file finder feature allows you to quickly shortcut your way when you are
+searching for a file in a repository using the GitLab UI.
+
+You can find the **Find File** button when in the **Files** section of a
+project.
+
+![Find file button](img/file_finder_find_button.png)
+
+---
+
+For those who prefer to keep their fingers on the keyboard, there is a
+[shortcut button](shortcuts.md) as well, which you can invoke from _anywhere_
+in a project.
+
+Press `t` to launch the File search function when in **Issues**,
+**Merge requests**, **Milestones**, even the project's settings.
+
+Start typing what you are searching for and watch the magic happen. With the
+up/down arrows, you go up and down the results, with `Esc` you close the search
+and go back to **Files**.
+
+## How it works
+
+The File finder feature is powered by the [Fuzzy filter] library.
+
+It implements a fuzzy search with highlight, and tries to provide intuitive
+results by recognizing patterns that people use while searching.
+
+For example, consider the [GitLab CE repository][ce] and that we want to open
+the `app/controllers/admin/deploy_keys_controller.rb` file.
+
+Using fuzzy search, we start by typing letters that get us closer to the file.
+
+**Protip:** To narrow down your search, include `/` in your search terms.
+
+![Find file button](img/file_finder_find_file.png)
+
+[gh-9889]: https://github.com/gitlabhq/gitlabhq/pull/9889 "File finder pull request"
+[fuzzy filter]: https://github.com/jeancroy/fuzzaldrin-plus "fuzzaldrin-plus on GitHub"
+[ce]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master "GitLab CE repository"
diff --git a/doc/workflow/img/file_finder_find_button.png b/doc/workflow/img/file_finder_find_button.png
new file mode 100644
index 00000000000..c5005d0d7ca
--- /dev/null
+++ b/doc/workflow/img/file_finder_find_button.png
Binary files differ
diff --git a/doc/workflow/img/file_finder_find_file.png b/doc/workflow/img/file_finder_find_file.png
new file mode 100644
index 00000000000..58500f4c163
--- /dev/null
+++ b/doc/workflow/img/file_finder_find_file.png
Binary files differ
diff --git a/doc/workflow/protected_branches.md b/doc/workflow/protected_branches.md
index 0adf9f8e3e8..fdf9a8d391c 100644
--- a/doc/workflow/protected_branches.md
+++ b/doc/workflow/protected_branches.md
@@ -1,6 +1,6 @@
# Protected branches
-Permission in GitLab are fundamentally defined around the idea of having read or write permission to the repository and branches.
+Permissions in GitLab are fundamentally defined around the idea of having read or write permission to the repository and branches.
To prevent people from messing with history or pushing code without review, we've created protected branches.
diff --git a/features/project/builds/artifacts.feature b/features/project/builds/artifacts.feature
index 4f68e44fd77..1185854453a 100644
--- a/features/project/builds/artifacts.feature
+++ b/features/project/builds/artifacts.feature
@@ -7,21 +7,21 @@ Feature: Project Builds Artifacts
Scenario: I download build artifacts
Given recent build has artifacts available
- When I visit recent build summary page
+ When I visit recent build details page
And I click artifacts download button
Then download of build artifacts archive starts
Scenario: I browse build artifacts
Given recent build has artifacts available
And recent build has artifacts metadata available
- When I visit recent build summary page
+ When I visit recent build details page
And I click artifacts browse button
Then I should see content of artifacts archive
Scenario: I browse subdirectory of build artifacts
Given recent build has artifacts available
And recent build has artifacts metadata available
- When I visit recent build summary page
+ When I visit recent build details page
And I click artifacts browse button
And I click link to subdirectory within build artifacts
Then I should see content of subdirectory within artifacts archive
@@ -30,7 +30,7 @@ Feature: Project Builds Artifacts
Given recent build has artifacts available
And recent build has artifacts metadata available
And recent build artifacts contain directory with UTF-8 characters
- When I visit recent build summary page
+ When I visit recent build details page
And I click artifacts browse button
And I navigate to directory with UTF-8 characters in name
Then I should see content of directory with UTF-8 characters in name
@@ -39,7 +39,7 @@ Feature: Project Builds Artifacts
Given recent build has artifacts available
And recent build has artifacts metadata available
And recent build artifacts contain directory with invalid UTF-8 characters
- When I visit recent build summary page
+ When I visit recent build details page
And I click artifacts browse button
And I navigate to parent directory of directory with invalid name
Then I should not see directory with invalid name on the list
@@ -47,7 +47,7 @@ Feature: Project Builds Artifacts
Scenario: I download a single file from build artifacts
Given recent build has artifacts available
And recent build has artifacts metadata available
- When I visit recent build summary page
+ When I visit recent build details page
And I click artifacts browse button
And I click a link to file within build artifacts
Then download of a file extracted from build artifacts should start
diff --git a/features/project/builds/summary.feature b/features/project/builds/summary.feature
index e90ea592aab..b69d279517b 100644
--- a/features/project/builds/summary.feature
+++ b/features/project/builds/summary.feature
@@ -5,7 +5,11 @@ Feature: Project Builds Summary
And project has CI enabled
And project has a recent build
- Scenario: I browse build summary page
- When I visit recent build summary page
- Then I see summary for build
+ Scenario: I browse build details page
+ When I visit recent build details page
+ Then I see details of a build
And I see build trace
+
+ Scenario: I browse project builds page
+ When I visit project builds page
+ Then I see button to CI Lint
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index ab234bc7507..1502b0952cd 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -52,6 +52,14 @@ Feature: Project Issues
And I should see an error alert section within the comment form
@javascript
+ Scenario: Visiting Issues after leaving a comment
+ Given I visit issue page "Release 0.4"
+ And I leave a comment like "XML attached"
+ And I visit project "Shop" issues page
+ And I sort the list by "Last updated"
+ Then I should see "Release 0.4" at the top
+
+ @javascript
Scenario: I search issue
Given I fill in issue search with "Re"
Then I should see "Release 0.4" in issues
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index aa9078b878f..f1629a26f10 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -76,6 +76,25 @@ Feature: Project Merge Requests
Then I should see comment "XML attached"
@javascript
+ Scenario: Visiting Merge Requests after leaving a comment
+ Given project "Shop" have "Bug NS-05" open merge request with diffs inside
+ And I visit merge request page "Bug NS-04"
+ And I leave a comment like "XML attached"
+ And I visit project "Shop" merge requests page
+ And I sort the list by "Last updated"
+ Then I should see "Bug NS-04" at the top
+
+ @javascript
+ Scenario: Visiting Merge Requests after commenting on diffs
+ Given project "Shop" have "Bug NS-05" open merge request with diffs inside
+ And I visit merge request page "Bug NS-05"
+ And I click on the Changes tab
+ And I leave a comment like "Line is wrong" on diff
+ And I visit project "Shop" merge requests page
+ And I sort the list by "Last updated"
+ Then I should see "Bug NS-05" at the top
+
+ @javascript
Scenario: I comment on a merge request diff
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
diff --git a/features/steps/project/builds/summary.rb b/features/steps/project/builds/summary.rb
index 2439d48fbef..036bc0a499e 100644
--- a/features/steps/project/builds/summary.rb
+++ b/features/steps/project/builds/summary.rb
@@ -4,11 +4,18 @@ class Spinach::Features::ProjectBuildsSummary < Spinach::FeatureSteps
include SharedBuilds
include RepoHelpers
- step 'I see summary for build' do
+ step 'I see details of a build' do
expect(page).to have_content "Build ##{@build.id}"
end
step 'I see build trace' do
expect(page).to have_css '#build-trace'
end
+
+ step 'I see button to CI Lint' do
+ page.within('.controls') do
+ ci_lint_tool_link = page.find_link('CI Lint')
+ expect(ci_lint_tool_link[:href]).to eq ci_lint_path
+ end
+ end
end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index 8e8c9c57452..d556b73f9fd 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -293,6 +293,11 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
expect(page).to have_content('Yay!')
end
end
+
+ step 'I should see "Release 0.4" at the top' do
+ expect(page.find('ul.content-list.issues-list li.issue:first-child')).to have_content("Release 0.4")
+ end
+
def filter_issue(text)
fill_in 'issue_search', with: text
end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index be993d11093..8af635689e0 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -41,7 +41,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should not see "master" branch' do
- expect(page).not_to have_content "master"
+ expect(find('.merge-request-info')).not_to have_content "master"
end
step 'I should see "other_branch" branch' do
@@ -415,6 +415,14 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
end
+ step 'I should see "Bug NS-05" at the top' do
+ expect(page.find('ul.content-list.mr-list li.merge-request:first-child')).to have_content("Bug NS-05")
+ end
+
+ step 'I should see "Bug NS-04" at the top' do
+ expect(page.find('ul.content-list.mr-list li.merge-request:first-child')).to have_content("Bug NS-04")
+ end
+
def merge_request
@merge_request ||= MergeRequest.find_by!(title: "Bug NS-05")
end
diff --git a/features/steps/shared/builds.rb b/features/steps/shared/builds.rb
index f88b01af84e..92bf362879b 100644
--- a/features/steps/shared/builds.rb
+++ b/features/steps/shared/builds.rb
@@ -10,10 +10,14 @@ module SharedBuilds
@build = create :ci_build, commit: ci_commit
end
- step 'I visit recent build summary page' do
+ step 'I visit recent build details page' do
visit namespace_project_build_path(@project.namespace, @project, @build)
end
+ step 'I visit project builds page' do
+ visit namespace_project_builds_path(@project.namespace, @project)
+ end
+
step 'recent build has artifacts available' do
artifacts = Rails.root + 'spec/fixtures/ci_build_artifacts.zip'
archive = fixture_file_upload(artifacts, 'application/zip')
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
index 444d6726f99..eb6df61b8e6 100644
--- a/features/steps/shared/note.rb
+++ b/features/steps/shared/note.rb
@@ -144,4 +144,11 @@ module SharedNote
expect(page).to have_content("+1 Awesome!")
end
end
+
+ step 'I sort the list by "Last updated"' do
+ find('button.dropdown-toggle.btn').click
+ page.within('ul.dropdown-menu.dropdown-menu-align-right li') do
+ click_link "Last updated"
+ end
+ end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 6d2380cf47d..3f528b9f7c0 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -264,6 +264,10 @@ module API
projects = projects.search(params[:search])
end
+ if params[:visibility].present?
+ projects = projects.search_by_visibility(params[:visibility])
+ end
+
projects.reorder(project_order_by => project_sort)
end
diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb
index 20bd4f7ee6e..3637b1bac94 100644
--- a/lib/banzai/filter/reference_filter.rb
+++ b/lib/banzai/filter/reference_filter.rb
@@ -133,6 +133,7 @@ module Banzai
next unless link && text
link = CGI.unescape(link)
+ next unless link.force_encoding('UTF-8').valid_encoding?
# Ignore ending punctionation like periods or commas
next unless link == text && text =~ /\A#{pattern}/
@@ -170,6 +171,7 @@ module Banzai
next unless link && text
link = CGI.unescape(link)
+ next unless link.force_encoding('UTF-8').valid_encoding?
next unless link && link =~ /\A#{pattern}\z/
html = yield link, text
diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb
index bcdfd38d292..1a3f662811a 100644
--- a/lib/ci/gitlab_ci_yaml_processor.rb
+++ b/lib/ci/gitlab_ci_yaml_processor.rb
@@ -115,6 +115,10 @@ module Ci
end
if @cache
+ if @cache[:key] && !validate_string(@cache[:key])
+ raise ValidationError, "cache:key parameter should be a string"
+ end
+
if @cache[:untracked] && !validate_boolean(@cache[:untracked])
raise ValidationError, "cache:untracked parameter should be an boolean"
end
@@ -198,6 +202,10 @@ module Ci
end
def validate_job_cache!(name, job)
+ if job[:cache][:key] && !validate_string(job[:cache][:key])
+ raise ValidationError, "#{name} job: cache:key parameter should be a string"
+ end
+
if job[:cache][:untracked] && !validate_boolean(job[:cache][:untracked])
raise ValidationError, "#{name} job: cache:untracked parameter should be an boolean"
end
diff --git a/lib/dnsxl_check.rb b/lib/dnsxl_check.rb
new file mode 100644
index 00000000000..1e506b2d9cb
--- /dev/null
+++ b/lib/dnsxl_check.rb
@@ -0,0 +1,105 @@
+require 'resolv'
+
+class DNSXLCheck
+
+ class Resolver
+ def self.search(query)
+ begin
+ Resolv.getaddress(query)
+ true
+ rescue Resolv::ResolvError
+ false
+ end
+ end
+ end
+
+ IP_REGEXP = /\A(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\z/
+ DEFAULT_THRESHOLD = 0.33
+
+ def self.create_from_list(list)
+ dnsxl_check = DNSXLCheck.new
+
+ list.each do |entry|
+ dnsxl_check.add_list(entry.domain, entry.weight)
+ end
+
+ dnsxl_check
+ end
+
+ def test(ip)
+ if use_threshold?
+ test_with_threshold(ip)
+ else
+ test_strict(ip)
+ end
+ end
+
+ def test_with_threshold(ip)
+ return false if lists.empty?
+
+ search(ip)
+ final_score >= threshold
+ end
+
+ def test_strict(ip)
+ return false if lists.empty?
+
+ search(ip)
+ @score > 0
+ end
+
+ def use_threshold=(value)
+ @use_threshold = value == true
+ end
+
+ def use_threshold?
+ @use_threshold &&= true
+ end
+
+ def threshold=(threshold)
+ raise ArgumentError, "'threshold' value must be grather than 0 and less than or equal to 1" unless threshold > 0 && threshold <= 1
+ @threshold = threshold
+ end
+
+ def threshold
+ @threshold ||= DEFAULT_THRESHOLD
+ end
+
+ def add_list(domain, weight)
+ @lists ||= []
+ @lists << { domain: domain, weight: weight }
+ end
+
+ def lists
+ @lists ||= []
+ end
+
+ private
+
+ def search(ip)
+ raise ArgumentError, "'ip' value must be in #{IP_REGEXP} format" unless ip.match(IP_REGEXP)
+
+ @score = 0
+
+ reversed = reverse_ip(ip)
+ search_in_rbls(reversed)
+ end
+
+ def reverse_ip(ip)
+ ip.split('.').reverse.join('.')
+ end
+
+ def search_in_rbls(reversed_ip)
+ lists.each do |rbl|
+ query = "#{reversed_ip}.#{rbl[:domain]}"
+ @score += rbl[:weight] if Resolver.search(query)
+ end
+ end
+
+ def final_score
+ weights = lists.map{ |rbl| rbl[:weight] }.reduce(:+).to_i
+ return 0 if weights == 0
+
+ (@score.to_f / weights.to_f).round(2)
+ end
+end
diff --git a/lib/gitlab/ci/build/artifacts/metadata.rb b/lib/gitlab/ci/build/artifacts/metadata.rb
index 1344f5d120b..f2020c82d40 100644
--- a/lib/gitlab/ci/build/artifacts/metadata.rb
+++ b/lib/gitlab/ci/build/artifacts/metadata.rb
@@ -13,8 +13,8 @@ module Gitlab
attr_reader :file, :path, :full_version
- def initialize(file, path)
- @file, @path = file, path
+ def initialize(file, path, **opts)
+ @file, @path, @opts = file, path, opts
@full_version = read_version
end
@@ -52,7 +52,9 @@ module Gitlab
def match_entries(gz)
entries = {}
- match_pattern = %r{^#{Regexp.escape(@path)}[^/]*/?$}
+
+ child_pattern = '[^/]*/?$' unless @opts[:recursive]
+ match_pattern = /^#{Regexp.escape(@path)}#{child_pattern}/
until gz.eof? do
begin
diff --git a/lib/gitlab/ci/build/artifacts/metadata/entry.rb b/lib/gitlab/ci/build/artifacts/metadata/entry.rb
index 25b71fc3275..7f4c750b6fd 100644
--- a/lib/gitlab/ci/build/artifacts/metadata/entry.rb
+++ b/lib/gitlab/ci/build/artifacts/metadata/entry.rb
@@ -95,6 +95,13 @@ module Gitlab
children.empty?
end
+ def total_size
+ descendant_pattern = %r{^#{Regexp.escape(@path)}}
+ entries.sum do |path, entry|
+ (entry[:size] if path =~ descendant_pattern).to_i
+ end
+ end
+
def to_s
@path
end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index 79061cd0141..a484177ae33 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -1,13 +1,22 @@
module Gitlab
module Diff
class File
- attr_reader :diff
+ attr_reader :diff, :diff_refs
delegate :new_file, :deleted_file, :renamed_file,
:old_path, :new_path, to: :diff, prefix: false
- def initialize(diff)
+ def initialize(diff, diff_refs)
@diff = diff
+ @diff_refs = diff_refs
+ end
+
+ def old_ref
+ diff_refs[0] if diff_refs
+ end
+
+ def new_ref
+ diff_refs[1] if diff_refs
end
# Array of Gitlab::DIff::Line objects
@@ -15,6 +24,14 @@ module Gitlab
@lines ||= parser.parse(raw_diff.lines)
end
+ def highlighted_diff_lines
+ Gitlab::Diff::Highlight.new(self).highlight
+ end
+
+ def parallel_diff_lines
+ Gitlab::Diff::ParallelDiff.new(self).parallelize
+ end
+
def mode_changed?
!!(diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode)
end
diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb
new file mode 100644
index 00000000000..a7f925ce134
--- /dev/null
+++ b/lib/gitlab/diff/highlight.rb
@@ -0,0 +1,82 @@
+module Gitlab
+ module Diff
+ class Highlight
+ attr_reader :diff_file, :diff_lines, :raw_lines
+
+ delegate :old_path, :new_path, :old_ref, :new_ref, to: :diff_file, prefix: :diff
+
+ def initialize(diff_lines)
+ if diff_lines.is_a?(Gitlab::Diff::File)
+ @diff_file = diff_lines
+ @diff_lines = @diff_file.diff_lines
+ else
+ @diff_lines = diff_lines
+ end
+ @raw_lines = @diff_lines.map(&:text)
+ end
+
+ def highlight
+ @diff_lines.map.with_index do |diff_line, i|
+ diff_line = diff_line.dup
+ # ignore highlighting for "match" lines
+ next diff_line if diff_line.type == 'match' || diff_line.type == 'nonewline'
+
+ rich_line = highlight_line(diff_line, i)
+
+ if line_inline_diffs = inline_diffs[i]
+ rich_line = InlineDiffMarker.new(diff_line.text, rich_line).mark(line_inline_diffs)
+ end
+
+ diff_line.text = rich_line.html_safe
+
+ diff_line
+ end
+ end
+
+ private
+
+ def highlight_line(diff_line, index)
+ return html_escape(diff_line.text) unless diff_file && diff_file.diff_refs
+
+ line_prefix = diff_line.text.match(/\A(.)/) ? $1 : ' '
+
+ case diff_line.type
+ when 'new', nil
+ rich_line = new_lines[diff_line.new_pos - 1]
+ when 'old'
+ rich_line = old_lines[diff_line.old_pos - 1]
+ end
+
+ # Only update text if line is found. This will prevent
+ # issues with submodules given the line only exists in diff content.
+ rich_line ? line_prefix + rich_line : html_escape(diff_line.text)
+ end
+
+ def inline_diffs
+ @inline_diffs ||= InlineDiff.new(@raw_lines).inline_diffs
+ end
+
+ def old_lines
+ return unless diff_file
+ @old_lines ||= Gitlab::Highlight.highlight_lines(*processing_args(:old))
+ end
+
+ def new_lines
+ return unless diff_file
+ @new_lines ||= Gitlab::Highlight.highlight_lines(*processing_args(:new))
+ end
+
+ def processing_args(version)
+ ref = send("diff_#{version}_ref")
+ path = send("diff_#{version}_path")
+
+ [ref.project.repository, ref.id, path]
+ end
+
+ def html_escape(str)
+ replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
+ str.gsub(/[&"'><]/, replacements)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/inline_diff.rb b/lib/gitlab/diff/inline_diff.rb
new file mode 100644
index 00000000000..b8a61ad6115
--- /dev/null
+++ b/lib/gitlab/diff/inline_diff.rb
@@ -0,0 +1,73 @@
+module Gitlab
+ module Diff
+ class InlineDiff
+ attr_accessor :lines
+
+ def initialize(lines)
+ @lines = lines
+ end
+
+ def inline_diffs
+ inline_diffs = []
+
+ local_edit_indexes.each do |index|
+ old_index = index
+ new_index = index + 1
+ old_line = @lines[old_index]
+ new_line = @lines[new_index]
+
+ # Skip inline diff if empty line was replaced with content
+ next if old_line[1..-1] == ""
+
+ # Add one, because this is based on the prefixless version
+ lcp = longest_common_prefix(old_line[1..-1], new_line[1..-1]) + 1
+ lcs = longest_common_suffix(old_line[lcp..-1], new_line[lcp..-1])
+
+ old_diff_range = lcp..(old_line.length - lcs - 1)
+ new_diff_range = lcp..(new_line.length - lcs - 1)
+
+ inline_diffs[old_index] = [old_diff_range] if old_diff_range.begin <= old_diff_range.end
+ inline_diffs[new_index] = [new_diff_range] if new_diff_range.begin <= new_diff_range.end
+ end
+
+ inline_diffs
+ end
+
+ private
+
+ # Find runs of single line edits
+ def local_edit_indexes
+ line_prefixes = @lines.map { |line| line.match(/\A([+-])/) ? $1 : ' ' }
+ joined_line_prefixes = " #{line_prefixes.join} "
+
+ offset = 0
+ local_edit_indexes = []
+ while index = joined_line_prefixes.index(" -+ ", offset)
+ local_edit_indexes << index
+ offset = index + 1
+ end
+
+ local_edit_indexes
+ end
+
+ def longest_common_prefix(a, b)
+ max_length = [a.length, b.length].max
+
+ length = 0
+ (0..max_length - 1).each do |pos|
+ old_char = a[pos]
+ new_char = b[pos]
+
+ break if old_char != new_char
+ length += 1
+ end
+
+ length
+ end
+
+ def longest_common_suffix(a, b)
+ longest_common_prefix(a.reverse, b.reverse)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/inline_diff_marker.rb b/lib/gitlab/diff/inline_diff_marker.rb
new file mode 100644
index 00000000000..1d7fa1bce06
--- /dev/null
+++ b/lib/gitlab/diff/inline_diff_marker.rb
@@ -0,0 +1,109 @@
+module Gitlab
+ module Diff
+ class InlineDiffMarker
+ attr_accessor :raw_line, :rich_line
+
+ def initialize(raw_line, rich_line = raw_line)
+ @raw_line = raw_line
+ @rich_line = rich_line
+ end
+
+ def mark(line_inline_diffs)
+ marker_ranges = []
+ line_inline_diffs.each do |inline_diff_range|
+ # Map the inline-diff range based on the raw line to character positions in the rich line
+ inline_diff_positions = position_mapping[inline_diff_range].flatten
+ # Turn the array of character positions into ranges
+ marker_ranges.concat(collapse_ranges(inline_diff_positions))
+ end
+
+ offset = 0
+ # Mark each range
+ marker_ranges.each do |range|
+ offset = insert_around_range(rich_line, range, "<span class='idiff'>", "</span>", offset)
+ end
+
+ rich_line
+ end
+
+ private
+
+ # Mapping of character positions in the raw line, to the rich (highlighted) line
+ def position_mapping
+ @position_mapping ||= begin
+ mapping = []
+ rich_pos = 0
+ (0..raw_line.length).each do |raw_pos|
+ rich_char = rich_line[rich_pos]
+
+ # The raw and rich lines are the same except for HTML tags,
+ # so skip over any `<...>` segment
+ while rich_char == '<'
+ until rich_char == '>'
+ rich_pos += 1
+ rich_char = rich_line[rich_pos]
+ end
+
+ rich_pos += 1
+ rich_char = rich_line[rich_pos]
+ end
+
+ # multi-char HTML entities in the rich line correspond to a single character in the raw line
+ if rich_char == '&'
+ multichar_mapping = [rich_pos]
+ until rich_char == ';'
+ rich_pos += 1
+ multichar_mapping << rich_pos
+ rich_char = rich_line[rich_pos]
+ end
+
+ mapping[raw_pos] = multichar_mapping
+ else
+ mapping[raw_pos] = rich_pos
+ end
+
+ rich_pos += 1
+ end
+
+ mapping
+ end
+ end
+
+ # Takes an array of integers, and returns an array of ranges covering the same integers
+ def collapse_ranges(positions)
+ return [] if positions.empty?
+ ranges = []
+
+ start = prev = positions[0]
+ range = start..prev
+ positions[1..-1].each do |pos|
+ if pos == prev + 1
+ range = start..pos
+ prev = pos
+ else
+ ranges << range
+ start = prev = pos
+ range = start..prev
+ end
+ end
+ ranges << range
+
+ ranges
+ end
+
+ # Inserts tags around the characters identified by the given range
+ def insert_around_range(text, range, before, after, offset = 0)
+ # Just to be sure
+ return offset if offset + range.end + 1 > text.length
+
+ text.insert(offset + range.begin, before)
+ offset += before.length
+
+ text.insert(offset + range.end + 1, after)
+ offset += after.length
+
+ offset
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
index 0072194606e..03730b435ad 100644
--- a/lib/gitlab/diff/line.rb
+++ b/lib/gitlab/diff/line.rb
@@ -1,7 +1,8 @@
module Gitlab
module Diff
class Line
- attr_reader :type, :text, :index, :old_pos, :new_pos
+ attr_reader :type, :index, :old_pos, :new_pos
+ attr_accessor :text
def initialize(text, type, index, old_pos, new_pos)
@text, @type, @index = text, type, index
diff --git a/lib/gitlab/diff/parallel_diff.rb b/lib/gitlab/diff/parallel_diff.rb
new file mode 100644
index 00000000000..74f9b3c050a
--- /dev/null
+++ b/lib/gitlab/diff/parallel_diff.rb
@@ -0,0 +1,119 @@
+module Gitlab
+ module Diff
+ class ParallelDiff
+ attr_accessor :diff_file
+
+ def initialize(diff_file)
+ @diff_file = diff_file
+ end
+
+ def parallelize
+ lines = []
+ skip_next = false
+
+ highlighted_diff_lines = diff_file.highlighted_diff_lines
+ highlighted_diff_lines.each do |line|
+ full_line = line.text
+ type = line.type
+ line_code = generate_line_code(diff_file.file_path, line)
+ line_new = line.new_pos
+ line_old = line.old_pos
+
+ next_line = diff_file.next_line(line.index)
+
+ if next_line
+ next_line = highlighted_diff_lines[next_line.index]
+ next_line_code = generate_line_code(diff_file.file_path, next_line)
+ next_type = next_line.type
+ next_line = next_line.text
+ end
+
+ case type
+ when 'match', nil
+ # line in the right panel is the same as in the left one
+ lines << {
+ left: {
+ type: type,
+ number: line_old,
+ text: full_line,
+ line_code: line_code,
+ },
+ right: {
+ type: type,
+ number: line_new,
+ text: full_line,
+ line_code: line_code
+ }
+ }
+ when 'old'
+ case next_type
+ when 'new'
+ # Left side has text removed, right side has text added
+ lines << {
+ left: {
+ type: type,
+ number: line_old,
+ text: full_line,
+ line_code: line_code,
+ },
+ right: {
+ type: next_type,
+ number: line_new,
+ text: next_line,
+ line_code: next_line_code
+ }
+ }
+ skip_next = true
+ when 'old', 'nonewline', nil
+ # Left side has text removed, right side doesn't have any change
+ # No next line code, no new line number, no new line text
+ lines << {
+ left: {
+ type: type,
+ number: line_old,
+ text: full_line,
+ line_code: line_code,
+ },
+ right: {
+ type: next_type,
+ number: nil,
+ text: "",
+ line_code: nil
+ }
+ }
+ end
+ when 'new'
+ if skip_next
+ # Change has been already included in previous line so no need to do it again
+ skip_next = false
+ next
+ else
+ # Change is only on the right side, left side has no change
+ lines << {
+ left: {
+ type: nil,
+ number: nil,
+ text: "",
+ line_code: line_code,
+ },
+ right: {
+ type: type,
+ number: line_new,
+ text: full_line,
+ line_code: line_code
+ }
+ }
+ end
+ end
+ end
+ lines
+ end
+
+ private
+
+ def generate_line_code(file_path, line)
+ Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb
index 516e59b87a3..3666063bf8b 100644
--- a/lib/gitlab/diff/parser.rb
+++ b/lib/gitlab/diff/parser.rb
@@ -11,13 +11,10 @@ module Gitlab
line_new = 1
type = nil
- lines_arr = ::Gitlab::InlineDiff.processing lines
-
- lines_arr.each do |line|
+ @lines.each do |line|
next if filename?(line)
- full_line = html_escape(line.gsub(/\n/, ''))
- full_line = ::Gitlab::InlineDiff.replace_markers full_line
+ full_line = line.gsub(/\n/, '')
if line.match(/^@@ -/)
type = "match"
@@ -29,6 +26,10 @@ module Gitlab
lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
line_obj_index += 1
next
+ elsif line[0] == '\\'
+ type = 'nonewline'
+ lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+ line_obj_index += 1
else
type = identification_type(line)
lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
@@ -36,10 +37,13 @@ module Gitlab
end
- if line[0] == "+"
+ case line[0]
+ when "+"
line_new += 1
- elsif line[0] == "-"
+ when "-"
line_old += 1
+ when "\\"
+ # No increment
else
line_new += 1
line_old += 1
@@ -62,19 +66,15 @@ module Gitlab
end
def identification_type(line)
- if line[0] == "+"
+ case line[0]
+ when "+"
"new"
- elsif line[0] == "-"
+ when "-"
"old"
else
nil
end
end
-
- def html_escape(str)
- replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
- str.gsub(/[&"'><]/, replacements)
- end
end
end
end
diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb
index a2eb7a70bd2..a05ffeb9cd2 100644
--- a/lib/gitlab/email/message/repository_push.rb
+++ b/lib/gitlab/email/message/repository_push.rb
@@ -9,6 +9,7 @@ module Gitlab
delegate :namespace, :name_with_namespace, to: :project, prefix: :project
delegate :name, to: :author, prefix: :author
+ delegate :username, to: :author, prefix: :author
def initialize(notify, project_id, recipient, opts = {})
raise ArgumentError, 'Missing options: author_id, ref, action' unless
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index 18929b9113b..663402e8197 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -82,8 +82,12 @@ module Gitlab
end
true
- rescue Gitlab::Shell::Error
- false
+ rescue Gitlab::Shell::Error => e
+ if e.message =~ /repository not exported/
+ true
+ else
+ false
+ end
end
end
end
diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb
index b7c47958cc7..f96fed0f5cf 100644
--- a/lib/gitlab/github_import/pull_request_formatter.rb
+++ b/lib/gitlab/github_import/pull_request_formatter.rb
@@ -18,7 +18,7 @@ module Gitlab
end
def cross_project?
- source_repo.fork == true
+ source_repo.id != target_repo.id
end
def number
@@ -73,6 +73,10 @@ module Gitlab
project
end
+ def target_repo
+ raw_data.base.repo
+ end
+
def target_branch
target_project.repository.find_branch(raw_data.base.ref)
end
diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb
new file mode 100644
index 00000000000..4ddb4fea977
--- /dev/null
+++ b/lib/gitlab/highlight.rb
@@ -0,0 +1,38 @@
+module Gitlab
+ class Highlight
+ def self.highlight(blob_name, blob_content, nowrap: true)
+ new(blob_name, blob_content, nowrap: nowrap).highlight(blob_content, continue: false)
+ end
+
+ def self.highlight_lines(repository, ref, file_name)
+ blob = repository.blob_at(ref, file_name)
+ return [] unless blob
+
+ highlight(file_name, blob.data).lines.map!(&:html_safe)
+ end
+
+ def initialize(blob_name, blob_content, nowrap: true)
+ @formatter = rouge_formatter(nowrap: nowrap)
+ @lexer = Rouge::Lexer.guess(filename: blob_name, source: blob_content).new rescue Rouge::Lexers::PlainText
+ end
+
+ def highlight(text, continue: true)
+ @formatter.format(@lexer.lex(text, continue: continue)).html_safe
+ rescue
+ @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe
+ end
+
+ private
+
+ def rouge_formatter(options = {})
+ options = options.reverse_merge(
+ nowrap: true,
+ cssclass: 'code highlight',
+ lineanchors: true,
+ lineanchorsid: 'LC'
+ )
+
+ Rouge::Formatters::HTMLGitlab.new(options)
+ end
+ end
+end
diff --git a/lib/gitlab/inline_diff.rb b/lib/gitlab/inline_diff.rb
deleted file mode 100644
index 44507bde25d..00000000000
--- a/lib/gitlab/inline_diff.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-module Gitlab
- class InlineDiff
- class << self
-
- START = "#!idiff-start!#"
- FINISH = "#!idiff-finish!#"
-
- def processing(diff_arr)
- indexes = _indexes_of_changed_lines diff_arr
-
- indexes.each do |index|
- first_line = diff_arr[index+1]
- second_line = diff_arr[index+2]
-
- # Skip inline diff if empty line was replaced with content
- next if first_line == "-\n"
-
- first_token = find_first_token(first_line, second_line)
- apply_first_token(diff_arr, index, first_token)
-
- last_token = find_last_token(first_line, second_line, first_token)
- apply_last_token(diff_arr, index, last_token)
- end
-
- diff_arr
- end
-
- def apply_first_token(diff_arr, index, first_token)
- start = first_token + START
-
- if first_token.empty?
- # In case if we remove string of spaces in commit
- diff_arr[index+1].sub!("-", "-" => "-#{START}")
- diff_arr[index+2].sub!("+", "+" => "+#{START}")
- else
- diff_arr[index+1].sub!(first_token, first_token => start)
- diff_arr[index+2].sub!(first_token, first_token => start)
- end
- end
-
- def apply_last_token(diff_arr, index, last_token)
- # This is tricky: escape backslashes so that `sub` doesn't interpret them
- # as backreferences. Regexp.escape does NOT do the right thing.
- replace_token = FINISH + last_token.gsub(/\\/, '\&\&')
- diff_arr[index+1].sub!(/#{Regexp.escape(last_token)}$/, replace_token)
- diff_arr[index+2].sub!(/#{Regexp.escape(last_token)}$/, replace_token)
- end
-
- def find_first_token(first_line, second_line)
- max_length = [first_line.size, second_line.size].max
- first_the_same_symbols = 0
-
- (0..max_length + 1).each do |i|
- first_the_same_symbols = i - 1
-
- if first_line[i] != second_line[i] && i > 0
- break
- end
- end
-
- first_line[0..first_the_same_symbols][1..-1]
- end
-
- def find_last_token(first_line, second_line, first_token)
- max_length = [first_line.size, second_line.size].max
- last_the_same_symbols = 0
-
- (1..max_length + 1).each do |i|
- last_the_same_symbols = -i
- shortest_line = second_line.size > first_line.size ? first_line : second_line
-
- if (first_line[-i] != second_line[-i]) || "#{first_token}#{START}".size == shortest_line[1..-i].size
- break
- end
- end
-
- last_the_same_symbols += 1
- first_line[last_the_same_symbols..-1]
- end
-
- def _indexes_of_changed_lines(diff_arr)
- chain_of_first_symbols = ""
- diff_arr.each_with_index do |line, i|
- chain_of_first_symbols += line[0]
- end
- chain_of_first_symbols.gsub!(/[^\-\+]/, "#")
-
- offset = 0
- indexes = []
- while index = chain_of_first_symbols.index("#-+#", offset)
- indexes << index
- offset = index + 1
- end
- indexes
- end
-
- def replace_markers(line)
- line.gsub!(START, "<span class='idiff'>")
- line.gsub!(FINISH, "</span>")
- line
- end
- end
- end
-end
diff --git a/lib/gitlab/ip_check.rb b/lib/gitlab/ip_check.rb
new file mode 100644
index 00000000000..f2e9b50d225
--- /dev/null
+++ b/lib/gitlab/ip_check.rb
@@ -0,0 +1,34 @@
+module Gitlab
+ class IpCheck
+
+ def initialize(ip)
+ @ip = ip
+
+ application_settings = ApplicationSetting.current
+ @ip_blocking_enabled = application_settings.ip_blocking_enabled
+ @dnsbl_servers_list = application_settings.dnsbl_servers_list
+ end
+
+ def spam?
+ @ip_blocking_enabled && blacklisted?
+ end
+
+ private
+
+ def blacklisted?
+ on_dns_blacklist?
+ end
+
+ def on_dns_blacklist?
+ dnsbl_check = DNSXLCheck.new
+ prepare_dnsbl_list(dnsbl_check)
+ dnsbl_check.test(@ip)
+ end
+
+ def prepare_dnsbl_list(dnsbl_check)
+ @dnsbl_servers_list.split(',').map(&:strip).reject(&:empty?).each do |domain|
+ dnsbl_check.add_list(domain, 1)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index aef08c97d1d..e044f0ecc6d 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -30,28 +30,31 @@ module Gitlab
end
def find_by_uid_and_provider
- self.class.find_by_uid_and_provider(
- auth_hash.uid, auth_hash.provider)
+ self.class.find_by_uid_and_provider(auth_hash.uid, auth_hash.provider)
end
def find_by_email
- ::User.find_by(email: auth_hash.email.downcase)
+ ::User.find_by(email: auth_hash.email.downcase) if auth_hash.has_email?
end
def update_user_attributes
- return unless persisted?
+ if persisted?
+ if auth_hash.has_email?
+ gl_user.skip_reconfirmation!
+ gl_user.email = auth_hash.email
+ end
- gl_user.skip_reconfirmation!
- gl_user.email = auth_hash.email
+ # 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)
- # 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 identity set extern_uid to the LDAP DN
+ # For an existing identity with matching email but changed DN, update the DN.
+ # For an existing identity with no change in DN, this line changes nothing.
+ identity.extern_uid = auth_hash.uid
+ end
- # 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.ldap_email = auth_hash.has_email?
gl_user
end
diff --git a/lib/gitlab/o_auth/auth_hash.rb b/lib/gitlab/o_auth/auth_hash.rb
index ba31599432b..36e5c2670bb 100644
--- a/lib/gitlab/o_auth/auth_hash.rb
+++ b/lib/gitlab/o_auth/auth_hash.rb
@@ -32,6 +32,10 @@ module Gitlab
@password ||= Gitlab::Utils.force_utf8(Devise.friendly_token[0, 8].downcase)
end
+ def has_email?
+ get_info(:email).present?
+ end
+
private
def info
@@ -46,8 +50,8 @@ module Gitlab
def username_and_email
@username_and_email ||= begin
- username = get_info(:username) || get_info(:nickname)
- email = get_info(:email)
+ username = get_info(:username).presence || get_info(:nickname).presence
+ email = get_info(:email).presence
username ||= generate_username(email) if email
email ||= generate_temporarily_email(username) if username
diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb
index e3d2cc65a8f..d87a72f7ba3 100644
--- a/lib/gitlab/o_auth/user.rb
+++ b/lib/gitlab/o_auth/user.rb
@@ -111,7 +111,7 @@ module Gitlab
def block_after_signup?
if creating_linked_ldap_user?
ldap_config.block_auto_created_users
- else
+ else
Gitlab.config.omniauth.block_auto_created_users
end
end
@@ -135,16 +135,16 @@ module Gitlab
def user_attributes
# Give preference to LDAP for sensitive information when creating a linked account
if creating_linked_ldap_user?
- username = ldap_person.username
- email = ldap_person.email.first
- else
- username = auth_hash.username
- email = auth_hash.email
+ username = ldap_person.username.presence
+ email = ldap_person.email.first.presence
end
+ username ||= auth_hash.username
+ email ||= auth_hash.email
+
name = auth_hash.name
name = ::Namespace.clean_path(username) if name.strip.empty?
-
+
{
name: name,
username: ::Namespace.clean_path(username),
diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab
index c5f07c8b508..1633891c8a0 100755
--- a/lib/support/init.d/gitlab
+++ b/lib/support/init.d/gitlab
@@ -38,6 +38,7 @@ 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_workhorse_dir=$(cd $app_root/../gitlab-workhorse && pwd)
gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080 -authSocket $rails_socket -documentRoot $app_root/public"
gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
@@ -233,10 +234,12 @@ start_gitlab() {
if [ "$gitlab_workhorse_status" = "0" ]; then
echo "The gitlab-workhorse is already running with pid $spid, not restarting"
else
- # No need to remove a socket, gitlab-workhorse does this itself
+ # No need to remove a socket, gitlab-workhorse does this itself.
+ # Because gitlab-workhorse has multiple executables we need to fix
+ # the PATH.
$app_root/bin/daemon_with_pidfile $gitlab_workhorse_pid_path \
- $app_root/../gitlab-workhorse/gitlab-workhorse \
- $gitlab_workhorse_options \
+ /usr/bin/env PATH=$gitlab_workhorse_dir:$PATH \
+ gitlab-workhorse $gitlab_workhorse_options \
>> $gitlab_workhorse_log 2>&1 &
fi
diff --git a/lib/support/init.d/gitlab.default.example b/lib/support/init.d/gitlab.default.example
index 1937ca582b0..4e6e56ac2db 100755
--- a/lib/support/init.d/gitlab.default.example
+++ b/lib/support/init.d/gitlab.default.example
@@ -30,6 +30,9 @@ web_server_pid_path="$pid_path/unicorn.pid"
# The default is "$pid_path/sidekiq.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
+# The directory where the gitlab-workhorse binaries are. Usually
+# /home/git/gitlab-workhorse .
+gitlab_workhorse_dir=$(cd $app_root/../gitlab-workhorse && pwd)
gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
# The -listenXxx settings determine where gitlab-workhorse
# listens for connections from NGINX. To listen on localhost:8181, write
diff --git a/spec/fixtures/parallel_diff_result.yml b/spec/fixtures/parallel_diff_result.yml
new file mode 100644
index 00000000000..a326b651aad
--- /dev/null
+++ b/spec/fixtures/parallel_diff_result.yml
@@ -0,0 +1,324 @@
+---
+- :left:
+ :type: match
+ :number: 6
+ :text: "@@ -6,12 +6,18 @@ module Popen"
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
+ :right:
+ :type: match
+ :number: 6
+ :text: "@@ -6,12 +6,18 @@ module Popen"
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
+- :left:
+ :type:
+ :number: 6
+ :text: |2
+ <span id="LC6" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
+ :right:
+ :type:
+ :number: 6
+ :text: |2
+ <span id="LC6" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
+- :left:
+ :type:
+ :number: 7
+ :text: |2
+ <span id="LC7" class="line"> <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7
+ :right:
+ :type:
+ :number: 7
+ :text: |2
+ <span id="LC7" class="line"> <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7
+- :left:
+ :type:
+ :number: 8
+ :text: |2
+ <span id="LC8" class="line"> <span class="k">unless</span> <span class="n">cmd</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="no">Array</span><span class="p">)</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8
+ :right:
+ :type:
+ :number: 8
+ :text: |2
+ <span id="LC8" class="line"> <span class="k">unless</span> <span class="n">cmd</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="no">Array</span><span class="p">)</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8
+- :left:
+ :type: old
+ :number: 9
+ :text: |
+ -<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">&quot;System commands must be given as an array of strings&quot;</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9
+ :right:
+ :type: new
+ :number: 9
+ :text: |
+ +<span id="LC9" class="line"> <span class="k">raise</span> <span class="no"><span class='idiff'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff'> </span><span class="s2">&quot;System commands must be given as an array of strings&quot;</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9
+- :left:
+ :type:
+ :number: 10
+ :text: |2
+ <span id="LC10" class="line"> <span class="k">end</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10
+ :right:
+ :type:
+ :number: 10
+ :text: |2
+ <span id="LC10" class="line"> <span class="k">end</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10
+- :left:
+ :type:
+ :number: 11
+ :text: |2
+ <span id="LC11" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11
+ :right:
+ :type:
+ :number: 11
+ :text: |2
+ <span id="LC11" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11
+- :left:
+ :type:
+ :number: 12
+ :text: |2
+ <span id="LC12" class="line"> <span class="n">path</span> <span class="o">||=</span> <span class="no">Dir</span><span class="p">.</span><span class="nf">pwd</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12
+ :right:
+ :type:
+ :number: 12
+ :text: |2
+ <span id="LC12" class="line"> <span class="n">path</span> <span class="o">||=</span> <span class="no">Dir</span><span class="p">.</span><span class="nf">pwd</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12
+- :left:
+ :type: old
+ :number: 13
+ :text: |
+ -<span id="LC13" class="line"> <span class="n">vars</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">&quot;PWD&quot;</span> <span class="o">=&gt;</span> <span class="n">path</span> <span class="p">}</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13
+ :right:
+ :type: old
+ :number:
+ :text: ''
+ :line_code:
+- :left:
+ :type: old
+ :number: 14
+ :text: |
+ -<span id="LC14" class="line"> <span class="n">options</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">chdir: </span><span class="n">path</span> <span class="p">}</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13
+ :right:
+ :type: new
+ :number: 13
+ :text: |
+ +<span id="LC13" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_13
+- :left:
+ :type:
+ :number:
+ :text: ''
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14
+ :right:
+ :type: new
+ :number: 14
+ :text: |
+ +<span id="LC14" class="line"> <span class="n">vars</span> <span class="o">=</span> <span class="p">{</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14
+- :left:
+ :type:
+ :number:
+ :text: ''
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15
+ :right:
+ :type: new
+ :number: 15
+ :text: |
+ +<span id="LC15" class="line"> <span class="s2">&quot;PWD&quot;</span> <span class="o">=&gt;</span> <span class="n">path</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15
+- :left:
+ :type:
+ :number:
+ :text: ''
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16
+ :right:
+ :type: new
+ :number: 16
+ :text: |
+ +<span id="LC16" class="line"> <span class="p">}</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16
+- :left:
+ :type:
+ :number:
+ :text: ''
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17
+ :right:
+ :type: new
+ :number: 17
+ :text: |
+ +<span id="LC17" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17
+- :left:
+ :type:
+ :number:
+ :text: ''
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18
+ :right:
+ :type: new
+ :number: 18
+ :text: |
+ +<span id="LC18" class="line"> <span class="n">options</span> <span class="o">=</span> <span class="p">{</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18
+- :left:
+ :type:
+ :number:
+ :text: ''
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19
+ :right:
+ :type: new
+ :number: 19
+ :text: |
+ +<span id="LC19" class="line"> <span class="ss">chdir: </span><span class="n">path</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19
+- :left:
+ :type:
+ :number:
+ :text: ''
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20
+ :right:
+ :type: new
+ :number: 20
+ :text: |
+ +<span id="LC20" class="line"> <span class="p">}</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20
+- :left:
+ :type:
+ :number: 15
+ :text: |2
+ <span id="LC21" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21
+ :right:
+ :type:
+ :number: 21
+ :text: |2
+ <span id="LC21" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21
+- :left:
+ :type:
+ :number: 16
+ :text: |2
+ <span id="LC22" class="line"> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22
+ :right:
+ :type:
+ :number: 22
+ :text: |2
+ <span id="LC22" class="line"> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22
+- :left:
+ :type:
+ :number: 17
+ :text: |2
+ <span id="LC23" class="line"> <span class="no">FileUtils</span><span class="p">.</span><span class="nf">mkdir_p</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23
+ :right:
+ :type:
+ :number: 23
+ :text: |2
+ <span id="LC23" class="line"> <span class="no">FileUtils</span><span class="p">.</span><span class="nf">mkdir_p</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23
+- :left:
+ :type: match
+ :number: 19
+ :text: "@@ -19,6 +25,7 @@ module Popen"
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
+ :right:
+ :type: match
+ :number: 25
+ :text: "@@ -19,6 +25,7 @@ module Popen"
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
+- :left:
+ :type:
+ :number: 19
+ :text: |2
+ <span id="LC25" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
+ :right:
+ :type:
+ :number: 25
+ :text: |2
+ <span id="LC25" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
+- :left:
+ :type:
+ :number: 20
+ :text: |2
+ <span id="LC26" class="line"> <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26
+ :right:
+ :type:
+ :number: 26
+ :text: |2
+ <span id="LC26" class="line"> <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26
+- :left:
+ :type:
+ :number: 21
+ :text: |2
+ <span id="LC27" class="line"> <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27
+ :right:
+ :type:
+ :number: 27
+ :text: |2
+ <span id="LC27" class="line"> <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27
+- :left:
+ :type:
+ :number:
+ :text: ''
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28
+ :right:
+ :type: new
+ :number: 28
+ :text: |
+ +<span id="LC28" class="line"></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28
+- :left:
+ :type:
+ :number: 22
+ :text: |2
+ <span id="LC29" class="line"> <span class="no">Open3</span><span class="p">.</span><span class="nf">popen3</span><span class="p">(</span><span class="n">vars</span><span class="p">,</span> <span class="o">*</span><span class="n">cmd</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">stdin</span><span class="p">,</span> <span class="n">stdout</span><span class="p">,</span> <span class="n">stderr</span><span class="p">,</span> <span class="n">wait_thr</span><span class="o">|</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29
+ :right:
+ :type:
+ :number: 29
+ :text: |2
+ <span id="LC29" class="line"> <span class="no">Open3</span><span class="p">.</span><span class="nf">popen3</span><span class="p">(</span><span class="n">vars</span><span class="p">,</span> <span class="o">*</span><span class="n">cmd</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">stdin</span><span class="p">,</span> <span class="n">stdout</span><span class="p">,</span> <span class="n">stderr</span><span class="p">,</span> <span class="n">wait_thr</span><span class="o">|</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29
+- :left:
+ :type:
+ :number: 23
+ :text: |2
+ <span id="LC30" class="line"> <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stdout</span><span class="p">.</span><span class="nf">read</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30
+ :right:
+ :type:
+ :number: 30
+ :text: |2
+ <span id="LC30" class="line"> <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stdout</span><span class="p">.</span><span class="nf">read</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30
+- :left:
+ :type:
+ :number: 24
+ :text: |2
+ <span id="LC31" class="line"> <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stderr</span><span class="p">.</span><span class="nf">read</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31
+ :right:
+ :type:
+ :number: 31
+ :text: |2
+ <span id="LC31" class="line"> <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stderr</span><span class="p">.</span><span class="nf">read</span></span>
+ :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index b8bba36439a..87849230dbe 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -1,22 +1,22 @@
require 'spec_helper'
describe BlobHelper do
- describe 'highlight' do
- let(:blob_name) { 'test.lisp' }
- let(:no_context_content) { ":type \"assem\"))" }
- let(:blob_content) { "(make-pathname :defaults name\n#{no_context_content}" }
- let(:split_content) { blob_content.split("\n") }
- let(:multiline_content) do
- %q(
- def test(input):
- """This is line 1 of a multi-line comment.
- This is line 2.
- """
- )
- end
+ let(:blob_name) { 'test.lisp' }
+ let(:no_context_content) { ":type \"assem\"))" }
+ let(:blob_content) { "(make-pathname :defaults name\n#{no_context_content}" }
+ let(:split_content) { blob_content.split("\n") }
+ let(:multiline_content) do
+ %q(
+ def test(input):
+ """This is line 1 of a multi-line comment.
+ This is line 2.
+ """
+ )
+ end
+ describe '#highlight' do
it 'should return plaintext for unknown lexer context' do
- result = highlight(blob_name, no_context_content, nowrap: true, continue: false)
+ result = helper.highlight(blob_name, no_context_content, nowrap: true)
expect(result).to eq('<span id="LC1" class="line">:type &quot;assem&quot;))</span>')
end
@@ -24,28 +24,17 @@ describe BlobHelper do
expected = %Q[<span id="LC1" class="line"><span class="p">(</span><span class="nb">make-pathname</span> <span class="ss">:defaults</span> <span class="nv">name</span></span>
<span id="LC2" class="line"><span class="ss">:type</span> <span class="s">&quot;assem&quot;</span><span class="p">))</span></span>]
- expect(highlight(blob_name, blob_content, nowrap: true, continue: false)).to eq(expected)
- end
-
- it 'should highlight continued blocks' do
- # Both lines have LC1 as ID since formatter doesn't support continue at the moment
- expected = [
- '<span id="LC1" class="line"><span class="p">(</span><span class="nb">make-pathname</span> <span class="ss">:defaults</span> <span class="nv">name</span></span>',
- '<span id="LC1" class="line"><span class="ss">:type</span> <span class="s">&quot;assem&quot;</span><span class="p">))</span></span>'
- ]
-
- result = split_content.map{ |content| highlight(blob_name, content, nowrap: true, continue: true) }
- expect(result).to eq(expected)
+ expect(helper.highlight(blob_name, blob_content, nowrap: true)).to eq(expected)
end
it 'should highlight multi-line comments' do
- result = highlight(blob_name, multiline_content, nowrap: true, continue: false)
+ result = helper.highlight(blob_name, multiline_content, nowrap: true)
html = Nokogiri::HTML(result)
lines = html.search('.s')
expect(lines.count).to eq(3)
expect(lines[0].text).to eq('"""This is line 1 of a multi-line comment.')
- expect(lines[1].text).to eq(' This is line 2.')
- expect(lines[2].text).to eq(' """')
+ expect(lines[1].text).to eq(' This is line 2.')
+ expect(lines[2].text).to eq(' """')
end
context 'diff highlighting' do
@@ -59,9 +48,23 @@ describe BlobHelper do
end
it 'should highlight each line properly' do
- result = highlight(blob_name, blob_content, nowrap: true, continue: false)
+ result = helper.highlight(blob_name, blob_content, nowrap: true)
expect(result).to eq(expected)
end
end
end
+
+ describe "#highlighter" do
+ it 'should highlight continued blocks' do
+ # Both lines have LC1 as ID since formatter doesn't support continue at the moment
+ expected = [
+ '<span id="LC1" class="line"><span class="p">(</span><span class="nb">make-pathname</span> <span class="ss">:defaults</span> <span class="nv">name</span></span>',
+ '<span id="LC1" class="line"><span class="ss">:type</span> <span class="s">&quot;assem&quot;</span><span class="p">))</span></span>'
+ ]
+
+ highlighter = helper.highlighter(blob_name, blob_content, nowrap: true)
+ result = split_content.map{ |content| highlighter.highlight(content) }
+ expect(result).to eq(expected)
+ end
+ end
end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index 7c96a74e581..955d2852cfd 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -4,10 +4,12 @@ describe DiffHelper do
include RepoHelpers
let(:project) { create(:project) }
+ let(:repository) { project.repository }
let(:commit) { project.commit(sample_commit.id) }
let(:diffs) { commit.diffs }
let(:diff) { diffs.first }
- let(:diff_file) { Gitlab::Diff::File.new(diff) }
+ let(:diff_refs) { [commit.parent, commit] }
+ let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs) }
describe 'diff_hard_limit_enabled?' do
it 'should return true if param is provided' do
@@ -44,55 +46,41 @@ describe DiffHelper do
describe 'safe_diff_files' do
it 'should return all files from a commit that is smaller than safe limits' do
- expect(safe_diff_files(diffs).length).to eq(2)
+ expect(safe_diff_files(diffs, diff_refs).length).to eq(2)
end
it 'should return only the first file if the diff line count in the 2nd file takes the total beyond safe limits' do
allow(diffs[1].diff).to receive(:lines).and_return([""] * 4999) #simulate 4999 lines
- expect(safe_diff_files(diffs).length).to eq(1)
+ expect(safe_diff_files(diffs, diff_refs).length).to eq(1)
end
it 'should return all files from a commit that is beyond safe limit for numbers of lines if force diff is true' do
allow(controller).to receive(:params) { { force_show_diff: true } }
allow(diffs[1].diff).to receive(:lines).and_return([""] * 4999) #simulate 4999 lines
- expect(safe_diff_files(diffs).length).to eq(2)
+ expect(safe_diff_files(diffs, diff_refs).length).to eq(2)
end
it 'should return only the first file if the diff line count in the 2nd file takes the total beyond hard limits' do
allow(controller).to receive(:params) { { force_show_diff: true } }
allow(diffs[1].diff).to receive(:lines).and_return([""] * 49999) #simulate 49999 lines
- expect(safe_diff_files(diffs).length).to eq(1)
+ expect(safe_diff_files(diffs, diff_refs).length).to eq(1)
end
it 'should return only a safe number of file diffs if a commit touches more files than the safe limits' do
large_diffs = diffs * 100 #simulate 200 diffs
- expect(safe_diff_files(large_diffs).length).to eq(100)
+ expect(safe_diff_files(large_diffs, diff_refs).length).to eq(100)
end
it 'should return all file diffs if a commit touches more files than the safe limits but force diff is true' do
allow(controller).to receive(:params) { { force_show_diff: true } }
large_diffs = diffs * 100 #simulate 200 diffs
- expect(safe_diff_files(large_diffs).length).to eq(200)
+ expect(safe_diff_files(large_diffs, diff_refs).length).to eq(200)
end
it 'should return a limited file diffs if a commit touches more files than the hard limits and force diff is true' do
allow(controller).to receive(:params) { { force_show_diff: true } }
very_large_diffs = diffs * 1000 #simulate 2000 diffs
- expect(safe_diff_files(very_large_diffs).length).to eq(1000)
- end
- end
-
- describe 'parallel_diff' do
- it 'should return an array of arrays containing the parsed diff' do
- expect(parallel_diff(diff_file, 0)).
- to match_array(parallel_diff_result_array)
- end
- end
-
- describe 'generate_line_code' do
- it 'should generate correct line code' do
- expect(generate_line_code(diff_file.file_path, diff_file.diff_lines.first)).
- to eq('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6')
+ expect(safe_diff_files(very_large_diffs, diff_refs).length).to eq(1000)
end
end
@@ -126,39 +114,11 @@ describe DiffHelper do
expect(diff_line_content(diff_file.diff_lines.first.text)).
to eq('@@ -6,12 +6,18 @@ module Popen')
expect(diff_line_content(diff_file.diff_lines.first.type)).to eq('match')
- expect(diff_line_content(diff_file.diff_lines.first.new_pos)).to eq(6)
+ expect(diff_file.diff_lines.first.new_pos).to eq(6)
end
- end
- def parallel_diff_result_array
- [
- ["match", 6, "@@ -6,12 +6,18 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6", "match", 6, "@@ -6,12 +6,18 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6"],
- [nil, 6, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6", nil, 6, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6"], [nil, 7, " def popen(cmd, path=nil)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7", nil, 7, " def popen(cmd, path=nil)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"],
- [nil, 8, " unless cmd.is_a?(Array)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8", nil, 8, " unless cmd.is_a?(Array)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"],
- ["old", 9, "- raise <span class='idiff'></span>&quot;System commands must be given as an array of strings&quot;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9", "new", 9, "+ raise <span class='idiff'>RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"],
- [nil, 10, " end", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10", nil, 10, " end", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"],
- [nil, 11, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11", nil, 11, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11"],
- [nil, 12, " path ||= Dir.pwd", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12", nil, 12, " path ||= Dir.pwd", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12"],
- ["old", 13, "- vars = { &quot;PWD&quot; =&gt; path }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13", "old", nil, "&nbsp;", nil],
- ["old", 14, "- options = { chdir: path }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13", "new", 13, "+", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_13"],
- [nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14", "new", 14, "+ vars = {", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14"],
- [nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15", "new", 15, "+ &quot;PWD&quot; =&gt; path", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15"],
- [nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16", "new", 16, "+ }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16"],
- [nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17", "new", 17, "+", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17"],
- [nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18", "new", 18, "+ options = {", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18"],
- [nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19", "new", 19, "+ chdir: path", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19"],
- [nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20", "new", 20, "+ }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20"],
- [nil, 15, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21", nil, 21, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21"],
- [nil, 16, " unless File.directory?(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22", nil, 22, " unless File.directory?(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22"],
- [nil, 17, " FileUtils.mkdir_p(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23", nil, 23, " FileUtils.mkdir_p(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23"],
- ["match", 19, "@@ -19,6 +25,7 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25", "match", 25, "@@ -19,6 +25,7 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25"],
- [nil, 19, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25", nil, 25, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25"],
- [nil, 20, " @cmd_output = &quot;&quot;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26", nil, 26, " @cmd_output = &quot;&quot;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26"],
- [nil, 21, " @cmd_status = 0", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27", nil, 27, " @cmd_status = 0", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27"],
- [nil, nil, "&nbsp;", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28", "new", 28, "+", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28"],
- [nil, 22, " Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29", nil, 29, " Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29"],
- [nil, 23, " @cmd_output &lt;&lt; stdout.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30", nil, 30, " @cmd_output &lt;&lt; stdout.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30"],
- [nil, 24, " @cmd_output &lt;&lt; stderr.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31", nil, 31, " @cmd_output &lt;&lt; stderr.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31"]
- ]
+ it 'should return safe HTML' do
+ expect(diff_line_content(diff_file.diff_lines.first.text)).to be_html_safe
+ end
end
end
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index d15100fc6d8..f3394910c5b 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -336,7 +336,7 @@ module Ci
describe "Caches" do
it "returns cache when defined globally" do
config = YAML.dump({
- cache: { paths: ["logs/", "binaries/"], untracked: true },
+ cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'key' },
rspec: {
script: "rspec"
}
@@ -348,13 +348,14 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
paths: ["logs/", "binaries/"],
untracked: true,
+ key: 'key',
)
end
it "returns cache when defined in a job" do
config = YAML.dump({
rspec: {
- cache: { paths: ["logs/", "binaries/"], untracked: true },
+ cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'key' },
script: "rspec"
}
})
@@ -365,15 +366,16 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
paths: ["logs/", "binaries/"],
untracked: true,
+ key: 'key',
)
end
it "overwrite cache when defined for a job and globally" do
config = YAML.dump({
- cache: { paths: ["logs/", "binaries/"], untracked: true },
+ cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'global' },
rspec: {
script: "rspec",
- cache: { paths: ["test/"], untracked: false },
+ cache: { paths: ["test/"], untracked: false, key: 'local' },
}
})
@@ -383,6 +385,7 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
paths: ["test/"],
untracked: false,
+ key: 'local',
)
end
end
@@ -615,6 +618,20 @@ module Ci
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "cache:paths parameter should be an array of strings")
end
+ it "returns errors if cache:key is not a string" do
+ config = YAML.dump({ cache: { key: 1 }, rspec: { script: "test" } })
+ expect do
+ GitlabCiYamlProcessor.new(config)
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "cache:key parameter should be a string")
+ end
+
+ it "returns errors if job cache:key is not an a string" do
+ config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", cache: { key: 1 } } })
+ expect do
+ GitlabCiYamlProcessor.new(config)
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: cache:key parameter should be a string")
+ end
+
it "returns errors if job cache:untracked is not an array of strings" do
config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", cache: { untracked: "string" } } })
expect do
diff --git a/spec/lib/dnsxl_check_spec.rb b/spec/lib/dnsxl_check_spec.rb
new file mode 100644
index 00000000000..a35a1be0c90
--- /dev/null
+++ b/spec/lib/dnsxl_check_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+require 'ostruct'
+
+describe 'DNSXLCheck', lib: true, no_db: true do
+ let(:spam_ip) { '127.0.0.2' }
+ let(:no_spam_ip) { '127.0.0.3' }
+ let(:invalid_ip) { 'a.b.c.d' }
+ let!(:dnsxl_check) { DNSXLCheck.create_from_list([OpenStruct.new({ domain: 'test', weight: 1 })]) }
+
+ before(:context) do
+ class DNSXLCheck::Resolver
+ class << self
+ alias_method :old_search, :search
+ def search(query)
+ return false if query.match(/always\.failing\.domain\z/)
+ return true if query.match(/\A2\.0\.0\.127\./)
+ return false if query.match(/\A3\.0\.0\.127\./)
+ end
+ end
+ end
+ end
+
+ describe '#test' do
+ before do
+ dnsxl_check.threshold = 0.75
+ dnsxl_check.add_list('always.failing.domain', 1)
+ end
+
+ context 'when threshold is used' do
+ before { dnsxl_check.use_threshold= true }
+
+ it { expect(dnsxl_check.test(spam_ip)).to be_falsey }
+ end
+
+ context 'when threshold is not used' do
+ before { dnsxl_check.use_threshold= false }
+
+ it { expect(dnsxl_check.test(spam_ip)).to be_truthy }
+ end
+ end
+
+ describe '#test_with_threshold' do
+ it { expect{ dnsxl_check.test_with_threshold(invalid_ip) }.to raise_error(ArgumentError) }
+
+ it { expect(dnsxl_check.test_with_threshold(spam_ip)).to be_truthy }
+ it { expect(dnsxl_check.test_with_threshold(no_spam_ip)).to be_falsey }
+ end
+
+ describe '#test_strict' do
+ before do
+ dnsxl_check.threshold = 1
+ dnsxl_check.add_list('always.failing.domain', 1)
+ end
+
+ it { expect{ dnsxl_check.test_strict(invalid_ip) }.to raise_error(ArgumentError) }
+
+ it { expect(dnsxl_check.test_with_threshold(spam_ip)).to be_falsey }
+ it { expect(dnsxl_check.test_with_threshold(no_spam_ip)).to be_falsey }
+ it { expect(dnsxl_check.test_strict(spam_ip)).to be_truthy }
+ it { expect(dnsxl_check.test_strict(no_spam_ip)).to be_falsey }
+ end
+
+ describe '#threshold=' do
+ it { expect{ dnsxl_check.threshold = 0 }.to raise_error(ArgumentError) }
+ it { expect{ dnsxl_check.threshold = 1.1 }.to raise_error(ArgumentError) }
+ it { expect{ dnsxl_check.threshold = 0.5 }.not_to raise_error }
+ end
+end
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
index 41257103ead..acca0b08bab 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
@@ -4,13 +4,13 @@ describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
let(:entries) do
{ 'path/' => {},
'path/dir_1/' => {},
- 'path/dir_1/file_1' => {},
- 'path/dir_1/file_b' => {},
+ 'path/dir_1/file_1' => { size: 10 },
+ 'path/dir_1/file_b' => { size: 10 },
'path/dir_1/subdir/' => {},
- 'path/dir_1/subdir/subfile' => {},
+ 'path/dir_1/subdir/subfile' => { size: 10 },
'path/second_dir' => {},
- 'path/second_dir/dir_3/file_2' => {},
- 'path/second_dir/dir_3/file_3'=> {},
+ 'path/second_dir/dir_3/file_2' => { size: 10 },
+ 'path/second_dir/dir_3/file_3'=> { size: 10 },
'another_directory/'=> {},
'another_file' => {},
'/file/with/absolute_path' => {} }
@@ -112,6 +112,11 @@ describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
subject { |example| path(example).empty? }
it { is_expected.to be false }
end
+
+ describe '#total_size' do
+ subject { |example| path(example).total_size }
+ it { is_expected.to eq(30) }
+ end
end
end
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
index 828eedfa7b0..eea01f91879 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
describe Gitlab::Ci::Build::Artifacts::Metadata do
- def metadata(path = '')
- described_class.new(metadata_file_path, path)
+ def metadata(path = '', **opts)
+ described_class.new(metadata_file_path, path, **opts)
end
let(:metadata_file_path) do
@@ -51,6 +51,19 @@ describe Gitlab::Ci::Build::Artifacts::Metadata do
end
end
+ describe '#find_entries! recursively for other_artifacts_0.1.2/' do
+ subject { metadata('other_artifacts_0.1.2/', recursive: true).find_entries! }
+
+ it 'matches correct paths' do
+ expect(subject.keys).
+ to contain_exactly 'other_artifacts_0.1.2/',
+ 'other_artifacts_0.1.2/doc_sample.txt',
+ 'other_artifacts_0.1.2/another-subdirectory/',
+ 'other_artifacts_0.1.2/another-subdirectory/empty_directory/',
+ 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif'
+ end
+ end
+
describe '#to_entry' do
subject { metadata('').to_entry }
it { is_expected.to be_an_instance_of(Gitlab::Ci::Build::Artifacts::Metadata::Entry) }
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index c7cdf8691d6..0d9694f2c13 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Diff::File, lib: true do
let(:project) { create(:project) }
let(:commit) { project.commit(sample_commit.id) }
let(:diff) { commit.diffs.first }
- let(:diff_file) { Gitlab::Diff::File.new(diff) }
+ let(:diff_file) { Gitlab::Diff::File.new(diff, [commit.parent, commit]) }
describe :diff_lines do
let(:diff_lines) { diff_file.diff_lines }
diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb
new file mode 100644
index 00000000000..b84a57f357a
--- /dev/null
+++ b/spec/lib/gitlab/diff/highlight_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+describe Gitlab::Diff::Highlight, lib: true do
+ include RepoHelpers
+
+ let(:project) { create(:project) }
+ let(:commit) { project.commit(sample_commit.id) }
+ let(:diff) { commit.diffs.first }
+ let(:diff_file) { Gitlab::Diff::File.new(diff, [commit.parent, commit]) }
+
+ describe '#highlight' do
+ let(:diff_lines) { Gitlab::Diff::Highlight.new(diff_file).highlight }
+
+ it 'should return Gitlab::Diff::Line elements' do
+ expect(diff_lines.first).to be_an_instance_of(Gitlab::Diff::Line)
+ end
+
+ it 'should not modify "match" lines' do
+ expect(diff_lines[0].text).to eq('@@ -6,12 +6,18 @@ module Popen')
+ expect(diff_lines[22].text).to eq('@@ -19,6 +25,7 @@ module Popen')
+ end
+
+ it 'should highlight unchanged lines' do
+ code = %Q{ <span id="LC7" class="line"> <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>\n}
+
+ expect(diff_lines[2].text).to eq(code)
+ end
+
+ it 'should highlight removed lines' do
+ code = %Q{-<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">&quot;System commands must be given as an array of strings&quot;</span></span>\n}
+
+ expect(diff_lines[4].text).to eq(code)
+ end
+
+ it 'should highlight added lines' do
+ code = %Q{+<span id="LC9" class="line"> <span class="k">raise</span> <span class="no"><span class='idiff'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff'> </span><span class="s2">&quot;System commands must be given as an array of strings&quot;</span></span>\n}
+
+ expect(diff_lines[5].text).to eq(code)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
new file mode 100644
index 00000000000..6f3276a8b53
--- /dev/null
+++ b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe Gitlab::Diff::InlineDiffMarker, lib: true do
+ describe '#inline_diffs' do
+ let(:raw) { "abc 'def'" }
+ let(:rich) { %{<span class="abc">abc</span><span class="space"> </span><span class="def">&#39;def&#39;</span>} }
+ let(:inline_diffs) { [2..5] }
+
+ let(:subject) { Gitlab::Diff::InlineDiffMarker.new(raw, rich).mark(inline_diffs) }
+
+ it 'marks the inline diffs' do
+ expect(subject).to eq(%{<span class="abc">ab<span class='idiff'>c</span></span><span class="space"><span class='idiff'> </span></span><span class="def"><span class='idiff'>&#39;d</span>ef&#39;</span>})
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/inline_diff_spec.rb b/spec/lib/gitlab/diff/inline_diff_spec.rb
new file mode 100644
index 00000000000..056917df893
--- /dev/null
+++ b/spec/lib/gitlab/diff/inline_diff_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Gitlab::Diff::InlineDiff, lib: true do
+ describe '#inline_diffs' do
+ let(:diff) do
+ <<eos
+ class Test
+- def initialize(test = true)
++ def initialize(test = false)
+ @test = test
+ end
+ end
+eos
+ end
+
+ let(:subject) { Gitlab::Diff::InlineDiff.new(diff.lines).inline_diffs }
+
+ it 'finds all inline diffs' do
+ expect(subject[0]).to be_nil
+ expect(subject[1]).to eq([25..27])
+ expect(subject[2]).to eq([25..28])
+ expect(subject[3]).to be_nil
+ expect(subject[4]).to be_nil
+ expect(subject[5]).to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/parallel_diff_spec.rb b/spec/lib/gitlab/diff/parallel_diff_spec.rb
new file mode 100644
index 00000000000..1c5bbc47120
--- /dev/null
+++ b/spec/lib/gitlab/diff/parallel_diff_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe Gitlab::Diff::ParallelDiff, lib: true do
+ include RepoHelpers
+
+ let(:project) { create(:project) }
+ let(:repository) { project.repository }
+ let(:commit) { project.commit(sample_commit.id) }
+ let(:diffs) { commit.diffs }
+ let(:diff) { diffs.first }
+ let(:diff_refs) { [commit.parent, commit] }
+ let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs) }
+ subject { described_class.new(diff_file) }
+
+ let(:parallel_diff_result_array) { YAML.load_file("#{Rails.root}/spec/fixtures/parallel_diff_result.yml") }
+
+ describe '#parallelize' do
+ it 'should return an array of arrays containing the parsed diff' do
+ expect(subject.parallelize).to match_array(parallel_diff_result_array)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb
index ba577bd28e5..fe0dea77909 100644
--- a/spec/lib/gitlab/diff/parser_spec.rb
+++ b/spec/lib/gitlab/diff/parser_spec.rb
@@ -86,7 +86,7 @@ eos
it { expect(line.type).to eq(nil) }
it { expect(line.old_pos).to eq(24) }
it { expect(line.new_pos).to eq(31) }
- it { expect(line.text).to eq(' @cmd_output &lt;&lt; stderr.read') }
+ it { expect(line.text).to eq(' @cmd_output << stderr.read') }
end
end
end
diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
index 9aefec77f6d..6cebcb5009a 100644
--- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
@@ -2,8 +2,11 @@ require 'spec_helper'
describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
let(:project) { create(:project) }
- let(:source_branch) { OpenStruct.new(ref: 'feature') }
- let(:target_branch) { OpenStruct.new(ref: 'master') }
+ let(:repository) { OpenStruct.new(id: 1, fork: false) }
+ let(:source_repo) { repository }
+ let(:source_branch) { OpenStruct.new(ref: 'feature', repo: source_repo) }
+ let(:target_repo) { repository }
+ let(:target_branch) { OpenStruct.new(ref: 'master', repo: target_repo) }
let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
@@ -125,10 +128,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end
describe '#cross_project?' do
- context 'when source repo is not a fork' do
- let(:local_repo) { OpenStruct.new(fork: false) }
- let(:source_branch) { OpenStruct.new(ref: 'feature', repo: local_repo) }
- let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch)) }
+ context 'when source, and target repositories are the same' do
+ let(:raw_data) { OpenStruct.new(base_data) }
it 'returns false' do
expect(pull_request.cross_project?).to eq false
@@ -136,9 +137,17 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end
context 'when source repo is a fork' do
- let(:forked_repo) { OpenStruct.new(fork: true) }
- let(:source_branch) { OpenStruct.new(ref: 'feature', repo: forked_repo) }
- let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch)) }
+ let(:source_repo) { OpenStruct.new(id: 2, fork: true) }
+ let(:raw_data) { OpenStruct.new(base_data) }
+
+ it 'returns true' do
+ expect(pull_request.cross_project?).to eq true
+ end
+ end
+
+ context 'when target repo is a fork' do
+ let(:target_repo) { OpenStruct.new(id: 2, fork: true) }
+ let(:raw_data) { OpenStruct.new(base_data) }
it 'returns true' do
expect(pull_request.cross_project?).to eq true
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
new file mode 100644
index 00000000000..1620eb6c60a
--- /dev/null
+++ b/spec/lib/gitlab/highlight_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Highlight, lib: true do
+ include RepoHelpers
+
+ let(:project) { create(:project) }
+ let(:commit) { project.commit(sample_commit.id) }
+
+ describe '.highlight_lines' do
+ let(:lines) do
+ Gitlab::Highlight.highlight_lines(project.repository, commit.id, 'files/ruby/popen.rb')
+ end
+
+ it 'should properly highlight all the lines' do
+ expect(lines[4]).to eq(%Q{<span id="LC5" class="line"> <span class="kp">extend</span> <span class="nb">self</span></span>\n})
+ expect(lines[21]).to eq(%Q{<span id="LC22" class="line"> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>\n})
+ expect(lines[26]).to eq(%Q{<span id="LC27" class="line"> <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>\n})
+ end
+ end
+
+end
diff --git a/spec/lib/gitlab/inline_diff_spec.rb b/spec/lib/gitlab/inline_diff_spec.rb
deleted file mode 100644
index c690c195112..00000000000
--- a/spec/lib/gitlab/inline_diff_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::InlineDiff, lib: true do
- describe '#processing' do
- let(:diff) do
- <<eos
---- a/test.rb
-+++ b/test.rb
-@@ -1,6 +1,6 @@
- class Test
- def cleanup_string(input)
- return nil if input.nil?
-- input.sub(/[\\r\\n].+/,'').sub(/\\\\[rn].+/, '').strip
-+ input.to_s.sub(/[\\r\\n].+/,'').sub(/\\\\[rn].+/, '').strip
- end
- end
-eos
- end
-
- let(:expected) do
- ["--- a/test.rb\n",
- "+++ b/test.rb\n",
- "@@ -1,6 +1,6 @@\n",
- " class Test\n",
- " def cleanup_string(input)\n",
- " return nil if input.nil?\n",
- "- input.#!idiff-start!##!idiff-finish!#sub(/[\\r\\n].+/,'').sub(/\\\\[rn].+/, '').strip\n",
- "+ input.#!idiff-start!#to_s.#!idiff-finish!#sub(/[\\r\\n].+/,'').sub(/\\\\[rn].+/, '').strip\n",
- " end\n",
- " end\n"]
- end
-
- let(:subject) { Gitlab::InlineDiff.processing(diff.lines) }
-
- it 'should retain backslashes' do
- expect(subject).to eq(expected)
- end
- end
-end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index 1e755259dae..03199a2523e 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -37,7 +37,7 @@ describe Gitlab::LDAP::User, lib: true do
end
it "dont marks existing ldap user as changed" do
- create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain')
+ create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', ldap_email: true)
expect(ldap_user.changed?).to be_falsey
end
end
@@ -110,6 +110,32 @@ describe Gitlab::LDAP::User, lib: true do
end
end
+ describe 'updating email' do
+ context "when LDAP sets an email" do
+ it "has a real email" do
+ expect(ldap_user.gl_user.email).to eq(info[:email])
+ end
+
+ it "has ldap_email set to true" do
+ expect(ldap_user.gl_user.ldap_email?).to be(true)
+ end
+ end
+
+ context "when LDAP doesn't set an email" do
+ before do
+ info.delete(:email)
+ end
+
+ it "has a temp email" do
+ expect(ldap_user.gl_user.temp_oauth_email?).to be(true)
+ end
+
+ it "has ldap_email set to false" do
+ expect(ldap_user.gl_user.ldap_email?).to be(false)
+ end
+ end
+ end
+
describe 'blocking' do
def configure_block(value)
allow_any_instance_of(Gitlab::LDAP::Config).
diff --git a/spec/lib/gitlab/note_data_builder_spec.rb b/spec/lib/gitlab/note_data_builder_spec.rb
index 6cbdae737f4..691f36e6cb7 100644
--- a/spec/lib/gitlab/note_data_builder_spec.rb
+++ b/spec/lib/gitlab/note_data_builder_spec.rb
@@ -37,7 +37,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
it 'returns the note and issue-specific data' do
expect(data).to have_key(:issue)
- expect(data[:issue]).to eq(issue.hook_attrs)
+ expect(data[:issue].except('updated_at')).to eq(issue.hook_attrs.except('updated_at'))
+ expect(data[:issue]['updated_at']).to be > issue.hook_attrs['updated_at']
end
end
@@ -47,7 +48,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
it 'returns the note and merge request data' do
expect(data).to have_key(:merge_request)
- expect(data[:merge_request]).to eq(merge_request.hook_attrs)
+ expect(data[:merge_request].except('updated_at')).to eq(merge_request.hook_attrs.except('updated_at'))
+ expect(data[:merge_request]['updated_at']).to be > merge_request.hook_attrs['updated_at']
end
end
@@ -57,7 +59,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
it 'returns the note and merge request diff data' do
expect(data).to have_key(:merge_request)
- expect(data[:merge_request]).to eq(merge_request.hook_attrs)
+ expect(data[:merge_request].except('updated_at')).to eq(merge_request.hook_attrs.except('updated_at'))
+ expect(data[:merge_request]['updated_at']).to be > merge_request.hook_attrs['updated_at']
end
end
@@ -67,7 +70,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
it 'returns the note and project snippet data' do
expect(data).to have_key(:snippet)
- expect(data[:snippet]).to eq(snippet.hook_attrs)
+ expect(data[:snippet].except('updated_at')).to eq(snippet.hook_attrs.except('updated_at'))
+ expect(data[:snippet]['updated_at']).to be > snippet.hook_attrs['updated_at']
end
end
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 8f86c491d3f..7289e596ef3 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -40,14 +40,38 @@ describe Notify do
end
end
+ shared_examples 'an email with X-GitLab headers containing project details' do
+ it 'has X-GitLab-Project* headers' do
+ is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
+ is_expected.to have_header 'X-GitLab-Project-Id', /#{project.id}/
+ is_expected.to have_header 'X-GitLab-Project-Path', /#{project.path_with_namespace}/
+ end
+ end
+
+ shared_examples 'an email with X-GitLab headers containing build details' do
+ it 'has X-GitLab-Build* headers' do
+ is_expected.to have_header 'X-GitLab-Build-Id', /#{build.id}/
+ is_expected.to have_header 'X-GitLab-Build-Ref', /#{build.ref}/
+ end
+ end
+
+ shared_examples 'an email that contains a header with author username' do
+ it 'has X-GitLab-Author header containing author\'s username' do
+ is_expected.to have_header 'X-GitLab-Author', user.username
+ end
+ end
+
shared_examples 'an email starting a new thread' do |message_id_prefix|
+ include_examples 'an email with X-GitLab headers containing project details'
+
it 'has a discussion identifier' do
is_expected.to have_header 'Message-ID', /<#{message_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
- is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
end
end
shared_examples 'an answer to an existing thread' do |thread_id_prefix|
+ include_examples 'an email with X-GitLab headers containing project details'
+
it 'has a subject that begins with Re: ' do
is_expected.to have_subject /^Re: /
end
@@ -56,7 +80,6 @@ describe Notify do
is_expected.to have_header 'Message-ID', /<(.*)@#{Gitlab.config.gitlab.host}>/
is_expected.to have_header 'References', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
is_expected.to have_header 'In-Reply-To', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
- is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
end
end
@@ -656,6 +679,8 @@ describe Notify do
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like "a user cannot unsubscribe through footer link"
+ it_behaves_like 'an email with X-GitLab headers containing project details'
+ it_behaves_like 'an email that contains a header with author username'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -685,6 +710,8 @@ describe Notify do
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like "a user cannot unsubscribe through footer link"
+ it_behaves_like 'an email with X-GitLab headers containing project details'
+ it_behaves_like 'an email that contains a header with author username'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -713,6 +740,8 @@ describe Notify do
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like "a user cannot unsubscribe through footer link"
+ it_behaves_like 'an email with X-GitLab headers containing project details'
+ it_behaves_like 'an email that contains a header with author username'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -737,6 +766,8 @@ describe Notify do
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like "a user cannot unsubscribe through footer link"
+ it_behaves_like 'an email with X-GitLab headers containing project details'
+ it_behaves_like 'an email that contains a header with author username'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -765,6 +796,8 @@ describe Notify do
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like "a user cannot unsubscribe through footer link"
+ it_behaves_like 'an email with X-GitLab headers containing project details'
+ it_behaves_like 'an email that contains a header with author username'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -871,6 +904,8 @@ describe Notify do
it_behaves_like 'it should show Gmail Actions View Commit link'
it_behaves_like "a user cannot unsubscribe through footer link"
+ it_behaves_like 'an email with X-GitLab headers containing project details'
+ it_behaves_like 'an email that contains a header with author username'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -904,6 +939,15 @@ describe Notify do
subject { Notify.build_success_email(build.id, 'wow@example.com') }
+ it_behaves_like 'an email with X-GitLab headers containing build details'
+ it_behaves_like 'an email with X-GitLab headers containing project details' do
+ let(:project) { build.project }
+ end
+
+ it 'has header indicating build status' do
+ is_expected.to have_header 'X-GitLab-Build-Status', 'success'
+ end
+
it 'has the correct subject' do
should have_subject /Build success for/
end
@@ -918,6 +962,15 @@ describe Notify do
subject { Notify.build_fail_email(build.id, 'wow@example.com') }
+ it_behaves_like 'an email with X-GitLab headers containing build details'
+ it_behaves_like 'an email with X-GitLab headers containing project details' do
+ let(:project) { build.project }
+ end
+
+ it 'has header indicating build status' do
+ is_expected.to have_header 'X-GitLab-Build-Status', 'failed'
+ end
+
it 'has the correct subject' do
should have_subject /Build failed for/
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 91b250265e6..f4c58882757 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -41,6 +41,8 @@
# recaptcha_site_key :string
# recaptcha_private_key :string
# metrics_port :integer default(8089)
+# sentry_enabled :boolean default(FALSE)
+# sentry_dsn :string
#
require 'spec_helper'
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index d12b9e65c82..d30bc7d0554 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -362,12 +362,12 @@ describe Ci::Build, models: true do
subject { build.artifacts_browse_url }
it "should be nil if artifacts browser is unsupported" do
- allow(build).to receive(:artifacts_browser_supported?).and_return(false)
+ allow(build).to receive(:artifacts_metadata?).and_return(false)
is_expected.to be_nil
end
it 'should not be nil if artifacts browser is supported' do
- allow(build).to receive(:artifacts_browser_supported?).and_return(true)
+ allow(build).to receive(:artifacts_metadata?).and_return(true)
is_expected.to_not be_nil
end
end
@@ -391,8 +391,8 @@ describe Ci::Build, models: true do
end
- describe :artifacts_browser_supported? do
- subject { build.artifacts_browser_supported? }
+ describe :artifacts_metadata? do
+ subject { build.artifacts_metadata? }
context 'artifacts metadata does not exist' do
it { is_expected.to be_falsy }
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 6f4c336b66c..2a310f3834d 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -90,6 +90,29 @@ describe API::API, api: true do
end
end
+ context 'and using the visibility filter' do
+ it 'should filter based on private visibility param' do
+ get api('/projects', user), { visibility: 'private' }
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).count)
+ end
+
+ it 'should filter based on internal visibility param' do
+ get api('/projects', user), { visibility: 'internal' }
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).count)
+ end
+
+ it 'should filter based on public visibility param' do
+ get api('/projects', user), { visibility: 'public' }
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PUBLIC).count)
+ end
+ end
+
context 'and using sorting' do
before do
project2
diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
index 449cecaa789..de9fed2b7dd 100644
--- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
+++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
@@ -6,7 +6,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
let(:mr_merge_if_green_enabled) do
create(:merge_request, merge_when_build_succeeds: true, merge_user: user,
- source_branch: "source_branch", target_branch: project.default_branch,
+ source_branch: "master", target_branch: 'feature',
source_project: project, target_project: project, state: "opened")
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 6d219f35895..2d0b5df4224 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -227,7 +227,7 @@ describe NotificationService, services: true do
end
describe :reassigned_issue do
- it 'should email new assignee' do
+ it 'emails new assignee' do
notification.reassigned_issue(issue, @u_disabled)
should_email(issue.assignee)
@@ -238,6 +238,62 @@ describe NotificationService, services: true do
should_not_email(@u_participating)
should_not_email(@u_disabled)
end
+
+ it 'emails previous assignee even if he has the "on mention" notif level' do
+ issue.update_attribute(:assignee, @u_mentioned)
+ issue.update_attributes(assignee: @u_watcher)
+ notification.reassigned_issue(issue, @u_disabled)
+
+ should_email(@u_mentioned)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
+ end
+
+ it 'emails new assignee even if he has the "on mention" notif level' do
+ issue.update_attributes(assignee: @u_mentioned)
+ notification.reassigned_issue(issue, @u_disabled)
+
+ expect(issue.assignee).to be @u_mentioned
+ should_email(issue.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
+ end
+
+ it 'emails new assignee' do
+ issue.update_attribute(:assignee, @u_mentioned)
+ notification.reassigned_issue(issue, @u_disabled)
+
+ expect(issue.assignee).to be @u_mentioned
+ should_email(issue.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
+ end
+
+ it 'does not email new assignee if they are the current user' do
+ issue.update_attribute(:assignee, @u_mentioned)
+ notification.reassigned_issue(issue, @u_mentioned)
+
+ expect(issue.assignee).to be @u_mentioned
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(issue.assignee)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
+ end
end
describe :close_issue do
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 5d0b18558b1..e43903dbd3c 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -32,6 +32,7 @@ describe Projects::CreateService, services: true do
it { expect(@project).to be_valid }
it { expect(@project.owner).to eq(@user) }
+ it { expect(@project.team.masters).to include(@user) }
it { expect(@project.namespace).to eq(@user.namespace) }
end