diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b917c645ff8c5ff2e7027971b470c349bdf40e88..ff8aa351226a1ac8a8e1171ed309fddfbb604aa2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,6 +18,7 @@ variables: SIMPLECOV: "true" USE_DB: "true" USE_BUNDLE_INSTALL: "true" + GIT_DEPTH: "20" before_script: - source ./scripts/prepare_build.sh diff --git a/.rubocop.yml b/.rubocop.yml index dbdabbb9d4cb6adb83fd661c836e0b529b92e157..cdcfd8150e56535f079be029dc3fe58814694ab0 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,6 @@ -require: rubocop-rspec +require: + - rubocop-rspec + - ./rubocop/rubocop AllCops: TargetRubyVersion: 2.1 @@ -532,11 +534,11 @@ Style/SingleLineMethods: # Use spaces after colons. Style/SpaceAfterColon: - Enabled: false + Enabled: true # Use spaces after commas. Style/SpaceAfterComma: - Enabled: false + Enabled: true # Do not put a space between a method name and the opening parenthesis in a # method definition. @@ -679,7 +681,7 @@ Style/UnlessElse: # Checks for %W when interpolation is not needed. Style/UnneededCapitalW: - Enabled: false + Enabled: true # TODO: Enable UnneededInterpolation Cop. # Checks for strings that are just an interpolated expression. diff --git a/CHANGELOG b/CHANGELOG index 6506f49174a3665849a80b95123aaabf3692f97d..4b754c2aba376ef94691c7b21631067d95da6fd5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,19 +1,64 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.10.0 (unreleased) + - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 + - Refactor repository paths handling to allow multiple git mount points + - Add Application Setting to configure default Repository Path for new projects - Wrap code blocks on Activies and Todos page. !4783 (winniehell) + - Align flash messages with left side of page content !4959 (winniehell) + - Display last commit of deleted branch in push events !4699 (winniehell) + - Apply the trusted_proxies config to the rack request object for use with rack_attack - Add Sidekiq queue duration to transaction metrics. + - Let Workhorse serve format-patch diffs - Make images fit to the size of the viewport !4810 - Fix check for New Branch button on Issue page !4630 (winniehell) - Fix MR-auto-close text added to description. !4836 - Fix pagination when sorting by columns with lots of ties (like priority) - Exclude email check from the standard health check - Fix changing issue state columns in milestone view + - Add notification settings dropdown for groups + - Allow importing from Github using Personal Access Tokens. (Eric K Idema) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) + - PipelinesFinder uses git cache data - Check for conflicts with existing Project's wiki path when creating a new project. + - Remove unused front-end variable -> default_issues_tracker + - Better caching of git calls on ProjectsController#show. - Add API endpoint for a group issues !4520 (mahcsig) + - Add Bugzilla integration !4930 (iamtjg) - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) + - Add basic system information like memory and disk usage to the admin panel + +v 8.9.4 + - Fix privilege escalation issue with OAuth external users. + - Ensure references to private repos aren't shown to logged-out users. + - Fixed search field blur not removing focus. !4704 + - Resolve "Sub nav isn't showing on file view". !4890 + - Fixes middle click and double request when navigating through the file browser. !4891 + - Fixed URL on label button when filtering. !4897 + - Fixed commit avatar alignment. !4933 + - Do not show build retry link when build is active. !4967 + - Fix restore Rake task warning message output. !4980 + - Handle external issues in IssueReferenceFilter. !4988 + - Expiry date on pinned nav cookie. !5009 + - Updated breakpoint for sidebar pinning. !5019 + +v 8.9.3 + - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem. !4963 + - Fix rendering of commit notes. !4953 + - Resolve "Pin should show up at 1280px min". !4947 + - Switched mobile button icons to ellipsis and angle. !4944 + - Correctly returns todo ID after creating todo. !4941 + - Better debugging for memory killer middleware. !4936 + - Remove duplicate new page btn from edit wiki. !4904 + - Use clock_gettime for all performance timestamps. !4899 + - Use memorized tags array when searching tags by name. !4859 + - Fixed avatar alignment in new MR view. !4901 + - Removed fade when filtering results. !4932 + - Fix missing avatar on system notes. !4954 + - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 + - Use update_columns to by_pass all the dirty code on active_record. !4985 + - Fix restore Rake task warning message output !4980 v 8.9.2 - Fix visibility of snippets when searching. @@ -64,6 +109,7 @@ v 8.9.1 - Remove duplicate 'New Page' button on edit wiki page v 8.9.0 + - Fix group visibility form layout in application settings - Fix builds API response not including commit data - Fix error when CI job variables key specified but not defined - Fix pipeline status when there are no builds in pipeline @@ -159,6 +205,7 @@ v 8.9.0 - Add Application Setting to configure Container Registry token expire delay (default 5min) - Cache assigned issue and merge request counts in sidebar nav - Use Knapsack only in CI environment + - Updated project creation page to match new UI #2542 - Cache project build count in sidebar nav - Add milestone expire date to the right sidebar - Manually mark a issue or merge request as a todo @@ -208,12 +255,21 @@ v 8.9.0 - Filter parameters for request_uri value on instrumented transactions. - Remove duplicated keys add UNIQUE index to keys fingerprint column - ExtractsPath get ref_names from repository cache, if not there access git. + - Show a flash warning about the error detail of XHR requests which failed with status code 404 and 500 - Cache user todo counts from TodoService - Ensure Todos counters doesn't count Todos for projects pending delete - Add left/right arrows horizontal navigation - Add tooltip to pin/unpin navbar - Add new sub nav style to Wiki and Graphs sub navigation +v 8.8.7 + - Fix privilege escalation issue with OAuth external users. + - Ensure references to private repos aren't shown to logged-out users. + +v 8.8.6 + - Fix visibility of snippets when searching. + - Update omniauth-saml to 1.6.0 !4951 + v 8.8.5 - Import GitHub repositories respecting the API rate limit !4166 - Fix todos page throwing errors when you have a project pending deletion !4300 @@ -344,6 +400,14 @@ v 8.8.0 - When creating a .gitignore file a dropdown with templates will be provided - Shows the issue/MR list search/filter form and corrects the mobile styling for guest users. #17562 +v 8.7.9 + - Fix privilege escalation issue with OAuth external users. + - Ensure references to private repos aren't shown to logged-out users. + +v 8.7.8 + - Fix visibility of snippets when searching. + - Update omniauth-saml to 1.6.0 !4951 + v 8.7.7 - Fix import by `Any Git URL` broken if the URL contains a space - Prevent unauthorized access to other projects build traces diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 4a36342fcab700951adb18ae7adc930997f6c3f4..fd2a01863fdd3035fac5918c59666363544bfe23 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -3.0.0 +3.1.0 diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 8bd6ba8c5c366585c0343c027cb738d5fdeb8d4d..879be8a98fc7a080771e966eb405fca1b40108de 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.7.5 +0.7.7 diff --git a/Gemfile b/Gemfile index 7228decf680a2e26a29f486526b26752376601bc..5213a59cab013bd681069dff7d7a684bd4be2b17 100644 --- a/Gemfile +++ b/Gemfile @@ -91,6 +91,7 @@ gem 'fog-core', '~> 1.40' gem 'fog-local', '~> 0.3' gem 'fog-google', '~> 0.3' gem 'fog-openstack', '~> 0.1' +gem 'fog-rackspace', '~> 0.1.1' # for aws storage gem "unf", '~> 0.1.4' @@ -302,7 +303,6 @@ group :development, :test do gem 'rubocop', '~> 0.40.0', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'scss_lint', '~> 0.47.0', require: false - gem 'coveralls', '~> 0.8.2', require: false gem 'simplecov', '~> 0.11.0', require: false gem 'flog', require: false gem 'flay', require: false @@ -346,3 +346,7 @@ gem "paranoia", "~> 2.0" # Health check gem 'health_check', '~> 1.5.1' + +# System information +gem 'vmstat', '~> 2.1.0' +gem 'sys-filesystem', '~> 1.1.6' diff --git a/Gemfile.lock b/Gemfile.lock index 66660f546e7ae78854d11d768f23ce764509afac..f99b373dbbd46e9634b1480cf29427304e885ece 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -141,12 +141,6 @@ GEM colorize (0.7.7) concurrent-ruby (1.0.2) connection_pool (2.2.0) - coveralls (0.8.13) - json (~> 1.8) - simplecov (~> 0.11.0) - term-ansicolor (~> 1.3) - thor (~> 0.19.1) - tins (~> 1.6.0) crack (0.4.3) safe_yaml (~> 1.0.0) creole (0.5.0) @@ -243,6 +237,11 @@ GEM fog-core (>= 1.39) fog-json (>= 1.0) ipaddress (>= 0.8) + fog-rackspace (0.1.1) + fog-core (>= 1.35) + fog-json (>= 1.0) + fog-xml (>= 0.1) + ipaddress (>= 0.8) fog-xml (0.1.2) fog-core nokogiri (~> 1.5, >= 1.5.11) @@ -716,6 +715,8 @@ GEM activerecord (>= 4.1, < 5.1) state_machines-activemodel (>= 0.3.0) stringex (2.5.2) + sys-filesystem (1.1.6) + ffi systemu (2.6.5) task_list (1.0.2) html-pipeline @@ -724,8 +725,6 @@ GEM teaspoon-jasmine (2.2.0) teaspoon (>= 1.0.0) temple (0.7.7) - term-ansicolor (1.3.2) - tins (~> 1.0) test_after_commit (0.4.2) activerecord (>= 3.2) thin (1.6.4) @@ -746,7 +745,6 @@ GEM mime-types multi_json (~> 1.7) twitter-stream (~> 0.1) - tins (1.6.0) turbolinks (2.5.3) coffee-rails twitter-stream (0.1.16) @@ -780,6 +778,7 @@ GEM coercible (~> 1.0) descendants_tracker (~> 0.0, >= 0.0.3) equalizer (~> 0.0, >= 0.0.9) + vmstat (2.1.0) warden (1.2.6) rack (>= 1.0) web-console (2.3.0) @@ -835,7 +834,6 @@ DEPENDENCIES chronic_duration (~> 0.10.6) coffee-rails (~> 4.1.0) connection_pool (~> 2.0) - coveralls (~> 0.8.2) creole (~> 0.5.0) d3_rails (~> 3.5.0) database_cleaner (~> 1.4.0) @@ -857,6 +855,7 @@ DEPENDENCIES fog-google (~> 0.3) fog-local (~> 0.3) fog-openstack (~> 0.1) + fog-rackspace (~> 0.1.1) font-awesome-rails (~> 4.6.1) foreman fuubar (~> 2.0.0) @@ -969,6 +968,7 @@ DEPENDENCIES spring-commands-teaspoon (~> 0.0.2) sprockets (~> 3.6.0) state_machines-activerecord (~> 0.4.0) + sys-filesystem (~> 1.1.6) task_list (~> 1.0.2) teaspoon (~> 1.1.0) teaspoon-jasmine (~> 2.2.0) @@ -984,6 +984,7 @@ DEPENDENCIES unicorn-worker-killer (~> 0.4.2) version_sorter (~> 2.0.0) virtus (~> 1.0.1) + vmstat (~> 2.1.0) web-console (~> 2.0) webmock (~> 1.21.0) wikicloth (= 0.8.1) diff --git a/app/assets/images/auth_buttons/azure_64.png b/app/assets/images/auth_buttons/azure_64.png index a82c751e001e4bcbbe3b9872513650aedf0cdb76..85de7793440c2226bf5af311488d5f7c755ae2e0 100644 Binary files a/app/assets/images/auth_buttons/azure_64.png and b/app/assets/images/auth_buttons/azure_64.png differ diff --git a/app/assets/images/auth_buttons/bitbucket_64.png b/app/assets/images/auth_buttons/bitbucket_64.png index 4b90a57bc7de93163275f99ea2971e2740af98af..b3d022a5a7019f199eaab18992c4bb5926824abe 100644 Binary files a/app/assets/images/auth_buttons/bitbucket_64.png and b/app/assets/images/auth_buttons/bitbucket_64.png differ diff --git a/app/assets/images/auth_buttons/facebook_64.png b/app/assets/images/auth_buttons/facebook_64.png index 1f1a80d7368ceb08b3e47d688f9e039b41ecfc0e..71ffb1c6a1fa4e7550d85c245e34b7cb5c690911 100644 Binary files a/app/assets/images/auth_buttons/facebook_64.png and b/app/assets/images/auth_buttons/facebook_64.png differ diff --git a/app/assets/images/auth_buttons/github_64.png b/app/assets/images/auth_buttons/github_64.png index 182a1a3f734fc1b7d712c68b04c29bad9460d6cd..1fa19c55d2f71505edf0f4d70840e817e7861c06 100644 Binary files a/app/assets/images/auth_buttons/github_64.png and b/app/assets/images/auth_buttons/github_64.png differ diff --git a/app/assets/images/auth_buttons/gitlab_64.png b/app/assets/images/auth_buttons/gitlab_64.png index 99a40583b3a7a4f96f1715350dfd9429b01976eb..f675678dc9d376dd166b8ad98207d192cc7db09c 100644 Binary files a/app/assets/images/auth_buttons/gitlab_64.png and b/app/assets/images/auth_buttons/gitlab_64.png differ diff --git a/app/assets/images/auth_buttons/google_64.png b/app/assets/images/auth_buttons/google_64.png index fb64f8bee686894a662e34162df0495800376404..720824230a50490f008d5e0c1c1d167e6923d900 100644 Binary files a/app/assets/images/auth_buttons/google_64.png and b/app/assets/images/auth_buttons/google_64.png differ diff --git a/app/assets/images/auth_buttons/twitter_64.png b/app/assets/images/auth_buttons/twitter_64.png index e3bd9169a343c5c005978060836ae98b9280e6bc..a4f14de57ae4a01d9ef9e905abb716504c8eb535 100644 Binary files a/app/assets/images/auth_buttons/twitter_64.png and b/app/assets/images/auth_buttons/twitter_64.png differ diff --git a/app/assets/images/bg_fallback.png b/app/assets/images/bg_fallback.png index e5fe659ba63db076784a420b69bf188d898ef52f..5c55bc79dec6eb904d293440e804fcc19f7632f1 100644 Binary files a/app/assets/images/bg_fallback.png and b/app/assets/images/bg_fallback.png differ diff --git a/app/assets/images/dark-scheme-preview.png b/app/assets/images/dark-scheme-preview.png index 2ef58e52549c6315b66a6dc960e4603de1c00d4b..8855babf14722e51b9757ea4c724910ba2a52bc1 100644 Binary files a/app/assets/images/dark-scheme-preview.png and b/app/assets/images/dark-scheme-preview.png differ diff --git a/app/assets/images/emoji.png b/app/assets/images/emoji.png index 1e7cf79ea4591fc59869c8146aeb735bfdd281c0..99093d4725a8a3f863e1fc3a48d2516d7c35c83f 100644 Binary files a/app/assets/images/emoji.png and b/app/assets/images/emoji.png differ diff --git a/app/assets/images/emoji@2x.png b/app/assets/images/emoji@2x.png index 74d67f7520db0dd0301481ee4a7967befa5155ad..48989942a9f9a177a9a91403a36597d1f1f20c9f 100644 Binary files a/app/assets/images/emoji@2x.png and b/app/assets/images/emoji@2x.png differ diff --git a/app/assets/images/gitlab_logo.png b/app/assets/images/gitlab_logo.png index 0c157546b9cf87d9aaf9a404c01f8a623f7c24c7..ca30b45901932973038fa3cadf7f715292562962 100644 Binary files a/app/assets/images/gitlab_logo.png and b/app/assets/images/gitlab_logo.png differ diff --git a/app/assets/images/gitorious-logo-black.png b/app/assets/images/gitorious-logo-black.png index 78f17a9af79dc2395acd9bcc2a391589dd6b6ed8..4a55fdc225a4f7080949d70875dfb103d2bf0420 100644 Binary files a/app/assets/images/gitorious-logo-black.png and b/app/assets/images/gitorious-logo-black.png differ diff --git a/app/assets/images/gitorious-logo-blue.png b/app/assets/images/gitorious-logo-blue.png index 4962cffba3153927ddd8cd5ff295fe4ca142bfa8..5eaa327d3dfc8657b30d6c1b84557a4571cf7f79 100644 Binary files a/app/assets/images/gitorious-logo-blue.png and b/app/assets/images/gitorious-logo-blue.png differ diff --git a/app/assets/images/icon-link.png b/app/assets/images/icon-link.png index 7d89da97e11a0030fbab56b3d172f547ac9f896e..5b55e12571c894c5f34d3cd0d5325919d1919e6f 100644 Binary files a/app/assets/images/icon-link.png and b/app/assets/images/icon-link.png differ diff --git a/app/assets/images/images.png b/app/assets/images/images.png index ad146246caf907144b468a121ef9524ba8ec3c74..bd60de994c41ec8059cc09d2a950679d9ee4a17d 100644 Binary files a/app/assets/images/images.png and b/app/assets/images/images.png differ diff --git a/app/assets/images/monokai-scheme-preview.png b/app/assets/images/monokai-scheme-preview.png index fbb339c6a9170de79c5fee8fc2a5abd6a785f4e7..d9c7d2d804127deadd0a19e3867252d2bb3f5af0 100644 Binary files a/app/assets/images/monokai-scheme-preview.png and b/app/assets/images/monokai-scheme-preview.png differ diff --git a/app/assets/images/msapplication-tile.png b/app/assets/images/msapplication-tile.png index 58bbf2b20cb2b925f96d2031d7d7875bac9b4344..1e0e2ed73ce26da60c9938055487f93337c2c3d9 100644 Binary files a/app/assets/images/msapplication-tile.png and b/app/assets/images/msapplication-tile.png differ diff --git a/app/assets/images/no_avatar.png b/app/assets/images/no_avatar.png index 8287acbce13e32d0823c8f5fd449099c1c61d6cd..5383d687b53a091bc16862a62d31f6da120330c6 100644 Binary files a/app/assets/images/no_avatar.png and b/app/assets/images/no_avatar.png differ diff --git a/app/assets/images/no_group_avatar.png b/app/assets/images/no_group_avatar.png index bfb31bb2184f6895c55c3027ddf9e357170bc338..71612d552869a35581ddd1cea35777dd90dde37a 100644 Binary files a/app/assets/images/no_group_avatar.png and b/app/assets/images/no_group_avatar.png differ diff --git a/app/assets/images/slider_handles.png b/app/assets/images/slider_handles.png index 884378ec96a20c1cb2a419e1dc1aa68ab9d85c15..52ad11ab7a1424e5a2346c4b50c16639fef14814 100644 Binary files a/app/assets/images/slider_handles.png and b/app/assets/images/slider_handles.png differ diff --git a/app/assets/images/touch-icon-ipad-retina.png b/app/assets/images/touch-icon-ipad-retina.png index feb32b48ec9619bb40266e507c4973fccec780f5..516dc2f4710b8dfb5ee317ff964999e248cd9c6a 100644 Binary files a/app/assets/images/touch-icon-ipad-retina.png and b/app/assets/images/touch-icon-ipad-retina.png differ diff --git a/app/assets/images/touch-icon-ipad.png b/app/assets/images/touch-icon-ipad.png index a6ddc5435098178b2e3ce30036c3495828c6ea9f..b2093d015b8fc7b6a81a350d706fe47333e77d9f 100644 Binary files a/app/assets/images/touch-icon-ipad.png and b/app/assets/images/touch-icon-ipad.png differ diff --git a/app/assets/images/touch-icon-iphone-retina.png b/app/assets/images/touch-icon-iphone-retina.png index 8bf7ccb75343386b43ba4bea76d9d58773f08163..438654e0d20367c8105cef063a191db125def584 100644 Binary files a/app/assets/images/touch-icon-iphone-retina.png and b/app/assets/images/touch-icon-iphone-retina.png differ diff --git a/app/assets/images/touch-icon-iphone.png b/app/assets/images/touch-icon-iphone.png index 87da550f8beb9531e107a1f7fb2199cf3c8ef3ba..e5f87fbbcf65470ac6d7476d5695feb404135225 100644 Binary files a/app/assets/images/touch-icon-iphone.png and b/app/assets/images/touch-icon-iphone.png differ diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index 5c5a4ca7670e902fc228e8680c8fb70cd6b02159..20fe5a5cc2733962fc3e893aa3dc04d42d66d046 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -185,6 +185,15 @@ $ -> else buttons.enable() + $(document).ajaxError (e, xhrObj, xhrSetting, xhrErrorText) -> + + if xhrObj.status is 401 + new Flash 'You need to be logged in.', 'alert' + + else if xhrObj.status in [ 404, 500 ] + new Flash 'Something went wrong on our end.', 'alert' + + # Show/Hide the profile menu when hovering the account box $('.account-box').hover -> $(@).toggleClass('hover') @@ -199,7 +208,6 @@ $ -> $('.header-content .header-logo').toggle() $('.header-content .navbar-collapse').toggle() $('.navbar-toggle').toggleClass('active') - $('.navbar-toggle i').toggleClass("fa-angle-right fa-angle-left") # Show/hide comments on diff $body.on "click", ".js-toggle-diff-comments", (e) -> @@ -261,8 +269,8 @@ $ -> new Aside() # Sidenav pinning - if $window.width() < 1440 and $.cookie('pin_nav') is 'true' - $.cookie('pin_nav', 'false', { path: '/' }) + if $window.width() < 1024 and $.cookie('pin_nav') is 'true' + $.cookie('pin_nav', 'false', { path: '/', expires: 365 * 10 }) $('.page-with-sidebar') .toggleClass('page-sidebar-collapsed page-sidebar-expanded') .removeClass('page-sidebar-pinned') @@ -293,7 +301,7 @@ $ -> .toggleClass('header-collapsed header-expanded') # Save settings - $.cookie 'pin_nav', doPinNav, { path: '/' } + $.cookie 'pin_nav', doPinNav, { path: '/', expires: 365 * 10 } if $.cookie('pin_nav') is 'true' or doPinNav tooltipText = 'Unpin navigation' diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 7fbff9214cf57abd86327a8566517c2a0c15117b..9493a57580183434dde2d1e017668c88383d78ca 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -84,6 +84,8 @@ class Dispatcher new Activities() when 'groups:show' shortcut_handler = new ShortcutsNavigation() + new NotificationsForm() + new NotificationsDropdown() when 'groups:group_members:index' new GroupMembers() new UsersSelect() diff --git a/app/assets/javascripts/flash.js.coffee b/app/assets/javascripts/flash.js.coffee index 4f73d215b8561a2a391a026bd177e99ca0fe8fd2..b76d214790af2bd459d95d45b5e8b73de5729cb5 100644 --- a/app/assets/javascripts/flash.js.coffee +++ b/app/assets/javascripts/flash.js.coffee @@ -4,11 +4,19 @@ class @Flash @flash.html("") innerDiv = $('<div/>', - class: "flash-#{type}", - text: message + class: "flash-#{type}" ) innerDiv.appendTo(".flash-container") + textDiv = $("<div/>", + class: "flash-text", + text: message + ) + textDiv.appendTo(innerDiv) + + if @flash.parent().hasClass('content-wrapper') + textDiv.addClass('container-fluid container-limited') + @flash.click -> $(@).fadeOut() @flash.show() diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 703128fecb306214c00d406c7baaef06c9974517..ed9dfcc917e9f1dbfe71c3e713404aa8866167ff 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -186,6 +186,8 @@ class GitLabDropdown @fullData = data @parseData @fullData + + @filter.input.trigger('keyup') if @options.filterable and @filter and @filter.input } # Init filterable @@ -218,6 +220,13 @@ class GitLabDropdown @dropdown.on 'keyup', (e) => if e.which is 27 # Escape key $('.dropdown-menu-close', @dropdown).trigger 'click' + @dropdown.on 'blur', 'a', (e) => + if e.relatedTarget? + $relatedTarget = $(e.relatedTarget) + $dropdownMenu = $relatedTarget.closest('.dropdown-menu') + + if $dropdownMenu.length is 0 + @dropdown.removeClass('open') if @dropdown.find(".dropdown-toggle-page").length @dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) => diff --git a/app/assets/javascripts/issuable.js.coffee b/app/assets/javascripts/issuable.js.coffee index 6a108c033eafdb22fc7ee28553a4486a6945342a..0527c66461c8d9d0f5e93f1cbde5cda936ff7c9a 100644 --- a/app/assets/javascripts/issuable.js.coffee +++ b/app/assets/javascripts/issuable.js.coffee @@ -59,13 +59,12 @@ issuable_created = false filterResults: (form) => formData = form.serialize() - $('.issues-holder, .merge-requests-holder').css('opacity', '0.5') formAction = form.attr('action') issuesUrl = formAction issuesUrl += ("#{if formAction.indexOf('?') < 0 then '?' else '&'}") issuesUrl += formData - Turbolinks.visit(issuesUrl); + Turbolinks.visit(issuesUrl) initChecks: -> @issuableBulkActions = $('.bulk-update').data('bulkActions') diff --git a/app/assets/javascripts/lib/utils/text_utility.js.coffee b/app/assets/javascripts/lib/utils/text_utility.js.coffee index bb2772dfed2efa36a577e46cb91d3d4961add07f..7bcb876d056ad2c262bd453a8d4231e8f96b6ed0 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js.coffee +++ b/app/assets/javascripts/lib/utils/text_utility.js.coffee @@ -10,17 +10,41 @@ gl.text.selectedText = (text, textarea) -> text.substring(textarea.selectionStart, textarea.selectionEnd) - gl.text.insertText = (textArea, text, tag, selected, wrap) -> + gl.text.lineBefore = (text, textarea) -> + split = text.substring(0, textarea.selectionStart).trim().split('\n') + split[split.length - 1] + + gl.text.lineAfter = (text, textarea) -> + text.substring(textarea.selectionEnd).trim().split('\n')[0] + + gl.text.blockTagText = (text, textArea, blockTag, selected) -> + lineBefore = @lineBefore(text, textArea) + lineAfter = @lineAfter(text, textArea) + + if lineBefore is blockTag and lineAfter is blockTag + # To remove the block tag we have to select the line before & after + if blockTag? + textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1) + textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1) + + selected + else + "#{blockTag}\n#{selected}\n#{blockTag}" + + gl.text.insertText = (textArea, text, tag, blockTag, selected, wrap) -> selectedSplit = selected.split('\n') startChar = if not wrap and textArea.selectionStart > 0 then '\n' else '' - if selectedSplit.length > 1 and not wrap - insertText = selectedSplit.map((val) -> - if val.indexOf(tag) is 0 - "#{val.replace(tag, '')}" - else - "#{tag}#{val}" - ).join('\n') + if selectedSplit.length > 1 and (not wrap or blockTag?) + if blockTag? + insertText = @blockTagText(text, textArea, blockTag, selected) + else + insertText = selectedSplit.map((val) -> + if val.indexOf(tag) is 0 + "#{val.replace(tag, '')}" + else + "#{tag}#{val}" + ).join('\n') else insertText = "#{startChar}#{tag}#{selected}#{if wrap then tag else ' '}" @@ -51,7 +75,7 @@ textArea.setSelectionRange pos, pos - gl.text.updateText = (textArea, tag, wrap) -> + gl.text.updateText = (textArea, tag, blockTag, wrap) -> $textArea = $(textArea) oldVal = $textArea.val() textArea = $textArea.get(0) @@ -59,7 +83,7 @@ selected = @selectedText(text, textArea) $textArea.focus() - @insertText(textArea, text, tag, selected, wrap) + @insertText(textArea, text, tag, blockTag, selected, wrap) gl.text.init = (form) -> self = @ @@ -70,6 +94,7 @@ self.updateText( $this.closest('.md-area').find('textarea'), $this.data('md-tag'), + $this.data('md-block'), not $this.data('md-prepend') ) diff --git a/app/assets/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee index 421328554b8d6c156537784493969087fc2b2d63..72b1d3dfb1e207be046d0b9a6aeb7ec51b9f32e6 100644 --- a/app/assets/javascripts/search_autocomplete.js.coffee +++ b/app/assets/javascripts/search_autocomplete.js.coffee @@ -171,22 +171,15 @@ class @SearchAutocomplete } bindEvents: -> - $(document).on 'click', @onDocumentClick @searchInput.on 'keydown', @onSearchInputKeyDown @searchInput.on 'keyup', @onSearchInputKeyUp @searchInput.on 'click', @onSearchInputClick @searchInput.on 'focus', @onSearchInputFocus + @searchInput.on 'blur', @onSearchInputBlur @clearInput.on 'click', @onClearInputClick @locationBadgeEl.on 'click', => @searchInput.focus() - onDocumentClick: (e) => - # If clicking outside the search box - # And search input is not focused - # And we are not clicking inside a suggestion - if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).closest('.search-form').length - @onSearchInputBlur() - enableAutocomplete: -> # No need to enable anything if user is not logged in return if !gon.current_user_id @@ -287,8 +280,6 @@ class @SearchAutocomplete value: @originalState._location ) - @dropdown.removeClass 'open' - badgePresent: -> @locationBadgeEl.length diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee index c03877e9b0697a6d5fe86d154505dee6361db98f..3319a67a79d9037d2a5cc6c0f33642f4f0413094 100644 --- a/app/assets/javascripts/shortcuts.js.coffee +++ b/app/assets/javascripts/shortcuts.js.coffee @@ -9,12 +9,12 @@ class @Shortcuts onToggleHelp: (e) => e.preventDefault() - @toggleHelp(@enabledHelp) + Shortcuts.toggleHelp(@enabledHelp) - toggleMarkdownPreview: (e) => + toggleMarkdownPreview: (e) -> $(document).triggerHandler('markdown-preview:toggle', [e]) - toggleHelp: (location) -> + @toggleHelp: (location) -> $modal = $('#modal-shortcuts') if $modal.length diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee index de8eebcd0b2c6c14a456bba0ceebadac817522b3..83de584f2d92ab6240a340cac8e2a05a5e25de67 100644 --- a/app/assets/javascripts/tree.js.coffee +++ b/app/assets/javascripts/tree.js.coffee @@ -5,9 +5,15 @@ class @TreeView # Code browser tree slider # Make the entire tree-item row clickable, but not if clicking another link (like a commit message) $(".tree-content-holder .tree-item").on 'click', (e) -> - if (e.target.nodeName != "A") - path = $('.tree-item-file-name a', this).attr('href') - Turbolinks.visit(path) + $clickedEl = $(e.target) + path = $('.tree-item-file-name a', this).attr('href') + + if not $clickedEl.is('a') and not $clickedEl.is('.str-truncated') + if e.metaKey or e.which is 2 + e.preventDefault() + window.open path, '_blank' + else + Turbolinks.visit path # Show the "Loading commit data" for only the first element $('span.log_loading:first').removeClass('hide') diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 38023818709d0847059797b44c68dc338cd5fe32..41e77a4ac682f5994f1daa118892c2274c4ca0bf 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -137,7 +137,7 @@ margin: 0; font-size: 24px; font-weight: normal; - margin-bottom: 5px; + margin-bottom: 10px; color: #4c4e54; font-size: 23px; line-height: 1.1; diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss index 1bfd0213995c45b4bdbd034803eb41b7dbc928bc..a951a2b97fe2baaf7d12ad6b42aa9583afebfa58 100644 --- a/app/assets/stylesheets/framework/flash.scss +++ b/app/assets/stylesheets/framework/flash.scss @@ -16,4 +16,11 @@ @extend .alert-danger; margin: 0; } + + .flash-notice, .flash-alert { + .container-fluid.flash-text { + background: transparent; + } + } } + diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index fd8eaa8a691a3ee7679bce034d865bc831382b71..5d3273ea64ddc8c50012b8ce6aadf0ccb42a9812 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -125,7 +125,8 @@ border: 0; outline: 0; - &:hover { + &:hover, + &:focus { color: $gl-link-color; } } diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 6211bc04597241175af5a3444c3433f6f95bf2db..6e5f216c894a4c6213e6fc83dadb4a5a650ee782 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -21,9 +21,8 @@ .fa { position: relative; - top: 3px; - font-size: 13px; - color: $btn-placeholder-gray; + top: 5px; + font-size: 18px; } } diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 98f917ce69b5c64df22c68286801d12c520512ea..e8d6a7f2775d4ec4caea5241a971cb60676b9e0f 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -1,5 +1,6 @@ .page-with-sidebar { padding-top: $header-height; + padding-bottom: 25px; transition: padding $sidebar-transition-duration; .sidebar-wrapper { diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index c37574ca7a1b9d9494b542c46dcb204b18915805..211a9af23483261cdf41dfbe7dce567e90e2ff44 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -7,7 +7,7 @@ $gutter_collapsed_width: 62px; $gutter_width: 290px; $gutter_inner_width: 258px; $sidebar-transition-duration: .15s; -$sidebar-breakpoint: 1440px; +$sidebar-breakpoint: 1024px; /* * UI elements diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index de534d284219326d0184ee708d92fbae3bfdc1fa..85bbf70e1883efead710d5b8bdd2f3dcc4d1e8b1 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -83,11 +83,7 @@ position: relative; @media (min-width: $screen-sm-min) { - padding-left: 20px; - - .commit-info-block { - padding-left: 44px; - } + padding-left: 46px; } &:not(:last-child) { @@ -102,9 +98,7 @@ .avatar { - position: absolute; - top: 10px; - left: 16px; + margin-left: -46px; } .item-title { diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index ac7721cbe1512ad19cfc6d2178794fefe36c2835..101faf5917430cead44c9c2b3f7c76d1652fd440 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -48,11 +48,7 @@ .access-request-button { @include btn-gray; - position: absolute; - right: 16px; - bottom: 32px; - padding: 3px 10px; + margin-right: 10px; text-transform: none; - background-color: $background-color; } } diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index aca82f7f7bf082b55913b4eb54100e77e6762168..124f4afaa0d497b7269bc75bbd108af0912a4f07 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -264,8 +264,15 @@ margin-bottom: 4px; } + .item-title { + @media (min-width: $screen-sm-min) { + width: 49%; + } + } + .avatar { - margin-left: 0; + left: 0; + top: 2px; } .commit-row-info { diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index ee7c98f805b9039bcdb0de505dc219445545b1fa..ac8c02b59dcbe7a10085d50ec4617ac2f8c69a8b 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -41,6 +41,10 @@ ul.notes { .timeline-icon { .avatar { visibility: hidden; + + .discussion-body & { + visibility: visible; + } } } } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index d3e59d7fdb95415f385059c5cc8fb58b6d63bcbb..89ce1b2df2093a8b6f327496cc59e577abc92334 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -13,10 +13,53 @@ .new_project, .edit-project { - fieldset.features { - .control-label { + fieldset { + &.features .control-label { font-weight: normal; } + .form-group { + margin-bottom: 5px; + } + &> .form-group { + padding-left: 0; + } + } + .help-block { + margin-bottom: 10px; + } + .project-path { + padding-right: 0; + .form-control { + border-radius: $border-radius-base; + } + } + .input-group > div { + &:last-child { + padding-right: 0; + } + } + @media (max-width: $screen-xs-max) { + .input-group > div { + margin-bottom: 14px; + &:last-child { + margin-bottom: 0; + } + } + fieldset > .form-group:first-child { + padding-right: 0; + } + } + + .input-group-addon { + &.static-namespace { + height: 35px; + border-radius: 3px; + border: 1px solid #e5e5e5; + } + &+ .select2 a { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } } } @@ -365,10 +408,28 @@ a.deploy-project-label { } } -.project-import .btn { - float: left; - margin-bottom: 10px; - margin-right: 10px; +.project-import { + .form-group { + margin-bottom: 0; + } + .import-buttons { + padding-left: 0; + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + .btn { + margin-right: 10px; + padding: 8px 12px; + } + &> div { + margin-bottom: 14px; + padding-left: 0; + &:last-child { + margin-bottom: 0; + } + } + } } .project-stats { diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 99c9e81ddb9acd69e4788756d14d97a6bfbb7b99..5b61270daa8ddeb2c18104a01beb131f1c9cdfcd 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -101,7 +101,8 @@ margin: 0; .commit { - padding: 0 0 0 55px; + padding-top: 0; + padding-bottom: 0; .commit-row-title { .commit-row-message { diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index f4eda864aac9285bc7ca588d4d90f731615f53ab..5f65dd3aff08942c433529328f8ec9e413decbb7 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -109,6 +109,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :metrics_packet_size, :send_user_confirmation_email, :container_registry_token_expire_delay, + :repository_storage, restricted_visibility_levels: [], import_sources: [], disabled_oauth_sign_in_sources: [] diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..e4c730088269169b3b5b3953d77e1e540b6776f7 --- /dev/null +++ b/app/controllers/admin/system_info_controller.rb @@ -0,0 +1,59 @@ +class Admin::SystemInfoController < Admin::ApplicationController + EXCLUDED_MOUNT_OPTIONS = [ + 'nobrowse', + 'read-only', + 'ro' + ] + + EXCLUDED_MOUNT_TYPES = [ + 'autofs', + 'binfmt_misc', + 'cgroup', + 'debugfs', + 'devfs', + 'devpts', + 'devtmpfs', + 'efivarfs', + 'fuse.gvfsd-fuse', + 'fuseblk', + 'fusectl', + 'hugetlbfs', + 'mqueue', + 'proc', + 'pstore', + 'securityfs', + 'sysfs', + 'tmpfs', + 'tracefs', + 'vfat' + ] + + def show + system_info = Vmstat.snapshot + mounts = Sys::Filesystem.mounts + + @disks = [] + mounts.each do |mount| + mount_options = mount.options.split(',') + + next if (EXCLUDED_MOUNT_OPTIONS & mount_options).any? + next if (EXCLUDED_MOUNT_TYPES & [mount.mount_type]).any? + + begin + disk = Sys::Filesystem.stat(mount.mount_point) + @disks.push({ + bytes_total: disk.bytes_total, + bytes_used: disk.bytes_used, + disk_name: mount.name, + mount_path: disk.path + }) + rescue Sys::Filesystem::Error + end + end + + @cpus = system_info.cpus.length + + @mem_used = system_info.memory.active_bytes + @mem_total = system_info.memory.total_bytes + end +end diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 8bf71a1adbb15e9cda1e38c85de3f23d0d122c02..aa894fde36b8fc978b0aeeb311c48618d8fd10fd 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -25,7 +25,7 @@ module Ci return render_404 unless @project image = Ci::ImageForBuildService.new.execute(@project, params) - send_file image.path, filename: image.name, disposition: 'inline', type:"image/svg+xml" + send_file image.path, filename: image.name, disposition: 'inline', type: "image/svg+xml" end protected diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index ee4fcc4e360e895f79f84a25fe52cb504e2a875a..a04bf7df722ae30525f7f34505fadd94674b8555 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -37,15 +37,12 @@ class GroupsController < Groups::ApplicationController end def show - @last_push = current_user.recent_push if current_user - - @projects = @projects.includes(:namespace) - @projects = @projects.sorted_by_activity - @projects = filter_projects(@projects) - @projects = @projects.sort(@sort = params[:sort]) - @projects = @projects.page(params[:page]) if params[:filter_projects].blank? + if current_user + @last_push = current_user.recent_push + @notification_setting = current_user.notification_settings_for(group) + end - @shared_projects = GroupProjectsFinder.new(group, only_shared: true).execute(current_user) + setup_projects respond_to do |format| format.html @@ -97,6 +94,16 @@ class GroupsController < Groups::ApplicationController protected + def setup_projects + @projects = @projects.includes(:namespace) + @projects = @projects.sorted_by_activity + @projects = filter_projects(@projects) + @projects = @projects.sort(@sort = params[:sort]) + @projects = @projects.page(params[:page]) if params[:filter_projects].blank? + + @shared_projects = GroupProjectsFinder.new(group, only_shared: true).execute(current_user) + end + def authorize_create_group! unless can?(current_user, :create_group, nil) return render_404 diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index 67bf4190e7e66ca5b84fc27cb8cb4b96f378fab0..9c1b0eb20f43e005011e89889b41ca55c66844b1 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -1,14 +1,29 @@ class Import::GithubController < Import::BaseController before_action :verify_github_import_enabled - before_action :github_auth, except: :callback + before_action :github_auth, only: [:status, :jobs, :create] rescue_from Octokit::Unauthorized, with: :github_unauthorized + helper_method :logged_in_with_github? + + def new + if logged_in_with_github? + go_to_github_for_permissions + elsif session[:github_access_token] + redirect_to status_import_github_url + end + end + def callback session[:github_access_token] = client.get_token(params[:code]) redirect_to status_import_github_url end + def personal_access_token + session[:github_access_token] = params[:personal_access_token] + redirect_to status_import_github_url + end + def status @repos = client.repos @already_added_projects = current_user.created_projects.where(import_type: "github") @@ -57,10 +72,14 @@ class Import::GithubController < Import::BaseController end def github_unauthorized - go_to_github_for_permissions + session[:github_access_token] = nil + redirect_to new_import_github_url, + alert: 'Access denied to your GitHub account.' end - private + def logged_in_with_github? + current_user.identities.exists?(provider: 'github') + end def access_params { github_access_token: session[:github_access_token] } diff --git a/app/controllers/notification_settings_controller.rb b/app/controllers/notification_settings_controller.rb index eddd03cc22949777ba0b03cc6993639b7a91e798..8ec4bb1233f52d44befe8d620b73736be39ce013 100644 --- a/app/controllers/notification_settings_controller.rb +++ b/app/controllers/notification_settings_controller.rb @@ -2,11 +2,9 @@ class NotificationSettingsController < ApplicationController before_action :authenticate_user! def create - project = Project.find(params[:project][:id]) + return render_404 unless can_read?(resource) - return render_404 unless can?(current_user, :read_project, project) - - @notification_setting = current_user.notification_settings_for(project) + @notification_setting = current_user.notification_settings_for(resource) @saved = @notification_setting.update_attributes(notification_setting_params) render_response @@ -21,6 +19,22 @@ class NotificationSettingsController < ApplicationController private + def resource + @resource ||= + if params[:project_id].present? + Project.find(params[:project_id]) + elsif params[:namespace_id].present? + Group.find(params[:namespace_id]) + end + end + + def can_read?(resource) + ability_name = resource.class.name.downcase + ability_name = "read_#{ability_name}".to_sym + + can?(current_user, ability_name, resource) + end + def render_response render json: { html: view_to_html_string("shared/notifications/_button", notification_setting: @notification_setting), diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 39c8ba40ca25e6b43b110be0e27ca2030d9ce6a0..dd86b940a08c62ae61e011ab4cb45b42854ad823 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -59,7 +59,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController respond_to do |format| format.html format.json { render json: @merge_request } - format.patch { render text: @merge_request.to_patch } + format.patch do + headers.store(*Gitlab::Workhorse.send_git_patch(@project.repository, + @merge_request.diff_base_commit.id, + @merge_request.last_commit.id)) + headers['Content-Disposition'] = 'inline' + head :ok + end format.diff do return render_404 unless @merge_request.diff_refs diff --git a/app/finders/pipelines_finder.rb b/app/finders/pipelines_finder.rb index c19a795d467ac9156d160d93ceee3adb86835a9c..641fbf838f143d89cf68ed2ce4b875c91aabc5da 100644 --- a/app/finders/pipelines_finder.rb +++ b/app/finders/pipelines_finder.rb @@ -29,10 +29,10 @@ class PipelinesFinder end def branches - project.repository.branches.map(&:name) + project.repository.branch_names end def tags - project.repository.tags.map(&:name) + project.repository.tag_names end end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 55313fd835763e593826961c924687123ad8eb19..6e580c62ccd74aea671b5a13699c379eb74b8013 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -78,4 +78,12 @@ module ApplicationSettingsHelper end end end + + def repository_storage_options_for_select + options = Gitlab.config.repositories.storages.map do |name, path| + ["#{name} - #{path}", name] + end + + options_for_select(options, @application_setting.repository_storage) + end end diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 4b4bc3d4276b8e85de9333086b8d26a91150b2d8..428a42266d0e12ec484a5b78b0be596ad0acce83 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -1,10 +1,10 @@ module BlobHelper - def highlighter(blob_name, blob_content, nowrap: false) - Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap) + def highlighter(blob_name, blob_content, repository: nil, nowrap: false) + Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap, repository: repository) end - def highlight(blob_name, blob_content, nowrap: false, plain: false) - Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain) + def highlight(blob_name, blob_content, repository: nil, nowrap: false, plain: false) + Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain, repository: repository) end def no_highlight_files diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb index 6b617e1730a627be19dcfd7adddc94ac81a0a821..7c140538012e5be23d0235b684cee67291426976 100644 --- a/app/helpers/dropdowns_helper.rb +++ b/app/helpers/dropdowns_helper.rb @@ -69,7 +69,7 @@ module DropdownsHelper def dropdown_filter(placeholder, search_id: nil) content_tag :div, class: "dropdown-input" do - filter_output = search_field_tag search_id, nil, class: "dropdown-input-field", placeholder: placeholder + filter_output = search_field_tag search_id, nil, class: "dropdown-input-field", placeholder: placeholder, autocomplete: 'off' filter_output << icon('search', class: "dropdown-input-search") filter_output << icon('times', class: "dropdown-input-clear js-dropdown-input-clear", role: "button") diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 5074e645769bda3ded7e3c6dc9309279c9423d0d..5e9f5837101608e60e80a160736bec970e2989cd 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -34,10 +34,7 @@ module LabelsHelper # Returns a String def link_to_label(label, project: nil, type: :issue, tooltip: true, css_class: nil, &block) project ||= @project || label.project - link = send("namespace_project_#{type.to_s.pluralize}_path", - project.namespace, - project, - label_name: [label.name]) + link = label_filter_path(project, label, type: type) if block_given? link_to link, class: css_class, &block @@ -46,6 +43,13 @@ module LabelsHelper end end + def label_filter_path(project, label, type: issue) + send("namespace_project_#{type.to_s.pluralize}_path", + project.namespace, + project, + label_name: [label.name]) + end + def project_label_names @project.labels.pluck(:title) end diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index b401c8385beeb2798f54222d89a890b7c7a92c55..e85ba76887d72873ca27d46ec77a010876a6638b 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -69,4 +69,14 @@ module NotesHelper button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button', data: data, title: 'Add a reply' end + + def note_max_access_for_user(note) + @max_access_by_user_id ||= Hash.new do |hash, key| + project = key[:project] + hash[key] = project.team.human_max_access(key[:user_id]) + end + + full_key = { project: note.project, user_id: note.author_id } + @max_access_by_user_id[full_key] + end end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 77783cd764060c392a1d922a75e564274ea46c82..7e8369d0a051b2d272981f597215981f69eceedb 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -72,6 +72,6 @@ module NotificationsHelper # Create hidden field to send notification setting source to controller def hidden_setting_source_input(notification_setting) return unless notification_setting.source_type - hidden_field_tag "#{notification_setting.source_type.downcase}[id]", notification_setting.source_id + hidden_field_tag "#{notification_setting.source_type.downcase}_id", notification_setting.source_id end end diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index e4e8b934bc8299d64d640e0b18411cb3d74f8871..22387d664518a9a55e79448d29339da1837ae8c5 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -52,7 +52,7 @@ module PageLayoutHelper raise ArgumentError, 'cannot provide more than two attributes' if map.length > 2 @page_card_attributes ||= {} - @page_card_attributes = map.reject { |_,v| v.blank? } if map.present? + @page_card_attributes = map.reject { |_, v| v.blank? } if map.present? @page_card_attributes end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index d91e3332e4879afa9086609f1ab35df3953f1b70..f312a7ccca3618f59f60e139e72af2d5d2eca10f 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -15,7 +15,7 @@ module ProjectsHelper def link_to_member_avatar(author, opts = {}) default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" } opts = default_opts.merge(opts) - image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar] + image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar] end def link_to_member(project, author, opts = {}, &block) @@ -27,7 +27,7 @@ module ProjectsHelper author_html = "" # Build avatar image tag - author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar] + author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar] # Build name span tag if opts[:by_username] @@ -327,9 +327,9 @@ module ProjectsHelper end end - def sanitize_repo_path(message) + def sanitize_repo_path(project, message) return '' unless message.present? - message.strip.gsub(Gitlab.config.gitlab_shell.repos_path.chomp('/'), "[REPOS PATH]") + message.strip.gsub(project.repository_storage_path.chomp('/'), "[REPOS PATH]") end end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index d914b0b26eb40206c631d115c3d43f98cbc1977c..5fa6eacd23453868df893fb54c5a7572b6c3a879 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -55,6 +55,10 @@ class ApplicationSetting < ActiveRecord::Base presence: true, numericality: { only_integer: true, greater_than: 0 } + validates :repository_storage, + presence: true, + inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } } + validates_each :restricted_visibility_levels do |record, attr, value| unless value.nil? value.each do |level| @@ -134,6 +138,7 @@ class ApplicationSetting < ActiveRecord::Base disabled_oauth_sign_in_sources: [], send_user_confirmation_email: false, container_registry_token_expire_delay: 5, + repository_storage: 'default', ) end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 2b0bec33131a5c6979d3b17cd7f9029e3dcd9ee7..c11f8e6884dc8935d39bd1a368d3874fdb8bf26f 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -90,7 +90,7 @@ module Ci end def retryable? - project.builds_enabled? && commands.present? + project.builds_enabled? && commands.present? && complete? end def retried? diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb index f8d5d4486fd43f93c20dea83e76cb8854d2f1099..c9c47ec7419641462301456fe88268bd77ed57ba 100644 --- a/app/models/ci/variable.rb +++ b/app/models/ci/variable.rb @@ -13,6 +13,7 @@ module Ci attr_encrypted :value, mode: :per_attribute_iv_and_salt, + insecure_mode: true, key: Gitlab::Application.secrets.db_key_base, algorithm: 'aes-256-cbc' end diff --git a/app/models/event.rb b/app/models/event.rb index 716039fb54b9533477c5be3fd286124b2f28086e..d7d23c7ae6dc236c96f907222fbb00e542a20d68 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -315,7 +315,7 @@ class Event < ActiveRecord::Base def body? if push? - push_with_commits? + push_with_commits? || rm_ref? elsif note? true else diff --git a/app/models/member.rb b/app/models/member.rb index c74a16367dbd9f0f8b27e071b6096ef8fceac8bf..57161397e2bc244bea742a65c070f88d1b82b473 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -32,6 +32,7 @@ class Member < ActiveRecord::Base scope :request, -> { where.not(requested_at: nil) } scope :non_request, -> { where(requested_at: nil) } scope :non_pending, -> { non_request.non_invite } + scope :has_access, -> { where('access_level > 0') } scope :guests, -> { where(access_level: GUEST) } scope :reporters, -> { where(access_level: REPORTER) } diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index f5c5b7c13065920ad3f34b436fe96f9b149873be..53d9aa588af8bba38d0279f7ac4d50774f686606 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -319,13 +319,6 @@ class MergeRequest < ActiveRecord::Base ) end - # Returns the commit as a series of email patches. - # - # see "git format-patch" - def to_patch - target_project.repository.format_patch(diff_base_commit.sha, source_sha) - end - def hook_attrs attrs = { source: source_project.try(:hook_attrs), diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index aca377cc6001b677660799a165ffdf396a6f2c2a..86331a33c051db7afbf978e2e342d42306a86f24 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -108,44 +108,46 @@ class MergeRequestDiff < ActiveRecord::Base # Reload all commits related to current merge request from repo # and save it as array of hashes in st_commits db field def reload_commits + new_attributes = {} + commit_objects = unmerged_commits if commit_objects.present? - self.st_commits = dump_commits(commit_objects) + new_attributes[:st_commits] = dump_commits(commit_objects) end - save + update_columns_serialized(new_attributes) end # Reload diffs between branches related to current merge request from repo # and save it as array of hashes in st_diffs db field def reload_diffs + new_attributes = {} new_diffs = [] if commits.size.zero? - self.state = :empty + new_attributes[:state] = :empty else diff_collection = unmerged_diffs if diff_collection.overflow? # Set our state to 'overflow' to make the #empty? and #collected? # methods (generated by StateMachine) return false. - self.state = :overflow + new_attributes[:state] = :overflow end - self.real_size = diff_collection.real_size + new_attributes[:real_size] = diff_collection.real_size if diff_collection.any? new_diffs = dump_diffs(diff_collection) - self.state = :collected + new_attributes[:state] = :collected end end - self.st_diffs = new_diffs - - self.base_commit_sha = self.repository.merge_base(self.head, self.base) + new_attributes[:st_diffs] = new_diffs + new_attributes[:base_commit_sha] = self.repository.merge_base(self.head, self.base) - self.save + update_columns_serialized(new_attributes) end # Collect array of Git::Diff objects @@ -190,4 +192,29 @@ class MergeRequestDiff < ActiveRecord::Base ) end end + + private + + # + # #save or #update_attributes providing changes on serialized attributes do a lot of + # serialization and deserialization calls resulting in bad performance. + # Using #update_columns solves the problem with just one YAML.dump per serialized attribute that we provide. + # As a tradeoff we need to reload the current instance to properly manage time objects on those serialized + # attributes. So to keep the same behaviour as the attribute assignment we reload the instance. + # The difference is in the usage of + # #write_attribute= (#update_attributes) and #raw_write_attribute= (#update_columns) + # + # Ex: + # + # new_attributes[:st_commits].first.slice(:committed_date) + # => {:committed_date=>2014-02-27 11:01:38 +0200} + # YAML.load(YAML.dump(new_attributes[:st_commits].first.slice(:committed_date))) + # => {:committed_date=>2014-02-27 10:01:38 +0100} + # + def update_columns_serialized(new_attributes) + return unless new_attributes.any? + + update_columns(new_attributes.merge(updated_at: current_time_from_proper_timezone)) + reload + end end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index da19462f2652ffe92182394dd3b45e4b3e091e0b..8b52cc824cd6c860cbf9af349cd7575bdb58170b 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -21,8 +21,10 @@ class Namespace < ActiveRecord::Base delegate :name, to: :owner, allow_nil: true, prefix: true - after_create :ensure_dir_exist after_update :move_dir, if: :path_changed? + + # Save the storage paths before the projects are destroyed to use them on after destroy + before_destroy(prepend: true) { @old_repository_storage_paths = repository_storage_paths } after_destroy :rm_dir scope :root, -> { where('type IS NULL') } @@ -87,51 +89,35 @@ class Namespace < ActiveRecord::Base owner_name end - def ensure_dir_exist - gitlab_shell.add_namespace(path) - end - - def rm_dir - # Move namespace directory into trash. - # We will remove it later async - new_path = "#{path}+#{id}+deleted" - - if gitlab_shell.mv_namespace(path, new_path) - message = "Namespace directory \"#{path}\" moved to \"#{new_path}\"" - Gitlab::AppLogger.info message - - # Remove namespace directroy async with delay so - # GitLab has time to remove all projects first - GitlabShellWorker.perform_in(5.minutes, :rm_namespace, new_path) - end - end - def move_dir - # Ensure old directory exists before moving it - gitlab_shell.add_namespace(path_was) - if any_project_has_container_registry_tags? raise Exception.new('Namespace cannot be moved, because at least one project has tags in container registry') end - if gitlab_shell.mv_namespace(path_was, path) - Gitlab::UploadsTransfer.new.rename_namespace(path_was, path) - - # If repositories moved successfully we need to - # send update instructions to users. - # However we cannot allow rollback since we moved namespace dir - # So we basically we mute exceptions in next actions - begin - send_update_instructions - rescue - # Returning false does not rollback after_* transaction but gives - # us information about failing some of tasks - false + # Move the namespace directory in all storages paths used by member projects + repository_storage_paths.each do |repository_storage_path| + # Ensure old directory exists before moving it + gitlab_shell.add_namespace(repository_storage_path, path_was) + + unless gitlab_shell.mv_namespace(repository_storage_path, path_was, path) + # if we cannot move namespace directory we should rollback + # db changes in order to prevent out of sync between db and fs + raise Exception.new('namespace directory cannot be moved') end - else - # if we cannot move namespace directory we should rollback - # db changes in order to prevent out of sync between db and fs - raise Exception.new('namespace directory cannot be moved') + end + + Gitlab::UploadsTransfer.new.rename_namespace(path_was, path) + + # If repositories moved successfully we need to + # send update instructions to users. + # However we cannot allow rollback since we moved namespace dir + # So we basically we mute exceptions in next actions + begin + send_update_instructions + rescue + # Returning false does not rollback after_* transaction but gives + # us information about failing some of tasks + false end end @@ -152,4 +138,33 @@ class Namespace < ActiveRecord::Base def find_fork_of(project) projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id) end + + private + + def repository_storage_paths + # We need to get the storage paths for all the projects, even the ones that are + # pending delete. Unscoping also get rids of the default order, which causes + # problems with SELECT DISTINCT. + Project.unscoped do + projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path) + end + end + + def rm_dir + # Remove the namespace directory in all storages paths used by member projects + @old_repository_storage_paths.each do |repository_storage_path| + # Move namespace directory into trash. + # We will remove it later async + new_path = "#{path}+#{id}+deleted" + + if gitlab_shell.mv_namespace(repository_storage_path, path, new_path) + message = "Namespace directory \"#{path}\" moved to \"#{new_path}\"" + Gitlab::AppLogger.info message + + # Remove namespace directroy async with delay so + # GitLab has time to remove all projects first + GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path) + end + end + end end diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index a2aee2f925bca3f13769243b312d25168cdcee9c..345041a6ad18b233cb77a5a016ab5cd5ba670a49 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -54,7 +54,7 @@ module Network @map = {} @reserved = {} - @commits.each_with_index do |c,i| + @commits.each_with_index do |c, i| c.time = i days[i] = c.committed_date @map[c.id] = c @@ -116,7 +116,7 @@ module Network end def commits_sort_by_ref - @commits.sort do |a,b| + @commits.sort do |a, b| if include_ref?(a) -1 elsif include_ref?(b) diff --git a/app/models/project.rb b/app/models/project.rb index 968373644238990eacbb18e0c5c33fb3e2bfa06b..6a950ee830d5a8f5f3827b33d7f26cc8c9c46769 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -24,8 +24,12 @@ class Project < ActiveRecord::Base default_value_for :wiki_enabled, gitlab_config_features.wiki default_value_for :snippets_enabled, gitlab_config_features.snippets default_value_for :container_registry_enabled, gitlab_config_features.container_registry + default_value_for(:repository_storage) { current_application_settings.repository_storage } default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled } + after_create :ensure_dir_exist + after_save :ensure_dir_exist, if: :namespace_id_changed? + # set last_activity_at to the same as created_at after_create :set_last_activity_at def set_last_activity_at @@ -81,6 +85,7 @@ class Project < ActiveRecord::Base has_one :jira_service, dependent: :destroy has_one :redmine_service, dependent: :destroy has_one :custom_issue_tracker_service, dependent: :destroy + has_one :bugzilla_service, dependent: :destroy has_one :gitlab_issue_tracker_service, dependent: :destroy, inverse_of: :project has_one :external_wiki_service, dependent: :destroy @@ -164,6 +169,9 @@ class Project < ActiveRecord::Base validate :visibility_level_allowed_by_group validate :visibility_level_allowed_as_fork validate :check_wiki_path_conflict + validates :repository_storage, + presence: true, + inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } } add_authentication_token_field :runners_token before_save :ensure_runners_token @@ -375,6 +383,10 @@ class Project < ActiveRecord::Base end end + def repository_storage_path + Gitlab.config.repositories.storages[repository_storage] + end + def team @team ||= ProjectTeam.new(self) end @@ -841,12 +853,12 @@ class Project < ActiveRecord::Base raise Exception.new('Project cannot be renamed, because tags are present in its container registry') end - if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace) + if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace) # If repository moved successfully we need to send update instructions to users. # However we cannot allow rollback since we moved repository # So we basically we mute exceptions in next actions begin - gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") + gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") send_move_instructions(old_path_with_namespace) reset_events_cache @@ -987,7 +999,7 @@ class Project < ActiveRecord::Base def create_repository # Forked import is handled asynchronously unless forked? - if gitlab_shell.add_repository(path_with_namespace) + if gitlab_shell.add_repository(repository_storage_path, path_with_namespace) repository.after_create true else @@ -1139,4 +1151,8 @@ class Project < ActiveRecord::Base _, status = Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete)) status.zero? end + + def ensure_dir_exist + gitlab_shell.add_namespace(repository_storage_path, namespace.path) + end end diff --git a/app/models/project_import_data.rb b/app/models/project_import_data.rb index ca8a9b4217b6e5334cf52d8f0bec6fd9047a5190..331123a5a5b58ca4c83a9963234442b452a5d5db 100644 --- a/app/models/project_import_data.rb +++ b/app/models/project_import_data.rb @@ -7,6 +7,7 @@ class ProjectImportData < ActiveRecord::Base marshal: true, encode: true, mode: :per_attribute_iv_and_salt, + insecure_mode: true, algorithm: 'aes-256-cbc' serialize :data, JSON diff --git a/app/models/project_services/bugzilla_service.rb b/app/models/project_services/bugzilla_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..260f60309576112905a5aa37598730310729e081 --- /dev/null +++ b/app/models/project_services/bugzilla_service.rb @@ -0,0 +1,25 @@ +class BugzillaService < IssueTrackerService + + prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url + + def title + if self.properties && self.properties['title'].present? + self.properties['title'] + else + 'Bugzilla' + end + end + + def description + if self.properties && self.properties['description'].present? + self.properties['description'] + else + 'Bugzilla issue tracker' + end + end + + def to_param + 'bugzilla' + end + +end diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb index 6b2b1daa724bab5559831c72abe931150911796a..8f2db46a7ba3832effcdeb8a28ce82e8e5e3839f 100644 --- a/app/models/project_services/custom_issue_tracker_service.rb +++ b/app/models/project_services/custom_issue_tracker_service.rb @@ -32,7 +32,4 @@ class CustomIssueTrackerService < IssueTrackerService ] end - def initialize_properties - self.properties = {} if properties.nil? - end end diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 0ff4f4c8dd2cd9e41295cbb95b2b071db64efa1c..23e5b16221bfb34f957c628c6b2c1432ec181091 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -106,7 +106,7 @@ class HipchatService < Service else message << "pushed to #{ref_type} <a href=\""\ "#{project.web_url}/commits/#{CGI.escape(ref)}\">#{ref}</a> " - message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> " + message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/, '')}</a> " message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)" push[:commits].take(MAX_COMMITS).each do |commit| diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index beda89d396317adf94b70a435d18ee2d6a50de35..8b3296c712fb260f8aca9ad815c3c51458fae0b4 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -124,7 +124,7 @@ class JiraService < IssueTrackerService def build_api_url_from_project_url server = URI(project_url) - default_ports = [["http",80],["https",443]].include?([server.scheme,server.port]) + default_ports = [["http", 80], ["https", 443]].include?([server.scheme, server.port]) server_url = "#{server.scheme}://#{server.host}" server_url.concat(":#{server.port}") unless default_ports "#{server_url}/rest/api/#{DEFAULT_API_VERSION}" diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 73e736820af25d81fcc2ba9b0eb65a3be44ea222..0865b979ce052cf6dc56e45db69e4e77f553199d 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -137,20 +137,10 @@ class ProjectTeam def max_member_access(user_id) access = [] - project.members.non_request.each do |member| - if member.user_id == user_id - access << member.access_field if member.access_field - break - end - end + access += project.members.non_request.where(user_id: user_id).has_access.pluck(:access_level) if group - group.members.non_request.each do |member| - if member.user_id == user_id - access << member.access_field if member.access_field - break - end - end + access += group.members.non_request.where(user_id: user_id).has_access.pluck(:access_level) end if project.invited_groups.any? && project.allowed_to_share_with_group? diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 25d82929c0b1ff454f6f8cb53e5be8f75fdb3a99..a255710f57711952d797d5ae5a8af20f27c0d579 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -159,7 +159,7 @@ class ProjectWiki private def init_repo(path_with_namespace) - gitlab_shell.add_repository(path_with_namespace) + gitlab_shell.add_repository(project.repository_storage_path, path_with_namespace) end def commit_details(action, message = nil, title = nil) @@ -173,7 +173,7 @@ class ProjectWiki end def path_to_repo - @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") + @path_to_repo ||= File.join(project.repository_storage_path, "#{path_with_namespace}.git") end def update_project_activity diff --git a/app/models/repository.rb b/app/models/repository.rb index acc720ccfa32b1575224d1f1fa6a03476d06a2c4..eb232ea681b95277cac610f0593ba82daccf9fba 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -39,7 +39,7 @@ class Repository # Return absolute path to repository def path_to_repo @path_to_repo ||= File.expand_path( - File.join(Gitlab.config.gitlab_shell.repos_path, path_with_namespace + ".git") + File.join(@project.repository_storage_path, path_with_namespace + ".git") ) end @@ -246,24 +246,26 @@ class Repository end end + # Keys for data that can be affected for any commit push. def cache_keys - %i(size branch_names tag_names branch_count tag_count commit_count + %i(size commit_count readme version contribution_guide changelog license_blob license_key gitignore) end + # Keys for data on branch/tag operations. + def cache_keys_for_branches_and_tags + %i(branch_names tag_names branch_count tag_count) + end + def build_cache - cache_keys.each do |key| + (cache_keys + cache_keys_for_branches_and_tags).each do |key| unless cache.exist?(key) send(key) end end end - def expire_gitignore - cache.expire(:gitignore) - end - def expire_tags_cache cache.expire(:tag_names) @tags = nil @@ -286,8 +288,6 @@ class Repository # This ensures this particular cache is flushed after the first commit to a # new repository. expire_emptiness_caches if empty? - expire_branch_count_cache - expire_tag_count_cache end def expire_branch_cache(branch_name = nil) @@ -978,6 +978,10 @@ class Repository raw_repository.ls_files(actual_ref) end + def gitattribute(path, name) + raw_repository.attributes(path)[name] + end + def copy_gitattributes(ref) actual_ref = ref || root_ref begin diff --git a/app/models/service.rb b/app/models/service.rb index 40d39933ad873ededeee4281602bd4462c839ed5..d7a32c282679221a095f523ee0b6bdb08e2517c3 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -170,6 +170,7 @@ class Service < ActiveRecord::Base bamboo buildkite builds_email + bugzilla campfire custom_issue_tracker drone_ci diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 51f6ae7b25c6b5a991d2c147205be6200a5a9f17..5ec933601ac8d2a8486e54ce90722587a748a549 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -20,6 +20,7 @@ class Snippet < ActiveRecord::Base length: { within: 0..255 }, format: { with: Gitlab::Regex.file_name_regex, message: Gitlab::Regex.file_name_regex_message } + validates :content, presence: true validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values } @@ -81,6 +82,11 @@ class Snippet < ActiveRecord::Base 0 end + # alias for compatibility with blobs and highlighting + def path + file_name + end + def name file_name end diff --git a/app/models/user.rb b/app/models/user.rb index 599b2fb1191852c629170d310cc7d5aa64ba0dd1..eac716b120ba606b7f9cc58d0e8858dfe7e7d000 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,6 +25,7 @@ class User < ActiveRecord::Base attr_encrypted :otp_secret, key: Gitlab::Application.config.secret_key_base, mode: :per_attribute_iv_and_salt, + insecure_mode: true, algorithm: 'aes-256-cbc' devise :two_factor_authenticatable, @@ -763,7 +764,7 @@ class User < ActiveRecord::Base unless email_domains.blank? match_found = email_domains.any? do |domain| - escaped = Regexp.escape(domain).gsub('\*','.*?') + escaped = Regexp.escape(domain).gsub('\*', '.*?') regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE email_domain = Mail::Address.new(self.email).domain email_domain =~ regexp diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index f09072975c3e9a109b18b00d7103984962dcbeb6..882606e38d0e9c907bfc8e56a1ed0ff65b7575c6 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -51,13 +51,13 @@ module Projects return true if params[:skip_repo] == true # There is a possibility project does not have repository or wiki - return true unless gitlab_shell.exists?(path + '.git') + return true unless gitlab_shell.exists?(project.repository_storage_path, path + '.git') new_path = removal_path(path) - if gitlab_shell.mv_repository(path, new_path) + if gitlab_shell.mv_repository(project.repository_storage_path, path, new_path) log_info("Repository \"#{path}\" moved to \"#{new_path}\"") - GitlabShellWorker.perform_in(5.minutes, :remove_repository, new_path) + GitlabShellWorker.perform_in(5.minutes, :remove_repository, project.repository_storage_path, new_path) else false end diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb index 43db29315a166cb3b2360765831a7c5e6220ff2d..a47df22f1bacbe51a3f760b5d3de9316effa4b7e 100644 --- a/app/services/projects/housekeeping_service.rb +++ b/app/services/projects/housekeeping_service.rb @@ -24,7 +24,7 @@ module Projects def execute raise LeaseTaken unless try_obtain_lease - GitlabShellOneShotWorker.perform_async(:gc, @project.path_with_namespace) + GitlabShellOneShotWorker.perform_async(:gc, @project.repository_storage_path, @project.path_with_namespace) ensure Gitlab::Metrics.measure(:reset_pushes_since_gc) do @project.update_column(:pushes_since_gc, 0) diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index 9159ec089593d122f9168de7c9a62a014cd1c2a2..163ebf26c84393982360b8f7652ae47d989bac3b 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -42,7 +42,7 @@ module Projects def import_repository begin - gitlab_shell.import_repository(project.path_with_namespace, project.import_url) + gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url) rescue Gitlab::Shell::Error => e raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}" end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 03b57dea51e4d4a9c8f83fa3d0ab8306ed19c3df..bc7f8bf433b6ed5f77bfdc8310fb0d0fa92c9b50 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -50,12 +50,12 @@ module Projects project.send_move_instructions(old_path) # Move main repository - unless gitlab_shell.mv_repository(old_path, new_path) + unless gitlab_shell.mv_repository(project.repository_storage_path, old_path, new_path) raise TransferError.new('Cannot move project') end # Move wiki repo also if present - gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki") + gitlab_shell.mv_repository(project.repository_storage_path, "#{old_path}.wiki", "#{new_path}.wiki") # clear project cached events project.reset_events_cache diff --git a/app/uploaders/lfs_object_uploader.rb b/app/uploaders/lfs_object_uploader.rb index 28085b310837712ae030988964280158950e0dee..046a1d641a92c7e77b07e99dc5d2e23346e75dd9 100644 --- a/app/uploaders/lfs_object_uploader.rb +++ b/app/uploaders/lfs_object_uploader.rb @@ -4,7 +4,7 @@ class LfsObjectUploader < CarrierWave::Uploader::Base storage :file def store_dir - "#{Gitlab.config.lfs.storage_path}/#{model.oid[0,2]}/#{model.oid[2,2]}" + "#{Gitlab.config.lfs.storage_path}/#{model.oid[0, 2]}/#{model.oid[2, 2]}" end def cache_dir diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index c883e8f97da5f3446039c79f7a6c55e493b04639..c1f70bc1866a65c38b0362fab15bea0536f52a2a 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -15,7 +15,7 @@ = f.label :default_snippet_visibility, class: 'control-label col-sm-2' .col-sm-10 = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: ProjectSnippet.new) - .form-group.group-visibility-level-holder + .form-group.project-visibility-level-holder = f.label :default_group_visibility, class: 'control-label col-sm-2' .col-sm-10 = render('shared/visibility_radios', model_method: :default_group_visibility, form: f, selected_level: @application_setting.default_group_visibility, form_model: Group.new) @@ -310,6 +310,15 @@ .col-sm-10 = f.text_field :sentry_dsn, class: 'form-control' + %fieldset + %legend Repository Storage + .form-group + = f.label :repository_storage, 'Storage path for new projects', class: 'control-label col-sm-2' + .col-sm-10 + = f.select :repository_storage, repository_storage_options_for_select, {}, class: 'form-control' + .help-block + You can manage the repository storage paths in your gitlab.yml configuration file + %fieldset %legend Repository Checks .form-group diff --git a/app/views/admin/background_jobs/_head.html.haml b/app/views/admin/background_jobs/_head.html.haml index d78682532ed29c74f89d10387d9cc8cd39a4753a..9d722bd7382ae560b12a9bb306420b7b35b04e3a 100644 --- a/app/views/admin/background_jobs/_head.html.haml +++ b/app/views/admin/background_jobs/_head.html.haml @@ -1,5 +1,9 @@ .nav-links.sub-nav %ul{ class: (container_class) } + = nav_link(controller: :system_info) do + = link_to admin_system_info_path, title: 'System Info' do + %span + System Info = nav_link(controller: :background_jobs) do = link_to admin_background_jobs_path, title: 'Background Jobs' do %span diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml index 654d261aa997712ba25441fe84508af1ad453ea0..4f680b507c493983d66295c120aebebd6610f200 100644 --- a/app/views/admin/background_jobs/show.html.haml +++ b/app/views/admin/background_jobs/show.html.haml @@ -2,7 +2,7 @@ - page_title "Background Jobs" = render 'admin/background_jobs/head' -%div{ class: (container_class) } +%div{ class: container_class } %h3.page-title Background Jobs %p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml index efd5b12cfeb4b182be40679949312c992ad1c9c8..1e60205f91a1e605540e9977d4d91c9c0f3d40ec 100644 --- a/app/views/admin/builds/index.html.haml +++ b/app/views/admin/builds/index.html.haml @@ -1,7 +1,7 @@ - @no_container = true = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area %ul.nav-links diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 4682016a8862378246759a91f7332315993f81c9..a2ac407c159b79d2d6e765538486b454bee659d3 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,7 +1,7 @@ - @no_container = true = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } .admin-dashboard.prepend-top-default .row .col-md-4 diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 4f1996ef7ab26de3b261d36ba04aac4540df1f4a..94aa5f5a942f81626e12b2c8af0610c2b3219a9b 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -2,7 +2,7 @@ - page_title "Groups" = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } %h3.page-title Groups (#{number_with_delimiter(@groups.total_count)}) @@ -39,7 +39,6 @@ = link_to 'New Group', new_admin_group_path, class: "btn btn-new" %ul.content-list - - @groups.each do |group| - = render 'group', group: group + = render @groups = paginate @groups, theme: "gitlab" diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml index 7b8407f9152ea221deb516a4d10be2c442e59da0..e79303240f0d6b08deb827865fb0d221ae356617 100644 --- a/app/views/admin/health_check/show.html.haml +++ b/app/views/admin/health_check/show.html.haml @@ -2,7 +2,7 @@ - page_title "Health Check" = render 'admin/background_jobs/head' -%div{ class: (container_class) } +%div{ class: container_class } %h3.page-title Health Check .bs-callout.clearfix diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 5ddc3b9ea85111de9f622ecbf53f3575da5cde04..676812121d773d2901c1b7ca0e3237975a53bbaf 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -5,7 +5,7 @@ Gitlab::RepositoryCheckLogger] = render 'admin/background_jobs/head' -%div{ class: (container_class) } +%div{ class: container_class } %ul.nav-links.log-tabs - loggers.each do |klass| %li{ class: (klass == Gitlab::GitLogger ? 'active' : '') } diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 4822cb693c2d2b2a99b8fe1ea67bee5b37a8a3a2..7d2eb423223cb02cdaf1a88ef9ceb12d4786e1ef 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -3,7 +3,7 @@ = render 'shared/show_aside' = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } .row.prepend-top-default %aside.col-md-3 .panel.admin-filter diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml index b5c6b5effe3ebbfb923a8ca0d6f3a1727d043787..a53876d67573d3e767473aacb1635be1292d304a 100644 --- a/app/views/admin/runners/index.html.haml +++ b/app/views/admin/runners/index.html.haml @@ -1,7 +1,7 @@ - @no_container = true = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } %p.prepend-top-default %span diff --git a/app/views/admin/system_info/show.html.haml b/app/views/admin/system_info/show.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..6956e5ab7958a003ae5eead0e8789b5a4daf0e20 --- /dev/null +++ b/app/views/admin/system_info/show.html.haml @@ -0,0 +1,25 @@ +- @no_container = true +- page_title "System Info" += render 'admin/background_jobs/head' + +%div{ class: container_class } + .prepend-top-default + .row + .col-sm-4 + .light-well + %h4 CPU + .data + %h1= "#{@cpus} cores" + .col-sm-4 + .light-well + %h4 Memory + .data + %h1= "#{number_to_human_size(@mem_used)} / #{number_to_human_size(@mem_total)}" + .col-sm-4 + .light-well + %h4 Disks + .data + - @disks.each do |disk| + %h1= "#{number_to_human_size(disk[:bytes_used])} / #{number_to_human_size(disk[:bytes_total])}" + %p= "#{disk[:disk_name]}" + %p= "#{disk[:mount_path]}" diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index d0a696da64b98d7ab6fd136437adc2502bf9d935..21bb99a792c4fac69e78569e1916e7820c5f998c 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -3,7 +3,7 @@ = render 'shared/show_aside' = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } .admin-filter %ul.nav-links %li{class: "#{'active' unless params[:filter]}"} diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml index dc4ff17e31abfc4bfd704e28327f8945cc6496a4..ea54ef226ec046deaefbdccfdb355a2c6d34fdc7 100644 --- a/app/views/events/event/_push.html.haml +++ b/app/views/events/event/_push.html.haml @@ -1,3 +1,5 @@ +- project = event.project + .event-title %span.author_name= link_to_author event %span.event_label.pushed #{event.action_name} #{event.ref_type} @@ -5,19 +7,18 @@ %strong= event.ref_name - else %strong - = link_to event.ref_name, namespace_project_commits_path(event.project.namespace, event.project, event.ref_name), title: h(event.target_title) + = link_to event.ref_name, namespace_project_commits_path(project.namespace, project, event.ref_name), title: h(event.target_title) at - = link_to_project event.project + = link_to_project project - if event.push_with_commits? - - project = event.project .event-body %ul.well-list.event_commits - few_commits = event.commits[0...2] - few_commits.each do |commit| = render "events/commit", commit: commit, project: project, event: event - - create_mr = event.new_ref? && create_mr_button?(event.project.default_branch, event.ref_name, event.project) + - create_mr = event.new_ref? && create_mr_button?(project.default_branch, event.ref_name, project) - if event.commits_count > 1 %li.commits-stat - if event.commits_count > 2 @@ -27,18 +28,26 @@ - from = event.commit_from - from_label = truncate_sha(from) - else - - from = event.project.default_branch + - from = project.default_branch - from_label = from - = link_to namespace_project_compare_path(event.project.namespace, event.project, from: from, to: event.commit_to) do + = link_to namespace_project_compare_path(project.namespace, project, from: from, to: event.commit_to) do Compare #{from_label}...#{truncate_sha(event.commit_to)} - if create_mr %span{"data-user-is" => event.author_id, "data-display" => "inline"} or - = link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do + = link_to create_mr_path(project.default_branch, event.ref_name, project) do create a merge request - elsif create_mr %li.commits-stat{"data-user-is" => event.author_id} - = link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do + = link_to create_mr_path(project.default_branch, event.ref_name, project) do Create Merge Request +- elsif event.rm_ref? + - repository = project.repository + - last_commit = repository.commit(event.commit_from) + - if last_commit + .event-body + %ul.well-list.event_commits + = render "events/commit", commit: last_commit, project: project, event: event + diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index aecefbc6e8f1da18c826491cdb119909b27c18b1..69f634e75b9b407c274171ebe447302e75b49526 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -5,7 +5,7 @@ = auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity") .cover-block.groups-cover-block - %div{ class: (container_class) } + %div{ class: container_class } = link_to group_icon(@group), target: '_blank' do = image_tag group_icon(@group), class: "avatar group-avatar s70" .group-info @@ -15,12 +15,17 @@ %span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) } = visibility_level_icon(@group.visibility_level, fw: false) + %span.hidden-xs + = render 'shared/notifications/button', notification_setting: @notification_setting + + - if current_user + .pull-right + = render 'shared/members/access_request_buttons', source: @group + - if @group.description.present? .cover-desc.description = markdown(@group.description, pipeline: :description) - - if current_user - = render 'shared/members/access_request_buttons', source: @group %div{ class: container_class } .top-area diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 57bc91ea5a95c76e02554ebfdbd7cd8fa2299793..57601ae9be0970a173f57489beba03099964052c 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -36,6 +36,6 @@ %ul.well-list %li= link_to 'See our website for getting help', promo_url + '/getting-help/' %li= link_to 'Use the search bar on the top of this page', '#', onclick: 'Shortcuts.focusSearch(event)' - %li= link_to 'Use shortcuts', '#', onclick: 'Shortcuts.showHelp(event)' + %li= link_to 'Use shortcuts', '#', onclick: 'Shortcuts.toggleHelp()' %li= link_to 'Get a support subscription', 'https://about.gitlab.com/pricing/' %li= link_to 'Compare GitLab editions', 'https://about.gitlab.com/features/#compare' diff --git a/app/views/import/github/new.html.haml b/app/views/import/github/new.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..435ed7bd4cb5c7b339a9cf5112f06dae345e9fbe --- /dev/null +++ b/app/views/import/github/new.html.haml @@ -0,0 +1,43 @@ +- page_title "GitHub Import" +- header_title "Projects", root_path + +%h3.page-title + = icon 'github', text: 'Import Projects from GitHub' + +- if github_import_configured? + %p + To import a GitHub project, you first need to authorize GitLab to access + the list of your GitHub repositories: + + = link_to 'List Your GitHub Repositories', status_import_github_path, class: 'btn btn-success' + + %hr + +%p + - if github_import_configured? + Alternatively, + - else + To import a GitHub project, + you can use a + = succeed '.' do + = link_to 'Personal Access Token', 'https://github.com/settings/tokens' + When you create your Personal Access Token, + you will need to select the <code>repo</code> scope, so we can display a + list of your public and private repositories which are available for import. + += form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do + .form-group + = text_field_tag :personal_access_token, '', class: 'form-control', placeholder: "Personal Access Token", size: 40 + = submit_tag 'List Your GitHub Repositories', class: 'btn btn-success' + +- unless github_import_configured? + %hr + %p + Note: + - if current_user.admin? + As an administrator you may like to configure + - else + Consider asking your GitLab administrator to configure + = link_to 'GitHub integration', help_page_path("integration", "github") + which will allow login via GitHub and allow importing projects without + generating a Personal Access Token. diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 40a2c81eebdbf074ed203d9834178b37a0d7bbb2..1a39572ac3cf044d17cc9f417bf27d688fc4eeed 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -6,7 +6,7 @@ = icon('bars') %button.navbar-toggle{type: 'button'} %span.sr-only Toggle navigation - = icon('angle-left') + = icon('ellipsis-v') .navbar-collapse.collapse %ul.nav.navbar-nav diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml index 0f264cd2e06e63db077e50daf607dfe9d6bfa0fe..5ee8772882ec68a9e31a00c7c06344cc79da6865 100644 --- a/app/views/layouts/nav/_admin.html.haml +++ b/app/views/layouts/nav/_admin.html.haml @@ -1,16 +1,16 @@ .scrolling-tabs-container{ class: nav_control_class } = render 'layouts/nav/admin_settings' .fade-left - = icon('arrow-left') + = icon('angle-left') .fade-right - = icon('arrow-right') + = icon('angle-right') %ul.nav-links.scrolling-tabs = nav_link(controller: %w(dashboard admin projects users groups builds runners), html_options: {class: 'home'}) do = link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do %span Overview - = nav_link(controller: %w(background_jobs logs health_check)) do - = link_to admin_background_jobs_path, title: 'Monitoring' do + = nav_link(controller: %w(system_info background_jobs logs health_check)) do + = link_to admin_system_info_path, title: 'Monitoring' do %span Monitoring = nav_link(controller: :broadcast_messages) do diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml index 5d657a9ac84d215d5d3bb8648ad4c46a5ebd24cd..d7d36c84b6caa9dc647e823af93cb427f2f1ea9d 100644 --- a/app/views/layouts/nav/_group.html.haml +++ b/app/views/layouts/nav/_group.html.haml @@ -1,9 +1,9 @@ .scrolling-tabs-container{ class: nav_control_class } = render 'layouts/nav/group_settings' .fade-left - = icon('arrow-left') + = icon('angle-left') .fade-right - = icon('arrow-right') + = icon('angle-right') %ul.nav-links.scrolling-tabs = nav_link(path: 'groups#show', html_options: {class: 'home'}) do = link_to group_path(@group), title: 'Home' do diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml index f37f9b0f5a3c8bfb9e1055204e93cd61113ad3b8..96fe62c39c3f6b755a56bd15dea8f3d55d0cd158 100644 --- a/app/views/layouts/nav/_profile.html.haml +++ b/app/views/layouts/nav/_profile.html.haml @@ -1,8 +1,8 @@ .scrolling-tabs-container .fade-left - = icon('arrow-left') + = icon('angle-left') .fade-right - = icon('arrow-right') + = icon('angle-right') %ul.nav-links.scrolling-tabs = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do = link_to profile_path, title: 'Profile Settings' do diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index a4bb56aa56f11c1f01a223ffbfe9dca78f11661f..dcef427cda30fca32f8199f6b783ebedbffd8698 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -26,9 +26,9 @@ .scrolling-tabs-container{ class: nav_control_class } .fade-left - = icon('arrow-left') + = icon('angle-left') .fade-right - = icon('arrow-right') + = icon('angle-right') %ul.nav-links.scrolling-tabs = nav_link(path: 'projects#show', html_options: {class: 'home'}) do = link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do diff --git a/app/views/projects/_github_import_modal.html.haml b/app/views/projects/_github_import_modal.html.haml deleted file mode 100644 index 46ad1559356ea26ece89af7db6548264e02a6721..0000000000000000000000000000000000000000 --- a/app/views/projects/_github_import_modal.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -%div#github_import_modal.modal - .modal-dialog - .modal-content - .modal-header - %a.close{href: "#", "data-dismiss" => "modal"} × - %h3 Import projects from GitHub - .modal-body - To enable importing projects from GitHub, - - if current_user.admin? - as administrator you need to configure - - else - ask your Gitlab administrator to configure - == #{link_to 'OAuth integration', help_page_path("integration", "github")}. diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 86ea08dd229a81f83b807a3ea40886388bed1126..8ce23379fb4e6af25ffc0f527ed295ea3a3d43a9 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -1,6 +1,6 @@ - empty_repo = @project.empty_repo? .project-home-panel.cover-block.clearfix{:class => ("empty-project" if empty_repo)} - %div{ class: (container_class) } + %div{ class: container_class } .row .project-image-container = project_icon(@project, alt: '', class: 'project-avatar avatar s70') diff --git a/app/views/projects/_last_push.html.haml b/app/views/projects/_last_push.html.haml index e0ca2a3109cd97ca8be9c456f6cc672bc2c40f68..434d8644b831e81c884daa565a0664d4ecb041f2 100644 --- a/app/views/projects/_last_push.html.haml +++ b/app/views/projects/_last_push.html.haml @@ -1,7 +1,7 @@ - if event = last_push_event - if show_last_push_widget?(event) .row-content-block.top-block.clear-block.hidden-xs - %div{ class: (container_class) } + %div{ class: container_class } .event-last-push .event-last-push-text %span You pushed to diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml index ca6714ef42b18c69f26f2df3d82f2ed0478b8f01..58d961d93ca0b79af8b4136b73a2820ca35e41a3 100644 --- a/app/views/projects/_md_preview.html.haml +++ b/app/views/projects/_md_preview.html.haml @@ -12,13 +12,13 @@ %li.confidential-issue-warning = icon('warning') %span This is a confidential issue. Your comment will not be visible to the public. - + %li.pull-right .toolbar-group = markdown_toolbar_button({icon: "bold fw", data: { "md-tag" => "**" }, title: "Add bold text" }) = markdown_toolbar_button({icon: "italic fw", data: { "md-tag" => "*" }, title: "Add italic text" }) = markdown_toolbar_button({icon: "quote-right fw", data: { "md-tag" => "> ", "md-prepend" => true }, title: "Insert a quote" }) - = markdown_toolbar_button({icon: "code fw", data: { "md-tag" => "`" }, title: "Insert code" }) + = markdown_toolbar_button({icon: "code fw", data: { "md-tag" => "`", "md-block" => "```" }, title: "Insert code" }) = markdown_toolbar_button({icon: "list-ul fw", data: { "md-tag" => "* ", "md-prepend" => true }, title: "Add a bullet list" }) = markdown_toolbar_button({icon: "list-ol fw", data: { "md-tag" => "1. ", "md-prepend" => true }, title: "Add a numbered list" }) = markdown_toolbar_button({icon: "check-square-o fw", data: { "md-tag" => "* [ ] ", "md-prepend" => true }, title: "Add a task list" }) diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml index b1769759dce7a62e1c4368ebe50d2b782a44af8e..58524418a6786d3d5619128a8375e2955b780599 100644 --- a/app/views/projects/blob/_text.html.haml +++ b/app/views/projects/blob/_text.html.haml @@ -16,4 +16,4 @@ .file-content.code .nothing-here-block Empty file - else - = render 'shared/file_highlight', blob: blob + = render 'shared/file_highlight', blob: blob, repository: @repository diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml index ed670dae88d9f91ab9c4cbfc10d0a53a0080e923..0ab78a39cf9a98f85370a7d71b53fde427fe4dbb 100644 --- a/app/views/projects/blob/show.html.haml +++ b/app/views/projects/blob/show.html.haml @@ -1,12 +1,15 @@ +- @no_container = true - page_title @blob.path, @ref += render "projects/commits/head" -= render 'projects/last_push' +%div{ class: container_class } + = render 'projects/last_push' -%div#tree-holder.tree-holder - = render 'blob', blob: @blob + %div#tree-holder.tree-holder + = render 'blob', blob: @blob -- if can_edit_blob?(@blob) - = render 'projects/blob/remove' + - if can_edit_blob?(@blob) + = render 'projects/blob/remove' - - title = "Replace #{@blob.name}" - = render 'projects/blob/upload', title: title, placeholder: title, button_title: 'Replace file', form_path: namespace_project_update_blob_path(@project.namespace, @project, @id), method: :put + - title = "Replace #{@blob.name}" + = render 'projects/blob/upload', title: title, placeholder: title, button_title: 'Replace file', form_path: namespace_project_update_blob_path(@project.namespace, @project, @id), method: :put diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index e0367c40272bf92cb4f7536cb2573f17631887a5..77b405f1f3977f1d7b51d4ebc35442bb0b03bd98 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -2,7 +2,7 @@ - page_title "Branches" = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text Protected branches can be managed in project settings @@ -27,7 +27,7 @@ = sort_title_recently_updated = link_to namespace_project_branches_path(sort: 'last_updated') do = sort_title_oldest_updated - - unless @branches.empty? + - if @branches.any? %ul.content-list.all-branches - @branches.each do |branch| = render "projects/branches/branch", branch: branch diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index 181547316aabcfe76b347344b4a5ae36a1dfecf0..a131289ee97d9e0767c3fb15a24d795a95928e21 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -2,7 +2,7 @@ - page_title "Builds" = render "projects/pipelines/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area %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 4e2702c2e445fedbf77c6078484ce9d590b1b2cf..d1c468c46927efe4eadba8bd82ff581bb46575c8 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -67,4 +67,4 @@ = render "sidebar" :javascript - new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}", "#{trace_with_state[:state]}") + new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build, :json)}", "#{@build.status}", "#{trace_with_state[:state]}") diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml index b11b6c24ccd6be8c126efd032559d0344d71228c..61152649907ddb7630ecd4ea9aaff97e9cb1a165 100644 --- a/app/views/projects/commits/_head.html.haml +++ b/app/views/projects/commits/_head.html.haml @@ -1,8 +1,8 @@ .scrolling-tabs-container.sub-nav-scroll .fade-left - = icon('arrow-left') + = icon('angle-left') .fade-right - = icon('arrow-right') + = icon('angle-right') .nav-links.sub-nav.scrolling-tabs %ul{ class: (container_class) } = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 51ca4eb903e547f333847e0db156c918ea0605ef..9a44ba94970cbba016f37bbbd064c9ec9a4ef1ec 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -7,7 +7,7 @@ = render "head" -%div{ class: (container_class) } +%div{ class: container_class } .row-content-block.second-block.content-component-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'commits' diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml index b22285c11e0df9b55c6681dde869c927460c4bff..e9ff8e90dd56989b1f6577fd0ab6307cedbe5e64 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -2,7 +2,7 @@ - page_title "Compare" = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block Compare branches, tags or commit ranges. %br diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index f4ec7b767f63e1c67469f13d747454753d265502..28a50e7031a14ca45ebd6b329c0d57627b4af008 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -2,7 +2,7 @@ - page_title "#{params[:from]}...#{params[:to]}" = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block.no-bottom-space = render "form" diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index a03f117291f6d12eaed18e1867551ab6279ac1c8..5242021243e7d5b5debe12886f0ab38bc510f92f 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -2,7 +2,7 @@ - page_title "Environments" = render "projects/pipelines/head" -%div{ class: (container_class) } +%div{ class: container_class } - if can?(current_user, :create_environment, @project) && !@environments.blank? .top-area .nav-controls diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml index 4c15e2759d6033b60284d406e8b57f414e93a430..53c62ef234d4549ac7cb3582932ebaf79489cca2 100644 --- a/app/views/projects/environments/show.html.haml +++ b/app/views/projects/environments/show.html.haml @@ -2,7 +2,7 @@ - page_title "Environments" = render "projects/pipelines/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area .col-md-9 %h3.page-title= @environment.name.titleize diff --git a/app/views/projects/graphs/ci.html.haml b/app/views/projects/graphs/ci.html.haml index e695d3ae369ca92585e9288acbd3d3dfe376287e..6be4273b6abbdae6aa19c0dcfc5516c2ece29943 100644 --- a/app/views/projects/graphs/ci.html.haml +++ b/app/views/projects/graphs/ci.html.haml @@ -2,7 +2,7 @@ - page_title "Continuous Integration", "Graphs" = render 'head' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block .oneline A collection of graphs for Continuous Integration diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index 0daffe68f6fd55fe7c001c983d9fbc708a809fe9..65db8af494d4926cc93a12bd46840c9875a9fee4 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -2,7 +2,7 @@ - page_title "Commits", "Graphs" = render 'head' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'graphs_commits' diff --git a/app/views/projects/graphs/languages.html.haml b/app/views/projects/graphs/languages.html.haml index 6d97f552a8e83f28b64b6fd1c806405d2ece3c48..fcfcae0be2098df40bd7c76e10e2fd4906faef3c 100644 --- a/app/views/projects/graphs/languages.html.haml +++ b/app/views/projects/graphs/languages.html.haml @@ -2,7 +2,7 @@ - page_title "Languages", "Graphs" = render 'head' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block .oneline Programming languages used in this repository diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index 9f7e2a361ff7ddca93806b1f4b02d8659816a53c..a985b442b2d6e6c303c701d1cd702f4c2c948916 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -2,7 +2,7 @@ - page_title "Contributors", "Graphs" = render 'head' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'graphs' diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml index a8a8caf728036728c601804cad75f5a6e5f9b80f..2cd8d03e30e9f20c86692304e50620de485f6152 100644 --- a/app/views/projects/imports/new.html.haml +++ b/app/views/projects/imports/new.html.haml @@ -10,7 +10,7 @@ .panel-body %pre :preserve - #{sanitize_repo_path(@project.import_error)} + #{sanitize_repo_path(@project, @project.import_error)} = form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f| = render "shared/import_form", f: f diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index cd876b5ea62d5aa58f65fc54278c44dd90108dcc..7ce4c1e555568ac146276f0d6452f659267c1c11 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -6,7 +6,7 @@ - if current_user = auto_discovery_link_tag(:atom, namespace_project_issues_url(@project.namespace, @project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") -%div{ class: (container_class) } +%div{ class: container_class } .top-area = render 'shared/issuable/nav', type: :issues .nav-controls diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index aa4d69550ec6b6cfc728e03970ffbc5b7b441741..db66a0edbd8f399469c2464e40cfd375a7c3c7ee 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -3,7 +3,7 @@ - hide_class = '' = render "projects/issues/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area.adjust .nav-text Labels can be applied to issues and merge requests. Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging. diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index 9f948d41ddaf8a963d3b0388d60d9da9d4bf7a0a..ace275c689b8770e1ae420c6802ecfca86424a32 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -3,7 +3,7 @@ = render "projects/issues/head" = render 'projects/last_push' -%div{ class: (container_class) } +%div{ class: container_class } .top-area = render 'shared/issuable/nav', type: :merge_requests .nav-controls diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index b0e0bdfff5ad60ca8d6eb8b7ee2e1dd00ae72321..ad2bfbec915d57387d843b5e38c398925faccbbf 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -2,7 +2,7 @@ - page_title "Milestones" = render "projects/issues/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area = render 'shared/milestones_filter' diff --git a/app/views/projects/network/_head.html.haml b/app/views/projects/network/_head.html.haml index 86295a3d0110034cda2efe4602b1c5a7672b8b33..8f6805268d506b581c40001ea697a8a3042b94a9 100644 --- a/app/views/projects/network/_head.html.haml +++ b/app/views/projects/network/_head.html.haml @@ -1,6 +1,6 @@ - @no_container = true -%div{ class: (container_class) } +%div{ class: container_class } .row-content-block.second-block.content-component-block .tree-ref-holder = render partial: 'shared/ref_switcher', locals: {destination: 'graph'} diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index 3ca30b4ba6b5cff8aab9bdd463ce409434d9921d..091af4df4a1fdec89a70598301a9c8166d40dc73 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -4,7 +4,7 @@ = page_specific_javascript_tag('network/application.js') = render "projects/commits/head" = render "head" -%div{ class: (container_class) } +%div{ class: container_class } .project-network .controls = form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f| diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 3c1c6060504256b9a5f3923ba84eb8f772a256b1..05f33b78a47e4e0394b1a17a91c4543acc0c1055 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -1,110 +1,115 @@ - page_title 'New Project' - header_title "Projects", dashboard_projects_path -%h3.page-title - New Project -%hr - .project-edit-container .project-edit-errors = render 'projects/errors' - .project-edit-content - - = form_for @project, html: { class: 'new_project form-horizontal js-requires-input' } do |f| - .form-group - = f.label :path, class: 'control-label' do - Project owner - .col-sm-10 - = f.select :namespace_id, namespaces_options(:current_user), {}, {class: 'select2 js-select-namespace', tabindex: 1} - - - if current_user.can_create_group? - .help-block - Want to house several dependent projects under the same namespace? - = link_to "Create a group", new_group_path - - .form-group - = f.label :path, class: 'control-label' do - Project name - .col-sm-10 - = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, autofocus: true, required: true - - - if import_sources_enabled? - .project-import.js-toggle-container - .form-group - %label.control-label Import project from - .col-sm-10 - - if github_import_enabled? - - if github_import_configured? - = link_to status_import_github_path, class: 'btn import_github' do - %i.fa.fa-github - GitHub - - else - = link_to '#', class: 'how_to_import_link btn import_github' do - %i.fa.fa-github - GitHub - = render 'github_import_modal' + .row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + New project + %p + Create or Import your project from popular Git services + .col-lg-9 + = form_for @project, html: { class: 'new_project' } do |f| + %fieldset.append-bottom-0 + .form-group.col-xs-12.col-sm-6 + = f.label :namespace_id, class: 'label-light' do + %span + Project path + .form-group + .input-group + - if current_user.can_select_namespace? + .input-group-addon + = root_url + = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user, display_path: true), {}, {class: 'select2 js-select-namespace', tabindex: 1} - - if bitbucket_import_enabled? - - if bitbucket_import_configured? - = link_to status_import_bitbucket_path, class: 'btn import_bitbucket', "data-no-turbolink" => "true" do - %i.fa.fa-bitbucket - Bitbucket - else - = link_to status_import_bitbucket_path, class: 'how_to_import_link btn import_bitbucket', "data-no-turbolink" => "true" do - %i.fa.fa-bitbucket - Bitbucket - = render 'bitbucket_import_modal' - - - if gitlab_import_enabled? - - if gitlab_import_configured? - = link_to status_import_gitlab_path, class: 'btn import_gitlab' do - %i.fa.fa-heart - GitLab.com - - else - = link_to status_import_gitlab_path, class: 'how_to_import_link btn import_gitlab' do - %i.fa.fa-heart - GitLab.com - = render 'gitlab_import_modal' - - - if gitorious_import_enabled? - = link_to new_import_gitorious_path, class: 'btn import_gitorious' do - %i.icon-gitorious.icon-gitorious-small - Gitorious.org - - - if google_code_import_enabled? - = link_to new_import_google_code_path, class: 'btn import_google_code' do - %i.fa.fa-google - Google Code - - - if fogbugz_import_enabled? - = link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do - %i.fa.fa-bug - Fogbugz - - - if git_import_enabled? - = link_to "#", class: 'btn js-toggle-button import_git' do - %i.fa.fa-git - %span Repo by URL - - - if gitlab_project_import_enabled? - = link_to new_import_gitlab_project_path, class: 'btn import_gitlab_project project-submit' do - %i.fa.fa-gitlab - %span GitLab export - - .js-toggle-content.hide - = render "shared/import_form", f: f - - .prepend-botton-10 - - .form-group - = f.label :description, class: 'control-label' do - Description - %span.light (optional) - .col-sm-10 - = f.text_area :description, class: "form-control", rows: 3, maxlength: 250, tabindex: 3 - = render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project + .input-group-addon.static-namespace + #{root_url}#{current_user.username}/ + .form-group.col-xs-12.col-sm-6.project-path + = f.label :namespace_id, class: 'label-light' do + %span + Project name + = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, autofocus: true, required: true + - if current_user.can_create_group? + .help-block + Want to house several dependent projects under the same namespace? + = link_to "Create a group", new_group_path + + - if import_sources_enabled? + .project-import.js-toggle-container + .form-group.clearfix + = f.label :visibility_level, class: 'label-light' do + Import project from + .col-sm-12.import-buttons + %div + - if github_import_enabled? + = link_to new_import_github_path, class: 'btn import_github' do + = icon 'github', text: 'GitHub' + %div + - if bitbucket_import_enabled? + - if bitbucket_import_configured? + = link_to status_import_bitbucket_path, class: 'btn import_bitbucket', "data-no-turbolink" => "true" do + %i.fa.fa-bitbucket + Bitbucket + - else + = link_to status_import_bitbucket_path, class: 'how_to_import_link btn import_bitbucket', "data-no-turbolink" => "true" do + %i.fa.fa-bitbucket + Bitbucket + = render 'bitbucket_import_modal' + %div + - if gitlab_import_enabled? + - if gitlab_import_configured? + = link_to status_import_gitlab_path, class: 'btn import_gitlab' do + %i.fa.fa-heart + GitLab.com + - else + = link_to status_import_gitlab_path, class: 'how_to_import_link btn import_gitlab' do + %i.fa.fa-heart + GitLab.com + = render 'gitlab_import_modal' + %div + - if gitorious_import_enabled? + = link_to new_import_gitorious_path, class: 'btn import_gitorious' do + %i.icon-gitorious.icon-gitorious-small + Gitorious.org + %div + - if google_code_import_enabled? + = link_to new_import_google_code_path, class: 'btn import_google_code' do + %i.fa.fa-google + Google Code + %div + - if fogbugz_import_enabled? + = link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do + %i.fa.fa-bug + Fogbugz + %div + - if git_import_enabled? + = link_to "#", class: 'btn js-toggle-button import_git' do + %i.fa.fa-git + %span Repo by URL + %div + - if gitlab_project_import_enabled? + = link_to new_import_gitlab_project_path, class: 'btn import_gitlab_project project-submit' do + %i.fa.fa-gitlab + %span GitLab export + + .js-toggle-content.hide + = render "shared/import_form", f: f + + .form-group + = f.label :description, class: 'label-light' do + Project description + %span.light (optional) + = f.text_area :description, placeholder: 'Description format', class: "form-control", rows: 3, maxlength: 250 + + .form-group.project-visibility-level-holder + = f.label :visibility_level, class: 'label-light' do + Visibility Level + = link_to "(?)", help_page_path("public_access", "public_access") + = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: @project.visibility_level, form_model: @project) - .form-actions = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4 = link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel' diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index a5e163b91e90821d22b1738c1e16265988fdbf99..af0046886fbbeab813e1c1bb70f9260a97eea64f 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -17,7 +17,7 @@ %a{ href: "##{dom_id(note)}" } = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note-created-ago') .note-actions - - access = note.project.team.human_max_access(note.author.id) + - access = note_max_access_for_user(note) - if access and not note.system %span.note-role.hidden-xs= access - if current_user and not note.system diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index b70693eeb62923d748691fe1b7398342ac623d7d..28b475d5c2f8aecb1cc5d2aa4ab5d453d5e05cd5 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -2,7 +2,7 @@ - page_title "Pipelines" = render "projects/pipelines/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area %ul.nav-links %li{class: ('active' if @scope.nil?)} diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 15f0d85194b899ee1da71875e0a30b31603891bd..f6e81af26386c8802af6170d8dd2a0286dc797b1 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -13,7 +13,7 @@ = render "home_panel" .project-stats.row-content-block.second-block - %div{ class: (container_class) } + %div{ class: container_class } %ul.nav %li = link_to project_files_path(@project) do diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml index 4ca1f58ac5c35cd116d57f8bbeed15611b275e7e..c375bb6dd1b37a09745e93d124677ea5c2bc7e15 100644 --- a/app/views/projects/tags/index.html.haml +++ b/app/views/projects/tags/index.html.haml @@ -2,7 +2,7 @@ - page_title "Tags" = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text Tags give the ability to mark specific points in history as being important @@ -25,7 +25,7 @@ = sort_title_oldest_updated .tags - - unless @tags.empty? + - if @tags.any? %ul.content-list = render partial: 'tag', collection: @tags diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index 2abcfcdd7b27d0fe66f56b085674e9a8d2031041..bf5360b4deee9195834eca9859419a845d3ad686 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -7,7 +7,7 @@ = render 'projects/last_push' = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .tree-controls = render 'projects/find_file_link' - if can? current_user, :download_code, @project diff --git a/app/views/projects/wikis/_new.html.haml b/app/views/projects/wikis/_new.html.haml index 4f8abcdc8e1a167b7b9908d3e011941ee4317785..c32cb122c26fe33b8e4f263fff88275f7033fab2 100644 --- a/app/views/projects/wikis/_new.html.haml +++ b/app/views/projects/wikis/_new.html.haml @@ -1,6 +1,6 @@ - @no_container = true -%div{ class: (container_class) } +%div{ class: container_class } %div#modal-new-wiki.modal .modal-dialog .modal-content diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml index 817bf9b3f69d898379d36084da08ceb00186b581..233538bb488cff19f8c1606c02ea9cb36c8dacfe 100644 --- a/app/views/projects/wikis/edit.html.haml +++ b/app/views/projects/wikis/edit.html.haml @@ -2,7 +2,7 @@ - page_title "Edit", @page.title.capitalize, "Wiki" = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text %strong diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml index 6caf7230f350d6ee4c3f5f471947bf40e1ab1105..b8811a28dd66cce0c58e3d57a6be4423415e617d 100644 --- a/app/views/projects/wikis/git_access.html.haml +++ b/app/views/projects/wikis/git_access.html.haml @@ -2,7 +2,7 @@ - page_title "Git Access", "Wiki" = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block %span.oneline Git access for diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml index 630ee35b70b9473104e764209db9a0f699ebee35..4c0b14e2c420e4bda836fc70760051077c6cf62a 100644 --- a/app/views/projects/wikis/history.html.haml +++ b/app/views/projects/wikis/history.html.haml @@ -1,6 +1,6 @@ - page_title "History", @page.title.capitalize, "Wiki" = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text %strong diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml index 81d9f391c1c50f435282afe30a2a3dec4f474416..9c10acd4cb6b6373ab937cd01f4277524f61a05e 100644 --- a/app/views/projects/wikis/pages.html.haml +++ b/app/views/projects/wikis/pages.html.haml @@ -3,7 +3,7 @@ = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } %ul.content-list - @wiki_pages.each do |wiki_page| %li diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml index 76f9b1ecd762b7ddda0e9a6e4735331491754af9..5cebb538cf563d51cf2fc97779a4eda0bc94b4f5 100644 --- a/app/views/projects/wikis/show.html.haml +++ b/app/views/projects/wikis/show.html.haml @@ -2,7 +2,7 @@ - page_title @page.title.capitalize, "Wiki" = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text %strong= @page.title.capitalize diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index ad944a19ca11b64f6e526d66aa71b7dcf6510fbb..e26693bf5b9613a0419b520b10e983371e6d1e9f 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -1,3 +1,5 @@ +- repository = nil unless local_assigns.key?(:repository) + .file-content.code.js-syntax-highlight .line-numbers - if blob.data.present? @@ -11,4 +13,4 @@ = link_icon = i .blob-content{data: {blob_id: blob.id}} - = highlight(blob.name, blob.data, plain: blob.no_highlighting?) + = highlight(blob.path, blob.data, repository: repository, plain: blob.no_highlighting?) diff --git a/app/views/shared/_labels_row.html.haml b/app/views/shared/_labels_row.html.haml index 87028ececd4bf21d4d1ee917c2909b5bff206957..5507a05f6c1f4690afdc794678f70716a7d40641 100644 --- a/app/views/shared/_labels_row.html.haml +++ b/app/views/shared/_labels_row.html.haml @@ -1,6 +1,6 @@ - labels.each do |label| %span.label-row.btn-group{ role: "group", aria: { label: escape_once(label.name) }, style: "color: #{text_color_for_bg(label.color)}" } - = link_to namespace_project_label_path(@project.namespace, @project, label), + = link_to label_filter_path(@project, label, type: controller.controller_name), class: "btn btn-transparent has-tooltip", style: "background-color: #{label.color};", title: escape_once(label.description), diff --git a/app/views/users/calendar_activities.html.haml b/app/views/users/calendar_activities.html.haml index 630d97e339db65a5fe81df7de03064c62b0dc6fa..f51599212db817e1d146b4b0045f22cf3b7f6312 100644 --- a/app/views/users/calendar_activities.html.haml +++ b/app/views/users/calendar_activities.html.haml @@ -14,7 +14,7 @@ - else = event_action_name(event) - if event.target - %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target] + %strong= link_to "#{event.target.to_reference}", [event.project.namespace.becomes(Namespace), event.project, event.target] at %strong diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index f3327ca9e61909f117fee35a63ba4daf8c5b1a5b..09035a7cf2daaaef53c1e531d1e8e8d9e9b25888 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -4,10 +4,10 @@ class PostReceive sidekiq_options queue: :post_receive def perform(repo_path, identifier, changes) - if repo_path.start_with?(Gitlab.config.gitlab_shell.repos_path.to_s) - repo_path.gsub!(Gitlab.config.gitlab_shell.repos_path.to_s, "") + if path = Gitlab.config.repositories.storages.find { |p| repo_path.start_with?(p[1].to_s) } + repo_path.gsub!(path[1].to_s, "") else - log("Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"") + log("Check gitlab.yml config for correct repositories.storages values. No repository storage path matches \"#{repo_path}\"") end post_received = Gitlab::GitPostReceive.new(repo_path, identifier, changes) diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb index d947f1055160b7f4ae23d6d1c42ee8d74e17ea25..f7604e48f8320778277c4140d3d10629502f20a4 100644 --- a/app/workers/repository_fork_worker.rb +++ b/app/workers/repository_fork_worker.rb @@ -12,7 +12,7 @@ class RepositoryForkWorker return end - result = gitlab_shell.fork_repository(source_path, target_path) + result = gitlab_shell.fork_repository(project.repository_storage_path, source_path, target_path) unless result logger.error("Unable to fork project #{project_id} for repository #{source_path} -> #{target_path}") project.mark_import_as_failed('The project could not be forked.') diff --git a/config/dependency_decisions.yml b/config/dependency_decisions.yml index 436a2c5e17a76a4921faa1c2bbf65a2b0c76df04..293f2b71d65df0d4d3a85a4c49d4af45a466283c 100644 --- a/config/dependency_decisions.yml +++ b/config/dependency_decisions.yml @@ -181,3 +181,9 @@ :why: Equivalent to LGPLv2 :versions: [] :when: 2016-06-07 17:14:10.907682000 Z +- - :whitelist + - Artistic 2.0 + - :who: Josh Frye + :why: Disk/mount information display on Admin pages + :versions: [] + :when: 2016-06-29 16:32:45.432113000 Z diff --git a/config/gitlab.teatro.yml b/config/gitlab.teatro.yml index 01c8dc5ff98e2cd278ccea0a1146131a69958137..75b79b837e0c75a3dd9c1fa3bd9b10fae294fa86 100644 --- a/config/gitlab.teatro.yml +++ b/config/gitlab.teatro.yml @@ -47,11 +47,13 @@ production: &base backup: path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) + repositories: + storages: # REPO PATHS MUST NOT BE A SYMLINK!!! + default: /apps/repositories/ + gitlab_shell: path: /apps/gitlab-shell/ - # REPOS_PATH MUST NOT BE A SYMLINK!!! - repos_path: /apps/repositories/ hooks_path: /apps/gitlab-shell/hooks/ upload_pack: true diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 75e1a3c1093343ffe062df4efa988c8f0603d86f..325eca72862841ab5c8d251edebfba41388b485c 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -428,6 +428,13 @@ production: &base satellites: path: /home/git/gitlab-satellites/ + ## Repositories settings + repositories: + # Paths where repositories can be stored. Give the canonicalized absolute pathname. + # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!! + storages: # You must have at least a `default` storage path. + default: /home/git/repositories/ + ## Backup settings backup: path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) @@ -452,9 +459,6 @@ production: &base ## GitLab Shell settings gitlab_shell: path: /home/git/gitlab-shell/ - - # REPOS_PATH MUST NOT BE A SYMLINK!!! - repos_path: /home/git/repositories/ hooks_path: /home/git/gitlab-shell/hooks/ # File that contains the secret key for verifying access for gitlab-shell. @@ -528,11 +532,13 @@ test: # user: YOUR_USERNAME satellites: path: tmp/tests/gitlab-satellites/ + repositories: + storages: + default: tmp/tests/repositories/ backup: path: tmp/tests/backups gitlab_shell: path: tmp/tests/gitlab-shell/ - repos_path: tmp/tests/repositories/ hooks_path: tmp/tests/gitlab-shell/hooks/ issues_tracker: redmine: diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index c6dc1e4ab38da2b2a162c878665d82ef7bbbc1e9..a93996cec72921f3120c9a9dac768632623959ea 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -304,13 +304,20 @@ Settings.gitlab_shell['hooks_path'] ||= Settings.gitlab['user_home'] + '/gitla Settings.gitlab_shell['secret_file'] ||= Rails.root.join('.gitlab_shell_secret') Settings.gitlab_shell['receive_pack'] = true if Settings.gitlab_shell['receive_pack'].nil? Settings.gitlab_shell['upload_pack'] = true if Settings.gitlab_shell['upload_pack'].nil? -Settings.gitlab_shell['repos_path'] ||= Settings.gitlab['user_home'] + '/repositories/' Settings.gitlab_shell['ssh_host'] ||= Settings.gitlab.ssh_host Settings.gitlab_shell['ssh_port'] ||= 22 Settings.gitlab_shell['ssh_user'] ||= Settings.gitlab.user Settings.gitlab_shell['owner_group'] ||= Settings.gitlab.user Settings.gitlab_shell['ssh_path_prefix'] ||= Settings.send(:build_gitlab_shell_ssh_path_prefix) +# +# Repositories +# +Settings['repositories'] ||= Settingslogic.new({}) +Settings.repositories['storages'] ||= {} +# Setting gitlab_shell.repos_path is DEPRECATED and WILL BE REMOVED in version 9.0 +Settings.repositories.storages['default'] ||= Settings.gitlab_shell['repos_path'] || Settings.gitlab['user_home'] + '/repositories/' + # # Backup # diff --git a/config/initializers/6_validations.rb b/config/initializers/6_validations.rb new file mode 100644 index 0000000000000000000000000000000000000000..3ba9e36c567c13aaacd8018524052358cbb7c0f5 --- /dev/null +++ b/config/initializers/6_validations.rb @@ -0,0 +1,24 @@ +def storage_name_valid?(name) + !!(name =~ /\A[a-zA-Z0-9\-_]+\z/) +end + +def find_parent_path(name, path) + Gitlab.config.repositories.storages.detect do |n, p| + name != n && path.chomp('/').start_with?(p.chomp('/')) + end +end + +def error(message) + raise "#{message}. Please fix this in your gitlab.yml before starting GitLab." +end + +error('No repository storage path defined') if Gitlab.config.repositories.storages.empty? + +Gitlab.config.repositories.storages.each do |name, path| + error("\"#{name}\" is not a valid storage name") unless storage_name_valid?(name) + + parent_name, _parent_path = find_parent_path(name, path) + if parent_name + error("#{name} is a nested path of #{parent_name}. Nested paths are not supported for repository storages") + end +end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 021bdb11251103fdee823492d0e8dfa0ca0c5f86..73977341b73ae679c5382f7c0390be6d39bd778c 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -212,7 +212,7 @@ Devise.setup do |config| if Gitlab::LDAP::Config.enabled? Gitlab.config.ldap.servers.values.each do |server| if server['allow_username_or_email_login'] - email_stripping_proc = ->(name) {name.gsub(/@.*\z/,'')} + email_stripping_proc = ->(name) {name.gsub(/@.*\z/, '')} else email_stripping_proc = ->(name) {name} end diff --git a/config/initializers/gitlab_shell_secret_token.rb b/config/initializers/gitlab_shell_secret_token.rb index 751fccead07c09537c7820da47a16cf2c01dcaa3..7454c33c9ddafd5ee0694b415eb602722096d109 100644 --- a/config/initializers/gitlab_shell_secret_token.rb +++ b/config/initializers/gitlab_shell_secret_token.rb @@ -1,19 +1 @@ -# Be sure to restart your server when you modify this file. - -require 'securerandom' - -# Your secret key for verifying the gitlab_shell. - - -secret_file = Gitlab.config.gitlab_shell.secret_file - -unless File.exist? secret_file - # Generate a new token of 16 random hexadecimal characters and store it in secret_file. - token = SecureRandom.hex(16) - File.write(secret_file, token) -end - -link_path = File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret') -if File.exist?(Gitlab.config.gitlab_shell.path) && !File.exist?(link_path) - FileUtils.symlink(secret_file, link_path) -end +Gitlab::Shell.new.generate_and_link_secret_token diff --git a/config/initializers/rack_attack.rb.example b/config/initializers/rack_attack.rb.example index 30d05f1615381e5fd7de7bfe12be323aba4836c1..69052c029f24d478fafdb4d85f524ca345a912fc 100644 --- a/config/initializers/rack_attack.rb.example +++ b/config/initializers/rack_attack.rb.example @@ -10,7 +10,8 @@ paths_to_be_protected = [ "#{Rails.application.config.relative_url_root}/api/#{API::API.version}/session", "#{Rails.application.config.relative_url_root}/users", "#{Rails.application.config.relative_url_root}/users/confirmation", - "#{Rails.application.config.relative_url_root}/unsubscribes/" + "#{Rails.application.config.relative_url_root}/unsubscribes/", + "#{Rails.application.config.relative_url_root}/import/github/personal_access_token" ] diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 7a2b9a7f6c1cfffb3fb51f6edd5b858bbd3931e6..593c14a289fa4b831a907522a038d669fa76827b 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -13,7 +13,7 @@ Sidekiq.configure_server do |config| # UGLY Hack to get nested hash from settingslogic cron_jobs = JSON.parse(Gitlab.config.cron_jobs.to_json) # UGLY hack: Settingslogic doesn't allow 'class' key - cron_jobs.each { |k,v| cron_jobs[k]['class'] = cron_jobs[k].delete('job_class') } + cron_jobs.each { |k, v| cron_jobs[k]['class'] = cron_jobs[k].delete('job_class') } Sidekiq::Cron::Job.load_from_hash! cron_jobs # Database pool should be at least `sidekiq_concurrency` + 2 diff --git a/config/initializers/trusted_proxies.rb b/config/initializers/trusted_proxies.rb index d256a16d42b803ba6274905a3d2272c388180ae0..df4a933e22f3aec9aa9a35ec5794b1252705b097 100644 --- a/config/initializers/trusted_proxies.rb +++ b/config/initializers/trusted_proxies.rb @@ -1,3 +1,16 @@ +# Override Rack::Request to make use of the same list of trusted_proxies +# as the ActionDispatch::Request object. This is necessary for libraries +# like rack_attack where they don't use ActionDispatch, and we want them +# to block/throttle requests on private networks. +# Rack Attack specific issue: https://github.com/kickstarter/rack-attack/issues/145 +module Rack + class Request + def trusted_proxy?(ip) + Rails.application.config.action_dispatch.trusted_proxies.any? { |proxy| proxy === ip } + end + end +end + Rails.application.config.action_dispatch.trusted_proxies = ( [ '127.0.0.1', '::1' ] + Array(Gitlab.config.gitlab.trusted_proxies) ).map { |proxy| IPAddr.new(proxy) } diff --git a/config/routes.rb b/config/routes.rb index e45293cdf7fd8db9dc15790c9c909579300c47ec..c04780fec88a8d40ac8960ebf8e7c2c1807f0a0b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -139,6 +139,7 @@ Rails.application.routes.draw do # namespace :import do resource :github, only: [:create, :new], controller: :github do + post :personal_access_token get :status get :callback get :jobs @@ -280,6 +281,7 @@ Rails.application.routes.draw do resource :logs, only: [:show] resource :health_check, controller: 'health_check', only: [:show] resource :background_jobs, controller: 'background_jobs', only: [:show] + resource :system_info, controller: 'system_info', only: [:show] resources :namespaces, path: '/projects', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do root to: 'projects#index', as: :projects @@ -652,7 +654,7 @@ Rails.application.routes.draw do get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID - post '/wikis/*id/markdown_preview', to:'wikis#markdown_preview', constraints: WIKI_SLUG_ID, as: 'wiki_markdown_preview' + post '/wikis/*id/markdown_preview', to: 'wikis#markdown_preview', constraints: WIKI_SLUG_ID, as: 'wiki_markdown_preview' end resource :repository, only: [:show, :create] do diff --git a/db/migrate/20160608195742_add_repository_storage_to_projects.rb b/db/migrate/20160608195742_add_repository_storage_to_projects.rb new file mode 100644 index 0000000000000000000000000000000000000000..c700d2b569d2d074997a700cad33d28eaf2fb903 --- /dev/null +++ b/db/migrate/20160608195742_add_repository_storage_to_projects.rb @@ -0,0 +1,12 @@ +class AddRepositoryStorageToProjects < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + disable_ddl_transaction! + + def up + add_column_with_default(:projects, :repository_storage, :string, default: 'default') + end + + def down + remove_column(:projects, :repository_storage) + end +end diff --git a/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb b/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb new file mode 100644 index 0000000000000000000000000000000000000000..6dae91b700b866f54f7d7c8904ec9e2023c26bb9 --- /dev/null +++ b/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb @@ -0,0 +1,5 @@ +class AddRepositoryStorageToApplicationSettings < ActiveRecord::Migration + def change + add_column :application_settings, :repository_storage, :string, default: 'default' + end +end diff --git a/db/schema.rb b/db/schema.rb index 7a8377f687c00aede850a1901fcd3414abdb3646..beb723c3bc584aa63bf86e35f214130dd201c640 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -85,6 +85,7 @@ ActiveRecord::Schema.define(version: 20160620115026) do t.boolean "send_user_confirmation_email", default: false t.integer "container_registry_token_expire_delay", default: 5 t.text "after_sign_up_text" + t.string "repository_storage", default: "default" end create_table "audit_events", force: :cascade do |t| @@ -796,38 +797,39 @@ ActiveRecord::Schema.define(version: 20160620115026) do t.datetime "created_at" t.datetime "updated_at" t.integer "creator_id" - t.boolean "issues_enabled", default: true, null: false - t.boolean "merge_requests_enabled", default: true, null: false - t.boolean "wiki_enabled", default: true, null: false + t.boolean "issues_enabled", default: true, null: false + t.boolean "merge_requests_enabled", default: true, null: false + t.boolean "wiki_enabled", default: true, null: false t.integer "namespace_id" - t.boolean "snippets_enabled", default: true, null: false + t.boolean "snippets_enabled", default: true, null: false t.datetime "last_activity_at" t.string "import_url" - t.integer "visibility_level", default: 0, null: false - t.boolean "archived", default: false, null: false + t.integer "visibility_level", default: 0, null: false + t.boolean "archived", default: false, null: false t.string "avatar" t.string "import_status" t.float "repository_size", default: 0.0 - t.integer "star_count", default: 0, null: false + t.integer "star_count", default: 0, null: false t.string "import_type" t.string "import_source" t.integer "commit_count", default: 0 t.text "import_error" t.integer "ci_id" - t.boolean "builds_enabled", default: true, null: false - t.boolean "shared_runners_enabled", default: true, null: false + t.boolean "builds_enabled", default: true, null: false + t.boolean "shared_runners_enabled", default: true, null: false t.string "runners_token" t.string "build_coverage_regex" - t.boolean "build_allow_git_fetch", default: true, null: false - t.integer "build_timeout", default: 3600, null: false + t.boolean "build_allow_git_fetch", default: true, null: false + t.integer "build_timeout", default: 3600, null: false t.boolean "pending_delete", default: false - t.boolean "public_builds", default: true, null: false + t.boolean "public_builds", default: true, null: false t.integer "pushes_since_gc", default: 0 t.boolean "last_repository_check_failed" t.datetime "last_repository_check_at" t.boolean "container_registry_enabled" - t.boolean "only_allow_merge_if_build_succeeds", default: false, null: false + t.boolean "only_allow_merge_if_build_succeeds", default: false, null: false t.boolean "has_external_issue_tracker" + t.string "repository_storage", default: "default", null: false end add_index "projects", ["builds_enabled", "shared_runners_enabled"], name: "index_projects_on_builds_enabled_and_shared_runners_enabled", using: :btree diff --git a/doc/README.md b/doc/README.md index be0d17084c7f6dcaac3cb6f3c6fb96356a848c30..b98d6812a81556af24b59e8f9cb67d38f3d82d76 100644 --- a/doc/README.md +++ b/doc/README.md @@ -34,6 +34,7 @@ - [Operations](operations/README.md) Keeping GitLab up and running. - [Raketasks](raketasks/README.md) Backups, maintenance, automatic webhook setup and the importing of projects. - [Repository checks](administration/repository_checks.md) Periodic Git repository checks. +- [Repository storages](administration/repository_storages.md) Manage the paths used to store repositories. - [Security](security/README.md) Learn what you can do to further secure your GitLab instance. - [System hooks](system_hooks/system_hooks.md) Notifications when users, projects and keys are changed. - [Update](update/README.md) Update guides to upgrade your installation. diff --git a/doc/administration/img/housekeeping_settings.png b/doc/administration/img/housekeeping_settings.png index f7c5bc44367e82ed3a62faa3685c50612f8fb315..f72ad9a45d5c16d31a63c3e4f8b4853b0d7dc281 100644 Binary files a/doc/administration/img/housekeeping_settings.png and b/doc/administration/img/housekeeping_settings.png differ diff --git a/doc/administration/repository_storages.md b/doc/administration/repository_storages.md new file mode 100644 index 0000000000000000000000000000000000000000..81bfe173151eb183a42993e3eb6fefb59c6533c1 --- /dev/null +++ b/doc/administration/repository_storages.md @@ -0,0 +1,18 @@ +# Repository storages + +GitLab allows you to define repository storage paths to enable distribution of +storage load between several mount points. + +## For installations from source + +Add your repository storage paths in your `gitlab.yml` under repositories -> storages, using key -> value pairs. + +>**Notes:** +- You must have at least one storage path called `default`. +- In order for backups to work correctly the storage path must **not** be a +mount point and the GitLab user should have correct permissions for the parent +directory of the path. + +## For omnibus installations + +Follow the instructions at https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/configuration.md#storing-git-data-in-an-alternative-directory diff --git a/doc/api/builds.md b/doc/api/builds.md index de9989443528fc425a86b581739d0695637a371e..2adea11247e7dedeceb8ad1747a1b918d9aebc2f 100644 --- a/doc/api/builds.md +++ b/doc/api/builds.md @@ -107,6 +107,11 @@ Example of response Get a list of builds for specific commit in a project. +This endpoint will return all builds, from all pipelines for a given commit. +If the commit SHA is not found, it will respond with 404, otherwise it will +return an array of builds (an empty array if there are no builds for this +particular commit). + ``` GET /projects/:id/repository/commits/:sha/builds ``` diff --git a/doc/api/settings.md b/doc/api/settings.md index 43a0fe35e42dbc5a9207998557fcf5f4d23659a9..741c5a295818e5f22fb85ae2c244ffbb0ac2703d 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -38,7 +38,8 @@ Example response: "default_project_visibility" : 0, "gravatar_enabled" : true, "sign_in_text" : null, - "container_registry_token_expire_delay": 5 + "container_registry_token_expire_delay": 5, + "repository_storage": "default" } ``` @@ -56,7 +57,7 @@ PUT /application/settings | `gravatar_enabled` | boolean | no | Enable Gravatar | | `sign_in_text` | string | no | Text on login page | | `home_page_url` | string | no | Redirect to this URL when not logged in | -| `default_branch_protection` | integer | no | Determine if developers can push to master. Can take `0` _(not protected, both developers and masters can push new commits, force push or delete the branch)_, `1` _(partially protected, developers can push new commits, but cannot force push or delete the branch, masters can do anything)_ or `2` _(fully protected, developers cannot push new commits, force push or delete the branch, masters can do anything)_ as a parameter. Default is `1`. | +| `default_branch_protection` | integer | no | Determine if developers can push to master. Can take `0` _(not protected, both developers and masters can push new commits, force push or delete the branch)_, `1` _(partially protected, developers can push new commits, but cannot force push or delete the branch, masters can do anything)_ or `2` _(fully protected, developers cannot push new commits, force push or delete the branch, masters can do anything)_ as a parameter. Default is `2`. | | `restricted_visibility_levels` | array of integers | no | Selected levels cannot be used by non-admin users for projects or snippets. Can take `0` _(Private)_, `1` _(Internal)_ and `2` _(Public)_ as a parameter. Default is null which means there is no restriction. | | `max_attachment_size` | integer | no | Limit attachment size in MB | | `session_expire_delay` | integer | no | Session duration in minutes. GitLab restart is required to apply changes | @@ -66,6 +67,7 @@ PUT /application/settings | `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider | | `after_sign_out_path` | string | no | Where to redirect users after logout | | `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes | +| `repository_storage` | string | no | Storage path for new projects. The value should be the name of one of the repository storage paths defined in your gitlab.yml | ```bash curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/application/settings?signup_enabled=false&default_project_visibility=1 @@ -93,6 +95,7 @@ Example response: "restricted_signup_domains": [], "user_oauth_applications": true, "after_sign_out_path": "", - "container_registry_token_expire_delay": 5 + "container_registry_token_expire_delay": 5, + "repository_storage": "default" } ``` diff --git a/doc/ci/build_artifacts/img/build_artifacts_browser.png b/doc/ci/build_artifacts/img/build_artifacts_browser.png index 73ed4eeb92781c798c3461283ca84d34d462c61c..59cf2b8746b1b3cd98ad5d0fd02ab69472e3a059 100644 Binary files a/doc/ci/build_artifacts/img/build_artifacts_browser.png and b/doc/ci/build_artifacts/img/build_artifacts_browser.png 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 index f5d15bc3e7d1bf1e5db53efb2e4ef7e771576a33..7801c2e6fa6d23639b1d92a24653741368c7fb56 100644 Binary files a/doc/ci/build_artifacts/img/build_artifacts_browser_button.png and b/doc/ci/build_artifacts/img/build_artifacts_browser_button.png differ diff --git a/doc/ci/img/builds_tab.png b/doc/ci/img/builds_tab.png index d088b8b329dc5dca75513e4fbe27d2323203d770..35780e277aefabbbae53233b123b2f1b1fa9c6d0 100644 Binary files a/doc/ci/img/builds_tab.png and b/doc/ci/img/builds_tab.png differ diff --git a/doc/ci/img/features_settings.png b/doc/ci/img/features_settings.png index 17aba5d14d89e3dbd5c3765859853d3646847c1b..38d7036f60610a6e47f175f4fd9337a712330d2b 100644 Binary files a/doc/ci/img/features_settings.png and b/doc/ci/img/features_settings.png differ diff --git a/doc/ci/quick_start/img/build_log.png b/doc/ci/quick_start/img/build_log.png index 89e6cd40cb61d890b7ee1ce0137c738a18526e74..b53a6cd86b082a11c0d5d4851fa75d4349ef2818 100644 Binary files a/doc/ci/quick_start/img/build_log.png and b/doc/ci/quick_start/img/build_log.png differ diff --git a/doc/ci/quick_start/img/builds_status.png b/doc/ci/quick_start/img/builds_status.png index b8e6c2a361a093059f2ab189a2e281a22175ad7a..47862761ffe50fd13d962289a9dbb2a5cc2f89e4 100644 Binary files a/doc/ci/quick_start/img/builds_status.png and b/doc/ci/quick_start/img/builds_status.png differ diff --git a/doc/ci/quick_start/img/new_commit.png b/doc/ci/quick_start/img/new_commit.png index 3d3c9d5c0bd078333a7bc1e670b9a7dc736a2fcc..a53562ce3284c8a68a118d215565fefd6f2464b6 100644 Binary files a/doc/ci/quick_start/img/new_commit.png and b/doc/ci/quick_start/img/new_commit.png differ diff --git a/doc/ci/quick_start/img/runners_activated.png b/doc/ci/quick_start/img/runners_activated.png index eafcfd6ecd5daa3ebdea96496b2126f756ace99e..23261123b1868d1c4ca77e80bcf5c588744a7073 100644 Binary files a/doc/ci/quick_start/img/runners_activated.png and b/doc/ci/quick_start/img/runners_activated.png differ diff --git a/doc/ci/quick_start/img/single_commit_status_pending.png b/doc/ci/quick_start/img/single_commit_status_pending.png index 23b3bb5acfcfd4d44f76152f92fab81d95d7b500..ccf3ac957bba91be78c4b0a6be1c57e765eb872b 100644 Binary files a/doc/ci/quick_start/img/single_commit_status_pending.png and b/doc/ci/quick_start/img/single_commit_status_pending.png differ diff --git a/doc/ci/quick_start/img/status_pending.png b/doc/ci/quick_start/img/status_pending.png index a049ec2a5ba560c222078da1c45b3e358ce15dd3..9feacf0c9612755538777af6f4ea339e4215e756 100644 Binary files a/doc/ci/quick_start/img/status_pending.png and b/doc/ci/quick_start/img/status_pending.png differ diff --git a/doc/ci/runners/project_specific.png b/doc/ci/runners/project_specific.png index f51ea694e78f964656c568e4ab95d2977772bd4b..c812defa67b054ca733c21fd5c4943edf6c0ff05 100644 Binary files a/doc/ci/runners/project_specific.png and b/doc/ci/runners/project_specific.png differ diff --git a/doc/ci/runners/shared_runner.png b/doc/ci/runners/shared_runner.png index 9755144eb08cdbf1656a50a8b86b4ad3f840082c..31574a17764ca714f83ebefaf562d594fb76d5d2 100644 Binary files a/doc/ci/runners/shared_runner.png and b/doc/ci/runners/shared_runner.png differ diff --git a/doc/ci/runners/shared_to_specific_admin.png b/doc/ci/runners/shared_to_specific_admin.png index 44a4bef22f7b30f4e0e859965ab4b5217de425cc..8f4010a58493ed1096634d14d4b7194dc0e5aec2 100644 Binary files a/doc/ci/runners/shared_to_specific_admin.png and b/doc/ci/runners/shared_to_specific_admin.png differ diff --git a/doc/ci/triggers/img/builds_page.png b/doc/ci/triggers/img/builds_page.png index e78794fbee767d82382d2d97e7c9f91a9d9c09c7..2dee8ee61073b453c422fb62d78041089ed7333f 100644 Binary files a/doc/ci/triggers/img/builds_page.png and b/doc/ci/triggers/img/builds_page.png differ diff --git a/doc/ci/triggers/img/trigger_single_build.png b/doc/ci/triggers/img/trigger_single_build.png index c25f27409d65ce5548cd26940cc568c62fcd5425..baf3fc183d8ba11d78389e0aa107d0d5d1374f17 100644 Binary files a/doc/ci/triggers/img/trigger_single_build.png and b/doc/ci/triggers/img/trigger_single_build.png differ diff --git a/doc/ci/triggers/img/trigger_variables.png b/doc/ci/triggers/img/trigger_variables.png index 2207e8b34cbd6b42970e3e47e0740973e0ca655f..908355c33a52103ec448176aee1d39799eb7e996 100644 Binary files a/doc/ci/triggers/img/trigger_variables.png and b/doc/ci/triggers/img/trigger_variables.png differ diff --git a/doc/ci/triggers/img/triggers_page.png b/doc/ci/triggers/img/triggers_page.png index 268368dc3c5b7c6046c2c15f0819641699e9d9a6..69cec5cdebfd14654fef9d3d43f126731632b37c 100644 Binary files a/doc/ci/triggers/img/triggers_page.png and b/doc/ci/triggers/img/triggers_page.png differ diff --git a/doc/container_registry/img/container_registry.png b/doc/container_registry/img/container_registry.png index e9505a73b408e29a78898014ccfc5b5f8eb80bf9..57d6f9f22c584d603d9393034dd7f24ab637b7a1 100644 Binary files a/doc/container_registry/img/container_registry.png and b/doc/container_registry/img/container_registry.png differ diff --git a/doc/container_registry/img/project_feature.png b/doc/container_registry/img/project_feature.png index 57a73d253c0b8ca6c92c80fca13068e5e764a69d..a59b4f82b561683642523ab735392b5249dc9bdd 100644 Binary files a/doc/container_registry/img/project_feature.png and b/doc/container_registry/img/project_feature.png differ diff --git a/doc/customization/branded_login_page/appearance.png b/doc/customization/branded_login_page/appearance.png index 6bce1f0a287298493d42fc8e8530214e448f6de8..023dc5599b434c9d64ac3004516dbc2ea099f76e 100644 Binary files a/doc/customization/branded_login_page/appearance.png and b/doc/customization/branded_login_page/appearance.png differ diff --git a/doc/customization/branded_login_page/custom_sign_in.png b/doc/customization/branded_login_page/custom_sign_in.png index d6020b029a2e8f01ab02bb5bc4edb956fe2d361c..7d99e0a2b3b97a7e0d34c3d7a0bb1409b0db3ecc 100644 Binary files a/doc/customization/branded_login_page/custom_sign_in.png and b/doc/customization/branded_login_page/custom_sign_in.png differ diff --git a/doc/customization/branded_login_page/default_login_page.png b/doc/customization/branded_login_page/default_login_page.png index 795c7954d8e7d87207877b80d8e2c600545ea38c..0cfa9da202ea8cbec8cf76ba65e4fddfa0f08147 100644 Binary files a/doc/customization/branded_login_page/default_login_page.png and b/doc/customization/branded_login_page/default_login_page.png differ diff --git a/doc/development/architecture.md b/doc/development/architecture.md index 12e33406cb694f32c25c7f1ae1e871c4a685fc48..33fd50f4c11d30423a08900a0668daa0a9584c2c 100644 --- a/doc/development/architecture.md +++ b/doc/development/architecture.md @@ -52,7 +52,9 @@ To serve repositories over SSH there's an add-on application called gitlab-shell ### Components - + + +_[edit diagram (for GitLab team members only)](https://docs.google.com/drawings/d/1fBzAyklyveF-i-2q-OHUIqDkYfjjxC4mq5shwKSZHLs/edit)_ A typical install of GitLab will be on GNU/Linux. It uses Nginx or Apache as a web front end to proxypass the Unicorn web server. By default, communication between Unicorn and the front end is via a Unix domain socket but forwarding requests via TCP is also supported. The web front end accesses `/home/git/gitlab/public` bypassing the Unicorn server to serve static pages, uploads (e.g. avatar images or attachments), and precompiled assets. GitLab serves web pages and a [GitLab API](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/api) using the Unicorn web server. It uses Sidekiq as a job queue which, in turn, uses redis as a non-persistent database backend for job information, meta data, and incoming jobs. diff --git a/doc/development/gitlab_architecture_diagram.png b/doc/development/gitlab_architecture_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..80e975718e09f11772879c759060ab02ab7ded50 Binary files /dev/null and b/doc/development/gitlab_architecture_diagram.png differ diff --git a/doc/development/gitlab_diagram_overview.png b/doc/development/gitlab_diagram_overview.png deleted file mode 100644 index d9b9eed3d8f6b244dabf5b3074324fcfa774704a..0000000000000000000000000000000000000000 Binary files a/doc/development/gitlab_diagram_overview.png and /dev/null differ diff --git a/doc/gitlab-basics/basicsimages/add_new_merge_request.png b/doc/gitlab-basics/basicsimages/add_new_merge_request.png index 9d93b217a59c00af16acd6b2f76024f2aea42e1a..e60992c4c6a21206ba39889c536aac597dff4361 100644 Binary files a/doc/gitlab-basics/basicsimages/add_new_merge_request.png and b/doc/gitlab-basics/basicsimages/add_new_merge_request.png differ diff --git a/doc/gitlab-basics/basicsimages/add_sshkey.png b/doc/gitlab-basics/basicsimages/add_sshkey.png index 2dede97aa405b5ef004bea3f8841d591518c3795..89c860186292fc02e160262d01c49d0af5ede952 100644 Binary files a/doc/gitlab-basics/basicsimages/add_sshkey.png and b/doc/gitlab-basics/basicsimages/add_sshkey.png differ diff --git a/doc/gitlab-basics/basicsimages/branch_info.png b/doc/gitlab-basics/basicsimages/branch_info.png index c5e38b552a5fd55473adac81c65f4110eee94f18..2264f3c5bf2460a41c4e676717ed8b596e34eabe 100644 Binary files a/doc/gitlab-basics/basicsimages/branch_info.png and b/doc/gitlab-basics/basicsimages/branch_info.png differ diff --git a/doc/gitlab-basics/basicsimages/branch_name.png b/doc/gitlab-basics/basicsimages/branch_name.png index 06e77f5eea994fb94bc3d4aec8159ec9322d6465..75fe8313611e209fcbd3cdb1e093cc0adb258590 100644 Binary files a/doc/gitlab-basics/basicsimages/branch_name.png and b/doc/gitlab-basics/basicsimages/branch_name.png differ diff --git a/doc/gitlab-basics/basicsimages/branches.png b/doc/gitlab-basics/basicsimages/branches.png index c18fa83b9682bdb4179a5ae628a02c8e3a181883..8621bc05776006f14c1d040f3bc960dda1fe4b84 100644 Binary files a/doc/gitlab-basics/basicsimages/branches.png and b/doc/gitlab-basics/basicsimages/branches.png differ diff --git a/doc/gitlab-basics/basicsimages/button-create-mr.png b/doc/gitlab-basics/basicsimages/button-create-mr.png index 457af459bb9f89a53abea4c550cba1d98dca1aa5..b52ab148839dba8c311790657a0b9d12734743cd 100644 Binary files a/doc/gitlab-basics/basicsimages/button-create-mr.png and b/doc/gitlab-basics/basicsimages/button-create-mr.png differ diff --git a/doc/gitlab-basics/basicsimages/click-on-new-group.png b/doc/gitlab-basics/basicsimages/click-on-new-group.png index 94b6d5756d3c14283a8dce508062c1d4ef9ab73b..6450deec6fc17e0e5a10c2660eb28990d3b09ac2 100644 Binary files a/doc/gitlab-basics/basicsimages/click-on-new-group.png and b/doc/gitlab-basics/basicsimages/click-on-new-group.png differ diff --git a/doc/gitlab-basics/basicsimages/commit_changes.png b/doc/gitlab-basics/basicsimages/commit_changes.png index 81588336f371437533b6dd6ddc87b953006ba5b4..a88809c5a3f7da41c4583fe5824f94e5f3ae14f2 100644 Binary files a/doc/gitlab-basics/basicsimages/commit_changes.png and b/doc/gitlab-basics/basicsimages/commit_changes.png differ diff --git a/doc/gitlab-basics/basicsimages/commit_message.png b/doc/gitlab-basics/basicsimages/commit_message.png index 0df2c32653c4d861fcd7aa5decf9498e8b8080c5..4abe4517f98f426507c7300a67dcd88b50c97279 100644 Binary files a/doc/gitlab-basics/basicsimages/commit_message.png and b/doc/gitlab-basics/basicsimages/commit_message.png differ diff --git a/doc/gitlab-basics/basicsimages/commits.png b/doc/gitlab-basics/basicsimages/commits.png index 7e6065390776e304b5bf3013b9eb185e949a0d41..2bfcaf75f016423bdd28c73a4a643a11774a8267 100644 Binary files a/doc/gitlab-basics/basicsimages/commits.png and b/doc/gitlab-basics/basicsimages/commits.png differ diff --git a/doc/gitlab-basics/basicsimages/compare_branches.png b/doc/gitlab-basics/basicsimages/compare_branches.png index 7eebaed9075079d18cd956b19beea7ff030c9c79..8a18453dd05b7989d178960ec1a0a66a07598d57 100644 Binary files a/doc/gitlab-basics/basicsimages/compare_branches.png and b/doc/gitlab-basics/basicsimages/compare_branches.png differ diff --git a/doc/gitlab-basics/basicsimages/create_file.png b/doc/gitlab-basics/basicsimages/create_file.png index 688e355cca267e467043e0467fb7a78390677b64..5ebe1b227dd56e027d17f4a408e5c2b917550404 100644 Binary files a/doc/gitlab-basics/basicsimages/create_file.png and b/doc/gitlab-basics/basicsimages/create_file.png differ diff --git a/doc/gitlab-basics/basicsimages/create_group.png b/doc/gitlab-basics/basicsimages/create_group.png index 57da898abdc811d8a7a708c706a66073c9f204af..7ecc3baa9900c069663ba8fa8fbce6c60c86af50 100644 Binary files a/doc/gitlab-basics/basicsimages/create_group.png and b/doc/gitlab-basics/basicsimages/create_group.png differ diff --git a/doc/gitlab-basics/basicsimages/edit_file.png b/doc/gitlab-basics/basicsimages/edit_file.png index afa6876010872a86de497c8ccc235879746a8bb3..9d3e817d0363e7fe476c67d312b6abe8db4f193a 100644 Binary files a/doc/gitlab-basics/basicsimages/edit_file.png and b/doc/gitlab-basics/basicsimages/edit_file.png differ diff --git a/doc/gitlab-basics/basicsimages/file_located.png b/doc/gitlab-basics/basicsimages/file_located.png index 1def489d16b2e82835bbe6598da4f19407c3fc30..e357cb5c6ab94e36522b8d554c518b75e71b8600 100644 Binary files a/doc/gitlab-basics/basicsimages/file_located.png and b/doc/gitlab-basics/basicsimages/file_located.png differ diff --git a/doc/gitlab-basics/basicsimages/file_name.png b/doc/gitlab-basics/basicsimages/file_name.png index 9ac2f1c355ff8186d1e7462bcd3f52d3a811be5f..01639c77d0da799cf27cd721b13149de8bdc2b31 100644 Binary files a/doc/gitlab-basics/basicsimages/file_name.png and b/doc/gitlab-basics/basicsimages/file_name.png differ diff --git a/doc/gitlab-basics/basicsimages/find_file.png b/doc/gitlab-basics/basicsimages/find_file.png index 98639149a39353cf8aab8a56ce4da565a2cd76fc..6f26d26ae182c2373763182555f0e11615d2d983 100644 Binary files a/doc/gitlab-basics/basicsimages/find_file.png and b/doc/gitlab-basics/basicsimages/find_file.png differ diff --git a/doc/gitlab-basics/basicsimages/find_group.png b/doc/gitlab-basics/basicsimages/find_group.png index 5ac33c7e9539bcdc49f3dc62838e63934492afbc..1211510aae9b0e927a7476401a4c90071c36fa34 100644 Binary files a/doc/gitlab-basics/basicsimages/find_group.png and b/doc/gitlab-basics/basicsimages/find_group.png differ diff --git a/doc/gitlab-basics/basicsimages/fork.png b/doc/gitlab-basics/basicsimages/fork.png index b1f949386138367ccfe1fd1fe6ada50d4e52db47..13ff834561627dacdc3b12b08fae83dbe65b2ee5 100644 Binary files a/doc/gitlab-basics/basicsimages/fork.png and b/doc/gitlab-basics/basicsimages/fork.png differ diff --git a/doc/gitlab-basics/basicsimages/group_info.png b/doc/gitlab-basics/basicsimages/group_info.png index e78d84e4d800876761baff4ef29d75b901763d6c..2507d6c295b72ffe8a41aa72e68dce014e4d76e2 100644 Binary files a/doc/gitlab-basics/basicsimages/group_info.png and b/doc/gitlab-basics/basicsimages/group_info.png differ diff --git a/doc/gitlab-basics/basicsimages/groups.png b/doc/gitlab-basics/basicsimages/groups.png index b8104343afa096a1fd1cf62a6cd852aa23f7a8a1..ef3dca60cc8f08d681014a1b00ce43e0ed3c27e6 100644 Binary files a/doc/gitlab-basics/basicsimages/groups.png and b/doc/gitlab-basics/basicsimages/groups.png differ diff --git a/doc/gitlab-basics/basicsimages/https.png b/doc/gitlab-basics/basicsimages/https.png index 2a31b4cf751009bd7838cb9f1729c8b1596001dc..e74dbc13f9ad4548543db00d801d8baaac097eee 100644 Binary files a/doc/gitlab-basics/basicsimages/https.png and b/doc/gitlab-basics/basicsimages/https.png differ diff --git a/doc/gitlab-basics/basicsimages/image_file.png b/doc/gitlab-basics/basicsimages/image_file.png index 1061d9c5082d2994acfd49b1fa30b8ba6bc7ec95..7f304b8e1f29fcd64ebbadf7a8f1b8f99f3c4349 100644 Binary files a/doc/gitlab-basics/basicsimages/image_file.png and b/doc/gitlab-basics/basicsimages/image_file.png differ diff --git a/doc/gitlab-basics/basicsimages/issue_title.png b/doc/gitlab-basics/basicsimages/issue_title.png index 7b69c705392a9b64ed851d4c15638554ae31f2aa..60a6f7973be56c4767b30dd19a2695e528f21ffa 100644 Binary files a/doc/gitlab-basics/basicsimages/issue_title.png and b/doc/gitlab-basics/basicsimages/issue_title.png differ diff --git a/doc/gitlab-basics/basicsimages/issues.png b/doc/gitlab-basics/basicsimages/issues.png index 9354d05319e6e994246049e7d86c0d877183bf5a..14e9cdb64e15edc485fbed53f33a2e8ca22e69c5 100644 Binary files a/doc/gitlab-basics/basicsimages/issues.png and b/doc/gitlab-basics/basicsimages/issues.png differ diff --git a/doc/gitlab-basics/basicsimages/key.png b/doc/gitlab-basics/basicsimages/key.png index 321805cda9833ace5a1e94fe5ce01e7967e82486..04400173ce8246804328e90c5a315563cb6ebe2c 100644 Binary files a/doc/gitlab-basics/basicsimages/key.png and b/doc/gitlab-basics/basicsimages/key.png differ diff --git a/doc/gitlab-basics/basicsimages/merge_requests.png b/doc/gitlab-basics/basicsimages/merge_requests.png index 7601d40de478c6573fa165936f0d23cf0cebf87f..570164df18b9d6112d9ae37318f1b5f44770a8c4 100644 Binary files a/doc/gitlab-basics/basicsimages/merge_requests.png and b/doc/gitlab-basics/basicsimages/merge_requests.png differ diff --git a/doc/gitlab-basics/basicsimages/new_merge_request.png b/doc/gitlab-basics/basicsimages/new_merge_request.png index 9120d2b1ab1a31bf149f196c5cf230c2d2b83f9f..842f5ebed74ca85a7f55b06f376b7afd79f6d259 100644 Binary files a/doc/gitlab-basics/basicsimages/new_merge_request.png and b/doc/gitlab-basics/basicsimages/new_merge_request.png differ diff --git a/doc/gitlab-basics/basicsimages/new_project.png b/doc/gitlab-basics/basicsimages/new_project.png index ac255270a66e058bec3b5ee4ae78f61fef0c4aa6..421e8bc247be7f2ecad18b94918623807e7e5469 100644 Binary files a/doc/gitlab-basics/basicsimages/new_project.png and b/doc/gitlab-basics/basicsimages/new_project.png differ diff --git a/doc/gitlab-basics/basicsimages/newbranch.png b/doc/gitlab-basics/basicsimages/newbranch.png index da1a6b604ea5bc657c3d1a9b2841da2ca824a88c..d5fcf33c4ea86b0483414c76ef07cc094118208d 100644 Binary files a/doc/gitlab-basics/basicsimages/newbranch.png and b/doc/gitlab-basics/basicsimages/newbranch.png differ diff --git a/doc/gitlab-basics/basicsimages/paste_sshkey.png b/doc/gitlab-basics/basicsimages/paste_sshkey.png index 9880ddfead1f3cd52fa4c559716c5fa6e9a4247e..578ebee4440f26167a9dc04a50c1b689114e2ed2 100644 Binary files a/doc/gitlab-basics/basicsimages/paste_sshkey.png and b/doc/gitlab-basics/basicsimages/paste_sshkey.png differ diff --git a/doc/gitlab-basics/basicsimages/profile_settings.png b/doc/gitlab-basics/basicsimages/profile_settings.png index 5f2e7a7e10cd762c7f373155714fb2c8264b37a4..cb3f79f1879b185e2ab55edb5a6ded59115678ac 100644 Binary files a/doc/gitlab-basics/basicsimages/profile_settings.png and b/doc/gitlab-basics/basicsimages/profile_settings.png differ diff --git a/doc/gitlab-basics/basicsimages/project_info.png b/doc/gitlab-basics/basicsimages/project_info.png index 6c06ff351facdae030439a883ac95834dd1287cd..e1adb8d48c21c125838f23589715d01c5c2dc6c4 100644 Binary files a/doc/gitlab-basics/basicsimages/project_info.png and b/doc/gitlab-basics/basicsimages/project_info.png differ diff --git a/doc/gitlab-basics/basicsimages/public_file_link.png b/doc/gitlab-basics/basicsimages/public_file_link.png index 1a60a3d880a4e9d7ded0e8b9d74ad445808c12ce..f60df6807f4196138d3264a206bce8528f363887 100644 Binary files a/doc/gitlab-basics/basicsimages/public_file_link.png and b/doc/gitlab-basics/basicsimages/public_file_link.png differ diff --git a/doc/gitlab-basics/basicsimages/select-group.png b/doc/gitlab-basics/basicsimages/select-group.png index d02c2255ff25e0f4b893f593db19a7f4486a2b3c..33b978dd89902255f3e3ee34a1ae4b0e360c9b9c 100644 Binary files a/doc/gitlab-basics/basicsimages/select-group.png and b/doc/gitlab-basics/basicsimages/select-group.png differ diff --git a/doc/gitlab-basics/basicsimages/select-group2.png b/doc/gitlab-basics/basicsimages/select-group2.png index fd40bce499b1aa79ca61930d968b755a3478cc89..aee22c638db37355f418ffbb205bb85c1ca6547f 100644 Binary files a/doc/gitlab-basics/basicsimages/select-group2.png and b/doc/gitlab-basics/basicsimages/select-group2.png differ diff --git a/doc/gitlab-basics/basicsimages/select_branch.png b/doc/gitlab-basics/basicsimages/select_branch.png index 3475b2df57623d4bf492cf9e832df64b22ee3926..f72a3ffb57fc005d4960f685dd94f78b406fcd67 100644 Binary files a/doc/gitlab-basics/basicsimages/select_branch.png and b/doc/gitlab-basics/basicsimages/select_branch.png differ diff --git a/doc/gitlab-basics/basicsimages/select_project.png b/doc/gitlab-basics/basicsimages/select_project.png index 6d5aa4391240eae714520cf2333a63318158fef2..3bb832ea8d001d49adf400264db2ec8cc9973a2e 100644 Binary files a/doc/gitlab-basics/basicsimages/select_project.png and b/doc/gitlab-basics/basicsimages/select_project.png differ diff --git a/doc/gitlab-basics/basicsimages/settings.png b/doc/gitlab-basics/basicsimages/settings.png index 9bf9c5a0d39eb2401b77ac704f198ac4aca9f5fe..78637013d9b2dc05c9c2f7ba06722387a1c101e4 100644 Binary files a/doc/gitlab-basics/basicsimages/settings.png and b/doc/gitlab-basics/basicsimages/settings.png differ diff --git a/doc/gitlab-basics/basicsimages/shh_keys.png b/doc/gitlab-basics/basicsimages/shh_keys.png index d7ef4dafe77d92a10ddf2d58ef4945bb0aa6c022..c87f11a9d3daa2d8b155797bb11b4372bb700130 100644 Binary files a/doc/gitlab-basics/basicsimages/shh_keys.png and b/doc/gitlab-basics/basicsimages/shh_keys.png differ diff --git a/doc/gitlab-basics/basicsimages/submit_new_issue.png b/doc/gitlab-basics/basicsimages/submit_new_issue.png index 1894441708529a7a429090c1c86f5755b2861563..78b854c8903ad855ad626b9aa9f0acb5a6149a3c 100644 Binary files a/doc/gitlab-basics/basicsimages/submit_new_issue.png and b/doc/gitlab-basics/basicsimages/submit_new_issue.png differ diff --git a/doc/gitlab-basics/basicsimages/title_description_mr.png b/doc/gitlab-basics/basicsimages/title_description_mr.png index e08eb628414e102046b086dc31c3015c616395b9..c31d61ec3366800147c3934d854f065165aeedee 100644 Binary files a/doc/gitlab-basics/basicsimages/title_description_mr.png and b/doc/gitlab-basics/basicsimages/title_description_mr.png differ diff --git a/doc/gitlab-basics/basicsimages/white_space.png b/doc/gitlab-basics/basicsimages/white_space.png index 6363a09360e87eb6d2b6ef7eb298848a7565b16b..eaa969bdcf4cdc1fe4ceafb28c62cde36bfac28c 100644 Binary files a/doc/gitlab-basics/basicsimages/white_space.png and b/doc/gitlab-basics/basicsimages/white_space.png differ diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index a2d7e922aadc2b762426f96b373ac978213f09d8..8d2c6351fb8dc608f0d08c18a9a771c0542b3003 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -1,7 +1,7 @@ # External issue tracker GitLab has a great issue tracker but you can also use an external one such as -Jira or Redmine. Issue trackers are configurable per GitLab project and allow +Jira, Redmine, or Bugzilla. Issue trackers are configurable per GitLab project and allow you to do the following: - the **Issues** link on the GitLab project pages takes you to the appropriate @@ -20,6 +20,7 @@ Visit the links below for details: - [Redmine](../project_services/redmine.md) - [Jira](../project_services/jira.md) +- [Bugzilla](../project_services/bugzilla.md) ### Service Template diff --git a/doc/integration/img/akismet_settings.png b/doc/integration/img/akismet_settings.png index ccdd3adb1c57acee6fbd9efc4bd8556815a75676..c2aa97b132e83e0e92a19384757e131a0b106c59 100644 Binary files a/doc/integration/img/akismet_settings.png and b/doc/integration/img/akismet_settings.png differ diff --git a/doc/integration/img/enabled-oauth-sign-in-sources.png b/doc/integration/img/enabled-oauth-sign-in-sources.png index 95f8bbdcd2489c4eb14c100c92dffadf3a1a65fc..b23d6dcc5956ece025eb3c9fd3d530a4857fb542 100644 Binary files a/doc/integration/img/enabled-oauth-sign-in-sources.png and b/doc/integration/img/enabled-oauth-sign-in-sources.png differ diff --git a/doc/integration/img/facebook_api_keys.png b/doc/integration/img/facebook_api_keys.png index d6c44ac0f117feebe69adb17abc31312688a76eb..995845d5a69340b7e35a76b78946236ecb452306 100644 Binary files a/doc/integration/img/facebook_api_keys.png and b/doc/integration/img/facebook_api_keys.png differ diff --git a/doc/integration/img/facebook_app_settings.png b/doc/integration/img/facebook_app_settings.png index 30dd21e198ad480931f4236ddb5f0b014efb12b4..1cd586ecd7c1dc493e4caa323222097c437ba2ba 100644 Binary files a/doc/integration/img/facebook_app_settings.png and b/doc/integration/img/facebook_app_settings.png differ diff --git a/doc/integration/img/facebook_website_url.png b/doc/integration/img/facebook_website_url.png index dc3088bb2faa68b6555f83faee04b04ecc762bf7..10e1bd5d5a61268c64a3ad7a062644fe15ad65fd 100644 Binary files a/doc/integration/img/facebook_website_url.png and b/doc/integration/img/facebook_website_url.png differ diff --git a/doc/integration/img/github_app.png b/doc/integration/img/github_app.png index d890345ced917f2c78ae77dc39c2b66d1362e0d5..de31242679ae4a4825935c47ee3579148badd90c 100644 Binary files a/doc/integration/img/github_app.png and b/doc/integration/img/github_app.png differ diff --git a/doc/integration/img/gitlab_app.png b/doc/integration/img/gitlab_app.png index 3f9391a821bcb2d625e4c8e4db10f1da66168240..065316fd3c79aa6e17601b7faf7f57498c36b9e8 100644 Binary files a/doc/integration/img/gitlab_app.png and b/doc/integration/img/gitlab_app.png differ diff --git a/doc/integration/img/gmail_action_buttons_for_gitlab.png b/doc/integration/img/gmail_action_buttons_for_gitlab.png index b08f54d137bd9ab1bde8471211f95016a9ee6aa0..a6704139091d187107f1f19720f0bb9a48120fb7 100644 Binary files a/doc/integration/img/gmail_action_buttons_for_gitlab.png and b/doc/integration/img/gmail_action_buttons_for_gitlab.png differ diff --git a/doc/integration/img/google_app.png b/doc/integration/img/google_app.png index 5a62ad35009bc7786600408837f96b5c9ed97a07..08f7f7145533869973d6433301709259b9863349 100644 Binary files a/doc/integration/img/google_app.png and b/doc/integration/img/google_app.png differ diff --git a/doc/integration/img/oauth_provider_admin_application.png b/doc/integration/img/oauth_provider_admin_application.png index a2d8e14c1205d751ced539d5c269b391ce01588e..fc5f7596fccc71ae4a240dabf486148acbfa7a8c 100644 Binary files a/doc/integration/img/oauth_provider_admin_application.png and b/doc/integration/img/oauth_provider_admin_application.png differ diff --git a/doc/integration/img/oauth_provider_application_form.png b/doc/integration/img/oauth_provider_application_form.png index 3a676b22393fe3e3d31843ef93d4453c7434f0c8..606ab3e3467a1d3d4d22f4e7364c3f6ce0f380f4 100644 Binary files a/doc/integration/img/oauth_provider_application_form.png and b/doc/integration/img/oauth_provider_application_form.png differ diff --git a/doc/integration/img/oauth_provider_application_id_secret.png b/doc/integration/img/oauth_provider_application_id_secret.png index 6d68df001af5f63476c313a0a52c936ade885e85..cbedcef8376762792e94c85f2b1ee124e9cf1405 100644 Binary files a/doc/integration/img/oauth_provider_application_id_secret.png and b/doc/integration/img/oauth_provider_application_id_secret.png differ diff --git a/doc/integration/img/oauth_provider_authorized_application.png b/doc/integration/img/oauth_provider_authorized_application.png index efc3b807d71f9f15d9b55170f5fe5a6372c3cb14..6a2ea09073c4bcd3df0bf4e79aa5634bfcc652c1 100644 Binary files a/doc/integration/img/oauth_provider_authorized_application.png and b/doc/integration/img/oauth_provider_authorized_application.png differ diff --git a/doc/integration/img/oauth_provider_user_wide_applications.png b/doc/integration/img/oauth_provider_user_wide_applications.png index 45ad8a6d46897bb09677225e243b3607a42f0661..0c7b095a2dd0dcaec0dc8d2790372f6d6f163cde 100644 Binary files a/doc/integration/img/oauth_provider_user_wide_applications.png and b/doc/integration/img/oauth_provider_user_wide_applications.png differ diff --git a/doc/integration/img/twitter_app_api_keys.png b/doc/integration/img/twitter_app_api_keys.png index 1076337172a98c81c09a851ef0f4dc4fbfd0c006..15b29ac7d16a6fd818db2b7d151b8bf9cae57693 100644 Binary files a/doc/integration/img/twitter_app_api_keys.png and b/doc/integration/img/twitter_app_api_keys.png differ diff --git a/doc/integration/img/twitter_app_details.png b/doc/integration/img/twitter_app_details.png index b95e8af8a74eb7e7a9455d7ef9fafdf339a9627f..323112a88bbe71aed499503c9cade3d453572445 100644 Binary files a/doc/integration/img/twitter_app_details.png and b/doc/integration/img/twitter_app_details.png differ diff --git a/doc/markdown/img/logo.png b/doc/markdown/img/logo.png index 7da5f23ed9bfa713c51b275987e464f15570fe40..05c8b0d0ccfdcefe43cdb1dae5e6fa0fa8366dae 100644 Binary files a/doc/markdown/img/logo.png and b/doc/markdown/img/logo.png differ diff --git a/doc/monitoring/img/health_check_token.png b/doc/monitoring/img/health_check_token.png index 2daf8606b009aedda120af03baa13c36a195f07d..2d7c82a65a8c96af2e3f8bc686698829a88b04b1 100644 Binary files a/doc/monitoring/img/health_check_token.png and b/doc/monitoring/img/health_check_token.png differ diff --git a/doc/monitoring/performance/img/grafana_dashboard_dropdown.png b/doc/monitoring/performance/img/grafana_dashboard_dropdown.png index b4448c7a09f42f3480f8bfbd513cfb8bd7dbfe3c..7e34fad71ce6ef121704f909617c827e7f706967 100644 Binary files a/doc/monitoring/performance/img/grafana_dashboard_dropdown.png and b/doc/monitoring/performance/img/grafana_dashboard_dropdown.png differ diff --git a/doc/monitoring/performance/img/grafana_dashboard_import.png b/doc/monitoring/performance/img/grafana_dashboard_import.png index 5a2d3c0937a8d0fda014c65e079ccd987800982a..f97624365c70d63dd24ef54ef578882b0081403e 100644 Binary files a/doc/monitoring/performance/img/grafana_dashboard_import.png and b/doc/monitoring/performance/img/grafana_dashboard_import.png differ diff --git a/doc/monitoring/performance/img/grafana_data_source_configuration.png b/doc/monitoring/performance/img/grafana_data_source_configuration.png index 7e2e111f570468652fdbf3f96be0b0387de6fb28..7d50e4c88c206027caadd602a7505ad31f8252a6 100644 Binary files a/doc/monitoring/performance/img/grafana_data_source_configuration.png and b/doc/monitoring/performance/img/grafana_data_source_configuration.png differ diff --git a/doc/monitoring/performance/img/grafana_data_source_empty.png b/doc/monitoring/performance/img/grafana_data_source_empty.png index 11e27571e64a4cff578c5ad7311f95d7ae10d54c..aa39a53acaeec2ac38f2d18f0cae31c58dd9c166 100644 Binary files a/doc/monitoring/performance/img/grafana_data_source_empty.png and b/doc/monitoring/performance/img/grafana_data_source_empty.png differ diff --git a/doc/monitoring/performance/img/grafana_save_icon.png b/doc/monitoring/performance/img/grafana_save_icon.png index 3d4265bee8e08e369f0ac0de9221835a214553a3..c740e33cd1c3bc105f247dcbec3d42a0a632dfd1 100644 Binary files a/doc/monitoring/performance/img/grafana_save_icon.png and b/doc/monitoring/performance/img/grafana_save_icon.png differ diff --git a/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png b/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png index 14d82b6ac98c5c942b93a83d17f6f82987a5c7b3..e6ed45a0386a7da94f95ccdbabd0ec6654506905 100644 Binary files a/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png and b/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png differ diff --git a/doc/profile/2fa.png b/doc/profile/2fa.png index bbf415210d5c0b188571171687eac948b2d25039..bb464efa68562fc54bb1f7f0e3a9eca3c5d2f245 100644 Binary files a/doc/profile/2fa.png and b/doc/profile/2fa.png differ diff --git a/doc/profile/2fa_auth.png b/doc/profile/2fa_auth.png index 4a4fbe68984ec41ddce3e90d4963ca1dc24c9aaf..0caaed10805d3cfa92c7f95773eb58f279696fa3 100644 Binary files a/doc/profile/2fa_auth.png and b/doc/profile/2fa_auth.png differ diff --git a/doc/project_services/bugzilla.md b/doc/project_services/bugzilla.md new file mode 100644 index 0000000000000000000000000000000000000000..215ed6fe9cc4f45677846843eb6c9d2ed9a44c94 --- /dev/null +++ b/doc/project_services/bugzilla.md @@ -0,0 +1,17 @@ +# Bugzilla Service + +Go to your project's **Settings > Services > Bugzilla** and fill in the required +details as described in the table below. + +| Field | Description | +| ----- | ----------- | +| `description` | A name for the issue tracker (to differentiate between instances, for example) | +| `project_url` | The URL to the project in Bugzilla which is being linked to this GitLab project. Note that the `project_url` requires PRODUCT_NAME to be updated with the product/project name in Bugzilla. | +| `issues_url` | The URL to the issue in Bugzilla project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. | +| `new_issue_url` | This is the URL to create a new issue in Bugzilla for the project linked to this GitLab project. Note that the `new_issue_url` requires PRODUCT_NAME to be updated with the product/project name in Bugzilla. | + +Once you have configured and enabled Bugzilla: + +- the **Issues** link on the GitLab project pages takes you to the appropriate + Bugzilla product page +- clicking **New issue** on the project dashboard takes you to Bugzilla for entering a new issue diff --git a/doc/project_services/img/builds_emails_service.png b/doc/project_services/img/builds_emails_service.png index e604dd73ffa1b54add10dc330572468af4c50445..88943dc410e8ad8a7edee5ff3dcc7d162ab00390 100644 Binary files a/doc/project_services/img/builds_emails_service.png and b/doc/project_services/img/builds_emails_service.png differ diff --git a/doc/project_services/img/jira_add_gitlab_commit_message.png b/doc/project_services/img/jira_add_gitlab_commit_message.png index 85e54861b3e830a1712c70548835c64ae9b63e19..aec472b911896de0354ca560a148ccca7f8b82fb 100644 Binary files a/doc/project_services/img/jira_add_gitlab_commit_message.png and b/doc/project_services/img/jira_add_gitlab_commit_message.png differ diff --git a/doc/project_services/img/jira_add_user_to_group.png b/doc/project_services/img/jira_add_user_to_group.png index e4576433889c8bbb28810e72481cbed6eed5154e..0ba737bda9a713c4ac57fe795c10b1af133a8dde 100644 Binary files a/doc/project_services/img/jira_add_user_to_group.png and b/doc/project_services/img/jira_add_user_to_group.png differ diff --git a/doc/project_services/img/jira_create_new_group.png b/doc/project_services/img/jira_create_new_group.png index edaa132605833816be8c85498a482f263f0c0bd5..0609060cb05c4d5827efdc9d685186ade64bbbf6 100644 Binary files a/doc/project_services/img/jira_create_new_group.png and b/doc/project_services/img/jira_create_new_group.png differ diff --git a/doc/project_services/img/jira_create_new_group_name.png b/doc/project_services/img/jira_create_new_group_name.png index 9e518ad7843e658855c2f4f246f0425eaccbec25..53d77b17df0168ecb2e2f037129f865d0549edcd 100644 Binary files a/doc/project_services/img/jira_create_new_group_name.png and b/doc/project_services/img/jira_create_new_group_name.png differ diff --git a/doc/project_services/img/jira_create_new_user.png b/doc/project_services/img/jira_create_new_user.png index 57e433dd8184786120e6301bbbea2ed39e029342..9eaa444ed25b9b17e12a311a77a36bba023368aa 100644 Binary files a/doc/project_services/img/jira_create_new_user.png and b/doc/project_services/img/jira_create_new_user.png differ diff --git a/doc/project_services/img/jira_group_access.png b/doc/project_services/img/jira_group_access.png index 47716ca6d0e782e7e17900140a01826ec7825285..8d4657427ae206efea0da2ee8a4b0a50196f576f 100644 Binary files a/doc/project_services/img/jira_group_access.png and b/doc/project_services/img/jira_group_access.png differ diff --git a/doc/project_services/img/jira_issue_closed.png b/doc/project_services/img/jira_issue_closed.png index cabec1ae137cd264dc3fa3924cebb7a6338a711b..acdd83702d3e29ce8506147f55682a141c287a26 100644 Binary files a/doc/project_services/img/jira_issue_closed.png and b/doc/project_services/img/jira_issue_closed.png differ diff --git a/doc/project_services/img/jira_issue_reference.png b/doc/project_services/img/jira_issue_reference.png index 15739a22dc7151af663316c1d44e8fcda704ce29..1a2d9f04a6c6bca62bb4e79ee3293ddc22b99739 100644 Binary files a/doc/project_services/img/jira_issue_reference.png and b/doc/project_services/img/jira_issue_reference.png differ diff --git a/doc/project_services/img/jira_issues_workflow.png b/doc/project_services/img/jira_issues_workflow.png index 28e17be3a84371f41cd8d44b869ad01ea655ee87..0703081d77b702abe072e08d3ecd99c7400c5982 100644 Binary files a/doc/project_services/img/jira_issues_workflow.png and b/doc/project_services/img/jira_issues_workflow.png differ diff --git a/doc/project_services/img/jira_merge_request_close.png b/doc/project_services/img/jira_merge_request_close.png index 1e78daf105f8936d048d3e0e37841e1877f4508a..47785e3ba27de9bc9c52a8d39406e6e0e1207144 100644 Binary files a/doc/project_services/img/jira_merge_request_close.png and b/doc/project_services/img/jira_merge_request_close.png differ diff --git a/doc/project_services/img/jira_project_name.png b/doc/project_services/img/jira_project_name.png index 5986fdb63fb8727b339b69d7fa6b64d3ef5f4b17..e785ec6140d4c69943a7c705d886515ce6ad2fa2 100644 Binary files a/doc/project_services/img/jira_project_name.png and b/doc/project_services/img/jira_project_name.png differ diff --git a/doc/project_services/img/jira_reference_commit_message_in_jira_issue.png b/doc/project_services/img/jira_reference_commit_message_in_jira_issue.png index 0149181dc86a26643bbf49ded08a045580bc2518..fb270d85e3c9c4dc05f7ddb2d9b0fbb44ad3593b 100644 Binary files a/doc/project_services/img/jira_reference_commit_message_in_jira_issue.png and b/doc/project_services/img/jira_reference_commit_message_in_jira_issue.png differ diff --git a/doc/project_services/img/jira_service.png b/doc/project_services/img/jira_service.png index 1f6628c43719edd55d415f80d28d8d4423002586..13aefce6f84628fa4e0bb05c674a96a6e12e4948 100644 Binary files a/doc/project_services/img/jira_service.png and b/doc/project_services/img/jira_service.png differ diff --git a/doc/project_services/img/jira_service_close_issue.png b/doc/project_services/img/jira_service_close_issue.png index 67dfc6144c44f0643e1373bef9961bf0c3a458fb..eed69e80d2c585939ccb82a37b2bb0a04b5ceb1c 100644 Binary files a/doc/project_services/img/jira_service_close_issue.png and b/doc/project_services/img/jira_service_close_issue.png differ diff --git a/doc/project_services/img/jira_service_page.png b/doc/project_services/img/jira_service_page.png index c225daa81e18d6c7e2ff26e30d7695fe218b2e1e..a5b49c501bab09d007c77221c3ed99e228f77b87 100644 Binary files a/doc/project_services/img/jira_service_page.png and b/doc/project_services/img/jira_service_page.png differ diff --git a/doc/project_services/img/jira_submit_gitlab_merge_request.png b/doc/project_services/img/jira_submit_gitlab_merge_request.png index e935d9362aacd90616ee5fd2ce00fa12d1e56617..77630d39d39ef81c5c5258d4ed454d37048b6a59 100644 Binary files a/doc/project_services/img/jira_submit_gitlab_merge_request.png and b/doc/project_services/img/jira_submit_gitlab_merge_request.png differ diff --git a/doc/project_services/img/jira_user_management_link.png b/doc/project_services/img/jira_user_management_link.png index 2745916972c87697e6e006ca5ba2737c433d8b64..5f002b59bac3ad76482355ac4534a1c297e3c636 100644 Binary files a/doc/project_services/img/jira_user_management_link.png and b/doc/project_services/img/jira_user_management_link.png differ diff --git a/doc/project_services/img/jira_workflow_screenshot.png b/doc/project_services/img/jira_workflow_screenshot.png index 8635a32eb6874fa64bc53ba671794c20e9df2f00..937a50a77d90e84e8bab18831ae0e0feed54b61e 100644 Binary files a/doc/project_services/img/jira_workflow_screenshot.png and b/doc/project_services/img/jira_workflow_screenshot.png differ diff --git a/doc/project_services/img/redmine_configuration.png b/doc/project_services/img/redmine_configuration.png index d14e526ad336d56ba5fcf6024e30e31b55d4fa3c..e9d8c0d2da81c224e88733a897aab6ec671ecd1c 100644 Binary files a/doc/project_services/img/redmine_configuration.png and b/doc/project_services/img/redmine_configuration.png differ diff --git a/doc/project_services/img/services_templates_redmine_example.png b/doc/project_services/img/services_templates_redmine_example.png index 384d057fc8ef9255a957ac339d043475f102aa34..77c2b98e5d03eac41209a9fb1893af43d23056cc 100644 Binary files a/doc/project_services/img/services_templates_redmine_example.png and b/doc/project_services/img/services_templates_redmine_example.png differ diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md index f81a035f70b2cad13ed8b0d3936e6fb1a47d47cf..e15d5db3253e0860321b46de8fc8ad50cdf80119 100644 --- a/doc/project_services/project_services.md +++ b/doc/project_services/project_services.md @@ -30,6 +30,7 @@ further configuration instructions and details. Contributions are welcome. | [Atlassian Bamboo CI](bamboo.md) | A continuous integration and build server | | Buildkite | Continuous integration and deployments | | [Builds emails](builds_emails.md) | Email the builds status to a list of recipients | +| [Bugzilla](bugzilla.md) | Bugzilla issue tracker | | Campfire | Simple web-based real-time group chat | | Custom Issue Tracker | Custom issue tracker | | Drone CI | Continuous Integration platform built on Docker, written in Go | diff --git a/doc/raketasks/backup_hrz.png b/doc/raketasks/backup_hrz.png index 03e50df1d76e57a667770b062a82898a6fa34d6b..42084717ebe249e49fd9ac6574ef65f2868bb2ab 100644 Binary files a/doc/raketasks/backup_hrz.png and b/doc/raketasks/backup_hrz.png differ diff --git a/doc/raketasks/check_repos_output.png b/doc/raketasks/check_repos_output.png index 916b16851018bd6de0258f465e6e125ea56d1e0c..1f632566b0071899a435f1f11a66b0dd3cbffcd7 100644 Binary files a/doc/raketasks/check_repos_output.png and b/doc/raketasks/check_repos_output.png differ diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md index 8a38937062e003b658d54d081539f00029735543..2b305cb5c991f7cb83eed7c37d171509e9e3ad4c 100644 --- a/doc/raketasks/import.md +++ b/doc/raketasks/import.md @@ -14,7 +14,8 @@ - For omnibus-gitlab, it is located at: `/var/opt/gitlab/git-data/repositories` by default, unless you changed it in the `/etc/gitlab/gitlab.rb` file. - For installations from source, it is usually located at: `/home/git/repositories` or you can see where -your repositories are located by looking at `config/gitlab.yml` under the `gitlab_shell => repos_path` entry. +your repositories are located by looking at `config/gitlab.yml` under the `repositories => storages` entries +(you'll usually use the `default` storage path to start). New folder needs to have git user ownership and read/write/execute access for git user and its group: diff --git a/doc/security/img/two_factor_authentication_settings.png b/doc/security/img/two_factor_authentication_settings.png index aa51ce030bb77346686f49633b67c3a2b262481e..6af5feabb133cb28f088ccddf6702cab1cfe2ea4 100644 Binary files a/doc/security/img/two_factor_authentication_settings.png and b/doc/security/img/two_factor_authentication_settings.png differ diff --git a/doc/update/8.8-to-8.9.md b/doc/update/8.8-to-8.9.md index f14046bb4be5595069833c8e475375bb930078be..423140a92c7bd515c1b496d93ffd46d8c4a762d7 100644 --- a/doc/update/8.8-to-8.9.md +++ b/doc/update/8.8-to-8.9.md @@ -122,6 +122,19 @@ via [/etc/default/gitlab]. [Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache [/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-9-stable/lib/support/init.d/gitlab.default.example#L37 +#### SMTP configuration + +If you're installing from source and use SMTP to deliver mail, you will need to add the following line +to config/initializers/smtp_settings.rb: + +```ruby +ActionMailer::Base.delivery_method = :smtp +``` + +See [smtp_settings.rb.sample] as an example. + +[smtp_settings.rb.sample]: https://gitlab.com/gitlab-org/gitlab-ce/blob/v8.9.0/config/initializers/smtp_settings.rb.sample#L13 + #### Init script Ensure you're still up-to-date with the latest init script changes: diff --git a/doc/user/project/highlighting.md b/doc/user/project/highlighting.md new file mode 100644 index 0000000000000000000000000000000000000000..73a2d176b54959b1cd6802fbf55ca124faf4ad12 --- /dev/null +++ b/doc/user/project/highlighting.md @@ -0,0 +1,31 @@ +[Rouge]: https://rubygems.org/gems/rouge + +# Syntax Highlighting + +GitLab provides syntax highlighting on all files and snippets through the [Rouge][] rubygem. It will try to guess what language to use based on the file extension, which most of the time is sufficient. + +If GitLab is guessing wrong, you can override its choice of language using the `gitlab-language` attribute in `.gitattributes`. For example, if you are working in a Prolog project and using the `.pl` file extension (which would normally be highlighted as Perl), you can add the following to your `.gitattributes` file: + +``` conf +*.pl gitlab-language=prolog +``` + +When you check in and push that change, all `*.pl` files in your project will be highlighted as Prolog. + +The paths here are simply git's builtin [`.gitattributes` interface](https://git-scm.com/docs/gitattributes). So, if you were to invent a file format called a `Nicefile` at the root of your project that used ruby syntax, all you need is: + +``` conf +/Nicefile gitlab-language=ruby +``` + +To disable highlighting entirely, use `gitlab-language=text`. Lots more fun shenanigans are available through CGI options, such as: + +``` conf +# json with erb in it +/my-cool-file gitlab-language=erb?parent=json + +# an entire file of highlighting errors! +/other-file gitlab-language=text?token=Error +``` + +Please note that these configurations will only take effect when the `.gitattributes` file is in your default branch (usually `master`). diff --git a/doc/web_hooks/ssl.png b/doc/web_hooks/ssl.png index 698f1a0f64a881ea9cf74eea8e116e763b8741ed..8c4f08d18256eb76ad146d133e67aea3dcef8c55 100644 Binary files a/doc/web_hooks/ssl.png and b/doc/web_hooks/ssl.png differ diff --git a/doc/workflow/add-user/img/add_new_user_to_project_settings.png b/doc/workflow/add-user/img/add_new_user_to_project_settings.png index 3da18cdae53724d01439c3dfebcdc9cad35ab4c1..5da0552f9d65764bf7960f6ce7a854470c8e9aa4 100644 Binary files a/doc/workflow/add-user/img/add_new_user_to_project_settings.png and b/doc/workflow/add-user/img/add_new_user_to_project_settings.png differ diff --git a/doc/workflow/add-user/img/add_user_email_accept.png b/doc/workflow/add-user/img/add_user_email_accept.png index 18aabf93d50bd9d5b24a9f5d9ce4b4491d19b01f..a2954ad7c37fefe0a2a62a8af1e5e912ab592255 100644 Binary files a/doc/workflow/add-user/img/add_user_email_accept.png and b/doc/workflow/add-user/img/add_user_email_accept.png differ diff --git a/doc/workflow/add-user/img/add_user_email_ready.png b/doc/workflow/add-user/img/add_user_email_ready.png index 385d64330c0a14fb2046683db3ba9ccd050ba095..19d91bc09993afbd6909a491f18e775b409e37a0 100644 Binary files a/doc/workflow/add-user/img/add_user_email_ready.png and b/doc/workflow/add-user/img/add_user_email_ready.png differ diff --git a/doc/workflow/add-user/img/add_user_email_search.png b/doc/workflow/add-user/img/add_user_email_search.png index 84741edbca405049c15e9b3e07054279bfb53918..cb31b77d941d18ef3607a80f3e6c288c3cb6ed78 100644 Binary files a/doc/workflow/add-user/img/add_user_email_search.png and b/doc/workflow/add-user/img/add_user_email_search.png differ diff --git a/doc/workflow/add-user/img/add_user_give_permissions.png b/doc/workflow/add-user/img/add_user_give_permissions.png index 7e580384e54566c504b70137059de04a1edb5607..e6b77022f06a635d5b90d51dd7bf7799ed52cf66 100644 Binary files a/doc/workflow/add-user/img/add_user_give_permissions.png and b/doc/workflow/add-user/img/add_user_give_permissions.png differ diff --git a/doc/workflow/add-user/img/add_user_import_members_from_another_project.png b/doc/workflow/add-user/img/add_user_import_members_from_another_project.png index 8dbd73a5bc82a294b44a592461fdc9f4279a2f40..1068589c5ff3ac763b021a08e6b0db79596e94e1 100644 Binary files a/doc/workflow/add-user/img/add_user_import_members_from_another_project.png and b/doc/workflow/add-user/img/add_user_import_members_from_another_project.png differ diff --git a/doc/workflow/add-user/img/add_user_imported_members.png b/doc/workflow/add-user/img/add_user_imported_members.png index abac1f59c026baaf201fd0977f21528b6768441c..5cd120a424504be9458f358b9bd6ebc841c07792 100644 Binary files a/doc/workflow/add-user/img/add_user_imported_members.png and b/doc/workflow/add-user/img/add_user_imported_members.png differ diff --git a/doc/workflow/add-user/img/add_user_list_members.png b/doc/workflow/add-user/img/add_user_list_members.png index e17d88c6f5f964ec47c1afbdd1ac2b1076ac542b..5fe3482192ef10a3ff0acbffe914018867e1b948 100644 Binary files a/doc/workflow/add-user/img/add_user_list_members.png and b/doc/workflow/add-user/img/add_user_list_members.png differ diff --git a/doc/workflow/add-user/img/add_user_members_menu.png b/doc/workflow/add-user/img/add_user_members_menu.png index ec5d39f402d92dfdfd98215707afd3113a45e63a..340d15c9830ba5cadec05b69a271f32443ad845d 100644 Binary files a/doc/workflow/add-user/img/add_user_members_menu.png and b/doc/workflow/add-user/img/add_user_members_menu.png differ diff --git a/doc/workflow/add-user/img/add_user_search_people.png b/doc/workflow/add-user/img/add_user_search_people.png index eaa062376f45d7ae71cd04d942a0526a0fe60cc4..1c05d70ca31435850b32b7c58e8b9206b06551c2 100644 Binary files a/doc/workflow/add-user/img/add_user_search_people.png and b/doc/workflow/add-user/img/add_user_search_people.png differ diff --git a/doc/workflow/award_emoji.png b/doc/workflow/award_emoji.png index 3408ed958410029f682b4c5932e5977b6fefdba1..481680af80c71c033d0d38dc73eb212b3a0a63bd 100644 Binary files a/doc/workflow/award_emoji.png and b/doc/workflow/award_emoji.png differ diff --git a/doc/workflow/ci_mr.png b/doc/workflow/ci_mr.png index a577356f8e899d55dab9b9137010ac23320cd762..f8a7708643e3cc1c98d2b49094200285ca54f9c8 100644 Binary files a/doc/workflow/ci_mr.png and b/doc/workflow/ci_mr.png differ diff --git a/doc/workflow/close_issue_mr.png b/doc/workflow/close_issue_mr.png index a136d642e125a782c8058417ff808b98159c0899..5e5202402336bcf50609857c91c15398fc57b86c 100644 Binary files a/doc/workflow/close_issue_mr.png and b/doc/workflow/close_issue_mr.png differ diff --git a/doc/workflow/environment_branches.png b/doc/workflow/environment_branches.png index ee893ced13bd764322cc4195945403731508c9cb..13fb0478eaad7a4a6f7a423b1be8c520437da889 100644 Binary files a/doc/workflow/environment_branches.png and b/doc/workflow/environment_branches.png differ diff --git a/doc/workflow/forking/branch_select.png b/doc/workflow/forking/branch_select.png index 275f64d113baa4800fe6a49c366d5bb3c1237068..7f19414f3a90439de69ac9fa831d402075979122 100644 Binary files a/doc/workflow/forking/branch_select.png and b/doc/workflow/forking/branch_select.png differ diff --git a/doc/workflow/forking/merge_request.png b/doc/workflow/forking/merge_request.png index 2dc00ed08a1df18629be937740f32ef35abbb87f..e2da42a2be7657f7b37ef71246d8bcb023c3dc79 100644 Binary files a/doc/workflow/forking/merge_request.png and b/doc/workflow/forking/merge_request.png differ diff --git a/doc/workflow/four_stages.png b/doc/workflow/four_stages.png index 2f444fc6f7967772980948dfec8f779a204bf915..49413087dcad51bda413bb62c188b943da85fe78 100644 Binary files a/doc/workflow/four_stages.png and b/doc/workflow/four_stages.png differ diff --git a/doc/workflow/git_pull.png b/doc/workflow/git_pull.png index 7d47064eb14176ccc23e472cbf1d9ea34f90d91f..9a1fdf899bfae40dc6209fcf49d46ec45aad1f68 100644 Binary files a/doc/workflow/git_pull.png and b/doc/workflow/git_pull.png differ diff --git a/doc/workflow/gitdashflow.png b/doc/workflow/gitdashflow.png index f2f091dd10b1b63a911977cdc4c059ac2f1925e6..e456cf9309da507fd868d6cd36c0f8d9a2a67b1f 100644 Binary files a/doc/workflow/gitdashflow.png and b/doc/workflow/gitdashflow.png differ diff --git a/doc/workflow/github_flow.png b/doc/workflow/github_flow.png index 88addb623ee0e554345dfbbde879e464befae85d..b3fca97cc2ddb362de4567a05ae8618db4a0c77d 100644 Binary files a/doc/workflow/github_flow.png and b/doc/workflow/github_flow.png differ diff --git a/doc/workflow/gitlab_flow.png b/doc/workflow/gitlab_flow.png index 1ea191a672b7cb177687cfa6e93dca43af8b8c55..d85d4ff374e82f1a81a2c54c986baaf98ba4d9ae 100644 Binary files a/doc/workflow/gitlab_flow.png and b/doc/workflow/gitlab_flow.png differ diff --git a/doc/workflow/good_commit.png b/doc/workflow/good_commit.png index 3737a0266445e6714980a693a7b031e678ad841a..7958feea4d9c83521268e0a92d1af8ed8703ce15 100644 Binary files a/doc/workflow/good_commit.png and b/doc/workflow/good_commit.png differ diff --git a/doc/workflow/groups/add_member_to_group.png b/doc/workflow/groups/add_member_to_group.png index fa340ce572f0804186abc0454c682bf16ebb524e..6e3f660d2e46ce427cb3837748826225acfb4523 100644 Binary files a/doc/workflow/groups/add_member_to_group.png and b/doc/workflow/groups/add_member_to_group.png differ diff --git a/doc/workflow/groups/group_dashboard.png b/doc/workflow/groups/group_dashboard.png index 7fc9048d74d6f59798693bebd219060db1a82755..662c932e536bca2c233dc938efcdfbe7949f0655 100644 Binary files a/doc/workflow/groups/group_dashboard.png and b/doc/workflow/groups/group_dashboard.png differ diff --git a/doc/workflow/groups/group_with_two_projects.png b/doc/workflow/groups/group_with_two_projects.png index 87242781e4fd492a85adf0f13a9679296808d5b1..dc3475949f54a400017235f8d61d9f4b3d153095 100644 Binary files a/doc/workflow/groups/group_with_two_projects.png and b/doc/workflow/groups/group_with_two_projects.png differ diff --git a/doc/workflow/groups/max_access_level.png b/doc/workflow/groups/max_access_level.png index 71106a8a5a0d4fc4f358a6777b50809511e6038e..2855a514013b2935682c2a22f1b5270073cf747f 100644 Binary files a/doc/workflow/groups/max_access_level.png and b/doc/workflow/groups/max_access_level.png differ diff --git a/doc/workflow/groups/new_group_button.png b/doc/workflow/groups/new_group_button.png index 51e827986586ca471c99999680f0688459124c13..26136312c8fa8321b345b49eb8402573a17aaf6b 100644 Binary files a/doc/workflow/groups/new_group_button.png and b/doc/workflow/groups/new_group_button.png differ diff --git a/doc/workflow/groups/new_group_form.png b/doc/workflow/groups/new_group_form.png index bf992c40bc2b08fc1d70783552871480a263bedb..dc50a069ef21fdc171cafba7c61fde2c323d2941 100644 Binary files a/doc/workflow/groups/new_group_form.png and b/doc/workflow/groups/new_group_form.png differ diff --git a/doc/workflow/groups/other_group_sees_shared_project.png b/doc/workflow/groups/other_group_sees_shared_project.png index cbf2c3c1fdc80ae5c0e6af976938a0fe49edaff1..2230720cecdb0a5da822e915f050184ffa12243f 100644 Binary files a/doc/workflow/groups/other_group_sees_shared_project.png and b/doc/workflow/groups/other_group_sees_shared_project.png differ diff --git a/doc/workflow/groups/override_access_level.png b/doc/workflow/groups/override_access_level.png index f4225a63679324d1d6c4a1093163a8b0b2bd67c0..9d6aaf4c363134071e385d797354959021231d84 100644 Binary files a/doc/workflow/groups/override_access_level.png and b/doc/workflow/groups/override_access_level.png differ diff --git a/doc/workflow/groups/project_members_via_group.png b/doc/workflow/groups/project_members_via_group.png index b13cb1cfd9528a501d2ee2a6802f77ed365fadb5..58270936a0ba9fd6dd073d22886b68d6b1453f12 100644 Binary files a/doc/workflow/groups/project_members_via_group.png and b/doc/workflow/groups/project_members_via_group.png differ diff --git a/doc/workflow/groups/share_project_with_groups.png b/doc/workflow/groups/share_project_with_groups.png index a5dbc89fe90870bb66ae04b436da94493549a7fe..5772d4deced8097fed945c06c6e41450b677aab7 100644 Binary files a/doc/workflow/groups/share_project_with_groups.png and b/doc/workflow/groups/share_project_with_groups.png differ diff --git a/doc/workflow/groups/transfer_project.png b/doc/workflow/groups/transfer_project.png index 044fe10d07337adedd8078f26bf42e0b4381eaab..0aef3ab3f0fbb83da4eb7ea1664d73d8645fb132 100644 Binary files a/doc/workflow/groups/transfer_project.png and b/doc/workflow/groups/transfer_project.png differ diff --git a/doc/workflow/img/award_emoji_select.png b/doc/workflow/img/award_emoji_select.png index fffdfedda5d7536fbc083cde4efac8e489bedf52..ad664c0aeff4b90a256ed16ea250e634ec0f8c9b 100644 Binary files a/doc/workflow/img/award_emoji_select.png and b/doc/workflow/img/award_emoji_select.png differ diff --git a/doc/workflow/img/award_emoji_votes_least_popular.png b/doc/workflow/img/award_emoji_votes_least_popular.png index 2ef5be7154f020d0a6e775abae42d4cb7a961b02..57d595d9602c6b77e0a1ba59e1c96159b2a03211 100644 Binary files a/doc/workflow/img/award_emoji_votes_least_popular.png and b/doc/workflow/img/award_emoji_votes_least_popular.png differ diff --git a/doc/workflow/img/award_emoji_votes_most_popular.png b/doc/workflow/img/award_emoji_votes_most_popular.png index 5b089730d936cff3788200889216eb85ff625654..432bd09b8a71e650ad0c0ffe6ad6226be821a3fd 100644 Binary files a/doc/workflow/img/award_emoji_votes_most_popular.png and b/doc/workflow/img/award_emoji_votes_most_popular.png differ diff --git a/doc/workflow/img/award_emoji_votes_sort_options.png b/doc/workflow/img/award_emoji_votes_sort_options.png index 9bbf3f82a0bdda442f3e908ebaa4d85a2fd78c8a..ae6e224b317721910c9a123be80600b97ca53f7a 100644 Binary files a/doc/workflow/img/award_emoji_votes_sort_options.png and b/doc/workflow/img/award_emoji_votes_sort_options.png differ diff --git a/doc/workflow/img/cherry_pick_changes_commit.png b/doc/workflow/img/cherry_pick_changes_commit.png index ae91d2cae53c5fe25b791ff415a6b436e33e2e0f..7fb68cc9e9b5b82c27971195d43e0ee4c0509b56 100644 Binary files a/doc/workflow/img/cherry_pick_changes_commit.png and b/doc/workflow/img/cherry_pick_changes_commit.png differ diff --git a/doc/workflow/img/cherry_pick_changes_commit_modal.png b/doc/workflow/img/cherry_pick_changes_commit_modal.png index f502f87677a233f96b2fcfc101404cd01f51f83f..5267e04562f9b3dc0a35384aae15da8b302138c9 100644 Binary files a/doc/workflow/img/cherry_pick_changes_commit_modal.png and b/doc/workflow/img/cherry_pick_changes_commit_modal.png differ diff --git a/doc/workflow/img/cherry_pick_changes_mr.png b/doc/workflow/img/cherry_pick_changes_mr.png index 59c610e620be5f531f6fbc4b2771dc41cb47be7a..975fb13e463b5608434bbbb217f12a58d153d9e9 100644 Binary files a/doc/workflow/img/cherry_pick_changes_mr.png and b/doc/workflow/img/cherry_pick_changes_mr.png differ diff --git a/doc/workflow/img/cherry_pick_changes_mr_modal.png b/doc/workflow/img/cherry_pick_changes_mr_modal.png index 96a80f4726de8be7ef0b78c15029484694738d87..6c003bacbe36b6dce488885e192fb50090b55fa0 100644 Binary files a/doc/workflow/img/cherry_pick_changes_mr_modal.png and b/doc/workflow/img/cherry_pick_changes_mr_modal.png differ diff --git a/doc/workflow/img/file_finder_find_button.png b/doc/workflow/img/file_finder_find_button.png index c5005d0d7cab1799875f75a55f74774560eb9a65..96e383f02130314c85726af8a3ec45d909be5b02 100644 Binary files a/doc/workflow/img/file_finder_find_button.png and b/doc/workflow/img/file_finder_find_button.png differ diff --git a/doc/workflow/img/file_finder_find_file.png b/doc/workflow/img/file_finder_find_file.png index 58500f4c163fbbe6e7889eb69a975aec95bfe2f3..c6508514c7659d0d49549f6809a052d5faa64a25 100644 Binary files a/doc/workflow/img/file_finder_find_file.png and b/doc/workflow/img/file_finder_find_file.png differ diff --git a/doc/workflow/img/forking_workflow_choose_namespace.png b/doc/workflow/img/forking_workflow_choose_namespace.png index eefe57695547cf1719b2f748710fe0937ad8d38a..1839d5e8be2905c45448a27b19228936cac5350e 100644 Binary files a/doc/workflow/img/forking_workflow_choose_namespace.png and b/doc/workflow/img/forking_workflow_choose_namespace.png differ diff --git a/doc/workflow/img/forking_workflow_fork_button.png b/doc/workflow/img/forking_workflow_fork_button.png index 49e68d33e89084f04c9c96ff8f85c08beba5ec30..cc79d6fd40c326483ceaa2dc5a4decfaddbbbc93 100644 Binary files a/doc/workflow/img/forking_workflow_fork_button.png and b/doc/workflow/img/forking_workflow_fork_button.png differ diff --git a/doc/workflow/img/forking_workflow_path_taken_error.png b/doc/workflow/img/forking_workflow_path_taken_error.png index 7a3139506fe02418ca51d2e829f3cfa11867f5c7..a859155aef0ebe4af4ba5b5940c9f883ddef62bc 100644 Binary files a/doc/workflow/img/forking_workflow_path_taken_error.png and b/doc/workflow/img/forking_workflow_path_taken_error.png differ diff --git a/doc/workflow/img/new_branch_from_issue.png b/doc/workflow/img/new_branch_from_issue.png index 394c139e17eadc81e8699aca05c727bf48c6a86d..61acdd30ae97da5effba86a7eb75434c524ea46e 100644 Binary files a/doc/workflow/img/new_branch_from_issue.png and b/doc/workflow/img/new_branch_from_issue.png differ diff --git a/doc/workflow/img/revert_changes_commit.png b/doc/workflow/img/revert_changes_commit.png index d84211e20db9fbca1c390faff5f3a7a401cfa0c3..e7194fc350469c46f5663e40186c22492bf3a4ff 100644 Binary files a/doc/workflow/img/revert_changes_commit.png and b/doc/workflow/img/revert_changes_commit.png differ diff --git a/doc/workflow/img/revert_changes_commit_modal.png b/doc/workflow/img/revert_changes_commit_modal.png index e94d151a2afe611b0f87c6c363ef644ab83dd94c..c660ec7eaec05a0fccb437c3fa368bf6b1b1b4ff 100644 Binary files a/doc/workflow/img/revert_changes_commit_modal.png and b/doc/workflow/img/revert_changes_commit_modal.png differ diff --git a/doc/workflow/img/revert_changes_mr.png b/doc/workflow/img/revert_changes_mr.png index 7adad88463b3be50e7fbbed3a817575f9438dbb5..3002f0ac1c567196dc30ac7c794eec8846cfec43 100644 Binary files a/doc/workflow/img/revert_changes_mr.png and b/doc/workflow/img/revert_changes_mr.png differ diff --git a/doc/workflow/img/revert_changes_mr_modal.png b/doc/workflow/img/revert_changes_mr_modal.png index 9da78f84828f311a11cb3b88c42a270faa32bd84..c6aaeecc8a6e474a93f6ee3651a2e56883b150bf 100644 Binary files a/doc/workflow/img/revert_changes_mr_modal.png and b/doc/workflow/img/revert_changes_mr_modal.png differ diff --git a/doc/workflow/img/todos_icon.png b/doc/workflow/img/todos_icon.png index a63bad0c258a6734172ccca23c487ea38c35ca45..bba77f88913beffd86c71c6a99be44debf4122dd 100644 Binary files a/doc/workflow/img/todos_icon.png and b/doc/workflow/img/todos_icon.png differ diff --git a/doc/workflow/img/todos_index.png b/doc/workflow/img/todos_index.png index 4ee18dd128535279f5d052dbffa0089a1ec7e152..f1438ef73557e72ebc5608ef36b0bbc3e355077c 100644 Binary files a/doc/workflow/img/todos_index.png and b/doc/workflow/img/todos_index.png differ diff --git a/doc/workflow/img/web_editor_new_branch_dropdown.png b/doc/workflow/img/web_editor_new_branch_dropdown.png index 009e4b05adf0ed418dc9163398e1fb0c1a7c4c73..a8e635d2fafbcf4ec5c7010c311f6d885715adfe 100644 Binary files a/doc/workflow/img/web_editor_new_branch_dropdown.png and b/doc/workflow/img/web_editor_new_branch_dropdown.png differ diff --git a/doc/workflow/img/web_editor_new_branch_page.png b/doc/workflow/img/web_editor_new_branch_page.png index dd6cfc6e7bb999fe9e6e4a6ffd46eca78f7a691e..7f36b7faf632ed057d4ff7898cf10e2d5b2ad1ea 100644 Binary files a/doc/workflow/img/web_editor_new_branch_page.png and b/doc/workflow/img/web_editor_new_branch_page.png differ diff --git a/doc/workflow/img/web_editor_new_directory_dialog.png b/doc/workflow/img/web_editor_new_directory_dialog.png index 2c76f84f395548a76364cc1408652da84f10dc0a..d16e3c671160166c5755f17649f25bd673292237 100644 Binary files a/doc/workflow/img/web_editor_new_directory_dialog.png and b/doc/workflow/img/web_editor_new_directory_dialog.png differ diff --git a/doc/workflow/img/web_editor_new_directory_dropdown.png b/doc/workflow/img/web_editor_new_directory_dropdown.png index cedf46aedfddf4eaec28a3c73097250d5aba5119..c8d77b16ee852872705eaf7579190fb212ba518a 100644 Binary files a/doc/workflow/img/web_editor_new_directory_dropdown.png and b/doc/workflow/img/web_editor_new_directory_dropdown.png differ diff --git a/doc/workflow/img/web_editor_new_file_dropdown.png b/doc/workflow/img/web_editor_new_file_dropdown.png index 6e884f6504d1558d785838a1a1f755654b759e94..3fcb91c9b93f949ffa0fd358cdf32c711e718bd5 100644 Binary files a/doc/workflow/img/web_editor_new_file_dropdown.png and b/doc/workflow/img/web_editor_new_file_dropdown.png differ diff --git a/doc/workflow/img/web_editor_new_file_editor.png b/doc/workflow/img/web_editor_new_file_editor.png index c76473bcfa7b57b1a5359556cb0f9338d2c5df2d..21c340b9288deeeffcf67f07e38d6e52a9365f09 100644 Binary files a/doc/workflow/img/web_editor_new_file_editor.png and b/doc/workflow/img/web_editor_new_file_editor.png differ diff --git a/doc/workflow/img/web_editor_new_push_widget.png b/doc/workflow/img/web_editor_new_push_widget.png index a21087357415e9da1a1c24a06f6888f6647b953a..c7738a4c930e6c88cce452e51a4302577998c6c0 100644 Binary files a/doc/workflow/img/web_editor_new_push_widget.png and b/doc/workflow/img/web_editor_new_push_widget.png differ diff --git a/doc/workflow/img/web_editor_new_tag_dropdown.png b/doc/workflow/img/web_editor_new_tag_dropdown.png index 263dd635b9506ec55822390e1ddd443734b0d6d9..ac7415009b3c8ab57639c1be704a43b16a6d6882 100644 Binary files a/doc/workflow/img/web_editor_new_tag_dropdown.png and b/doc/workflow/img/web_editor_new_tag_dropdown.png differ diff --git a/doc/workflow/img/web_editor_new_tag_page.png b/doc/workflow/img/web_editor_new_tag_page.png index 64d7cd11ed1473a7813a42c8534d851404bf6e63..231e1a13fc0f8ff3b8d69c2b98c5478afefc8c89 100644 Binary files a/doc/workflow/img/web_editor_new_tag_page.png and b/doc/workflow/img/web_editor_new_tag_page.png differ diff --git a/doc/workflow/img/web_editor_start_new_merge_request.png b/doc/workflow/img/web_editor_start_new_merge_request.png index be12a151cac06aba64f4028bec4e167aaacada89..2755501dfd1a0fdaf362017f16eaa1f167654da7 100644 Binary files a/doc/workflow/img/web_editor_start_new_merge_request.png and b/doc/workflow/img/web_editor_start_new_merge_request.png differ diff --git a/doc/workflow/img/web_editor_upload_file_dialog.png b/doc/workflow/img/web_editor_upload_file_dialog.png index 6dd2207bca0b1dbc80ca6ef07bf55b9f527c50a6..9d6d8250bbe9f2347f7f1e4da23f29d4d61451b9 100644 Binary files a/doc/workflow/img/web_editor_upload_file_dialog.png and b/doc/workflow/img/web_editor_upload_file_dialog.png differ diff --git a/doc/workflow/img/web_editor_upload_file_dropdown.png b/doc/workflow/img/web_editor_upload_file_dropdown.png index bf6528701b074d42ac86d29c860a98b1e6bb3fab..6b5205b05ec5ed7b11aabb247b5cb8190392fb5c 100644 Binary files a/doc/workflow/img/web_editor_upload_file_dropdown.png and b/doc/workflow/img/web_editor_upload_file_dropdown.png differ diff --git a/doc/workflow/importing/bitbucket_importer/bitbucket_import_select_project.png b/doc/workflow/importing/bitbucket_importer/bitbucket_import_select_project.png index 0e08703f4219067ceeee1510c47e03ddca0b1c3c..1a5661de75d556dea016fe86a67ca043a7c2cd93 100644 Binary files a/doc/workflow/importing/bitbucket_importer/bitbucket_import_select_project.png and b/doc/workflow/importing/bitbucket_importer/bitbucket_import_select_project.png differ diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png index 205c515bd3f804342e4302f7d012201ad0320bfc..fd7a4d3fabf2a1087fc256148a4d8e0bfdaf5b7e 100644 Binary files a/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png and b/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png differ diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png index a1e348d46ad6ecae30a9f0965ccbedee1cdeb03b..fd1ba6f588406b76f5509843800a070825fa9ff3 100644 Binary files a/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png and b/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png differ diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png index ed362846909bf0edf0ef5ee220faa79df99b99ff..186c15639512352fd7290dadc00e1e28012f68b8 100644 Binary files a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png and b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png differ diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png index d2fbd0267bdefb41309726243beab282f3130e25..2f84d3232f2a4bacaf1ef5c79d5ab4aa8a7b1344 100644 Binary files a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png and b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png differ diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png index b1cc4b58525154dbb83e89479f1a25788d344f70..652ca20b9abd0fff1b53963fc43978690e2d280a 100644 Binary files a/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png and b/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png differ diff --git a/doc/workflow/importing/gitlab_importer/importer.png b/doc/workflow/importing/gitlab_importer/importer.png index d2a286d8cac32caf6594537b6842ebdcfaedee58..35a7ddc831866c5d9425859a4666453cf430250e 100644 Binary files a/doc/workflow/importing/gitlab_importer/importer.png and b/doc/workflow/importing/gitlab_importer/importer.png differ diff --git a/doc/workflow/importing/gitlab_importer/new_project_page.png b/doc/workflow/importing/gitlab_importer/new_project_page.png index 5e239208e1e73ec80d5ff16eced9ea371b721df2..81074d2d016e2e735d9c99d12745f87e7cab2455 100644 Binary files a/doc/workflow/importing/gitlab_importer/new_project_page.png and b/doc/workflow/importing/gitlab_importer/new_project_page.png differ diff --git a/doc/workflow/importing/img/import_projects_from_github_importer.png b/doc/workflow/importing/img/import_projects_from_github_importer.png index f744dc06f8195c7944e16053a8ce102741228633..b6ed8dd692aa5140cdae9839c55869139573efd3 100644 Binary files a/doc/workflow/importing/img/import_projects_from_github_importer.png and b/doc/workflow/importing/img/import_projects_from_github_importer.png differ diff --git a/doc/workflow/importing/img/import_projects_from_github_new_project_page.png b/doc/workflow/importing/img/import_projects_from_github_new_project_page.png index 86be35acb3735f00b2d6b86c098bc37771892eca..c8f35a50f48dcfdc60c1cfd0fec986936b821894 100644 Binary files a/doc/workflow/importing/img/import_projects_from_github_new_project_page.png and b/doc/workflow/importing/img/import_projects_from_github_new_project_page.png differ diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md index a7dfac2c12066139773216e2e93f0a2b256b31be..a2b2a4b88f9d6690d525c207fa01be3d50f1958c 100644 --- a/doc/workflow/importing/import_projects_from_github.md +++ b/doc/workflow/importing/import_projects_from_github.md @@ -1,8 +1,10 @@ # Import your project from GitHub to GitLab >**Note:** -In order to enable the GitHub import setting, you should first -enable the [GitHub integration][gh-import] in your GitLab instance. +In order to enable the GitHub import setting, you may also want to +enable the [GitHub integration][gh-import] in your GitLab instance. This +configuration is optional, you will be able import your GitHub repositories +with a Personal Access Token. At its current state, GitHub importer can import: @@ -20,9 +22,15 @@ It is not yet possible to import your cross-repository pull requests (those from forks). We are working on improving this in the near future. The importer page is visible when you [create a new project][new-project]. -Click on the **GitHub** link and you will be redirected to GitHub for -permission to access your projects. After accepting, you'll be automatically -redirected to the importer. +Click on the **GitHub** link and, if you are logged in via the GitHub +integration, you will be redirected to GitHub for permission to access your +projects. After accepting, you'll be automatically redirected to the importer. + +If you are not using the GitHub integration, you can still perform a one-off +authorization with GitHub to access your projects. + +Alternatively, you can also enter a GitHub Personal Access Token. Once you enter +your token, you'll be taken to the importer.  diff --git a/doc/workflow/merge_commits.png b/doc/workflow/merge_commits.png index 757b589d0dbb71c56b56905eb9fb1af895d859b6..8aa1587cde6bef530fb1514250209941ffb76d53 100644 Binary files a/doc/workflow/merge_commits.png and b/doc/workflow/merge_commits.png differ diff --git a/doc/workflow/merge_request.png b/doc/workflow/merge_request.png index fde3ff5c854f877e2a621f6b15ee1c6ed7ac5a8d..6aad1d82f6e05a218f2d914359f622ce00cf96a3 100644 Binary files a/doc/workflow/merge_request.png and b/doc/workflow/merge_request.png differ diff --git a/doc/workflow/merge_requests/commit_compare.png b/doc/workflow/merge_requests/commit_compare.png index dfd7ee220f0f53e89c8cf083732a6fd510db0abb..0e4a2b23c040bff65366f8032415e192e0d4231c 100644 Binary files a/doc/workflow/merge_requests/commit_compare.png and b/doc/workflow/merge_requests/commit_compare.png differ diff --git a/doc/workflow/merge_requests/merge_request_diff.png b/doc/workflow/merge_requests/merge_request_diff.png index f368423c74640634b9a330249faffe4858e722f8..3ebbfb75ea38f1157491357f8a93d3ee3b729794 100644 Binary files a/doc/workflow/merge_requests/merge_request_diff.png and b/doc/workflow/merge_requests/merge_request_diff.png differ diff --git a/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png b/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png index b2d03bb66f92a260e8b188a15e9b1671b49d00ce..a0db535019c3cc6466646570ee8a1204d82d2c16 100644 Binary files a/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png and b/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png differ diff --git a/doc/workflow/merge_when_build_succeeds/enable.png b/doc/workflow/merge_when_build_succeeds/enable.png index 633efa1246f997ba0070c5ca483c9ac4057dc20b..b86e6d7b3fd113401415b0bec1f93e3f3806ca83 100644 Binary files a/doc/workflow/merge_when_build_succeeds/enable.png and b/doc/workflow/merge_when_build_succeeds/enable.png differ diff --git a/doc/workflow/merge_when_build_succeeds/status.png b/doc/workflow/merge_when_build_succeeds/status.png index c856c7d14dc6ba2f0c89f3e6d7c0e3de39e0dcfe..f3ea61d814785228e1f0413ccab7db6a42034ffd 100644 Binary files a/doc/workflow/merge_when_build_succeeds/status.png and b/doc/workflow/merge_when_build_succeeds/status.png differ diff --git a/doc/workflow/messy_flow.png b/doc/workflow/messy_flow.png index 1addb95ca5455fc9ea12da3868c322a9e5fdaa01..8d2c0dae8c26c03fa98ded44767bd6cdca498500 100644 Binary files a/doc/workflow/messy_flow.png and b/doc/workflow/messy_flow.png differ diff --git a/doc/workflow/milestones/form.png b/doc/workflow/milestones/form.png index de44c1ffc1a44c21e7d6eff77ff8752d84b6ea8f..3965ca4d083448edea6a97946daa082a16545fde 100644 Binary files a/doc/workflow/milestones/form.png and b/doc/workflow/milestones/form.png differ diff --git a/doc/workflow/milestones/group_form.png b/doc/workflow/milestones/group_form.png index 38862dcca6895c28a09c6173fc8a2d7b1552b528..ff20df8081f383fee1c525bea96e7edb1d3e005c 100644 Binary files a/doc/workflow/milestones/group_form.png and b/doc/workflow/milestones/group_form.png differ diff --git a/doc/workflow/mr_inline_comments.png b/doc/workflow/mr_inline_comments.png index e851b95bcefff033e075d76221c29f2541a38245..af7df3100d0bafb882bf15361235b4a1e58c0ea3 100644 Binary files a/doc/workflow/mr_inline_comments.png and b/doc/workflow/mr_inline_comments.png differ diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md index fe4485e148a629423eb1939c11b9f618a8036a77..b4a9c2f3d3e622a837cdc943607261656efecd64 100644 --- a/doc/workflow/notifications.md +++ b/doc/workflow/notifications.md @@ -37,12 +37,14 @@ This means that you can set a different level of notifications per group while s to have a finer level setting per project. Organization like this is suitable for users that belong to different groups but don't have the same need for being notified for every group they are member of. +These settings can be configured on group page or user profile notifications dropdown. #### Project Settings Project Settings are at the top level and any setting placed at this level will take precedence of any other setting. This is suitable for users that have different needs for notifications per project basis. +These settings can be configured on project page or user profile notifications dropdown. ## Notification events diff --git a/doc/workflow/notifications/settings.png b/doc/workflow/notifications/settings.png index 7c6857aad1a88f92b42b5ea30656d0ff0b75fc63..d50757beffcda8506f4a0e3c52ff587bc1756d4f 100644 Binary files a/doc/workflow/notifications/settings.png and b/doc/workflow/notifications/settings.png differ diff --git a/doc/workflow/production_branch.png b/doc/workflow/production_branch.png index 33fb26dd62163cc5d9436a91db508971e73fc1f5..d88a368715163ece1b9d8c89bc0fc9d44c3f2c77 100644 Binary files a/doc/workflow/production_branch.png and b/doc/workflow/production_branch.png differ diff --git a/doc/workflow/protected_branches/protected_branches1.png b/doc/workflow/protected_branches/protected_branches1.png index 5c2a3de5f7043225788bb65cf35652525a0bb357..bb3ab7d791322e94a439a02a495ee322f03a3bf3 100644 Binary files a/doc/workflow/protected_branches/protected_branches1.png and b/doc/workflow/protected_branches/protected_branches1.png differ diff --git a/doc/workflow/protected_branches/protected_branches2.png b/doc/workflow/protected_branches/protected_branches2.png index 2dca35413655a79768911db229db1462e5397018..58ace31ac571e4d5e72d4dcd3378a17f2c486875 100644 Binary files a/doc/workflow/protected_branches/protected_branches2.png and b/doc/workflow/protected_branches/protected_branches2.png differ diff --git a/doc/workflow/rebase.png b/doc/workflow/rebase.png index ef82c834755c7b3e2c53145418c461044344f430..df353311fa06dd858cd07b8f1451b5bdfa1aad6b 100644 Binary files a/doc/workflow/rebase.png and b/doc/workflow/rebase.png differ diff --git a/doc/workflow/release_branches.png b/doc/workflow/release_branches.png index da7ae53413a77246118b2cbb320b5707d4ee965e..c2162248d25abe36b88b19d5792687d945a8fbe5 100644 Binary files a/doc/workflow/release_branches.png and b/doc/workflow/release_branches.png differ diff --git a/doc/workflow/releases/new_tag.png b/doc/workflow/releases/new_tag.png index e2b64bfe17fb95f221cbd57ec3da684b5e47ee39..2456a8500f4b4e7028d3e483b633ad92b0d40288 100644 Binary files a/doc/workflow/releases/new_tag.png and b/doc/workflow/releases/new_tag.png differ diff --git a/doc/workflow/releases/tags.png b/doc/workflow/releases/tags.png index aca91906c68a439d0987085db345cb82c04a51b4..eeda967afd6bb7f02b525d1aba84951c170e879a 100644 Binary files a/doc/workflow/releases/tags.png and b/doc/workflow/releases/tags.png differ diff --git a/doc/workflow/remove_checkbox.png b/doc/workflow/remove_checkbox.png index 3e247d381556a2f1f05ea8649105885d53174cd5..3b0393deb0fa235fd1df4d55d7a4adaddd756986 100644 Binary files a/doc/workflow/remove_checkbox.png and b/doc/workflow/remove_checkbox.png differ diff --git a/doc/workflow/share_with_group.png b/doc/workflow/share_with_group.png index a0ca6f145521ca7a7e359cc53df73e69f21cecff..2c47625e29a88c37fe7b85b1c04f999af767551e 100644 Binary files a/doc/workflow/share_with_group.png and b/doc/workflow/share_with_group.png differ diff --git a/doc/workflow/shortcuts.png b/doc/workflow/shortcuts.png index 16be0413b64ac6be977d54ad78e9f23b0c5e6a13..a9b1c4b4dccf119a33781fd5e839e3dc4d6a808f 100644 Binary files a/doc/workflow/shortcuts.png and b/doc/workflow/shortcuts.png differ diff --git a/doc/workflow/wip_merge_requests/blocked_accept_button.png b/doc/workflow/wip_merge_requests/blocked_accept_button.png index 4791e5de972b56e90aaf577a2b1a58e2adb8e693..89c458aa8d960f5c148639964708059f256e9a85 100644 Binary files a/doc/workflow/wip_merge_requests/blocked_accept_button.png and b/doc/workflow/wip_merge_requests/blocked_accept_button.png differ diff --git a/doc/workflow/wip_merge_requests/mark_as_wip.png b/doc/workflow/wip_merge_requests/mark_as_wip.png index 8fa83a201ac8bcbfc3293b06c46302a798c1215c..9c37354a65363c82b397e1d92161d3b77903356c 100644 Binary files a/doc/workflow/wip_merge_requests/mark_as_wip.png and b/doc/workflow/wip_merge_requests/mark_as_wip.png differ diff --git a/doc/workflow/wip_merge_requests/unmark_as_wip.png b/doc/workflow/wip_merge_requests/unmark_as_wip.png index d45e68f31c53845eea6dd3c09e6bb6f11d05cdd0..31f7326beb0e2c90bebe9c40059375d2f64713b0 100644 Binary files a/doc/workflow/wip_merge_requests/unmark_as_wip.png and b/doc/workflow/wip_merge_requests/unmark_as_wip.png differ diff --git a/features/dashboard/new_project.feature b/features/dashboard/new_project.feature index 56b4a639c015f9a3b26babde961de28f0fc77c26..8ddafb6a7ac13c6b41789c92f9ee89462d539f5c 100644 --- a/features/dashboard/new_project.feature +++ b/features/dashboard/new_project.feature @@ -21,7 +21,7 @@ Background: Scenario: I should see instructions on how to import from GitHub Given I see "New Project" page When I click on "Import project from GitHub" - Then I see instructions on how to import from GitHub + Then I am redirected to the GitHub import page @javascript Scenario: I should see Google Code import page diff --git a/features/steps/dashboard/new_project.rb b/features/steps/dashboard/new_project.rb index 29e6b9f1a016284ec0563d899b22f6ab6e83b002..09373168dadb615296ee129aef121057ffe25628 100644 --- a/features/steps/dashboard/new_project.rb +++ b/features/steps/dashboard/new_project.rb @@ -10,7 +10,7 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps end step 'I see "New Project" page' do - expect(page).to have_content('Project owner') + expect(page).to have_content('Project path') expect(page).to have_content('Project name') end @@ -28,14 +28,8 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps first('.import_github').click end - step 'I see instructions on how to import from GitHub' do - github_modal = first('.modal-body') - expect(github_modal).to be_visible - expect(github_modal).to have_content "To enable importing projects from GitHub" - - page.all('.modal-body').each do |element| - expect(element).not_to be_visible unless element == github_modal - end + step 'I am redirected to the GitHub import page' do + expect(current_path).to eq new_import_github_path end step 'I click on "Repo by URL"' do diff --git a/features/steps/groups.rb b/features/steps/groups.rb index 483370f41c6f775cc43f5081aacd392ff96bbd60..4fa7d7c656775b03cc8669ae6b6593a9bf723d26 100644 --- a/features/steps/groups.rb +++ b/features/steps/groups.rb @@ -93,7 +93,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps step 'I should see new group "Owned" avatar' do expect(owned_group.avatar).to be_instance_of AvatarUploader - expect(owned_group.avatar.url).to eq "/uploads/group/avatar/#{Group.find_by(name:"Owned").id}/banana_sample.gif" + expect(owned_group.avatar.url).to eq "/uploads/group/avatar/#{Group.find_by(name: "Owned").id}/banana_sample.gif" end step 'I should see the "Remove avatar" button' do diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index 0ead83d6937d9660c5316716f1615eee73496181..6b56a77b832b99eebfdc3421344fa279a9aad8f7 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -153,6 +153,6 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps # Verify a link is generated against the correct project def verify_commit_link(container_div, container_project) # This should force a wait for the javascript to execute - expect(find(:div,container_div).find(".commit_short_id")['href']).to have_content "#{container_project.path_with_namespace}/commit" + expect(find(:div, container_div).find(".commit_short_id")['href']).to have_content "#{container_project.path_with_namespace}/commit" end end diff --git a/features/support/env.rb b/features/support/env.rb index edc08cf0986a5397a69c2f82f128c7c36e4a8e1b..ab3f0ca7aeb8d70beb684c64358f0028c3fa26ea 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -2,11 +2,6 @@ if ENV['SIMPLECOV'] require 'simplecov' end -if ENV['COVERALLS'] - require 'coveralls' - Coveralls.wear_merged! -end - ENV['RAILS_ENV'] = 'test' require './config/environment' require 'rspec/expectations' diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 979328efe0edb2f9e2bdd37009263ad2db08c3ee..086d8511e8ffafd3da92cb007058719701eb79be 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -33,10 +33,10 @@ module API get ':id/repository/commits/:sha/builds' do authorize_read_builds! - commit = user_project.pipelines.find_by_sha(params[:sha]) - return not_found! unless commit + return not_found! unless user_project.commit(params[:sha]) - builds = commit.builds.order('id DESC') + pipelines = user_project.pipelines.where(sha: params[:sha]) + builds = user_project.builds.where(pipeline: pipelines).order('id DESC') builds = filter_builds(builds, params[:scope]) present paginate(builds), with: Entities::Build, diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5a23a18fe9c7e22dda765b9b86130f26276a609e..4e2a43e45e2e990470c8c143d9e2e64efc8215b2 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -376,6 +376,7 @@ module API expose :user_oauth_applications expose :after_sign_out_path expose :container_registry_token_expire_delay + expose :repository_storage end class Release < Grape::Entity diff --git a/lib/api/group_members.rb b/lib/api/group_members.rb index ab9b7c602b5dc728f206b05a2f8edac8face4b50..dbe5bb08d3ff05bf22e8de31acbd80ee8967c175 100644 --- a/lib/api/group_members.rb +++ b/lib/api/group_members.rb @@ -77,7 +77,7 @@ module API member = group.group_members.find_by(user_id: params[:user_id]) if member.nil? - render_api_error!("404 Not Found - user_id:#{params[:user_id]} not a member of group #{group.name}",404) + render_api_error!("404 Not Found - user_id:#{params[:user_id]} not a member of group #{group.name}", 404) else member.destroy end diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 1d361569d595c623b4ea178df6c0905e2f9b0216..b32503e8516b7608eae864a99e46be97d89818db 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -20,6 +20,20 @@ module API @wiki ||= params[:project].end_with?('.wiki') && !Project.find_with_namespace(params[:project]) end + + def project + @project ||= begin + project_path = params[:project] + + # Check for *.wiki repositories. + # Strip out the .wiki from the pathname before finding the + # project. This applies the correct project permissions to + # the wiki repository as well. + project_path.chomp!('.wiki') if wiki? + + Project.find_with_namespace(project_path) + end + end end post "/allowed" do @@ -32,16 +46,6 @@ module API User.find_by(id: params[:user_id]) end - project_path = params[:project] - - # Check for *.wiki repositories. - # Strip out the .wiki from the pathname before finding the - # project. This applies the correct project permissions to - # the wiki repository as well. - project_path.chomp!('.wiki') if wiki? - - project = Project.find_with_namespace(project_path) - access = if wiki? Gitlab::GitAccessWiki.new(actor, project) @@ -49,7 +53,17 @@ module API Gitlab::GitAccess.new(actor, project) end - access.check(params[:action], params[:changes]) + access_status = access.check(params[:action], params[:changes]) + + response = { status: access_status.status, message: access_status.message } + + if access_status.status + # Return the repository full path so that gitlab-shell has it when + # handling ssh commands + response[:repository_path] = project.repository.path_to_repo + end + + response end # diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index 7b91215d50b6f17118917404ae5a01089bdd5bd1..b9773f98d752a7c8ea4a077c387f8b3776a1bd57 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -2,8 +2,6 @@ require 'yaml' module Backup class Repository - attr_reader :repos_path - def dump prepare @@ -50,10 +48,12 @@ module Backup end def restore - if File.exists?(repos_path) + Gitlab.config.repositories.storages.each do |name, path| + next unless File.exists?(path) + # Move repos dir to 'repositories.old' dir - bk_repos_path = File.join(repos_path, '..', 'repositories.old.' + Time.now.to_i.to_s) - FileUtils.mv(repos_path, bk_repos_path) + bk_repos_path = File.join(path, '..', 'repositories.old.' + Time.now.to_i.to_s) + FileUtils.mv(path, bk_repos_path) end FileUtils.mkdir_p(repos_path) @@ -61,7 +61,7 @@ module Backup Project.find_each(batch_size: 1000) do |project| $progress.print " * #{project.path_with_namespace} ... " - project.namespace.ensure_dir_exist if project.namespace + project.ensure_dir_exist if File.exists?(path_to_bundle(project)) FileUtils.mkdir_p(path_to_repo(project)) @@ -100,8 +100,8 @@ module Backup end $progress.print 'Put GitLab hooks in repositories dirs'.color(:yellow) - cmd = "#{Gitlab.config.gitlab_shell.path}/bin/create-hooks" - if system(cmd) + cmd = %W(#{Gitlab.config.gitlab_shell.path}/bin/create-hooks) + repository_storage_paths_args + if system(*cmd) $progress.puts " [DONE]".color(:green) else puts " [FAILED]".color(:red) @@ -120,10 +120,6 @@ module Backup File.join(backup_repos_path, project.path_with_namespace + ".bundle") end - def repos_path - Gitlab.config.gitlab_shell.repos_path - end - def backup_repos_path File.join(Gitlab.config.backup.path, "repositories") end @@ -139,5 +135,11 @@ module Backup def silent {err: '/dev/null', out: '/dev/null'} end + + private + + def repository_storage_paths_args + Gitlab.config.repositories.storages.values + end end end diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index 81d66271136ab19f7006f1d1bb130fa42de5c6cf..d77a5e3ff09099ef5047d2d0517702d75ed595ef 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -160,11 +160,7 @@ module Banzai title = object_link_title(object) klass = reference_class(object_sym) - data = data_attribute( - original: link_text || match, - project: project.id, - object_sym => object.id - ) + data = data_attributes_for(link_text || match, project, object) if matches.names.include?("url") && matches[:url] url = matches[:url] @@ -183,6 +179,14 @@ module Banzai end end + def data_attributes_for(text, project, object) + data_attribute( + original: text, + project: project.id, + object_sym => object.id + ) + end + def object_link_text_extras(object, matches) extras = [] diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb index 5351272f42d0b4ce514d9f06a17e0968e90f767e..4042e9a4c250f0bc29c307ba73451cbff6d5564f 100644 --- a/lib/banzai/filter/issue_reference_filter.rb +++ b/lib/banzai/filter/issue_reference_filter.rb @@ -46,6 +46,26 @@ module Banzai end end + def object_link_title(object) + if object.is_a?(ExternalIssue) + "Issue in #{object.project.external_issue_tracker.title}" + else + super + end + end + + def data_attributes_for(text, project, object) + if object.is_a?(ExternalIssue) + data_attribute( + project: project.id, + external_issue: object.id, + reference_type: ExternalIssueReferenceFilter.reference_type + ) + else + super + end + end + def find_projects_for_paths(paths) super(paths).includes(:gitlab_issue_tracker_service) end diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb index 2d6f34c9cd8633fec321e97241b5e556e9981765..bf058241cda706d8896b8ad76ab2103b3cc26375 100644 --- a/lib/banzai/filter/reference_filter.rb +++ b/lib/banzai/filter/reference_filter.rb @@ -29,7 +29,7 @@ module Banzai def data_attribute(attributes = {}) attributes = attributes.reject { |_, v| v.nil? } - attributes[:reference_type] = self.class.reference_type + attributes[:reference_type] ||= self.class.reference_type attributes.delete(:original) if context[:no_original_data] attributes.map { |key, value| %Q(data-#{key.to_s.dasherize}="#{escape_once(value)}") }.join(" ") end diff --git a/lib/gitlab.rb b/lib/gitlab.rb index 37f4c34054fedace368980ef3acf70f822e171c7..c3064163e076d0c3a2a7d0e8cff0f1a9033cc51e 100644 --- a/lib/gitlab.rb +++ b/lib/gitlab.rb @@ -2,6 +2,11 @@ require_dependency 'gitlab/git' module Gitlab def self.com? - Gitlab.config.gitlab.url == 'https://gitlab.com' + # Check `staging?` as well to keep parity with gitlab.com + Gitlab.config.gitlab.url == 'https://gitlab.com' || staging? + end + + def self.staging? + Gitlab.config.gitlab.url == 'https://staging.gitlab.com' end end diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index ab7b811c5d81c59e3d45194c3f91f35c3c1c9abd..ad412f56cca42eaa6182dab9fdad80c11f96b187 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -22,7 +22,7 @@ module Grack # Need this if under RELATIVE_URL_ROOT unless Gitlab.config.gitlab.relative_url_root.empty? # If website is mounted using relative_url_root need to remove it first - @env['PATH_INFO'] = @request.path.sub(Gitlab.config.gitlab.relative_url_root,'') + @env['PATH_INFO'] = @request.path.sub(Gitlab.config.gitlab.relative_url_root, '') else @env['PATH_INFO'] = @request.path end diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 3e3986d63827811c894e741869c09f1fadb64da1..34e0143a82ee793bce189617e36fd9cce4ff4306 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -1,3 +1,5 @@ +require 'securerandom' + module Gitlab class Shell class Error < StandardError; end @@ -18,77 +20,82 @@ module Gitlab # Init new repository # + # storage - project's storage path # name - project path with namespace # # Ex. - # add_repository("gitlab/gitlab-ci") + # add_repository("/path/to/storage", "gitlab/gitlab-ci") # - def add_repository(name) + def add_repository(storage, name) Gitlab::Utils.system_silent([gitlab_shell_projects_path, - 'add-project', "#{name}.git"]) + 'add-project', storage, "#{name}.git"]) end # Import repository # + # storage - project's storage path # name - project path with namespace # # Ex. - # import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git") + # import_repository("/path/to/storage", "gitlab/gitlab-ci", "https://github.com/randx/six.git") # - def import_repository(name, url) - output, status = Popen::popen([gitlab_shell_projects_path, 'import-project', "#{name}.git", url, '900']) + def import_repository(storage, name, url) + output, status = Popen::popen([gitlab_shell_projects_path, 'import-project', + storage, "#{name}.git", url, '900']) raise Error, output unless status.zero? true end # Move repository - # + # storage - project's storage path # path - project path with namespace # new_path - new project path with namespace # # Ex. - # mv_repository("gitlab/gitlab-ci", "randx/gitlab-ci-new") + # mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new") # - def mv_repository(path, new_path) + def mv_repository(storage, path, new_path) Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'mv-project', - "#{path}.git", "#{new_path}.git"]) + storage, "#{path}.git", "#{new_path}.git"]) end # Fork repository to new namespace - # + # storage - project's storage path # path - project path with namespace # fork_namespace - namespace for forked project # # Ex. - # fork_repository("gitlab/gitlab-ci", "randx") + # fork_repository("/path/to/storage", "gitlab/gitlab-ci", "randx") # - def fork_repository(path, fork_namespace) + def fork_repository(storage, path, fork_namespace) Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'fork-project', - "#{path}.git", fork_namespace]) + storage, "#{path}.git", fork_namespace]) end # Remove repository from file system # + # storage - project's storage path # name - project path with namespace # # Ex. - # remove_repository("gitlab/gitlab-ci") + # remove_repository("/path/to/storage", "gitlab/gitlab-ci") # - def remove_repository(name) + def remove_repository(storage, name) Gitlab::Utils.system_silent([gitlab_shell_projects_path, - 'rm-project', "#{name}.git"]) + 'rm-project', storage, "#{name}.git"]) end # Gc repository # + # storage - project storage path # path - project path with namespace # # Ex. - # gc("gitlab/gitlab-ci") + # gc("/path/to/storage", "gitlab/gitlab-ci") # - def gc(path) + def gc(storage, path) Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'gc', - "#{path}.git"]) + storage, "#{path}.git"]) end # Add new key to gitlab-shell @@ -133,31 +140,31 @@ module Gitlab # Add empty directory for storing repositories # # Ex. - # add_namespace("gitlab") + # add_namespace("/path/to/storage", "gitlab") # - def add_namespace(name) - FileUtils.mkdir(full_path(name), mode: 0770) unless exists?(name) + def add_namespace(storage, name) + FileUtils.mkdir(full_path(storage, name), mode: 0770) unless exists?(storage, name) end # Remove directory from repositories storage # Every repository inside this directory will be removed too # # Ex. - # rm_namespace("gitlab") + # rm_namespace("/path/to/storage", "gitlab") # - def rm_namespace(name) - FileUtils.rm_r(full_path(name), force: true) + def rm_namespace(storage, name) + FileUtils.rm_r(full_path(storage, name), force: true) end # Move namespace directory inside repositories storage # # Ex. - # mv_namespace("gitlab", "gitlabhq") + # mv_namespace("/path/to/storage", "gitlab", "gitlabhq") # - def mv_namespace(old_name, new_name) - return false if exists?(new_name) || !exists?(old_name) + def mv_namespace(storage, old_name, new_name) + return false if exists?(storage, new_name) || !exists?(storage, old_name) - FileUtils.mv(full_path(old_name), full_path(new_name)) + FileUtils.mv(full_path(storage, old_name), full_path(storage, new_name)) end def url_to_repo(path) @@ -176,11 +183,26 @@ module Gitlab # Check if such directory exists in repositories. # # Usage: - # exists?('gitlab') - # exists?('gitlab/cookies.git') + # exists?(storage, 'gitlab') + # exists?(storage, 'gitlab/cookies.git') # - def exists?(dir_name) - File.exist?(full_path(dir_name)) + def exists?(storage, dir_name) + File.exist?(full_path(storage, dir_name)) + end + + # Create (if necessary) and link the secret token file + def generate_and_link_secret_token + secret_file = Gitlab.config.gitlab_shell.secret_file + unless File.exist? secret_file + # Generate a new token of 16 random hexadecimal characters and store it in secret_file. + token = SecureRandom.hex(16) + File.write(secret_file, token) + end + + link_path = File.join(gitlab_shell_path, '.gitlab_shell_secret') + if File.exist?(gitlab_shell_path) && !File.exist?(link_path) + FileUtils.symlink(secret_file, link_path) + end end protected @@ -193,14 +215,10 @@ module Gitlab File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") end - def repos_path - Gitlab.config.gitlab_shell.repos_path - end - - def full_path(dir_name) + def full_path(storage, dir_name) raise ArgumentError.new("Directory name can't be blank") if dir_name.blank? - File.join(repos_path, dir_name) + File.join(storage, dir_name) end def gitlab_shell_projects_path diff --git a/lib/gitlab/blame.rb b/lib/gitlab/blame.rb index 997a22779a0406ba08e9a749dcb1ab54c38b8488..d62bc50ce78e06536cb276d3432fe024d88837b2 100644 --- a/lib/gitlab/blame.rb +++ b/lib/gitlab/blame.rb @@ -41,7 +41,8 @@ module Gitlab def highlighted_lines @blob.load_all_data!(repository) - @highlighted_lines ||= Gitlab::Highlight.highlight(@blob.name, @blob.data).lines + @highlighted_lines ||= + Gitlab::Highlight.highlight(@blob.path, @blob.data, repository: repository).lines end def project diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 28c34429c1f910527216d5771485119ec581167a..54b46e5d23f8eb3571d1c0c098560dbe6a0d248c 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -9,10 +9,14 @@ module Gitlab end def ensure_application_settings! - settings = ::ApplicationSetting.cached + if connect_to_db? + begin + settings = ::ApplicationSetting.current + # In case Redis isn't running or the Redis UNIX socket file is not available + rescue ::Redis::BaseError, ::Errno::ENOENT + settings = ::ApplicationSetting.last + end - if !settings && connect_to_db? - settings = ::ApplicationSetting.current settings ||= ::ApplicationSetting.create_from_defaults unless ActiveRecord::Migrator.needs_migration? end diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index d325eca6d99cd4ab6a6d0a967a8a0b3a1b305803..043f10d96a953192f84668446005377c2d92fbf4 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -4,26 +4,39 @@ module Gitlab GITHUB_SAFE_REMAINING_REQUESTS = 100 GITHUB_SAFE_SLEEP_TIME = 500 - attr_reader :client, :api + attr_reader :access_token def initialize(access_token) - @client = ::OAuth2::Client.new( - config.app_id, - config.app_secret, - github_options.merge(ssl: { verify: config['verify_ssl'] }) - ) + @access_token = access_token if access_token ::Octokit.auto_paginate = false + end + end + + def api + @api ||= ::Octokit::Client.new( + access_token: access_token, + api_endpoint: github_options[:site], + # If there is no config, we're connecting to github.com and we + # should verify ssl. + connection_options: { + ssl: { verify: config ? config['verify_ssl'] : true } + } + ) + end - @api = ::Octokit::Client.new( - access_token: access_token, - api_endpoint: github_options[:site], - connection_options: { - ssl: { verify: config['verify_ssl'] } - } - ) + def client + unless config + raise Projects::ImportService::Error, + 'OAuth configuration for GitHub missing.' end + + @client ||= ::OAuth2::Client.new( + config.app_id, + config.app_secret, + github_options.merge(ssl: { verify: config['verify_ssl'] }) + ) end def authorize_url(redirect_uri) @@ -56,7 +69,11 @@ module Gitlab end def github_options - config["args"]["client_options"].deep_symbolize_keys + if config + config["args"]["client_options"].deep_symbolize_keys + else + OmniAuth::Strategies::GitHub.default_options[:client_options].symbolize_keys + end end def rate_limit diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 2286ac8829c9813ca17e60670e0aecc3b85046b9..730978d502b501b613c59299cda2beca9145f85f 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -167,7 +167,7 @@ module Gitlab def import_wiki unless project.wiki_enabled? wiki = WikiFormatter.new(project) - gitlab_shell.import_repository(wiki.path_with_namespace, wiki.import_url) + gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url) project.update_attribute(:wiki_enabled, true) end diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index f751a3a12fdf90c46533a4e9d2fe8c50a66a0a37..d4f12cb1df9716cc86c7b115049ec03f9a370ee6 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -3,7 +3,6 @@ module Gitlab def add_gon_variables gon.api_version = API::API.version gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s - gon.default_issues_tracker = Project.new.default_issue_tracker.to_param gon.max_file_size = current_application_settings.max_attachment_size gon.relative_url_root = Gitlab.config.gitlab.relative_url_root gon.shortcuts_path = help_shortcuts_path diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index 280120b0f9eb04a04aee5b18849a384229009930..41296415e35700619c36d02ba5982d1c4018e0a5 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -1,7 +1,7 @@ module Gitlab class Highlight - def self.highlight(blob_name, blob_content, nowrap: true, plain: false) - new(blob_name, blob_content, nowrap: nowrap). + def self.highlight(blob_name, blob_content, repository: nil, nowrap: true, plain: false) + new(blob_name, blob_content, nowrap: nowrap, repository: repository). highlight(blob_content, continue: false, plain: plain) end @@ -10,12 +10,21 @@ module Gitlab return [] unless blob blob.load_all_data!(repository) - highlight(file_name, blob.data).lines.map!(&:html_safe) + highlight(file_name, blob.data, repository: repository).lines.map!(&:html_safe) end - def initialize(blob_name, blob_content, nowrap: true) + attr_reader :lexer + def initialize(blob_name, blob_content, repository: nil, nowrap: true) + @blob_name = blob_name + @blob_content = blob_content + @repository = repository @formatter = rouge_formatter(nowrap: nowrap) - @lexer = Rouge::Lexer.guess(filename: blob_name, source: blob_content).new rescue Rouge::Lexers::PlainText + + @lexer = custom_language || begin + Rouge::Lexer.guess(filename: blob_name, source: blob_content).new + rescue Rouge::Lexer::AmbiguousGuess => e + e.alternatives.sort_by(&:tag).first + end end def highlight(text, continue: true, plain: false) @@ -30,6 +39,14 @@ module Gitlab private + def custom_language + language_name = @repository && @repository.gitattribute(@blob_name, 'gitlab-language') + + return nil unless language_name + + Rouge::Lexer.find_fancy(language_name) + end + def rouge_formatter(options = {}) options = options.reverse_merge( nowrap: true, diff --git a/lib/gitlab/key_fingerprint.rb b/lib/gitlab/key_fingerprint.rb index 8684b4636ea1fbb80c6f7bf68a33ff9fdd8ee924..b75ae512d9264ca42828078265764fb0c116edf3 100644 --- a/lib/gitlab/key_fingerprint.rb +++ b/lib/gitlab/key_fingerprint.rb @@ -39,7 +39,7 @@ module Gitlab # OpenSSH 6.8 introduces a new default output format for fingerprints. # Check the version and decide which command to use. - version_output, version_status = popen(%W(ssh -V)) + version_output, version_status = popen(%w(ssh -V)) return false unless version_status.zero? version_matches = version_output.match(/OpenSSH_(?<major>\d+)\.(?<minor>\d+)/) diff --git a/lib/gitlab/metrics/method_call.rb b/lib/gitlab/metrics/method_call.rb index faf0d9b6318f8a9da2f260ce9827e1f1597cb0af..c048fe20ba7c8e0bbcddebf1d733f60ed90fb8b0 100644 --- a/lib/gitlab/metrics/method_call.rb +++ b/lib/gitlab/metrics/method_call.rb @@ -18,12 +18,12 @@ module Gitlab # Measures the real and CPU execution time of the supplied block. def measure - start_real = Time.now + start_real = System.monotonic_time start_cpu = System.cpu_time retval = yield - @real_time += (Time.now - start_real) * 1000.0 - @cpu_time += System.cpu_time.to_f - start_cpu + @real_time += System.monotonic_time - start_real + @cpu_time += System.cpu_time - start_cpu @call_count += 1 retval diff --git a/lib/gitlab/metrics/metric.rb b/lib/gitlab/metrics/metric.rb index 1cd1ca30f701b28580bfa13b997eef4f2f2ccfda..f23d67e1e3849f4ab512c2d390110605009988d9 100644 --- a/lib/gitlab/metrics/metric.rb +++ b/lib/gitlab/metrics/metric.rb @@ -4,16 +4,15 @@ module Gitlab class Metric JITTER_RANGE = 0.000001..0.001 - attr_reader :series, :values, :tags, :created_at + attr_reader :series, :values, :tags # series - The name of the series (as a String) to store the metric in. # values - A Hash containing the values to store. # tags - A Hash containing extra tags to add to the metrics. def initialize(series, values, tags = {}) - @values = values - @series = series - @tags = tags - @created_at = Time.now.utc + @values = values + @series = series + @tags = tags end # Returns a Hash in a format that can be directly written to InfluxDB. @@ -27,20 +26,20 @@ module Gitlab # # Due to the way InfluxDB is set up there's no solution to this problem, # all we can do is lower the amount of collisions. We do this by using - # Time#to_f which returns the seconds as a Float providing greater - # accuracy. We then add a small random value that is large enough to - # distinguish most timestamps but small enough to not alter the amount - # of seconds. + # System.real_time which returns the nanoseconds as a Float providing + # greater accuracy. We then add a small random value that is large + # enough to distinguish most timestamps but small enough to not alter + # the timestamp significantly. # # See https://gitlab.com/gitlab-com/operations/issues/175 for more # information. - time = @created_at.to_f + rand(JITTER_RANGE) + time = System.real_time(:nanosecond) + rand(JITTER_RANGE) { series: @series, tags: @tags, values: @values, - timestamp: (time * 1_000_000_000).to_i + timestamp: time.to_i } end end diff --git a/lib/gitlab/metrics/system.rb b/lib/gitlab/metrics/system.rb index a7d183b2f94a801f9c8f44d72034e35cf3edd312..82c18bb108b6364d69ccba84af54ecc17986a4a0 100644 --- a/lib/gitlab/metrics/system.rb +++ b/lib/gitlab/metrics/system.rb @@ -34,13 +34,29 @@ module Gitlab # THREAD_CPUTIME is not supported on OS X if Process.const_defined?(:CLOCK_THREAD_CPUTIME_ID) def self.cpu_time - Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :millisecond) + Process. + clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :millisecond).to_f end else def self.cpu_time - Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :millisecond) + Process. + clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :millisecond).to_f end end + + # Returns the current real time in a given precision. + # + # Returns the time as a Float. + def self.real_time(precision = :millisecond) + Process.clock_gettime(Process::CLOCK_REALTIME, precision).to_f + end + + # Returns the current monotonic clock time in a given precision. + # + # Returns the time as a Float. + def self.monotonic_time(precision = :millisecond) + Process.clock_gettime(Process::CLOCK_MONOTONIC, precision).to_f + end end end end diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 4bc5081aa0361e7c2879b39fc3c3120cefd95363..bded245da43de27432ecd1773ce9e8ad36cce053 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -30,7 +30,7 @@ module Gitlab end def duration - @finished_at ? (@finished_at - @started_at) * 1000.0 : 0.0 + @finished_at ? (@finished_at - @started_at) : 0.0 end def allocated_memory @@ -41,12 +41,12 @@ module Gitlab Thread.current[THREAD_KEY] = self @memory_before = System.memory_usage - @started_at = Time.now + @started_at = System.monotonic_time yield ensure @memory_after = System.memory_usage - @finished_at = Time.now + @finished_at = System.monotonic_time Thread.current[THREAD_KEY] = nil end diff --git a/lib/gitlab/o_auth/auth_hash.rb b/lib/gitlab/o_auth/auth_hash.rb index 36e5c2670bbf04c1c8b0f3fe897a371f8156f58f..7d6911a1ab3e19fc8f25b6bdd122f62c642fcbfb 100644 --- a/lib/gitlab/o_auth/auth_hash.rb +++ b/lib/gitlab/o_auth/auth_hash.rb @@ -66,7 +66,7 @@ module Gitlab # Get the first part of the email address (before @) # In addtion in removes illegal characters def generate_username(email) - email.match(/^[^@]*/)[0].mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/,'').to_s + email.match(/^[^@]*/)[0].mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/, '').to_s end def generate_temporarily_email(username) diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 40e8299c36b36d5ba5e430eb11371c1d786e66be..ef1241f8600a883399df294662e592414fa34cc4 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -52,6 +52,19 @@ module Gitlab ] end + def send_git_patch(repository, from, to) + params = { + 'RepoPath' => repository.path_to_repo, + 'ShaFrom' => from, + 'ShaTo' => to + } + + [ + SEND_DATA_HEADER, + "git-format-patch:#{encode(params)}" + ] + end + protected def encode(hash) diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 9ee72fde92f021c9669ac39b1ced24bfe375c5d7..b43ee5b338312ee2e13bc824ce0f23bbe6c1092d 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -33,12 +33,13 @@ namespace :gitlab do unless backup.skipped?('db') unless ENV['force'] == 'yes' - warning = warning = <<-MSG.strip_heredoc + warning = <<-MSG.strip_heredoc Before restoring the database we recommend removing all existing tables to avoid future upgrade problems. Be aware that if you have custom tables in the GitLab database these tables and all data will be removed. MSG + puts warning.color(:red) ask_to_continue puts 'Removing all tables. Press `Ctrl-C` within 5 seconds to abort'.color(:yellow) sleep(5) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 12d6ac45fb6d0a75008f35b6cc7306b12a6c51d0..e9a4e37ec484b9063ee0d4aa6b3d3eab5b5d0305 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -356,97 +356,108 @@ namespace :gitlab do ######################## def check_repo_base_exists - print "Repo base directory exists? ... " + puts "Repo base directory exists?" - repo_base_path = Gitlab.config.gitlab_shell.repos_path + Gitlab.config.repositories.storages.each do |name, repo_base_path| + print "#{name}... " - if File.exists?(repo_base_path) - puts "yes".color(:green) - else - puts "no".color(:red) - puts "#{repo_base_path} is missing".color(:red) - try_fixing_it( - "This should have been created when setting up GitLab Shell.", - "Make sure it's set correctly in config/gitlab.yml", - "Make sure GitLab Shell is installed correctly." - ) - for_more_information( - see_installation_guide_section "GitLab Shell" - ) - fix_and_rerun + if File.exists?(repo_base_path) + puts "yes".color(:green) + else + puts "no".color(:red) + puts "#{repo_base_path} is missing".color(:red) + try_fixing_it( + "This should have been created when setting up GitLab Shell.", + "Make sure it's set correctly in config/gitlab.yml", + "Make sure GitLab Shell is installed correctly." + ) + for_more_information( + see_installation_guide_section "GitLab Shell" + ) + fix_and_rerun + end end end def check_repo_base_is_not_symlink - print "Repo base directory is a symlink? ... " + puts "Repo storage directories are symlinks?" - repo_base_path = Gitlab.config.gitlab_shell.repos_path - unless File.exists?(repo_base_path) - puts "can't check because of previous errors".color(:magenta) - return - end + Gitlab.config.repositories.storages.each do |name, repo_base_path| + print "#{name}... " - unless File.symlink?(repo_base_path) - puts "no".color(:green) - else - puts "yes".color(:red) - try_fixing_it( - "Make sure it's set to the real directory in config/gitlab.yml" - ) - fix_and_rerun + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".color(:magenta) + return + end + + unless File.symlink?(repo_base_path) + puts "no".color(:green) + else + puts "yes".color(:red) + try_fixing_it( + "Make sure it's set to the real directory in config/gitlab.yml" + ) + fix_and_rerun + end end end def check_repo_base_permissions - print "Repo base access is drwxrws---? ... " + puts "Repo paths access is drwxrws---?" - repo_base_path = Gitlab.config.gitlab_shell.repos_path - unless File.exists?(repo_base_path) - puts "can't check because of previous errors".color(:magenta) - return - end + Gitlab.config.repositories.storages.each do |name, repo_base_path| + print "#{name}... " - if File.stat(repo_base_path).mode.to_s(8).ends_with?("2770") - puts "yes".color(:green) - else - puts "no".color(:red) - try_fixing_it( - "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}", - "sudo chmod -R ug-s #{repo_base_path}", - "sudo find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" - ) - for_more_information( - see_installation_guide_section "GitLab Shell" - ) - fix_and_rerun + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".color(:magenta) + return + end + + if File.stat(repo_base_path).mode.to_s(8).ends_with?("2770") + puts "yes".color(:green) + else + puts "no".color(:red) + try_fixing_it( + "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}", + "sudo chmod -R ug-s #{repo_base_path}", + "sudo find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" + ) + for_more_information( + see_installation_guide_section "GitLab Shell" + ) + fix_and_rerun + end end end def check_repo_base_user_and_group gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user gitlab_shell_owner_group = Gitlab.config.gitlab_shell.owner_group - print "Repo base owned by #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group}? ... " + puts "Repo paths owned by #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group}?" - repo_base_path = Gitlab.config.gitlab_shell.repos_path - unless File.exists?(repo_base_path) - puts "can't check because of previous errors".color(:magenta) - return - end + Gitlab.config.repositories.storages.each do |name, repo_base_path| + print "#{name}... " - uid = uid_for(gitlab_shell_ssh_user) - gid = gid_for(gitlab_shell_owner_group) - if File.stat(repo_base_path).uid == uid && File.stat(repo_base_path).gid == gid - puts "yes".color(:green) - else - puts "no".color(:red) - puts " User id for #{gitlab_shell_ssh_user}: #{uid}. Groupd id for #{gitlab_shell_owner_group}: #{gid}".color(:blue) - try_fixing_it( - "sudo chown -R #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group} #{repo_base_path}" - ) - for_more_information( - see_installation_guide_section "GitLab Shell" - ) - fix_and_rerun + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".color(:magenta) + return + end + + uid = uid_for(gitlab_shell_ssh_user) + gid = gid_for(gitlab_shell_owner_group) + if File.stat(repo_base_path).uid == uid && File.stat(repo_base_path).gid == gid + puts "yes".color(:green) + else + puts "no".color(:red) + puts " User id for #{gitlab_shell_ssh_user}: #{uid}. Groupd id for #{gitlab_shell_owner_group}: #{gid}".color(:blue) + try_fixing_it( + "sudo chown -R #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group} #{repo_base_path}" + ) + for_more_information( + see_installation_guide_section "GitLab Shell" + ) + fix_and_rerun + end end end @@ -473,7 +484,7 @@ namespace :gitlab do else puts "wrong or missing hooks".color(:red) try_fixing_it( - sudo_gitlab("#{File.join(gitlab_shell_path, 'bin/create-hooks')}"), + sudo_gitlab("#{File.join(gitlab_shell_path, 'bin/create-hooks')} #{repository_storage_paths_args.join(' ')}"), 'Check the hooks_path in config/gitlab.yml', 'Check your gitlab-shell installation' ) @@ -785,13 +796,13 @@ namespace :gitlab do namespace :repo do desc "GitLab | Check the integrity of the repositories managed by GitLab" task check: :environment do - namespace_dirs = Dir.glob( - File.join(Gitlab.config.gitlab_shell.repos_path, '*') - ) + Gitlab.config.repositories.storages.each do |name, path| + namespace_dirs = Dir.glob(File.join(path, '*')) - namespace_dirs.each do |namespace_dir| - repo_dirs = Dir.glob(File.join(namespace_dir, '*')) - repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) } + namespace_dirs.each do |namespace_dir| + repo_dirs = Dir.glob(File.join(namespace_dir, '*')) + repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) } + end end end end @@ -799,12 +810,12 @@ namespace :gitlab do namespace :user do desc "GitLab | Check the integrity of a specific user's repositories" task :check_repos, [:username] => :environment do |t, args| - username = args[:username] || prompt("Check repository integrity for which username? ".color(:blue)) + username = args[:username] || prompt("Check repository integrity for fsername? ".color(:blue)) user = User.find_by(username: username) if user repo_dirs = user.authorized_projects.map do |p| File.join( - Gitlab.config.gitlab_shell.repos_path, + p.repository_storage_path, "#{p.path_with_namespace}.git" ) end diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake index ab0028d6603013ad73ef92fdf97ac643282e6fdc..b7cbdc6cd78f2901cf7aeee2d3b8771886cf793f 100644 --- a/lib/tasks/gitlab/cleanup.rake +++ b/lib/tasks/gitlab/cleanup.rake @@ -5,36 +5,36 @@ namespace :gitlab do warn_user_is_not_gitlab remove_flag = ENV['REMOVE'] - namespaces = Namespace.pluck(:path) - git_base_path = Gitlab.config.gitlab_shell.repos_path - all_dirs = Dir.glob(git_base_path + '/*') + Gitlab.config.repositories.storages.each do |name, git_base_path| + all_dirs = Dir.glob(git_base_path + '/*') - puts git_base_path.color(:yellow) - puts "Looking for directories to remove... " + puts git_base_path.color(:yellow) + puts "Looking for directories to remove... " - all_dirs.reject! do |dir| - # skip if git repo - dir =~ /.git$/ - end + all_dirs.reject! do |dir| + # skip if git repo + dir =~ /.git$/ + end - all_dirs.reject! do |dir| - dir_name = File.basename dir + all_dirs.reject! do |dir| + dir_name = File.basename dir - # skip if namespace present - namespaces.include?(dir_name) - end + # skip if namespace present + namespaces.include?(dir_name) + end - all_dirs.each do |dir_path| + all_dirs.each do |dir_path| - if remove_flag - if FileUtils.rm_rf dir_path - puts "Removed...#{dir_path}".color(:red) + if remove_flag + if FileUtils.rm_rf dir_path + puts "Removed...#{dir_path}".color(:red) + else + puts "Cannot remove #{dir_path}".color(:red) + end else - puts "Cannot remove #{dir_path}".color(:red) + puts "Can be removed: #{dir_path}".color(:red) end - else - puts "Can be removed: #{dir_path}".color(:red) end end @@ -48,20 +48,21 @@ namespace :gitlab do warn_user_is_not_gitlab move_suffix = "+orphaned+#{Time.now.to_i}" - repo_root = Gitlab.config.gitlab_shell.repos_path - # Look for global repos (legacy, depth 1) and normal repos (depth 2) - IO.popen(%W(find #{repo_root} -mindepth 1 -maxdepth 2 -name *.git)) do |find| - find.each_line do |path| - path.chomp! - repo_with_namespace = path. - sub(repo_root, ''). - sub(%r{^/*}, ''). - chomp('.git'). - chomp('.wiki') - next if Project.find_with_namespace(repo_with_namespace) - new_path = path + move_suffix - puts path.inspect + ' -> ' + new_path.inspect - File.rename(path, new_path) + Gitlab.config.repositories.storages.each do |name, repo_root| + # Look for global repos (legacy, depth 1) and normal repos (depth 2) + IO.popen(%W(find #{repo_root} -mindepth 1 -maxdepth 2 -name *.git)) do |find| + find.each_line do |path| + path.chomp! + repo_with_namespace = path. + sub(repo_root, ''). + sub(%r{^/*}, ''). + chomp('.git'). + chomp('.wiki') + next if Project.find_with_namespace(repo_with_namespace) + new_path = path + move_suffix + puts path.inspect + ' -> ' + new_path.inspect + File.rename(path, new_path) + end end end end diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index 4753f00c26ab76512a3033c939e04e6e2a49bb8b..dbdd4e977e8becc230551f32abbda26a691ab8b6 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -2,73 +2,73 @@ namespace :gitlab do namespace :import do # How to use: # - # 1. copy the bare repos under the repos_path (commonly /home/git/repositories) + # 1. copy the bare repos under the repository storage paths (commonly the default path is /home/git/repositories) # 2. run: bundle exec rake gitlab:import:repos RAILS_ENV=production # # Notes: # * The project owner will set to the first administator of the system # * Existing projects will be skipped # - desc "GitLab | Import bare repositories from gitlab_shell -> repos_path into GitLab project instance" + desc "GitLab | Import bare repositories from repositories -> storages into GitLab project instance" task repos: :environment do + Gitlab.config.repositories.storages.each do |name, git_base_path| + repos_to_import = Dir.glob(git_base_path + '/**/*.git') - git_base_path = Gitlab.config.gitlab_shell.repos_path - repos_to_import = Dir.glob(git_base_path + '/**/*.git') + repos_to_import.each do |repo_path| + # strip repo base path + repo_path[0..git_base_path.length] = '' - repos_to_import.each do |repo_path| - # strip repo base path - repo_path[0..git_base_path.length] = '' + path = repo_path.sub(/\.git$/, '') + group_name, name = File.split(path) + group_name = nil if group_name == '.' - path = repo_path.sub(/\.git$/, '') - group_name, name = File.split(path) - group_name = nil if group_name == '.' + puts "Processing #{repo_path}".color(:yellow) - puts "Processing #{repo_path}".color(:yellow) - - if path.end_with?('.wiki') - puts " * Skipping wiki repo" - next - end + if path.end_with?('.wiki') + puts " * Skipping wiki repo" + next + end - project = Project.find_with_namespace(path) + project = Project.find_with_namespace(path) - if project - puts " * #{project.name} (#{repo_path}) exists" - else - user = User.admins.reorder("id").first + if project + puts " * #{project.name} (#{repo_path}) exists" + else + user = User.admins.reorder("id").first - project_params = { - name: name, - path: name - } + project_params = { + name: name, + path: name + } - # find group namespace - if group_name - group = Namespace.find_by(path: group_name) - # create group namespace - unless group - group = Group.new(:name => group_name) - group.path = group_name - group.owner = user - if group.save - puts " * Created Group #{group.name} (#{group.id})".color(:green) - else - puts " * Failed trying to create group #{group.name}".color(:red) + # find group namespace + if group_name + group = Namespace.find_by(path: group_name) + # create group namespace + unless group + group = Group.new(:name => group_name) + group.path = group_name + group.owner = user + if group.save + puts " * Created Group #{group.name} (#{group.id})".color(:green) + else + puts " * Failed trying to create group #{group.name}".color(:red) + end end + # set project group + project_params[:namespace_id] = group.id end - # set project group - project_params[:namespace_id] = group.id - end - project = Projects::CreateService.new(user, project_params).execute + project = Projects::CreateService.new(user, project_params).execute - if project.persisted? - puts " * Created #{project.name} (#{repo_path})".color(:green) - project.update_repository_size - project.update_commit_count - else - puts " * Failed trying to create #{project.name} (#{repo_path})".color(:red) - puts " Errors: #{project.errors.messages}".color(:red) + if project.persisted? + puts " * Created #{project.name} (#{repo_path})".color(:green) + project.update_repository_size + project.update_commit_count + else + puts " * Failed trying to create #{project.name} (#{repo_path})".color(:red) + puts " Errors: #{project.errors.messages}".color(:red) + end end end end diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake index 352b566df247a5a58f53ee9647df945777a114c4..fe43d40e6d23dac528ca1b3dc8f8185a049f7e00 100644 --- a/lib/tasks/gitlab/info.rake +++ b/lib/tasks/gitlab/info.rake @@ -62,7 +62,10 @@ namespace :gitlab do puts "" puts "GitLab Shell".color(:yellow) puts "Version:\t#{gitlab_shell_version || "unknown".color(:red)}" - puts "Repositories:\t#{Gitlab.config.gitlab_shell.repos_path}" + puts "Repository storage paths:" + Gitlab.config.repositories.storages.each do |name, path| + puts "- #{name}: \t#{path}" + end puts "Hooks:\t\t#{Gitlab.config.gitlab_shell.hooks_path}" puts "Git:\t\t#{Gitlab.config.git.bin_path}" diff --git a/lib/tasks/gitlab/list_repos.rake b/lib/tasks/gitlab/list_repos.rake index c7596e7abcb72d33b1403f84c37a4f43dcf8362c..ffcc76e549891f1ff13051f35d146c968b08abfe 100644 --- a/lib/tasks/gitlab/list_repos.rake +++ b/lib/tasks/gitlab/list_repos.rake @@ -9,7 +9,7 @@ namespace :gitlab do scope = scope.where('id IN (?) OR namespace_id in (?)', project_ids, namespace_ids) end scope.find_each do |project| - base = File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace) + base = File.join(project.repository_storage_path, project.path_with_namespace) puts base + '.git' puts base + '.wiki.git' end diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index b1648a4602abab48320fdb1a0350017b722df1e9..c85ebdf8619b0072f1264b211a4119df3c8119d0 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -12,7 +12,6 @@ namespace :gitlab do gitlab_url = Gitlab.config.gitlab.url # gitlab-shell requires a / at the end of the url gitlab_url += '/' unless gitlab_url.end_with?('/') - repos_path = Gitlab.config.gitlab_shell.repos_path target_dir = Gitlab.config.gitlab_shell.path # Clone if needed @@ -35,7 +34,6 @@ namespace :gitlab do user: user, gitlab_url: gitlab_url, http_settings: {self_signed_cert: false}.stringify_keys, - repos_path: repos_path, auth_file: File.join(home_dir, ".ssh", "authorized_keys"), redis: { bin: %x{which redis-cli}.chomp, @@ -58,10 +56,10 @@ namespace :gitlab do File.open("config.yml", "w+") {|f| f.puts config.to_yaml} # Launch installation process - system(*%W(bin/install)) + system(*%W(bin/install) + repository_storage_paths_args) # (Re)create hooks - system(*%W(bin/create-hooks)) + system(*%W(bin/create-hooks) + repository_storage_paths_args) end # Required for debian packaging with PKGR: Setup .ssh/environment with @@ -73,6 +71,8 @@ namespace :gitlab do File.open(File.join(home_dir, ".ssh", "environment"), "w+") do |f| f.puts "PATH=#{ENV['PATH']}" end + + Gitlab::Shell.new.generate_and_link_secret_token end desc "GitLab | Setup gitlab-shell" @@ -87,7 +87,8 @@ namespace :gitlab do if File.exists?(path_to_repo) print '-' else - if Gitlab::Shell.new.add_repository(project.path_with_namespace) + if Gitlab::Shell.new.add_repository(project.repository_storage_path, + project.path_with_namespace) print '.' else print 'F' @@ -138,4 +139,3 @@ namespace :gitlab do system(*%W(#{Gitlab.config.git.bin_path} reset --hard #{tag})) end end - diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index d0c019044b7eed695b8a82d2a810a799894e492f..ab96b1d35932c9802787ef65e6db2f189961993e 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -125,10 +125,16 @@ namespace :gitlab do end def all_repos - IO.popen(%W(find #{Gitlab.config.gitlab_shell.repos_path} -mindepth 2 -maxdepth 2 -type d -name *.git)) do |find| - find.each_line do |path| - yield path.chomp + Gitlab.config.repositories.storages.each do |name, path| + IO.popen(%W(find #{path} -mindepth 2 -maxdepth 2 -type d -name *.git)) do |find| + find.each_line do |path| + yield path.chomp + end end end end + + def repository_storage_paths_args + Gitlab.config.repositories.storages.values + end end diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake index c5666d49e61d3cbc939f9ed6d56e404459b050a2..21c0e5f1d41c398765f2823cf0b3ec972dd4ae60 100644 --- a/lib/tasks/test.rake +++ b/lib/tasks/test.rake @@ -6,8 +6,6 @@ task :test do end unless Rails.env.production? - require 'coveralls/rake/task' - Coveralls::RakeTask.new desc "GitLab | Run all tests on CI with simplecov" - task :test_ci => [:rubocop, :brakeman, 'teaspoon', :spinach, :spec, 'coveralls:push'] + task test_ci: [:rubocop, :brakeman, 'teaspoon', :spinach, :spec] end diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png index 7da5f23ed9bfa713c51b275987e464f15570fe40..05c8b0d0ccfdcefe43cdb1dae5e6fa0fa8366dae 100644 Binary files a/public/apple-touch-icon-precomposed.png and b/public/apple-touch-icon-precomposed.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index 7da5f23ed9bfa713c51b275987e464f15570fe40..05c8b0d0ccfdcefe43cdb1dae5e6fa0fa8366dae 100644 Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ diff --git a/rubocop/cop/migration/add_index.rb b/rubocop/cop/migration/add_index.rb new file mode 100644 index 0000000000000000000000000000000000000000..d9247a1f7ea379d4ceff88974b6408b47cec4948 --- /dev/null +++ b/rubocop/cop/migration/add_index.rb @@ -0,0 +1,46 @@ +module RuboCop + module Cop + module Migration + # Cop that checks if indexes are added in a concurrent manner. + class AddIndex < RuboCop::Cop::Cop + include MigrationHelpers + + MSG = 'add_index requires downtime, use add_concurrent_index instead' + + def on_def(node) + return unless in_migration?(node) + + new_tables = [] + + node.each_descendant(:send) do |send_node| + first_arg = first_argument(send_node) + + # The first argument of "create_table" / "add_index" is the table + # name. + new_tables << first_arg if create_table?(send_node) + + next if method_name(send_node) != :add_index + + # Using "add_index" is fine for newly created tables as there's no + # data in these tables yet. + next if new_tables.include?(first_arg) + + add_offense(send_node, :selector) + end + end + + def create_table?(node) + method_name(node) == :create_table + end + + def method_name(node) + node.children[1] + end + + def first_argument(node) + node.children[2] ? node.children[0] : nil + end + end + end + end +end diff --git a/rubocop/cop/migration/column_with_default.rb b/rubocop/cop/migration/column_with_default.rb new file mode 100644 index 0000000000000000000000000000000000000000..97ee8b11044d293209e0f37811cb550a65b4b929 --- /dev/null +++ b/rubocop/cop/migration/column_with_default.rb @@ -0,0 +1,50 @@ +module RuboCop + module Cop + module Migration + # Cop that checks if columns are added in a way that doesn't require + # downtime. + class ColumnWithDefault < RuboCop::Cop::Cop + include MigrationHelpers + + WHITELISTED_TABLES = [:application_settings] + + MSG = 'add_column with a default value requires downtime, ' \ + 'use add_column_with_default instead' + + def on_send(node) + return unless in_migration?(node) + + name = node.children[1] + + return unless name == :add_column + + # Ignore whitelisted tables. + return if table_whitelisted?(node.children[2]) + + opts = node.children.last + + return unless opts && opts.type == :hash + + opts.each_node(:pair) do |pair| + if hash_key_type(pair) == :sym && hash_key_name(pair) == :default + add_offense(node, :selector) + end + end + end + + def table_whitelisted?(symbol) + symbol && symbol.type == :sym && + WHITELISTED_TABLES.include?(symbol.children[0]) + end + + def hash_key_type(pair) + pair.children[0].type + end + + def hash_key_name(pair) + pair.children[0].children[0] + end + end + end + end +end diff --git a/rubocop/migration_helpers.rb b/rubocop/migration_helpers.rb new file mode 100644 index 0000000000000000000000000000000000000000..3160a784a042299eb5cc450ca09cd859eef96a36 --- /dev/null +++ b/rubocop/migration_helpers.rb @@ -0,0 +1,10 @@ +module RuboCop + # Module containing helper methods for writing migration cops. + module MigrationHelpers + # Returns true if the given node originated from the db/migrate directory. + def in_migration?(node) + File.dirname(node.location.expression.source_buffer.name). + end_with?('db/migrate') + end + end +end diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb new file mode 100644 index 0000000000000000000000000000000000000000..7922e19768b6a75d3e788e5e4f4ad026f15469bc --- /dev/null +++ b/rubocop/rubocop.rb @@ -0,0 +1,3 @@ +require_relative 'migration_helpers' +require_relative 'cop/migration/add_index' +require_relative 'cop/migration/column_with_default' diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index c55a3c28208f7c66a5bb628597f9a921e2d6c112..51d595268541584acd3be7bb0164ef68788c28c1 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -16,6 +16,24 @@ describe Import::GithubController do allow(controller).to receive(:github_import_enabled?).and_return(true) end + describe "GET new" do + it "redirects to GitHub for an access token if logged in with GitHub" do + allow(controller).to receive(:logged_in_with_github?).and_return(true) + expect(controller).to receive(:go_to_github_for_permissions) + + get :new + end + + it "redirects to status if we already have a token" do + assign_session_token + allow(controller).to receive(:logged_in_with_github?).and_return(false) + + get :new + + expect(controller).to redirect_to(status_import_github_url) + end + end + describe "GET callback" do it "updates access token" do token = "asdasd12345" @@ -32,6 +50,20 @@ describe Import::GithubController do end end + describe "POST personal_access_token" do + it "updates access token" do + token = "asdfasdf9876" + + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:user).and_return(true) + + post :personal_access_token, personal_access_token: token + + expect(session[:github_access_token]).to eq(token) + expect(controller).to redirect_to(status_import_github_url) + end + end + describe "GET status" do before do @repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim') @@ -59,6 +91,17 @@ describe Import::GithubController do expect(assigns(:already_added_projects)).to eq([@project]) expect(assigns(:repos)).to eq([]) end + + it "handles an invalid access token" do + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:repos).and_raise(Octokit::Unauthorized) + + get :status + + expect(session[:github_access_token]).to eq(nil) + expect(controller).to redirect_to(new_import_github_url) + expect(flash[:alert]).to eq('Access denied to your GitHub account.') + end end describe "POST create" do diff --git a/spec/controllers/notification_settings_controller_spec.rb b/spec/controllers/notification_settings_controller_spec.rb index 6be9489edb2af609db8fb64d41adee7915a6fe07..79b819a137706e4d6584481b3319426aba6ba1c7 100644 --- a/spec/controllers/notification_settings_controller_spec.rb +++ b/spec/controllers/notification_settings_controller_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe NotificationSettingsController do let(:project) { create(:empty_project) } + let(:group) { create(:group, :internal) } let(:user) { create(:user) } before do @@ -12,7 +13,7 @@ describe NotificationSettingsController do context 'when not authorized' do it 'redirects to sign in page' do post :create, - project: { id: project.id }, + project_id: project.id, notification_setting: { level: :participating } expect(response).to redirect_to(new_user_session_path) @@ -20,33 +21,73 @@ describe NotificationSettingsController do end context 'when authorized' do + let(:custom_events) do + events = {} + + NotificationSetting::EMAIL_EVENTS.each do |event| + events[event.to_s] = true + end + + events + end + before do sign_in(user) end - it 'returns success' do - post :create, - project: { id: project.id }, - notification_setting: { level: :participating } + context 'for projects' do + let(:notification_setting) { user.notification_settings_for(project) } - expect(response.status).to eq 200 - end + it 'creates notification setting' do + post :create, + project_id: project.id, + notification_setting: { level: :participating } - context 'and setting custom notification setting' do - let(:custom_events) do - events = {} + expect(response.status).to eq 200 + expect(notification_setting.level).to eq("participating") + expect(notification_setting.user_id).to eq(user.id) + expect(notification_setting.source_id).to eq(project.id) + expect(notification_setting.source_type).to eq("Project") + end - NotificationSetting::EMAIL_EVENTS.each do |event| - events[event] = "true" + context 'with custom settings' do + it 'creates notification setting' do + post :create, + project_id: project.id, + notification_setting: { level: :custom }.merge(custom_events) + + expect(response.status).to eq 200 + expect(notification_setting.level).to eq("custom") + expect(notification_setting.events).to eq(custom_events) end end + end - it 'returns success' do + context 'for groups' do + let(:notification_setting) { user.notification_settings_for(group) } + + it 'creates notification setting' do post :create, - project: { id: project.id }, - notification_setting: { level: :participating, events: custom_events } + namespace_id: group.id, + notification_setting: { level: :watch } expect(response.status).to eq 200 + expect(notification_setting.level).to eq("watch") + expect(notification_setting.user_id).to eq(user.id) + expect(notification_setting.source_id).to eq(group.id) + expect(notification_setting.source_type).to eq("Namespace") + end + + context 'with custom settings' do + it 'creates notification setting' do + post :create, + namespace_id: group.id, + notification_setting: { level: :custom }.merge(custom_events) + + expect(response.status).to eq 200 + expect(notification_setting.level).to eq("custom") + expect(notification_setting.events).to eq(custom_events) + end end end end @@ -57,7 +98,7 @@ describe NotificationSettingsController do it 'returns 404' do post :create, - project: { id: private_project.id }, + project_id: private_project.id, notification_setting: { level: :participating } expect(response).to have_http_status(404) diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 1cc35c66c8fdcdce7b9540edc04d1bc58bbd2c20..74c050f48f1b80e4af72bb9048e3ae498fc65be4 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -96,26 +96,14 @@ describe Projects::MergeRequestsController do end describe "as patch" do - include_examples "export merge as", :patch - let(:format) { :patch } - - it "should really be a git email patch with commit" do - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: merge_request.iid, format: format) - - expect(response.body[0..100]).to start_with("From #{merge_request.commits.last.id}") - end - - it "should contain git diffs" do + it 'triggers workhorse to serve the request' do get(:show, namespace_id: project.namespace.to_param, project_id: project.to_param, id: merge_request.iid, - format: format) + format: :patch) - expect(response.body).to match(/^diff --git/) + expect(response.headers['Gitlab-Workhorse-Send-Data']).to start_with("git-format-patch:") end end end diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..f4e5c26b51918579b76041fd35ae40d7f8d973e6 --- /dev/null +++ b/spec/features/admin/admin_system_info_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe 'Admin System Info' do + before do + login_as :admin + end + + describe 'GET /admin/system_info' do + it 'shows system info page' do + visit admin_system_info_path + + expect(page).to have_content 'CPU' + expect(page).to have_content 'Memory' + expect(page).to have_content 'Disks' + end + end +end diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 5065dfb849cf07d3471d5fe1adaaa81231e0adb7..17df66e73b4d9b059ed41598a9c1a6cd05cb5081 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -92,7 +92,7 @@ describe 'Issues', feature: true do end context 'on edit form' do - let(:issue) { create(:issue, author: @user,project: project, due_date: Date.today.at_beginning_of_month.to_s) } + let(:issue) { create(:issue, author: @user, project: project, due_date: Date.today.at_beginning_of_month.to_s) } before do visit edit_namespace_project_issue_path(project.namespace, project, issue) diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index c5fb0fc783be1be6f9f6a463ac64e9b9f8b3dc41..9d66f76ef58b402304a7cadb64d1e7427dc27122 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -24,7 +24,7 @@ feature 'project import', feature: true, js: true do visit new_project_path select2('2', from: '#project_namespace_id') - fill_in :project_path, with:'test-project-path', visible: true + fill_in :project_path, with: 'test-project-path', visible: true click_link 'GitLab export' expect(page).to have_content('GitLab project export') diff --git a/spec/fixtures/dk.png b/spec/fixtures/dk.png index 87ce25e877ab8a9602b77af019f191e6749003f9..1247f2fecd7cc6621a205ca3df25c9aa71d98f34 100644 Binary files a/spec/fixtures/dk.png and b/spec/fixtures/dk.png differ diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..08a9350325872fb451a6657f9791ba41ba4826c5 --- /dev/null +++ b/spec/helpers/notes_helper_spec.rb @@ -0,0 +1,46 @@ +require "spec_helper" + +describe NotesHelper do + describe "#notes_max_access_for_users" do + let(:owner) { create(:owner) } + let(:group) { create(:group) } + let(:project) { create(:empty_project, namespace: group) } + let(:master) { create(:user) } + let(:reporter) { create(:user) } + let(:guest) { create(:user) } + + let(:owner_note) { create(:note, author: owner, project: project) } + let(:master_note) { create(:note, author: master, project: project) } + let(:reporter_note) { create(:note, author: reporter, project: project) } + let!(:notes) { [owner_note, master_note, reporter_note] } + + before do + group.add_owner(owner) + project.team << [master, :master] + project.team << [reporter, :reporter] + project.team << [guest, :guest] + end + + it 'return human access levels' do + original_method = project.team.method(:human_max_access) + expect_any_instance_of(ProjectTeam).to receive(:human_max_access).exactly(3).times do |*args| + original_method.call(args[1]) + end + + expect(helper.note_max_access_for_user(owner_note)).to eq('Owner') + expect(helper.note_max_access_for_user(master_note)).to eq('Master') + expect(helper.note_max_access_for_user(reporter_note)).to eq('Reporter') + # Call it again to ensure value is cached + expect(helper.note_max_access_for_user(owner_note)).to eq('Owner') + end + + it 'handles access in different projects' do + second_project = create(:empty_project) + second_project.team << [master, :reporter] + other_note = create(:note, author: master, project: second_project) + + expect(helper.note_max_access_for_user(master_note)).to eq('Master') + expect(helper.note_max_access_for_user(other_note)).to eq('Reporter') + end + end +end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 09e0bbfd00b807f702bd336cc980a396975f56bb..604204cca0a4c3a6ce760694bd4101d50990fde0 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -123,11 +123,17 @@ describe ProjectsHelper do end describe '#sanitized_import_error' do + let(:project) { create(:project) } + + before do + allow(project).to receive(:repository_storage_path).and_return('/base/repo/path') + end + it 'removes the repo path' do - repo = File.join(Gitlab.config.gitlab_shell.repos_path, '/namespace/test.git') + repo = '/base/repo/path/namespace/test.git' import_error = "Could not clone #{repo}\n" - expect(sanitize_repo_path(import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git') + expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git') end end end diff --git a/spec/initializers/6_validations_spec.rb b/spec/initializers/6_validations_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..5178bd130f4c1748935693ddbae1266abf5f9448 --- /dev/null +++ b/spec/initializers/6_validations_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe '6_validations', lib: true do + context 'with correct settings' do + before do + mock_storages('foo' => '/a/b/c', 'bar' => 'a/b/d') + end + + it 'passes through' do + expect { load_validations }.not_to raise_error + end + end + + context 'with invalid storage names' do + before do + mock_storages('name with spaces' => '/a/b/c') + end + + it 'throws an error' do + expect { load_validations }.to raise_error('"name with spaces" is not a valid storage name. Please fix this in your gitlab.yml before starting GitLab.') + end + end + + context 'with nested storage paths' do + before do + mock_storages('foo' => '/a/b/c', 'bar' => '/a/b/c/d') + end + + it 'throws an error' do + expect { load_validations }.to raise_error('bar is a nested path of foo. Nested paths are not supported for repository storages. Please fix this in your gitlab.yml before starting GitLab.') + end + end + + def mock_storages(storages) + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + + def load_validations + load File.join(__dir__, '../../config/initializers/6_validations.rb') + end +end diff --git a/spec/initializers/trusted_proxies_spec.rb b/spec/initializers/trusted_proxies_spec.rb index 4bb149f25ffe8961eb55157b2f2f1ff829f61e54..14c8df954a6fc7b41a8cf7be7f9f3b8e1e6ef25b 100644 --- a/spec/initializers/trusted_proxies_spec.rb +++ b/spec/initializers/trusted_proxies_spec.rb @@ -6,14 +6,16 @@ describe 'trusted_proxies', lib: true do set_trusted_proxies([]) end - it 'preserves private IPs as remote_ip' do + it 'preserves private IPs' do request = stub_request('HTTP_X_FORWARDED_FOR' => '10.1.5.89') expect(request.remote_ip).to eq('10.1.5.89') + expect(request.ip).to eq('10.1.5.89') end - it 'filters out localhost from remote_ip' do + it 'filters out localhost' do request = stub_request('HTTP_X_FORWARDED_FOR' => '1.1.1.1, 10.1.5.89, 127.0.0.1') expect(request.remote_ip).to eq('10.1.5.89') + expect(request.ip).to eq('10.1.5.89') end end @@ -22,9 +24,10 @@ describe 'trusted_proxies', lib: true do set_trusted_proxies([ "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" ]) end - it 'filters out private and local IPs from remote_ip' do + it 'filters out private and local IPs' do request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 10.1.5.89, 127.0.0.1') expect(request.remote_ip).to eq('1.1.1.1') + expect(request.ip).to eq('1.1.1.1') end end @@ -33,9 +36,10 @@ describe 'trusted_proxies', lib: true do set_trusted_proxies([ "60.98.25.47" ]) end - it 'filters out proxy IP from remote_ip' do + it 'filters out proxy IP' do request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 60.98.25.47, 127.0.0.1') expect(request.remote_ip).to eq('1.1.1.1') + expect(request.ip).to eq('1.1.1.1') end end diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index 8d6ce114aa90be3ee4daf3b652e8dbe727d2f255..a005b4990e7937e9affaa6d651a430c98edc12f5 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -199,6 +199,19 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do end end + context 'referencing external issues' do + let(:project) { create(:redmine_project) } + + it 'renders internal issue IDs as external issue links' do + doc = reference_filter('#1') + link = doc.css('a').first + + expect(link.attr('data-reference-type')).to eq('external_issue') + expect(link.attr('title')).to eq('Issue in Redmine') + expect(link.attr('data-external-issue')).to eq('1') + end + end + describe '#issues_per_Project' do context 'using an internal issue tracker' do it 'returns a Hash containing the issues per project' do diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/backend/shell_spec.rb index fd869f48b5c223890d58c5f85b86219212b986fb..6e5ba21138210ba34d9212c30d6fc5bae044229e 100644 --- a/spec/lib/gitlab/backend/shell_spec.rb +++ b/spec/lib/gitlab/backend/shell_spec.rb @@ -13,9 +13,37 @@ describe Gitlab::Shell, lib: true do it { is_expected.to respond_to :add_repository } it { is_expected.to respond_to :remove_repository } it { is_expected.to respond_to :fork_repository } + it { is_expected.to respond_to :gc } + it { is_expected.to respond_to :add_namespace } + it { is_expected.to respond_to :rm_namespace } + it { is_expected.to respond_to :mv_namespace } + it { is_expected.to respond_to :exists? } it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") } + describe 'generate_and_link_secret_token' do + let(:secret_file) { 'tmp/tests/.secret_shell_test' } + let(:link_file) { 'tmp/tests/shell-secret-test/.gitlab_shell_secret' } + + before do + allow(Gitlab.config.gitlab_shell).to receive(:path).and_return('tmp/tests/shell-secret-test') + allow(Gitlab.config.gitlab_shell).to receive(:secret_file).and_return(secret_file) + FileUtils.mkdir('tmp/tests/shell-secret-test') + gitlab_shell.generate_and_link_secret_token + end + + after do + FileUtils.rm_rf('tmp/tests/shell-secret-test') + FileUtils.rm_rf(secret_file) + end + + it 'creates and links the secret token file' do + expect(File.exist?(secret_file)).to be(true) + expect(File.symlink?(link_file)).to be(true) + expect(File.readlink(link_file)).to eq(secret_file) + end + end + describe Gitlab::Shell::KeyAdder, lib: true do describe '#add_key' do it 'normalizes space characters in the key' do diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..004341ffd0214cc05eb1a39cf7c5bac04e4e5ac1 --- /dev/null +++ b/spec/lib/gitlab/current_settings_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe Gitlab::CurrentSettings do + describe '#current_application_settings' do + it 'attempts to use cached values first' do + allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true) + expect(ApplicationSetting).to receive(:current).and_return(::ApplicationSetting.create_from_defaults) + expect(ApplicationSetting).not_to receive(:last) + + expect(current_application_settings).to be_a(ApplicationSetting) + end + + it 'does not attempt to connect to DB or Redis' do + allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(false) + expect(ApplicationSetting).not_to receive(:current) + expect(ApplicationSetting).not_to receive(:last) + + expect(current_application_settings).to eq fake_application_settings + end + + it 'falls back to DB if Redis returns an empty value' do + allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true) + expect(ApplicationSetting).to receive(:last).and_call_original + + expect(current_application_settings).to be_a(ApplicationSetting) + end + + it 'falls back to DB if Redis fails' do + allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true) + expect(ApplicationSetting).to receive(:current).and_raise(::Redis::BaseError) + expect(ApplicationSetting).to receive(:last).and_call_original + + expect(current_application_settings).to be_a(ApplicationSetting) + end + end +end diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index 7c21cbe96d9fdbd26da9d33d3f8f811fa296ae33..3b023a3544681b0d9386065f49f8f376a99778d6 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -20,6 +20,20 @@ describe Gitlab::GithubImport::Client, lib: true do expect { client.api }.not_to raise_error end + context 'when config is missing' do + before do + allow(Gitlab.config.omniauth).to receive(:providers).and_return([]) + end + + it 'is still possible to get an Octokit client' do + expect { client.api }.not_to raise_error + end + + it 'is not be possible to get an OAuth2 client' do + expect { client.client }.to raise_error(Projects::ImportService::Error) + end + end + context 'allow SSL verification to be configurable on API' do before do github_provider['verify_ssl'] = false diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index 1620eb6c60adb507920d56cd7cbf47b8828961a5..364532e94e30956eb37967dee45f6b85cdacc545 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -4,6 +4,7 @@ describe Gitlab::Highlight, lib: true do include RepoHelpers let(:project) { create(:project) } + let(:repository) { project.repository } let(:commit) { project.commit(sample_commit.id) } describe '.highlight_lines' do @@ -18,4 +19,30 @@ describe Gitlab::Highlight, lib: true do end end + describe 'custom highlighting from .gitattributes' do + let(:branch) { 'gitattributes' } + let(:blob) { repository.blob_at_branch(branch, path) } + + let(:highlighter) do + Gitlab::Highlight.new(blob.path, blob.data, repository: repository) + end + + before { project.change_head('gitattributes') } + + describe 'basic language selection' do + let(:path) { 'custom-highlighting/test.gitlab-custom' } + it 'highlights as ruby' do + expect(highlighter.lexer.tag).to eq 'ruby' + end + end + + describe 'cgi options' do + let(:path) { 'custom-highlighting/test.gitlab-cgi' } + + it 'highlights as json with erb' do + expect(highlighter.lexer.tag).to eq 'erb' + expect(highlighter.lexer.parent.tag).to eq 'json' + end + end + end end diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb index 109522fa626a0bb27e6d500b46b9514ab9a30c47..211ef68dfababe564408868e5840e7fe48833524 100644 --- a/spec/lib/gitlab/import_export/reader_spec.rb +++ b/spec/lib/gitlab/import_export/reader_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::ImportExport::Reader, lib: true do - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path:'') } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: '') } let(:test_config) { 'spec/support/import_export/import_export.yml' } let(:project_tree_hash) do { diff --git a/spec/lib/gitlab/metrics/system_spec.rb b/spec/lib/gitlab/metrics/system_spec.rb index d6ae54e25e859830a534a11ed47eea2dc8f23f32..cf0e282c2fb17391368e6f0ebcbd3999ce8e277a 100644 --- a/spec/lib/gitlab/metrics/system_spec.rb +++ b/spec/lib/gitlab/metrics/system_spec.rb @@ -28,8 +28,20 @@ describe Gitlab::Metrics::System do end describe '.cpu_time' do - it 'returns a Fixnum' do - expect(described_class.cpu_time).to be_an_instance_of(Fixnum) + it 'returns a Float' do + expect(described_class.cpu_time).to be_an_instance_of(Float) + end + end + + describe '.real_time' do + it 'returns a Float' do + expect(described_class.real_time).to be_an_instance_of(Float) + end + end + + describe '.monotonic_time' do + it 'returns a Float' do + expect(described_class.monotonic_time).to be_an_instance_of(Float) end end end diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 6727a83e58a70c41975229884ceb21ac517e460d..5ec5ab40b6f436a68d790808c8543dc78269208b 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -122,7 +122,7 @@ describe Gitlab::OAuth::User, lib: true do before do allow(ldap_user).to receive(:uid) { uid } allow(ldap_user).to receive(:username) { uid } - allow(ldap_user).to receive(:email) { ['johndoe@example.com','john2@example.com'] } + allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] } allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' } allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) end @@ -203,7 +203,7 @@ describe Gitlab::OAuth::User, lib: true do stub_omniauth_config(auto_link_ldap_user: true) allow(ldap_user).to receive(:uid) { uid } allow(ldap_user).to receive(:username) { uid } - allow(ldap_user).to receive(:email) { ['johndoe@example.com','john2@example.com'] } + allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] } allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' } allow(oauth_user).to receive(:ldap_person).and_return(ldap_user) end diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb index 795cf241278aad1abd989a6b1d1b2ef39b0c5ff1..e8b236426e907248b41d4c25d52662f7ecf01355 100644 --- a/spec/lib/gitlab/popen_spec.rb +++ b/spec/lib/gitlab/popen_spec.rb @@ -10,7 +10,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do context 'zero status' do before do - @output, @status = @klass.new.popen(%W(ls), path) + @output, @status = @klass.new.popen(%w(ls), path) end it { expect(@status).to be_zero } @@ -19,7 +19,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do context 'non-zero status' do before do - @output, @status = @klass.new.popen(%W(cat NOTHING), path) + @output, @status = @klass.new.popen(%w(cat NOTHING), path) end it { expect(@status).to eq(1) } @@ -34,7 +34,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do context 'without a directory argument' do before do - @output, @status = @klass.new.popen(%W(ls)) + @output, @status = @klass.new.popen(%w(ls)) end it { expect(@status).to be_zero } diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb index c59dfea5c55f1dce507915547fcff4ee8f2541a6..c4c107c9eea387cc66d6e1d9fe42cb3f86efe67d 100644 --- a/spec/lib/gitlab_spec.rb +++ b/spec/lib/gitlab_spec.rb @@ -8,6 +8,12 @@ describe Gitlab, lib: true do expect(described_class.com?).to eq true end + it 'is true when on staging' do + stub_config_setting(url: 'https://staging.gitlab.com') + + expect(described_class.com?).to eq true + end + it 'is false when not on GitLab.com' do stub_config_setting(url: 'http://example.com') diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index d84f3e998f570b467e2466c345ab1f20d077169a..2ea1320267c34927b0aa4d808da01bb92d3b49c1 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -40,6 +40,16 @@ describe ApplicationSetting, models: true do it_behaves_like 'an object with email-formated attributes', :admin_notification_email do subject { setting } end + + context 'repository storages inclussion' do + before do + storages = { 'custom' => 'tmp/tests/custom_repositories' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + + it { is_expected.to allow_value('custom').for(:repository_storage) } + it { is_expected.not_to allow_value('alternative').for(:repository_storage) } + end end context 'restricted signup domains' do diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index 8154001cf460e4f0f87038220d89e7d8daeea5f5..97b28686d8273d1ac7dfcb82871dc62a4ccb8f7e 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -669,4 +669,22 @@ describe Ci::Build, models: true do expect(build.commit).to eq project.commit end end + + describe '#retryable?' do + context 'when build is running' do + before { build.run! } + + it 'should return false' do + expect(build.retryable?).to be false + end + end + + context 'when build is finished' do + before { build.success! } + + it 'should return true' do + expect(build.retryable?).to be true + end + end + end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 4e68ac5e63af9e0e9894a28732a76bde4ed147e9..cbea407f9bff89feee999517517c501555a2d16c 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -57,6 +57,7 @@ describe Namespace, models: true do describe :move_dir do before do @namespace = create :namespace + @project = create :project, namespace: @namespace allow(@namespace).to receive(:path_changed?).and_return(true) end @@ -87,8 +88,13 @@ describe Namespace, models: true do end describe :rm_dir do - it "should remove dir" do - expect(namespace.rm_dir).to be_truthy + let!(:project) { create(:project, namespace: namespace) } + let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) } + + before { namespace.destroy } + + it "should remove its dirs when deleted" do + expect(File.exist?(path)).to be(false) end end diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..a6d9717ccb52038af69880c59c1b4787cef9e834 --- /dev/null +++ b/spec/models/project_services/bugzilla_service_spec.rb @@ -0,0 +1,49 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null +# + +require 'spec_helper' + +describe BugzillaService, models: true do + describe 'Associations' do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:project_url) } + it { is_expected.to validate_presence_of(:issues_url) } + it { is_expected.to validate_presence_of(:new_issue_url) } + it_behaves_like 'issue tracker service URL attribute', :project_url + it_behaves_like 'issue tracker service URL attribute', :issues_url + it_behaves_like 'issue tracker service URL attribute', :new_issue_url + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:project_url) } + it { is_expected.not_to validate_presence_of(:issues_url) } + it { is_expected.not_to validate_presence_of(:new_issue_url) } + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index d305cd9ff1e39e4a77a065c932af9bfc1a3d79fe..42308035d8c39ad841c81d048346f6c673c38221 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -56,6 +56,7 @@ describe Project, models: true do it { is_expected.to validate_length_of(:description).is_within(0..2000) } it { is_expected.to validate_presence_of(:creator) } it { is_expected.to validate_presence_of(:namespace) } + it { is_expected.to validate_presence_of(:repository_storage) } it 'should not allow new projects beyond user limits' do project2 = build(:project) @@ -84,6 +85,20 @@ describe Project, models: true do end end end + + context 'repository storages inclussion' do + let(:project2) { build(:project, repository_storage: 'missing') } + + before do + storages = { 'custom' => 'tmp/tests/custom_repositories' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + + it "should not allow repository storages that don't match a label in the configuration" do + expect(project2).not_to be_valid + expect(project2.errors[:repository_storage].first).to match(/is not included in the list/) + end + end end describe 'default_scope' do @@ -131,6 +146,24 @@ describe Project, models: true do end end + describe '#repository_storage_path' do + let(:project) { create(:project, repository_storage: 'custom') } + + before do + FileUtils.mkdir('tmp/tests/custom_repositories') + storages = { 'custom' => 'tmp/tests/custom_repositories' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + + after do + FileUtils.rm_rf('tmp/tests/custom_repositories') + end + + it 'returns the repository storage path' do + expect(project.repository_storage_path).to eq('tmp/tests/custom_repositories') + end + end + it 'should return valid url to repo' do project = Project.new(path: 'somewhere') expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git') @@ -574,6 +607,21 @@ describe Project, models: true do end end + context 'repository storage by default' do + let(:project) { create(:empty_project) } + + subject { project.repository_storage } + + before do + storages = { 'alternative_storage' => '/some/path' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + stub_application_setting(repository_storage: 'alternative_storage') + allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(true) + end + + it { is_expected.to eq('alternative_storage') } + end + context 'shared runners by default' do let(:project) { create(:empty_project) } @@ -729,12 +777,12 @@ describe Project, models: true do expect(gitlab_shell).to receive(:mv_repository). ordered. - with("#{ns}/foo", "#{ns}/#{project.path}"). + with(project.repository_storage_path, "#{ns}/foo", "#{ns}/#{project.path}"). and_return(true) expect(gitlab_shell).to receive(:mv_repository). ordered. - with("#{ns}/foo.wiki", "#{ns}/#{project.path}.wiki"). + with(project.repository_storage_path, "#{ns}/foo.wiki", "#{ns}/#{project.path}.wiki"). and_return(true) expect_any_instance_of(SystemHooksService). @@ -826,7 +874,7 @@ describe Project, models: true do context 'using a regular repository' do it 'creates the repository' do expect(shell).to receive(:add_repository). - with(project.path_with_namespace). + with(project.repository_storage_path, project.path_with_namespace). and_return(true) expect(project.repository).to receive(:after_create) @@ -836,7 +884,7 @@ describe Project, models: true do it 'adds an error if the repository could not be created' do expect(shell).to receive(:add_repository). - with(project.path_with_namespace). + with(project.repository_storage_path, project.path_with_namespace). and_return(false) expect(project.repository).not_to receive(:after_create) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index d8350000bf63044ef0ec91752ef5a136d6b162e4..8ae083d7132e63d99b0de4cd5ea7e96f85277aaa 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -531,8 +531,6 @@ describe Repository, models: true do describe '#expire_cache' do it 'expires all caches' do expect(repository).to receive(:expire_branch_cache) - expect(repository).to receive(:expire_branch_count_cache) - expect(repository).to receive(:expire_tag_count_cache) repository.expire_cache end @@ -1055,12 +1053,14 @@ describe Repository, models: true do let(:cache) { repository.send(:cache) } it 'builds the caches if they do not already exist' do + cache_keys = repository.cache_keys + repository.cache_keys_for_branches_and_tags + expect(cache).to receive(:exist?). - exactly(repository.cache_keys.length). + exactly(cache_keys.length). times. and_return(false) - repository.cache_keys.each do |key| + cache_keys.each do |key| expect(repository).to receive(key) end @@ -1068,12 +1068,14 @@ describe Repository, models: true do end it 'does not build any caches that already exist' do + cache_keys = repository.cache_keys + repository.cache_keys_for_branches_and_tags + expect(cache).to receive(:exist?). - exactly(repository.cache_keys.length). + exactly(cache_keys.length). times. and_return(true) - repository.cache_keys.each do |key| + cache_keys.each do |key| expect(repository).not_to receive(key) end diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index 2ab9d640269a1eb41a8934c6ed3bbdb014744e5d..f5b39c3d69857663d00bc57e201d2eb76ad882a8 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -63,23 +63,60 @@ describe API::API, api: true do end describe 'GET /projects/:id/repository/commits/:sha/builds' do - before do - project.ensure_pipeline(pipeline.sha, 'master') - get api("/projects/#{project.id}/repository/commits/#{pipeline.sha}/builds", api_user) - end + context 'when commit does not exist in repository' do + before do + get api("/projects/#{project.id}/repository/commits/1a271fd1/builds", api_user) + end - context 'authorized user' do - it 'should return project builds for specific commit' do - expect(response).to have_http_status(200) - expect(json_response).to be_an Array + it 'responds with 404' do + expect(response).to have_http_status(404) end end - context 'unauthorized user' do - let(:api_user) { nil } + context 'when commit exists in repository' do + context 'when user is authorized' do + context 'when pipeline has builds' do + before do + create(:ci_pipeline, project: project, sha: project.commit.id) + create(:ci_build, pipeline: pipeline) + create(:ci_build) + + get api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", api_user) + end + + it 'should return project builds for specific commit' do + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq 2 + end + end - it 'should not return project builds' do - expect(response).to have_http_status(401) + context 'when pipeline has no builds' do + before do + branch_head = project.commit('feature').id + get api("/projects/#{project.id}/repository/commits/#{branch_head}/builds", api_user) + end + + it 'returns an empty array' do + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response).to be_empty + end + end + end + + context 'when user is not authorized' do + before do + create(:ci_pipeline, project: project, sha: project.commit.id) + create(:ci_build, pipeline: pipeline) + + get api("/projects/#{project.id}/repository/commits/#{project.commit.id}/builds", nil) + end + + it 'should not return project builds' do + expect(response).to have_http_status(401) + expect(json_response.except('message')).to be_empty + end end end end diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index 437c89c35776ab35a7424a8bd58cd5253072bb6d..fcea45f19bad486070cd0f8ea58e64d5075859e4 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -72,6 +72,7 @@ describe API::API, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy + expect(json_response["repository_path"]).to eq(project.repository.path_to_repo) end end @@ -81,6 +82,7 @@ describe API::API, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy + expect(json_response["repository_path"]).to eq(project.repository.path_to_repo) end end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 41b5ed9bc3384cbb71106e5231efeb91592c59e7..5c909d8b3b33a3868cb118097a636f1bb4031a8d 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -217,7 +217,7 @@ describe API::API, api: true do post api('/projects', user), project - project.each_pair do |k,v| + project.each_pair do |k, v| expect(json_response[k.to_s]).to eq(v) end end @@ -325,7 +325,7 @@ describe API::API, api: true do post api("/projects/user/#{user.id}", admin), project - project.each_pair do |k,v| + project.each_pair do |k, v| next if k == :path expect(json_response[k.to_s]).to eq(v) end @@ -805,7 +805,7 @@ describe API::API, api: true do context 'when authenticated' do it 'should return an array of projects' do - get api("/projects/search/#{query}",user) + get api("/projects/search/#{query}", user) expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.size).to eq(6) diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index f756101c51402f00badd86206fabeabf9a9e4316..6629a5a65e2b1967589bbdd99d030cc4c84cac7a 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -14,16 +14,23 @@ describe API::API, 'Settings', api: true do expect(json_response).to be_an Hash expect(json_response['default_projects_limit']).to eq(42) expect(json_response['signin_enabled']).to be_truthy + expect(json_response['repository_storage']).to eq('default') end end describe "PUT /application/settings" do + before do + storages = { 'custom' => 'tmp/tests/custom_repositories' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + it "should update application settings" do put api("/application/settings", admin), - default_projects_limit: 3, signin_enabled: false + default_projects_limit: 3, signin_enabled: false, repository_storage: 'custom' expect(response).to have_http_status(200) expect(json_response['default_projects_limit']).to eq(3) expect(json_response['signin_enabled']).to be_falsey + expect(json_response['repository_storage']).to eq('custom') end end end diff --git a/spec/services/destroy_group_service_spec.rb b/spec/services/destroy_group_service_spec.rb index afa89b84175a778dbc10224f686288676aaf8878..eca8ddd8ea4bc4d2da1d96fdf0b0ef6c6039a6ea 100644 --- a/spec/services/destroy_group_service_spec.rb +++ b/spec/services/destroy_group_service_spec.rb @@ -23,8 +23,8 @@ describe DestroyGroupService, services: true do Sidekiq::Testing.inline! { destroy_group(group, user) } end - it { expect(gitlab_shell.exists?(group.path)).to be_falsey } - it { expect(gitlab_shell.exists?(remove_path)).to be_falsey } + it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey } + it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey } end context 'Sidekiq fake' do @@ -33,8 +33,8 @@ describe DestroyGroupService, services: true do Sidekiq::Testing.fake! { destroy_group(group, user) } end - it { expect(gitlab_shell.exists?(group.path)).to be_falsey } - it { expect(gitlab_shell.exists?(remove_path)).to be_truthy } + it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey } + it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_truthy } end end diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index f99ad046f0dbba07203a42a41e8c014b06ec5bb1..48d374883d75c3ab13852fd68e16db40059c9ba6 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -40,6 +40,18 @@ describe GitPushService, services: true do subject end + + it 'flushes the branches cache' do + expect(project.repository).to receive(:expire_branches_cache) + + subject + end + + it 'flushes the branch count cache' do + expect(project.repository).to receive(:expire_branch_count_cache) + + subject + end end context 'existing branch' do @@ -52,6 +64,18 @@ describe GitPushService, services: true do subject end + + it 'does not flush the branches cache' do + expect(project.repository).not_to receive(:expire_branches_cache) + + subject + end + + it 'does not flush the branch count cache' do + expect(project.repository).not_to receive(:expire_branch_count_cache) + + subject + end end context 'rm branch' do @@ -66,6 +90,18 @@ describe GitPushService, services: true do subject end + it 'flushes the branches cache' do + expect(project.repository).to receive(:expire_branches_cache) + + subject + end + + it 'flushes the branch count cache' do + expect(project.repository).to receive(:expire_branch_count_cache) + + subject + end + it 'flushes general cached data' do expect(project.repository).to receive(:expire_cache). with('master', newrev) @@ -314,6 +350,8 @@ describe GitPushService, services: true do it "doesn't close issues when external issue tracker is in use" do allow_any_instance_of(Project).to receive(:default_issues_tracker?). and_return(false) + external_issue_tracker = double(title: 'My Tracker', issue_path: issue.iid) + allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(external_issue_tracker) # The push still shouldn't create cross-reference notes. expect do diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index a63656e626801a040eaad3253a1f82bf6d38b7ce..a4fcd44882d987294ded49c00902c073c0925355 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -11,6 +11,31 @@ describe GitTagPushService, services: true do let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0 let(:ref) { 'refs/tags/v1.1.0' } + describe "Push tags" do + subject do + service.execute + service + end + + it 'flushes general cached data' do + expect(project.repository).to receive(:expire_cache) + + subject + end + + it 'flushes the tags cache' do + expect(project.repository).to receive(:expire_tags_cache) + + subject + end + + it 'flushes the tag count cache' do + expect(project.repository).to receive(:expire_tag_count_cache) + + subject + end + end + describe "Git Tag Push Data" do before do service.execute diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb index 4c5ced7e746a29bb00fe8bcbd9533c9b30ef39c2..bd4dc6a0f7989d3c2815991b8a04230d53e0c1a2 100644 --- a/spec/services/projects/housekeeping_service_spec.rb +++ b/spec/services/projects/housekeeping_service_spec.rb @@ -12,7 +12,7 @@ describe Projects::HousekeepingService do it 'enqueues a sidekiq job' do expect(subject).to receive(:try_obtain_lease).and_return(true) - expect(GitlabShellOneShotWorker).to receive(:perform_async).with(:gc, project.path_with_namespace) + expect(GitlabShellOneShotWorker).to receive(:perform_async).with(:gc, project.repository_storage_path, project.path_with_namespace) subject.execute expect(project.pushes_since_gc).to eq(0) diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index 068c9a1219c984f127524b7004d8843c00cc9975..d5d4d7c56ef5d492f7a03a861b4797d0113c9cdd 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -36,7 +36,7 @@ describe Projects::ImportService, services: true do end it 'succeeds if repository import is successfully' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) result = subject.execute @@ -44,7 +44,7 @@ describe Projects::ImportService, services: true do end it 'fails if repository import fails' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) result = subject.execute @@ -64,7 +64,7 @@ describe Projects::ImportService, services: true do end it 'succeeds if importer succeeds' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(true) result = subject.execute @@ -74,7 +74,7 @@ describe Projects::ImportService, services: true do it 'flushes various caches' do expect_any_instance_of(Gitlab::Shell).to receive(:import_repository). - with(project.path_with_namespace, project.import_url). + with(project.repository_storage_path, project.path_with_namespace, project.import_url). and_return(true) expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute). @@ -90,7 +90,7 @@ describe Projects::ImportService, services: true do end it 'fails if importer fails' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(false) result = subject.execute @@ -100,7 +100,7 @@ describe Projects::ImportService, services: true do end it 'fails if importer raise an error' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_raise(Projects::ImportService::Error.new('Github: failed to connect API')) result = subject.execute diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b43f38ef2021c24ee46432a432df6645d8f6eccb..606da1b7605b6de5e75873e555c5b1ca399f81b4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,11 +3,6 @@ if ENV['SIMPLECOV'] SimpleCov.start :rails end -if ENV['COVERALLS'] - require 'coveralls' - Coveralls.wear_merged! -end - ENV["RAILS_ENV"] ||= 'test' require File.expand_path("../../config/environment", __FILE__) diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 498bd4bf8000e9203c643f93aa129d6e4f225f70..9f9ef20f99b55015692d58f5bd0e92b5d53a2ee3 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -17,6 +17,7 @@ module TestEnv "'test'" => 'e56497b', 'orphaned-branch' => '45127a9', 'binary-encoding' => '7b1cf43', + 'gitattributes' => '5a62481', } # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily @@ -79,7 +80,7 @@ module TestEnv end def setup_gitlab_shell - unless File.directory?(Rails.root.join(*%w(tmp tests gitlab-shell))) + unless File.directory?(Gitlab.config.gitlab_shell.path) `rake gitlab:shell:install` end end @@ -126,14 +127,14 @@ module TestEnv def copy_repo(project) base_repo_path = File.expand_path(factory_repo_path_bare) - target_repo_path = File.expand_path(repos_path + "/#{project.namespace.path}/#{project.path}.git") + target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.namespace.path}/#{project.path}.git") FileUtils.mkdir_p(target_repo_path) FileUtils.cp_r("#{base_repo_path}/.", target_repo_path) FileUtils.chmod_R 0755, target_repo_path end def repos_path - Gitlab.config.gitlab_shell.repos_path + Gitlab.config.repositories.storages.default end def backup_path @@ -142,7 +143,7 @@ module TestEnv def copy_forked_repo_with_submodules(project) base_repo_path = File.expand_path(forked_repo_path_bare) - target_repo_path = File.expand_path(repos_path + "/#{project.namespace.path}/#{project.path}.git") + target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.namespace.path}/#{project.path}.git") FileUtils.mkdir_p(target_repo_path) FileUtils.cp_r("#{base_repo_path}/.", target_repo_path) FileUtils.chmod_R 0755, target_repo_path diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index 25da0917134cdb819157f77327580da9780da22a..02308530d13db6459da27bdb833ab5c452df6878 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -98,67 +98,107 @@ describe 'gitlab:app namespace rake task' do @backup_tar = tars_glob.first end - before do - create_backup - end - - after do - FileUtils.rm(@backup_tar) - end + context 'tar creation' do + before do + create_backup + end - context 'archive file permissions' do - it 'should set correct permissions on the tar file' do - expect(File.exist?(@backup_tar)).to be_truthy - expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100600') + after do + FileUtils.rm(@backup_tar) end - context 'with custom archive_permissions' do - before do - allow(Gitlab.config.backup).to receive(:archive_permissions).and_return(0651) - # We created a backup in a before(:all) so it got the default permissions. - # We now need to do some work to create a _new_ backup file using our stub. - FileUtils.rm(@backup_tar) - create_backup + context 'archive file permissions' do + it 'should set correct permissions on the tar file' do + expect(File.exist?(@backup_tar)).to be_truthy + expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100600') end - it 'uses the custom permissions' do - expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100651') + context 'with custom archive_permissions' do + before do + allow(Gitlab.config.backup).to receive(:archive_permissions).and_return(0651) + # We created a backup in a before(:all) so it got the default permissions. + # We now need to do some work to create a _new_ backup file using our stub. + FileUtils.rm(@backup_tar) + create_backup + end + + it 'uses the custom permissions' do + expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100651') + end end end - end - it 'should set correct permissions on the tar contents' do - tar_contents, exit_status = Gitlab::Popen.popen( - %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz registry.tar.gz} - ) - expect(exit_status).to eq(0) - expect(tar_contents).to match('db/') - expect(tar_contents).to match('uploads.tar.gz') - expect(tar_contents).to match('repositories/') - expect(tar_contents).to match('builds.tar.gz') - expect(tar_contents).to match('artifacts.tar.gz') - expect(tar_contents).to match('lfs.tar.gz') - expect(tar_contents).to match('registry.tar.gz') - expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz|registry.tar.gz)\/$/) - end + it 'should set correct permissions on the tar contents' do + tar_contents, exit_status = Gitlab::Popen.popen( + %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz registry.tar.gz} + ) + expect(exit_status).to eq(0) + expect(tar_contents).to match('db/') + expect(tar_contents).to match('uploads.tar.gz') + expect(tar_contents).to match('repositories/') + expect(tar_contents).to match('builds.tar.gz') + expect(tar_contents).to match('artifacts.tar.gz') + expect(tar_contents).to match('lfs.tar.gz') + expect(tar_contents).to match('registry.tar.gz') + expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz|registry.tar.gz)\/$/) + end - it 'should delete temp directories' do - temp_dirs = Dir.glob( - File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,lfs,registry}') - ) + it 'should delete temp directories' do + temp_dirs = Dir.glob( + File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,lfs,registry}') + ) + + expect(temp_dirs).to be_empty + end - expect(temp_dirs).to be_empty + context 'registry disabled' do + let(:enable_registry) { false } + + it 'should not create registry.tar.gz' do + tar_contents, exit_status = Gitlab::Popen.popen( + %W{tar -tvf #{@backup_tar}} + ) + expect(exit_status).to eq(0) + expect(tar_contents).not_to match('registry.tar.gz') + end + end end - context 'registry disabled' do - let(:enable_registry) { false } + context 'multiple repository storages' do + let(:project_a) { create(:project, repository_storage: 'default') } + let(:project_b) { create(:project, repository_storage: 'custom') } + + before do + FileUtils.mkdir('tmp/tests/default_storage') + FileUtils.mkdir('tmp/tests/custom_storage') + storages = { + 'default' => 'tmp/tests/default_storage', + 'custom' => 'tmp/tests/custom_storage' + } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + + # Create the projects now, after mocking the settings but before doing the backup + project_a + project_b + + # We only need a backup of the repositories for this test + ENV["SKIP"] = "db,uploads,builds,artifacts,lfs,registry" + create_backup + end + + after do + FileUtils.rm_rf('tmp/tests/default_storage') + FileUtils.rm_rf('tmp/tests/custom_storage') + FileUtils.rm(@backup_tar) + end - it 'should not create registry.tar.gz' do + it 'should include repositories in all repository storages' do tar_contents, exit_status = Gitlab::Popen.popen( - %W{tar -tvf #{@backup_tar}} + %W{tar -tvf #{@backup_tar} repositories} ) expect(exit_status).to eq(0) - expect(tar_contents).not_to match('registry.tar.gz') + expect(tar_contents).to match("repositories/#{project_a.path_with_namespace}.bundle") + expect(tar_contents).to match("repositories/#{project_b.path_with_namespace}.bundle") end end end # backup_create task diff --git a/spec/views/projects/builds/show.html.haml_spec.rb b/spec/views/projects/builds/show.html.haml_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..cd18d19ef5e7c2cbc5eedd34bd7b4e146a8b696b --- /dev/null +++ b/spec/views/projects/builds/show.html.haml_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'projects/builds/show' do + include Devise::TestHelpers + + let(:build) { create(:ci_build) } + let(:project) { build.project } + + before do + assign(:build, build) + assign(:project, project) + + allow(view).to receive(:can?).and_return(true) + end + + context 'when build is running' do + before do + build.run! + render + end + + it 'does not show retry button' do + expect(rendered).not_to have_link('Retry') + end + end + + context 'when build is not running' do + before do + build.success! + render + end + + it 'shows retry button' do + expect(rendered).to have_link('Retry') + end + end +end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index b8e73682c91ca61910d3f1c1674de82a546a39c5..20b1a343c27887d7d7121652dc5e3ed3dfd976b6 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -91,6 +91,6 @@ describe PostReceive do end def pwd(project) - File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace) + File.join(Gitlab.config.repositories.storages.default, project.path_with_namespace) end end diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb index 4ef05eb29d2b3f1c95f7b97bd7ed92325b0aa2ec..5f762282b5ea7ddae6a61adc14e006fe1c8780e3 100644 --- a/spec/workers/repository_fork_worker_spec.rb +++ b/spec/workers/repository_fork_worker_spec.rb @@ -14,6 +14,7 @@ describe RepositoryForkWorker do describe "#perform" do it "creates a new repository from a fork" do expect(shell).to receive(:fork_repository).with( + project.repository_storage_path, project.path_with_namespace, fork_project.namespace.path ).and_return(true) @@ -25,9 +26,11 @@ describe RepositoryForkWorker do end it 'flushes various caches' do - expect(shell).to receive(:fork_repository). - with(project.path_with_namespace, fork_project.namespace.path). - and_return(true) + expect(shell).to receive(:fork_repository).with( + project.repository_storage_path, + project.path_with_namespace, + fork_project.namespace.path + ).and_return(true) expect_any_instance_of(Repository).to receive(:expire_emptiness_caches). and_call_original