diff options
434 files changed, 1745 insertions, 697 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index dbdabbb9d4c..cdcfd8150e5 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 7a92f9f52d0..b97116af73c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,8 +3,12 @@ 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 @@ -13,23 +17,49 @@ v 8.10.0 (unreleased) - 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. - Don't instantiate a git tree on Projects show default view - 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.3 (unreleased) - - MergeRequestDiff reload content use update_columns to avoid multiple YAML de/serializations - - Decreased min width of screen to 1280px for pinned sidebar - - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - - Update mobile button icons to be more inline with typical UI paradigms - - Fixes missing avatar on system notes. !4954 - - Improve performance of obtaining the maximum access of a user in a project +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. @@ -80,7 +110,6 @@ v 8.9.1 - Remove duplicate 'New Page' button on edit wiki page v 8.9.0 -v 8.9.0 (unreleased) - 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 @@ -227,12 +256,17 @@ v 8.9.0 (unreleased) - 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 @@ -367,6 +401,10 @@ 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 diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 4a36342fcab..fd2a01863fd 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -3.0.0 +3.1.0 @@ -303,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 @@ -350,3 +349,4 @@ 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 4c5350ba639..f99b373dbbd 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) @@ -721,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 @@ -729,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) @@ -751,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) @@ -841,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) @@ -976,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) diff --git a/app/assets/images/auth_buttons/azure_64.png b/app/assets/images/auth_buttons/azure_64.png Binary files differindex a82c751e001..85de7793440 100644 --- a/app/assets/images/auth_buttons/azure_64.png +++ b/app/assets/images/auth_buttons/azure_64.png diff --git a/app/assets/images/auth_buttons/bitbucket_64.png b/app/assets/images/auth_buttons/bitbucket_64.png Binary files differindex 4b90a57bc7d..b3d022a5a70 100644 --- a/app/assets/images/auth_buttons/bitbucket_64.png +++ b/app/assets/images/auth_buttons/bitbucket_64.png diff --git a/app/assets/images/auth_buttons/facebook_64.png b/app/assets/images/auth_buttons/facebook_64.png Binary files differindex 1f1a80d7368..71ffb1c6a1f 100644 --- a/app/assets/images/auth_buttons/facebook_64.png +++ b/app/assets/images/auth_buttons/facebook_64.png diff --git a/app/assets/images/auth_buttons/github_64.png b/app/assets/images/auth_buttons/github_64.png Binary files differindex 182a1a3f734..1fa19c55d2f 100644 --- a/app/assets/images/auth_buttons/github_64.png +++ b/app/assets/images/auth_buttons/github_64.png diff --git a/app/assets/images/auth_buttons/gitlab_64.png b/app/assets/images/auth_buttons/gitlab_64.png Binary files differindex 99a40583b3a..f675678dc9d 100644 --- a/app/assets/images/auth_buttons/gitlab_64.png +++ b/app/assets/images/auth_buttons/gitlab_64.png diff --git a/app/assets/images/auth_buttons/google_64.png b/app/assets/images/auth_buttons/google_64.png Binary files differindex fb64f8bee68..720824230a5 100644 --- a/app/assets/images/auth_buttons/google_64.png +++ b/app/assets/images/auth_buttons/google_64.png diff --git a/app/assets/images/auth_buttons/twitter_64.png b/app/assets/images/auth_buttons/twitter_64.png Binary files differindex e3bd9169a34..a4f14de57ae 100644 --- a/app/assets/images/auth_buttons/twitter_64.png +++ b/app/assets/images/auth_buttons/twitter_64.png diff --git a/app/assets/images/bg_fallback.png b/app/assets/images/bg_fallback.png Binary files differindex e5fe659ba63..5c55bc79dec 100644 --- a/app/assets/images/bg_fallback.png +++ b/app/assets/images/bg_fallback.png diff --git a/app/assets/images/dark-scheme-preview.png b/app/assets/images/dark-scheme-preview.png Binary files differindex 2ef58e52549..8855babf147 100644 --- a/app/assets/images/dark-scheme-preview.png +++ b/app/assets/images/dark-scheme-preview.png diff --git a/app/assets/images/emoji.png b/app/assets/images/emoji.png Binary files differindex 1e7cf79ea45..99093d4725a 100644 --- a/app/assets/images/emoji.png +++ b/app/assets/images/emoji.png diff --git a/app/assets/images/emoji@2x.png b/app/assets/images/emoji@2x.png Binary files differindex 74d67f7520d..48989942a9f 100644 --- a/app/assets/images/emoji@2x.png +++ b/app/assets/images/emoji@2x.png diff --git a/app/assets/images/gitlab_logo.png b/app/assets/images/gitlab_logo.png Binary files differindex 0c157546b9c..ca30b459019 100644 --- a/app/assets/images/gitlab_logo.png +++ b/app/assets/images/gitlab_logo.png diff --git a/app/assets/images/gitorious-logo-black.png b/app/assets/images/gitorious-logo-black.png Binary files differindex 78f17a9af79..4a55fdc225a 100644 --- a/app/assets/images/gitorious-logo-black.png +++ b/app/assets/images/gitorious-logo-black.png diff --git a/app/assets/images/gitorious-logo-blue.png b/app/assets/images/gitorious-logo-blue.png Binary files differindex 4962cffba31..5eaa327d3df 100644 --- a/app/assets/images/gitorious-logo-blue.png +++ b/app/assets/images/gitorious-logo-blue.png diff --git a/app/assets/images/icon-link.png b/app/assets/images/icon-link.png Binary files differindex 7d89da97e11..5b55e12571c 100644 --- a/app/assets/images/icon-link.png +++ b/app/assets/images/icon-link.png diff --git a/app/assets/images/images.png b/app/assets/images/images.png Binary files differindex ad146246caf..bd60de994c4 100644 --- a/app/assets/images/images.png +++ b/app/assets/images/images.png diff --git a/app/assets/images/monokai-scheme-preview.png b/app/assets/images/monokai-scheme-preview.png Binary files differindex fbb339c6a91..d9c7d2d8041 100644 --- a/app/assets/images/monokai-scheme-preview.png +++ b/app/assets/images/monokai-scheme-preview.png diff --git a/app/assets/images/msapplication-tile.png b/app/assets/images/msapplication-tile.png Binary files differindex 58bbf2b20cb..1e0e2ed73ce 100644 --- a/app/assets/images/msapplication-tile.png +++ b/app/assets/images/msapplication-tile.png diff --git a/app/assets/images/no_avatar.png b/app/assets/images/no_avatar.png Binary files differindex 8287acbce13..5383d687b53 100644 --- a/app/assets/images/no_avatar.png +++ b/app/assets/images/no_avatar.png diff --git a/app/assets/images/no_group_avatar.png b/app/assets/images/no_group_avatar.png Binary files differindex bfb31bb2184..71612d55286 100644 --- a/app/assets/images/no_group_avatar.png +++ b/app/assets/images/no_group_avatar.png diff --git a/app/assets/images/slider_handles.png b/app/assets/images/slider_handles.png Binary files differindex 884378ec96a..52ad11ab7a1 100644 --- a/app/assets/images/slider_handles.png +++ b/app/assets/images/slider_handles.png diff --git a/app/assets/images/touch-icon-ipad-retina.png b/app/assets/images/touch-icon-ipad-retina.png Binary files differindex feb32b48ec9..516dc2f4710 100644 --- a/app/assets/images/touch-icon-ipad-retina.png +++ b/app/assets/images/touch-icon-ipad-retina.png diff --git a/app/assets/images/touch-icon-ipad.png b/app/assets/images/touch-icon-ipad.png Binary files differindex a6ddc543509..b2093d015b8 100644 --- a/app/assets/images/touch-icon-ipad.png +++ b/app/assets/images/touch-icon-ipad.png diff --git a/app/assets/images/touch-icon-iphone-retina.png b/app/assets/images/touch-icon-iphone-retina.png Binary files differindex 8bf7ccb7534..438654e0d20 100644 --- a/app/assets/images/touch-icon-iphone-retina.png +++ b/app/assets/images/touch-icon-iphone-retina.png diff --git a/app/assets/images/touch-icon-iphone.png b/app/assets/images/touch-icon-iphone.png Binary files differindex 87da550f8be..e5f87fbbcf6 100644 --- a/app/assets/images/touch-icon-iphone.png +++ b/app/assets/images/touch-icon-iphone.png diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index b6dbf2d0cc1..20fe5a5cc27 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') @@ -260,8 +269,8 @@ $ -> new Aside() # Sidenav pinning - if $window.width() < 1280 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') @@ -292,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 7fbff9214cf..9493a575801 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 4f73d215b85..b76d214790a 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 1b0d9f0b1ae..ed9dfcc917e 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -220,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/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee index 421328554b8..72b1d3dfb1e 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 c03877e9b06..3319a67a79d 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 de8eebcd0b2..83de584f2d9 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 38023818709..41e77a4ac68 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 1bfd0213995..a951a2b97fe 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 fd8eaa8a691..5d3273ea64d 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/variables.scss b/app/assets/stylesheets/framework/variables.scss index 87f8a17659f..211a9af2348 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: 1280px; +$sidebar-breakpoint: 1024px; /* * UI elements diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index de534d28421..85bbf70e188 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 ac7721cbe15..101faf59174 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/tree.scss b/app/assets/stylesheets/pages/tree.scss index 99c9e81ddb9..5b61270daa8 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 f4eda864aac..5f65dd3aff0 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 index 3c67370b667..e4c73008826 100644 --- a/app/controllers/admin/system_info_controller.rb +++ b/app/controllers/admin/system_info_controller.rb @@ -1,13 +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 - - @disk_used = system_info.disks[0].used_bytes - @disk_total = system_info.disks[0].total_bytes end end diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 8bf71a1adbb..aa894fde36b 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 ee4fcc4e360..a04bf7df722 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 67bf4190e7e..9c1b0eb20f4 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 eddd03cc229..8ec4bb1233f 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/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 55313fd8357..6e580c62ccd 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/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb index 6b617e1730a..7c140538012 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 5074e645769..5e9f5837101 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 b401c8385be..e85ba76887d 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 77783cd7640..7e8369d0a05 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 e4e8b934bc8..22387d66451 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 d91e3332e48..f312a7ccca3 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 d914b0b26eb..5fa6eacd234 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 2b0bec33131..c11f8e6884d 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/namespace.rb b/app/models/namespace.rb index da19462f265..8b52cc824cd 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 a2aee2f925b..345041a6ad1 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 73ded09c162..6a950ee830d 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 @@ -165,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 @@ -376,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 @@ -842,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 @@ -988,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 @@ -1140,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_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 0ff4f4c8dd2..23e5b16221b 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 beda89d3963..8b3296c712f 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_wiki.rb b/app/models/project_wiki.rb index 25d82929c0b..a255710f577 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 2a6a3b086c2..eb232ea681b 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) diff --git a/app/models/user.rb b/app/models/user.rb index 767d6366c79..eac716b120b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -764,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 f09072975c3..882606e38d0 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 43db29315a1..a47df22f1ba 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 9159ec08959..163ebf26c84 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 03b57dea51e..bc7f8bf433b 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 28085b31083..046a1d641a9 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 30ab0717164..c1f70bc1866 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -311,6 +311,15 @@ = 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 .col-sm-offset-2.col-sm-10 diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml index 654d261aa99..4f680b507c4 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 efd5b12cfeb..1e60205f91a 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 4682016a886..a2ac407c159 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 4f1996ef7ab..94aa5f5a942 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 7b8407f9152..e79303240f0 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 5ddc3b9ea85..676812121d7 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 4822cb693c2..7d2eb423223 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 5eff77aff2d..114bea92fc2 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 index 3ef2f20b589..6956e5ab795 100644 --- a/app/views/admin/system_info/show.html.haml +++ b/app/views/admin/system_info/show.html.haml @@ -2,7 +2,7 @@ - page_title "System Info" = render 'admin/background_jobs/head' -%div{ class: (container_class) } +%div{ class: container_class } .prepend-top-default .row .col-sm-4 @@ -17,6 +17,9 @@ %h1= "#{number_to_human_size(@mem_used)} / #{number_to_human_size(@mem_total)}" .col-sm-4 .light-well - %h4 Disk + %h4 Disks .data - %h1= "#{number_to_human_size(@disk_used)} / #{number_to_human_size(@disk_total)}" + - @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 d0a696da64b..21bb99a792c 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/groups/show.html.haml b/app/views/groups/show.html.haml index aecefbc6e8f..69f634e75b9 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 57bc91ea5a9..57601ae9be0 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 00000000000..435ed7bd4cb --- /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/projects/_github_import_modal.html.haml b/app/views/projects/_github_import_modal.html.haml deleted file mode 100644 index 46ad1559356..00000000000 --- 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 86ea08dd229..8ce23379fb4 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 e0ca2a3109c..434d8644b83 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/blob/show.html.haml b/app/views/projects/blob/show.html.haml index ed670dae88d..0ab78a39cf9 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 e0367c40272..77b405f1f39 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 181547316aa..a131289ee97 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 4e2702c2e44..d1c468c4692 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/show.html.haml b/app/views/projects/commits/show.html.haml index 51ca4eb903e..9a44ba94970 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 b22285c11e0..e9ff8e90dd5 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 f4ec7b767f6..28a50e7031a 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 a03f117291f..5242021243e 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 4c15e2759d6..53c62ef234d 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 e695d3ae369..6be4273b6ab 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 0daffe68f6f..65db8af494d 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 6d97f552a8e..fcfcae0be20 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 9f7e2a361ff..a985b442b2d 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 a8a8caf7280..2cd8d03e30e 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 cd876b5ea62..7ce4c1e5555 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 aa4d69550ec..db66a0edbd8 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 9f948d41dda..ace275c689b 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 b0e0bdfff5a..ad2bfbec915 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 86295a3d011..8f6805268d5 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 3ca30b4ba6b..091af4df4a1 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 8a73b077357..05f33b78a47 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -23,6 +23,7 @@ .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} + - else .input-group-addon.static-namespace #{root_url}#{current_user.username}/ @@ -44,15 +45,8 @@ .col-sm-12.import-buttons %div - 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' + = link_to new_import_github_path, class: 'btn import_github' do + = icon 'github', text: 'GitHub' %div - if bitbucket_import_enabled? - if bitbucket_import_configured? diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index a5e163b91e9..af0046886fb 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 b70693eeb62..28b475d5c2f 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 15f0d85194b..f6e81af2638 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 4ca1f58ac5c..c375bb6dd1b 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 2abcfcdd7b2..bf5360b4dee 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 4f8abcdc8e1..c32cb122c26 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 817bf9b3f69..233538bb488 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 6caf7230f35..b8811a28dd6 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 630ee35b70b..4c0b14e2c42 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 81d9f391c1c..9c10acd4cb6 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 76f9b1ecd76..5cebb538cf5 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/_labels_row.html.haml b/app/views/shared/_labels_row.html.haml index 87028ececd4..5507a05f6c1 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/workers/post_receive.rb b/app/workers/post_receive.rb index f3327ca9e61..09035a7cf2d 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 d947f105516..f7604e48f83 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 436a2c5e17a..293f2b71d65 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 01c8dc5ff98..75b79b837e0 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 75e1a3c1093..325eca72862 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 c6dc1e4ab38..a93996cec72 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -304,7 +304,6 @@ 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 @@ -312,6 +311,14 @@ 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 # Settings['backup'] ||= Settingslogic.new({}) diff --git a/config/initializers/6_validations.rb b/config/initializers/6_validations.rb new file mode 100644 index 00000000000..3ba9e36c567 --- /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 021bdb11251..73977341b73 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 751fccead07..7454c33c9dd 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 30d05f16153..69052c029f2 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 7a2b9a7f6c1..593c14a289f 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 d256a16d42b..df4a933e22f 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 bdfb16a66bf..c04780fec88 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 @@ -653,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 00000000000..c700d2b569d --- /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 00000000000..6dae91b700b --- /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 7a8377f687c..beb723c3bc5 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 be0d17084c7..b98d6812a81 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 Binary files differindex f7c5bc44367..f72ad9a45d5 100644 --- a/doc/administration/img/housekeeping_settings.png +++ b/doc/administration/img/housekeeping_settings.png diff --git a/doc/administration/repository_storages.md b/doc/administration/repository_storages.md new file mode 100644 index 00000000000..81bfe173151 --- /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/settings.md b/doc/api/settings.md index b5152311f28..741c5a29581 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" } ``` @@ -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 Binary files differindex 73ed4eeb927..59cf2b8746b 100644 --- a/doc/ci/build_artifacts/img/build_artifacts_browser.png +++ b/doc/ci/build_artifacts/img/build_artifacts_browser.png diff --git a/doc/ci/build_artifacts/img/build_artifacts_browser_button.png b/doc/ci/build_artifacts/img/build_artifacts_browser_button.png Binary files differindex f5d15bc3e7d..7801c2e6fa6 100644 --- a/doc/ci/build_artifacts/img/build_artifacts_browser_button.png +++ b/doc/ci/build_artifacts/img/build_artifacts_browser_button.png diff --git a/doc/ci/img/builds_tab.png b/doc/ci/img/builds_tab.png Binary files differindex d088b8b329d..35780e277ae 100644 --- a/doc/ci/img/builds_tab.png +++ b/doc/ci/img/builds_tab.png diff --git a/doc/ci/img/features_settings.png b/doc/ci/img/features_settings.png Binary files differindex 17aba5d14d8..38d7036f606 100644 --- a/doc/ci/img/features_settings.png +++ b/doc/ci/img/features_settings.png diff --git a/doc/ci/quick_start/img/build_log.png b/doc/ci/quick_start/img/build_log.png Binary files differindex 89e6cd40cb6..b53a6cd86b0 100644 --- a/doc/ci/quick_start/img/build_log.png +++ b/doc/ci/quick_start/img/build_log.png diff --git a/doc/ci/quick_start/img/builds_status.png b/doc/ci/quick_start/img/builds_status.png Binary files differindex b8e6c2a361a..47862761ffe 100644 --- a/doc/ci/quick_start/img/builds_status.png +++ b/doc/ci/quick_start/img/builds_status.png diff --git a/doc/ci/quick_start/img/new_commit.png b/doc/ci/quick_start/img/new_commit.png Binary files differindex 3d3c9d5c0bd..a53562ce328 100644 --- a/doc/ci/quick_start/img/new_commit.png +++ b/doc/ci/quick_start/img/new_commit.png diff --git a/doc/ci/quick_start/img/runners_activated.png b/doc/ci/quick_start/img/runners_activated.png Binary files differindex eafcfd6ecd5..23261123b18 100644 --- a/doc/ci/quick_start/img/runners_activated.png +++ b/doc/ci/quick_start/img/runners_activated.png diff --git a/doc/ci/quick_start/img/single_commit_status_pending.png b/doc/ci/quick_start/img/single_commit_status_pending.png Binary files differindex 23b3bb5acfc..ccf3ac957bb 100644 --- a/doc/ci/quick_start/img/single_commit_status_pending.png +++ b/doc/ci/quick_start/img/single_commit_status_pending.png diff --git a/doc/ci/quick_start/img/status_pending.png b/doc/ci/quick_start/img/status_pending.png Binary files differindex a049ec2a5ba..9feacf0c961 100644 --- a/doc/ci/quick_start/img/status_pending.png +++ b/doc/ci/quick_start/img/status_pending.png diff --git a/doc/ci/runners/project_specific.png b/doc/ci/runners/project_specific.png Binary files differindex f51ea694e78..c812defa67b 100644 --- a/doc/ci/runners/project_specific.png +++ b/doc/ci/runners/project_specific.png diff --git a/doc/ci/runners/shared_runner.png b/doc/ci/runners/shared_runner.png Binary files differindex 9755144eb08..31574a17764 100644 --- a/doc/ci/runners/shared_runner.png +++ b/doc/ci/runners/shared_runner.png diff --git a/doc/ci/runners/shared_to_specific_admin.png b/doc/ci/runners/shared_to_specific_admin.png Binary files differindex 44a4bef22f7..8f4010a5849 100644 --- a/doc/ci/runners/shared_to_specific_admin.png +++ b/doc/ci/runners/shared_to_specific_admin.png diff --git a/doc/ci/triggers/img/builds_page.png b/doc/ci/triggers/img/builds_page.png Binary files differindex e78794fbee7..2dee8ee6107 100644 --- a/doc/ci/triggers/img/builds_page.png +++ b/doc/ci/triggers/img/builds_page.png diff --git a/doc/ci/triggers/img/trigger_single_build.png b/doc/ci/triggers/img/trigger_single_build.png Binary files differindex c25f27409d6..baf3fc183d8 100644 --- a/doc/ci/triggers/img/trigger_single_build.png +++ b/doc/ci/triggers/img/trigger_single_build.png diff --git a/doc/ci/triggers/img/trigger_variables.png b/doc/ci/triggers/img/trigger_variables.png Binary files differindex 2207e8b34cb..908355c33a5 100644 --- a/doc/ci/triggers/img/trigger_variables.png +++ b/doc/ci/triggers/img/trigger_variables.png diff --git a/doc/ci/triggers/img/triggers_page.png b/doc/ci/triggers/img/triggers_page.png Binary files differindex 268368dc3c5..69cec5cdebf 100644 --- a/doc/ci/triggers/img/triggers_page.png +++ b/doc/ci/triggers/img/triggers_page.png diff --git a/doc/container_registry/img/container_registry.png b/doc/container_registry/img/container_registry.png Binary files differindex e9505a73b40..57d6f9f22c5 100644 --- a/doc/container_registry/img/container_registry.png +++ b/doc/container_registry/img/container_registry.png diff --git a/doc/container_registry/img/project_feature.png b/doc/container_registry/img/project_feature.png Binary files differindex 57a73d253c0..a59b4f82b56 100644 --- a/doc/container_registry/img/project_feature.png +++ b/doc/container_registry/img/project_feature.png diff --git a/doc/customization/branded_login_page/appearance.png b/doc/customization/branded_login_page/appearance.png Binary files differindex 6bce1f0a287..023dc5599b4 100644 --- a/doc/customization/branded_login_page/appearance.png +++ b/doc/customization/branded_login_page/appearance.png diff --git a/doc/customization/branded_login_page/custom_sign_in.png b/doc/customization/branded_login_page/custom_sign_in.png Binary files differindex d6020b029a2..7d99e0a2b3b 100644 --- a/doc/customization/branded_login_page/custom_sign_in.png +++ b/doc/customization/branded_login_page/custom_sign_in.png diff --git a/doc/customization/branded_login_page/default_login_page.png b/doc/customization/branded_login_page/default_login_page.png Binary files differindex 795c7954d8e..0cfa9da202e 100644 --- a/doc/customization/branded_login_page/default_login_page.png +++ b/doc/customization/branded_login_page/default_login_page.png diff --git a/doc/development/gitlab_architecture_diagram.png b/doc/development/gitlab_architecture_diagram.png Binary files differindex 9ab7ffd3c7b..80e975718e0 100644 --- a/doc/development/gitlab_architecture_diagram.png +++ b/doc/development/gitlab_architecture_diagram.png diff --git a/doc/gitlab-basics/basicsimages/add_new_merge_request.png b/doc/gitlab-basics/basicsimages/add_new_merge_request.png Binary files differindex 9d93b217a59..e60992c4c6a 100644 --- a/doc/gitlab-basics/basicsimages/add_new_merge_request.png +++ b/doc/gitlab-basics/basicsimages/add_new_merge_request.png diff --git a/doc/gitlab-basics/basicsimages/add_sshkey.png b/doc/gitlab-basics/basicsimages/add_sshkey.png Binary files differindex 2dede97aa40..89c86018629 100644 --- a/doc/gitlab-basics/basicsimages/add_sshkey.png +++ b/doc/gitlab-basics/basicsimages/add_sshkey.png diff --git a/doc/gitlab-basics/basicsimages/branch_info.png b/doc/gitlab-basics/basicsimages/branch_info.png Binary files differindex c5e38b552a5..2264f3c5bf2 100644 --- a/doc/gitlab-basics/basicsimages/branch_info.png +++ b/doc/gitlab-basics/basicsimages/branch_info.png diff --git a/doc/gitlab-basics/basicsimages/branch_name.png b/doc/gitlab-basics/basicsimages/branch_name.png Binary files differindex 06e77f5eea9..75fe8313611 100644 --- a/doc/gitlab-basics/basicsimages/branch_name.png +++ b/doc/gitlab-basics/basicsimages/branch_name.png diff --git a/doc/gitlab-basics/basicsimages/branches.png b/doc/gitlab-basics/basicsimages/branches.png Binary files differindex c18fa83b968..8621bc05776 100644 --- a/doc/gitlab-basics/basicsimages/branches.png +++ b/doc/gitlab-basics/basicsimages/branches.png diff --git a/doc/gitlab-basics/basicsimages/button-create-mr.png b/doc/gitlab-basics/basicsimages/button-create-mr.png Binary files differindex 457af459bb9..b52ab148839 100644 --- a/doc/gitlab-basics/basicsimages/button-create-mr.png +++ b/doc/gitlab-basics/basicsimages/button-create-mr.png diff --git a/doc/gitlab-basics/basicsimages/click-on-new-group.png b/doc/gitlab-basics/basicsimages/click-on-new-group.png Binary files differindex 94b6d5756d3..6450deec6fc 100644 --- a/doc/gitlab-basics/basicsimages/click-on-new-group.png +++ b/doc/gitlab-basics/basicsimages/click-on-new-group.png diff --git a/doc/gitlab-basics/basicsimages/commit_changes.png b/doc/gitlab-basics/basicsimages/commit_changes.png Binary files differindex 81588336f37..a88809c5a3f 100644 --- a/doc/gitlab-basics/basicsimages/commit_changes.png +++ b/doc/gitlab-basics/basicsimages/commit_changes.png diff --git a/doc/gitlab-basics/basicsimages/commit_message.png b/doc/gitlab-basics/basicsimages/commit_message.png Binary files differindex 0df2c32653c..4abe4517f98 100644 --- a/doc/gitlab-basics/basicsimages/commit_message.png +++ b/doc/gitlab-basics/basicsimages/commit_message.png diff --git a/doc/gitlab-basics/basicsimages/commits.png b/doc/gitlab-basics/basicsimages/commits.png Binary files differindex 7e606539077..2bfcaf75f01 100644 --- a/doc/gitlab-basics/basicsimages/commits.png +++ b/doc/gitlab-basics/basicsimages/commits.png diff --git a/doc/gitlab-basics/basicsimages/compare_branches.png b/doc/gitlab-basics/basicsimages/compare_branches.png Binary files differindex 7eebaed9075..8a18453dd05 100644 --- a/doc/gitlab-basics/basicsimages/compare_branches.png +++ b/doc/gitlab-basics/basicsimages/compare_branches.png diff --git a/doc/gitlab-basics/basicsimages/create_file.png b/doc/gitlab-basics/basicsimages/create_file.png Binary files differindex 688e355cca2..5ebe1b227dd 100644 --- a/doc/gitlab-basics/basicsimages/create_file.png +++ b/doc/gitlab-basics/basicsimages/create_file.png diff --git a/doc/gitlab-basics/basicsimages/create_group.png b/doc/gitlab-basics/basicsimages/create_group.png Binary files differindex 57da898abdc..7ecc3baa990 100644 --- a/doc/gitlab-basics/basicsimages/create_group.png +++ b/doc/gitlab-basics/basicsimages/create_group.png diff --git a/doc/gitlab-basics/basicsimages/edit_file.png b/doc/gitlab-basics/basicsimages/edit_file.png Binary files differindex afa68760108..9d3e817d036 100644 --- a/doc/gitlab-basics/basicsimages/edit_file.png +++ b/doc/gitlab-basics/basicsimages/edit_file.png diff --git a/doc/gitlab-basics/basicsimages/file_located.png b/doc/gitlab-basics/basicsimages/file_located.png Binary files differindex 1def489d16b..e357cb5c6ab 100644 --- a/doc/gitlab-basics/basicsimages/file_located.png +++ b/doc/gitlab-basics/basicsimages/file_located.png diff --git a/doc/gitlab-basics/basicsimages/file_name.png b/doc/gitlab-basics/basicsimages/file_name.png Binary files differindex 9ac2f1c355f..01639c77d0d 100644 --- a/doc/gitlab-basics/basicsimages/file_name.png +++ b/doc/gitlab-basics/basicsimages/file_name.png diff --git a/doc/gitlab-basics/basicsimages/find_file.png b/doc/gitlab-basics/basicsimages/find_file.png Binary files differindex 98639149a39..6f26d26ae18 100644 --- a/doc/gitlab-basics/basicsimages/find_file.png +++ b/doc/gitlab-basics/basicsimages/find_file.png diff --git a/doc/gitlab-basics/basicsimages/find_group.png b/doc/gitlab-basics/basicsimages/find_group.png Binary files differindex 5ac33c7e953..1211510aae9 100644 --- a/doc/gitlab-basics/basicsimages/find_group.png +++ b/doc/gitlab-basics/basicsimages/find_group.png diff --git a/doc/gitlab-basics/basicsimages/fork.png b/doc/gitlab-basics/basicsimages/fork.png Binary files differindex b1f94938613..13ff8345616 100644 --- a/doc/gitlab-basics/basicsimages/fork.png +++ b/doc/gitlab-basics/basicsimages/fork.png diff --git a/doc/gitlab-basics/basicsimages/group_info.png b/doc/gitlab-basics/basicsimages/group_info.png Binary files differindex e78d84e4d80..2507d6c295b 100644 --- a/doc/gitlab-basics/basicsimages/group_info.png +++ b/doc/gitlab-basics/basicsimages/group_info.png diff --git a/doc/gitlab-basics/basicsimages/groups.png b/doc/gitlab-basics/basicsimages/groups.png Binary files differindex b8104343afa..ef3dca60cc8 100644 --- a/doc/gitlab-basics/basicsimages/groups.png +++ b/doc/gitlab-basics/basicsimages/groups.png diff --git a/doc/gitlab-basics/basicsimages/https.png b/doc/gitlab-basics/basicsimages/https.png Binary files differindex 2a31b4cf751..e74dbc13f9a 100644 --- a/doc/gitlab-basics/basicsimages/https.png +++ b/doc/gitlab-basics/basicsimages/https.png diff --git a/doc/gitlab-basics/basicsimages/image_file.png b/doc/gitlab-basics/basicsimages/image_file.png Binary files differindex 1061d9c5082..7f304b8e1f2 100644 --- a/doc/gitlab-basics/basicsimages/image_file.png +++ b/doc/gitlab-basics/basicsimages/image_file.png diff --git a/doc/gitlab-basics/basicsimages/issue_title.png b/doc/gitlab-basics/basicsimages/issue_title.png Binary files differindex 7b69c705392..60a6f7973be 100644 --- a/doc/gitlab-basics/basicsimages/issue_title.png +++ b/doc/gitlab-basics/basicsimages/issue_title.png diff --git a/doc/gitlab-basics/basicsimages/issues.png b/doc/gitlab-basics/basicsimages/issues.png Binary files differindex 9354d05319e..14e9cdb64e1 100644 --- a/doc/gitlab-basics/basicsimages/issues.png +++ b/doc/gitlab-basics/basicsimages/issues.png diff --git a/doc/gitlab-basics/basicsimages/key.png b/doc/gitlab-basics/basicsimages/key.png Binary files differindex 321805cda98..04400173ce8 100644 --- a/doc/gitlab-basics/basicsimages/key.png +++ b/doc/gitlab-basics/basicsimages/key.png diff --git a/doc/gitlab-basics/basicsimages/merge_requests.png b/doc/gitlab-basics/basicsimages/merge_requests.png Binary files differindex 7601d40de47..570164df18b 100644 --- a/doc/gitlab-basics/basicsimages/merge_requests.png +++ b/doc/gitlab-basics/basicsimages/merge_requests.png diff --git a/doc/gitlab-basics/basicsimages/new_merge_request.png b/doc/gitlab-basics/basicsimages/new_merge_request.png Binary files differindex 9120d2b1ab1..842f5ebed74 100644 --- a/doc/gitlab-basics/basicsimages/new_merge_request.png +++ b/doc/gitlab-basics/basicsimages/new_merge_request.png diff --git a/doc/gitlab-basics/basicsimages/new_project.png b/doc/gitlab-basics/basicsimages/new_project.png Binary files differindex ac255270a66..421e8bc247b 100644 --- a/doc/gitlab-basics/basicsimages/new_project.png +++ b/doc/gitlab-basics/basicsimages/new_project.png diff --git a/doc/gitlab-basics/basicsimages/newbranch.png b/doc/gitlab-basics/basicsimages/newbranch.png Binary files differindex da1a6b604ea..d5fcf33c4ea 100644 --- a/doc/gitlab-basics/basicsimages/newbranch.png +++ b/doc/gitlab-basics/basicsimages/newbranch.png diff --git a/doc/gitlab-basics/basicsimages/paste_sshkey.png b/doc/gitlab-basics/basicsimages/paste_sshkey.png Binary files differindex 9880ddfead1..578ebee4440 100644 --- a/doc/gitlab-basics/basicsimages/paste_sshkey.png +++ b/doc/gitlab-basics/basicsimages/paste_sshkey.png diff --git a/doc/gitlab-basics/basicsimages/profile_settings.png b/doc/gitlab-basics/basicsimages/profile_settings.png Binary files differindex 5f2e7a7e10c..cb3f79f1879 100644 --- a/doc/gitlab-basics/basicsimages/profile_settings.png +++ b/doc/gitlab-basics/basicsimages/profile_settings.png diff --git a/doc/gitlab-basics/basicsimages/project_info.png b/doc/gitlab-basics/basicsimages/project_info.png Binary files differindex 6c06ff351fa..e1adb8d48c2 100644 --- a/doc/gitlab-basics/basicsimages/project_info.png +++ b/doc/gitlab-basics/basicsimages/project_info.png diff --git a/doc/gitlab-basics/basicsimages/public_file_link.png b/doc/gitlab-basics/basicsimages/public_file_link.png Binary files differindex 1a60a3d880a..f60df6807f4 100644 --- a/doc/gitlab-basics/basicsimages/public_file_link.png +++ b/doc/gitlab-basics/basicsimages/public_file_link.png diff --git a/doc/gitlab-basics/basicsimages/select-group.png b/doc/gitlab-basics/basicsimages/select-group.png Binary files differindex d02c2255ff2..33b978dd899 100644 --- a/doc/gitlab-basics/basicsimages/select-group.png +++ b/doc/gitlab-basics/basicsimages/select-group.png diff --git a/doc/gitlab-basics/basicsimages/select-group2.png b/doc/gitlab-basics/basicsimages/select-group2.png Binary files differindex fd40bce499b..aee22c638db 100644 --- a/doc/gitlab-basics/basicsimages/select-group2.png +++ b/doc/gitlab-basics/basicsimages/select-group2.png diff --git a/doc/gitlab-basics/basicsimages/select_branch.png b/doc/gitlab-basics/basicsimages/select_branch.png Binary files differindex 3475b2df576..f72a3ffb57f 100644 --- a/doc/gitlab-basics/basicsimages/select_branch.png +++ b/doc/gitlab-basics/basicsimages/select_branch.png diff --git a/doc/gitlab-basics/basicsimages/select_project.png b/doc/gitlab-basics/basicsimages/select_project.png Binary files differindex 6d5aa439124..3bb832ea8d0 100644 --- a/doc/gitlab-basics/basicsimages/select_project.png +++ b/doc/gitlab-basics/basicsimages/select_project.png diff --git a/doc/gitlab-basics/basicsimages/settings.png b/doc/gitlab-basics/basicsimages/settings.png Binary files differindex 9bf9c5a0d39..78637013d9b 100644 --- a/doc/gitlab-basics/basicsimages/settings.png +++ b/doc/gitlab-basics/basicsimages/settings.png diff --git a/doc/gitlab-basics/basicsimages/shh_keys.png b/doc/gitlab-basics/basicsimages/shh_keys.png Binary files differindex d7ef4dafe77..c87f11a9d3d 100644 --- a/doc/gitlab-basics/basicsimages/shh_keys.png +++ b/doc/gitlab-basics/basicsimages/shh_keys.png diff --git a/doc/gitlab-basics/basicsimages/submit_new_issue.png b/doc/gitlab-basics/basicsimages/submit_new_issue.png Binary files differindex 18944417085..78b854c8903 100644 --- a/doc/gitlab-basics/basicsimages/submit_new_issue.png +++ b/doc/gitlab-basics/basicsimages/submit_new_issue.png diff --git a/doc/gitlab-basics/basicsimages/title_description_mr.png b/doc/gitlab-basics/basicsimages/title_description_mr.png Binary files differindex e08eb628414..c31d61ec336 100644 --- a/doc/gitlab-basics/basicsimages/title_description_mr.png +++ b/doc/gitlab-basics/basicsimages/title_description_mr.png diff --git a/doc/gitlab-basics/basicsimages/white_space.png b/doc/gitlab-basics/basicsimages/white_space.png Binary files differindex 6363a09360e..eaa969bdcf4 100644 --- a/doc/gitlab-basics/basicsimages/white_space.png +++ b/doc/gitlab-basics/basicsimages/white_space.png diff --git a/doc/integration/img/akismet_settings.png b/doc/integration/img/akismet_settings.png Binary files differindex ccdd3adb1c5..c2aa97b132e 100644 --- a/doc/integration/img/akismet_settings.png +++ b/doc/integration/img/akismet_settings.png diff --git a/doc/integration/img/enabled-oauth-sign-in-sources.png b/doc/integration/img/enabled-oauth-sign-in-sources.png Binary files differindex 95f8bbdcd24..b23d6dcc595 100644 --- a/doc/integration/img/enabled-oauth-sign-in-sources.png +++ b/doc/integration/img/enabled-oauth-sign-in-sources.png diff --git a/doc/integration/img/facebook_api_keys.png b/doc/integration/img/facebook_api_keys.png Binary files differindex d6c44ac0f11..995845d5a69 100644 --- a/doc/integration/img/facebook_api_keys.png +++ b/doc/integration/img/facebook_api_keys.png diff --git a/doc/integration/img/facebook_app_settings.png b/doc/integration/img/facebook_app_settings.png Binary files differindex 30dd21e198a..1cd586ecd7c 100644 --- a/doc/integration/img/facebook_app_settings.png +++ b/doc/integration/img/facebook_app_settings.png diff --git a/doc/integration/img/facebook_website_url.png b/doc/integration/img/facebook_website_url.png Binary files differindex dc3088bb2fa..10e1bd5d5a6 100644 --- a/doc/integration/img/facebook_website_url.png +++ b/doc/integration/img/facebook_website_url.png diff --git a/doc/integration/img/github_app.png b/doc/integration/img/github_app.png Binary files differindex d890345ced9..de31242679a 100644 --- a/doc/integration/img/github_app.png +++ b/doc/integration/img/github_app.png diff --git a/doc/integration/img/gitlab_app.png b/doc/integration/img/gitlab_app.png Binary files differindex 3f9391a821b..065316fd3c7 100644 --- a/doc/integration/img/gitlab_app.png +++ b/doc/integration/img/gitlab_app.png diff --git a/doc/integration/img/gmail_action_buttons_for_gitlab.png b/doc/integration/img/gmail_action_buttons_for_gitlab.png Binary files differindex b08f54d137b..a6704139091 100644 --- a/doc/integration/img/gmail_action_buttons_for_gitlab.png +++ b/doc/integration/img/gmail_action_buttons_for_gitlab.png diff --git a/doc/integration/img/google_app.png b/doc/integration/img/google_app.png Binary files differindex 5a62ad35009..08f7f714553 100644 --- a/doc/integration/img/google_app.png +++ b/doc/integration/img/google_app.png diff --git a/doc/integration/img/oauth_provider_admin_application.png b/doc/integration/img/oauth_provider_admin_application.png Binary files differindex a2d8e14c120..fc5f7596fcc 100644 --- a/doc/integration/img/oauth_provider_admin_application.png +++ b/doc/integration/img/oauth_provider_admin_application.png diff --git a/doc/integration/img/oauth_provider_application_form.png b/doc/integration/img/oauth_provider_application_form.png Binary files differindex 3a676b22393..606ab3e3467 100644 --- a/doc/integration/img/oauth_provider_application_form.png +++ b/doc/integration/img/oauth_provider_application_form.png diff --git a/doc/integration/img/oauth_provider_application_id_secret.png b/doc/integration/img/oauth_provider_application_id_secret.png Binary files differindex 6d68df001af..cbedcef8376 100644 --- a/doc/integration/img/oauth_provider_application_id_secret.png +++ b/doc/integration/img/oauth_provider_application_id_secret.png diff --git a/doc/integration/img/oauth_provider_authorized_application.png b/doc/integration/img/oauth_provider_authorized_application.png Binary files differindex efc3b807d71..6a2ea09073c 100644 --- a/doc/integration/img/oauth_provider_authorized_application.png +++ b/doc/integration/img/oauth_provider_authorized_application.png diff --git a/doc/integration/img/oauth_provider_user_wide_applications.png b/doc/integration/img/oauth_provider_user_wide_applications.png Binary files differindex 45ad8a6d468..0c7b095a2dd 100644 --- a/doc/integration/img/oauth_provider_user_wide_applications.png +++ b/doc/integration/img/oauth_provider_user_wide_applications.png diff --git a/doc/integration/img/twitter_app_api_keys.png b/doc/integration/img/twitter_app_api_keys.png Binary files differindex 1076337172a..15b29ac7d16 100644 --- a/doc/integration/img/twitter_app_api_keys.png +++ b/doc/integration/img/twitter_app_api_keys.png diff --git a/doc/integration/img/twitter_app_details.png b/doc/integration/img/twitter_app_details.png Binary files differindex b95e8af8a74..323112a88bb 100644 --- a/doc/integration/img/twitter_app_details.png +++ b/doc/integration/img/twitter_app_details.png diff --git a/doc/markdown/img/logo.png b/doc/markdown/img/logo.png Binary files differindex 7da5f23ed9b..05c8b0d0ccf 100644 --- a/doc/markdown/img/logo.png +++ b/doc/markdown/img/logo.png diff --git a/doc/monitoring/img/health_check_token.png b/doc/monitoring/img/health_check_token.png Binary files differindex 2daf8606b00..2d7c82a65a8 100644 --- a/doc/monitoring/img/health_check_token.png +++ b/doc/monitoring/img/health_check_token.png diff --git a/doc/monitoring/performance/img/grafana_dashboard_dropdown.png b/doc/monitoring/performance/img/grafana_dashboard_dropdown.png Binary files differindex b4448c7a09f..7e34fad71ce 100644 --- a/doc/monitoring/performance/img/grafana_dashboard_dropdown.png +++ b/doc/monitoring/performance/img/grafana_dashboard_dropdown.png diff --git a/doc/monitoring/performance/img/grafana_dashboard_import.png b/doc/monitoring/performance/img/grafana_dashboard_import.png Binary files differindex 5a2d3c0937a..f97624365c7 100644 --- a/doc/monitoring/performance/img/grafana_dashboard_import.png +++ b/doc/monitoring/performance/img/grafana_dashboard_import.png diff --git a/doc/monitoring/performance/img/grafana_data_source_configuration.png b/doc/monitoring/performance/img/grafana_data_source_configuration.png Binary files differindex 7e2e111f570..7d50e4c88c2 100644 --- a/doc/monitoring/performance/img/grafana_data_source_configuration.png +++ b/doc/monitoring/performance/img/grafana_data_source_configuration.png diff --git a/doc/monitoring/performance/img/grafana_data_source_empty.png b/doc/monitoring/performance/img/grafana_data_source_empty.png Binary files differindex 11e27571e64..aa39a53acae 100644 --- a/doc/monitoring/performance/img/grafana_data_source_empty.png +++ b/doc/monitoring/performance/img/grafana_data_source_empty.png diff --git a/doc/monitoring/performance/img/grafana_save_icon.png b/doc/monitoring/performance/img/grafana_save_icon.png Binary files differindex 3d4265bee8e..c740e33cd1c 100644 --- a/doc/monitoring/performance/img/grafana_save_icon.png +++ b/doc/monitoring/performance/img/grafana_save_icon.png diff --git a/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png b/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png Binary files differindex 14d82b6ac98..e6ed45a0386 100644 --- a/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png +++ b/doc/monitoring/performance/img/metrics_gitlab_configuration_settings.png diff --git a/doc/profile/2fa.png b/doc/profile/2fa.png Binary files differindex bbf415210d5..bb464efa685 100644 --- a/doc/profile/2fa.png +++ b/doc/profile/2fa.png diff --git a/doc/profile/2fa_auth.png b/doc/profile/2fa_auth.png Binary files differindex 4a4fbe68984..0caaed10805 100644 --- a/doc/profile/2fa_auth.png +++ b/doc/profile/2fa_auth.png diff --git a/doc/project_services/img/builds_emails_service.png b/doc/project_services/img/builds_emails_service.png Binary files differindex e604dd73ffa..88943dc410e 100644 --- a/doc/project_services/img/builds_emails_service.png +++ b/doc/project_services/img/builds_emails_service.png diff --git a/doc/project_services/img/jira_add_gitlab_commit_message.png b/doc/project_services/img/jira_add_gitlab_commit_message.png Binary files differindex 85e54861b3e..aec472b9118 100644 --- a/doc/project_services/img/jira_add_gitlab_commit_message.png +++ b/doc/project_services/img/jira_add_gitlab_commit_message.png diff --git a/doc/project_services/img/jira_add_user_to_group.png b/doc/project_services/img/jira_add_user_to_group.png Binary files differindex e4576433889..0ba737bda9a 100644 --- a/doc/project_services/img/jira_add_user_to_group.png +++ b/doc/project_services/img/jira_add_user_to_group.png diff --git a/doc/project_services/img/jira_create_new_group.png b/doc/project_services/img/jira_create_new_group.png Binary files differindex edaa1326058..0609060cb05 100644 --- a/doc/project_services/img/jira_create_new_group.png +++ b/doc/project_services/img/jira_create_new_group.png diff --git a/doc/project_services/img/jira_create_new_group_name.png b/doc/project_services/img/jira_create_new_group_name.png Binary files differindex 9e518ad7843..53d77b17df0 100644 --- a/doc/project_services/img/jira_create_new_group_name.png +++ b/doc/project_services/img/jira_create_new_group_name.png diff --git a/doc/project_services/img/jira_create_new_user.png b/doc/project_services/img/jira_create_new_user.png Binary files differindex 57e433dd818..9eaa444ed25 100644 --- a/doc/project_services/img/jira_create_new_user.png +++ b/doc/project_services/img/jira_create_new_user.png diff --git a/doc/project_services/img/jira_group_access.png b/doc/project_services/img/jira_group_access.png Binary files differindex 47716ca6d0e..8d4657427ae 100644 --- a/doc/project_services/img/jira_group_access.png +++ b/doc/project_services/img/jira_group_access.png diff --git a/doc/project_services/img/jira_issue_closed.png b/doc/project_services/img/jira_issue_closed.png Binary files differindex cabec1ae137..acdd83702d3 100644 --- a/doc/project_services/img/jira_issue_closed.png +++ b/doc/project_services/img/jira_issue_closed.png diff --git a/doc/project_services/img/jira_issue_reference.png b/doc/project_services/img/jira_issue_reference.png Binary files differindex 15739a22dc7..1a2d9f04a6c 100644 --- a/doc/project_services/img/jira_issue_reference.png +++ b/doc/project_services/img/jira_issue_reference.png diff --git a/doc/project_services/img/jira_issues_workflow.png b/doc/project_services/img/jira_issues_workflow.png Binary files differindex 28e17be3a84..0703081d77b 100644 --- a/doc/project_services/img/jira_issues_workflow.png +++ b/doc/project_services/img/jira_issues_workflow.png diff --git a/doc/project_services/img/jira_merge_request_close.png b/doc/project_services/img/jira_merge_request_close.png Binary files differindex 1e78daf105f..47785e3ba27 100644 --- a/doc/project_services/img/jira_merge_request_close.png +++ b/doc/project_services/img/jira_merge_request_close.png diff --git a/doc/project_services/img/jira_project_name.png b/doc/project_services/img/jira_project_name.png Binary files differindex 5986fdb63fb..e785ec6140d 100644 --- a/doc/project_services/img/jira_project_name.png +++ b/doc/project_services/img/jira_project_name.png 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 Binary files differindex 0149181dc86..fb270d85e3c 100644 --- 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 diff --git a/doc/project_services/img/jira_service.png b/doc/project_services/img/jira_service.png Binary files differindex 1f6628c4371..13aefce6f84 100644 --- a/doc/project_services/img/jira_service.png +++ b/doc/project_services/img/jira_service.png diff --git a/doc/project_services/img/jira_service_close_issue.png b/doc/project_services/img/jira_service_close_issue.png Binary files differindex 67dfc6144c4..eed69e80d2c 100644 --- a/doc/project_services/img/jira_service_close_issue.png +++ b/doc/project_services/img/jira_service_close_issue.png diff --git a/doc/project_services/img/jira_service_page.png b/doc/project_services/img/jira_service_page.png Binary files differindex c225daa81e1..a5b49c501ba 100644 --- a/doc/project_services/img/jira_service_page.png +++ b/doc/project_services/img/jira_service_page.png diff --git a/doc/project_services/img/jira_submit_gitlab_merge_request.png b/doc/project_services/img/jira_submit_gitlab_merge_request.png Binary files differindex e935d9362aa..77630d39d39 100644 --- a/doc/project_services/img/jira_submit_gitlab_merge_request.png +++ b/doc/project_services/img/jira_submit_gitlab_merge_request.png diff --git a/doc/project_services/img/jira_user_management_link.png b/doc/project_services/img/jira_user_management_link.png Binary files differindex 2745916972c..5f002b59bac 100644 --- a/doc/project_services/img/jira_user_management_link.png +++ b/doc/project_services/img/jira_user_management_link.png diff --git a/doc/project_services/img/jira_workflow_screenshot.png b/doc/project_services/img/jira_workflow_screenshot.png Binary files differindex 8635a32eb68..937a50a77d9 100644 --- a/doc/project_services/img/jira_workflow_screenshot.png +++ b/doc/project_services/img/jira_workflow_screenshot.png diff --git a/doc/project_services/img/redmine_configuration.png b/doc/project_services/img/redmine_configuration.png Binary files differindex d14e526ad33..e9d8c0d2da8 100644 --- a/doc/project_services/img/redmine_configuration.png +++ b/doc/project_services/img/redmine_configuration.png diff --git a/doc/project_services/img/services_templates_redmine_example.png b/doc/project_services/img/services_templates_redmine_example.png Binary files differindex 384d057fc8e..77c2b98e5d0 100644 --- a/doc/project_services/img/services_templates_redmine_example.png +++ b/doc/project_services/img/services_templates_redmine_example.png diff --git a/doc/raketasks/backup_hrz.png b/doc/raketasks/backup_hrz.png Binary files differindex 03e50df1d76..42084717ebe 100644 --- a/doc/raketasks/backup_hrz.png +++ b/doc/raketasks/backup_hrz.png diff --git a/doc/raketasks/check_repos_output.png b/doc/raketasks/check_repos_output.png Binary files differindex 916b1685101..1f632566b00 100644 --- a/doc/raketasks/check_repos_output.png +++ b/doc/raketasks/check_repos_output.png diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md index 8a38937062e..2b305cb5c99 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 Binary files differindex aa51ce030bb..6af5feabb13 100644 --- a/doc/security/img/two_factor_authentication_settings.png +++ b/doc/security/img/two_factor_authentication_settings.png diff --git a/doc/web_hooks/ssl.png b/doc/web_hooks/ssl.png Binary files differindex 698f1a0f64a..8c4f08d1825 100644 --- a/doc/web_hooks/ssl.png +++ b/doc/web_hooks/ssl.png 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 Binary files differindex 3da18cdae53..5da0552f9d6 100644 --- 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 diff --git a/doc/workflow/add-user/img/add_user_email_accept.png b/doc/workflow/add-user/img/add_user_email_accept.png Binary files differindex 18aabf93d50..a2954ad7c37 100644 --- a/doc/workflow/add-user/img/add_user_email_accept.png +++ b/doc/workflow/add-user/img/add_user_email_accept.png diff --git a/doc/workflow/add-user/img/add_user_email_ready.png b/doc/workflow/add-user/img/add_user_email_ready.png Binary files differindex 385d64330c0..19d91bc0999 100644 --- a/doc/workflow/add-user/img/add_user_email_ready.png +++ b/doc/workflow/add-user/img/add_user_email_ready.png diff --git a/doc/workflow/add-user/img/add_user_email_search.png b/doc/workflow/add-user/img/add_user_email_search.png Binary files differindex 84741edbca4..cb31b77d941 100644 --- a/doc/workflow/add-user/img/add_user_email_search.png +++ b/doc/workflow/add-user/img/add_user_email_search.png diff --git a/doc/workflow/add-user/img/add_user_give_permissions.png b/doc/workflow/add-user/img/add_user_give_permissions.png Binary files differindex 7e580384e54..e6b77022f06 100644 --- a/doc/workflow/add-user/img/add_user_give_permissions.png +++ b/doc/workflow/add-user/img/add_user_give_permissions.png 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 Binary files differindex 8dbd73a5bc8..1068589c5ff 100644 --- 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 diff --git a/doc/workflow/add-user/img/add_user_imported_members.png b/doc/workflow/add-user/img/add_user_imported_members.png Binary files differindex abac1f59c02..5cd120a4245 100644 --- a/doc/workflow/add-user/img/add_user_imported_members.png +++ b/doc/workflow/add-user/img/add_user_imported_members.png diff --git a/doc/workflow/add-user/img/add_user_list_members.png b/doc/workflow/add-user/img/add_user_list_members.png Binary files differindex e17d88c6f5f..5fe3482192e 100644 --- a/doc/workflow/add-user/img/add_user_list_members.png +++ b/doc/workflow/add-user/img/add_user_list_members.png diff --git a/doc/workflow/add-user/img/add_user_members_menu.png b/doc/workflow/add-user/img/add_user_members_menu.png Binary files differindex ec5d39f402d..340d15c9830 100644 --- a/doc/workflow/add-user/img/add_user_members_menu.png +++ b/doc/workflow/add-user/img/add_user_members_menu.png diff --git a/doc/workflow/add-user/img/add_user_search_people.png b/doc/workflow/add-user/img/add_user_search_people.png Binary files differindex eaa062376f4..1c05d70ca31 100644 --- a/doc/workflow/add-user/img/add_user_search_people.png +++ b/doc/workflow/add-user/img/add_user_search_people.png diff --git a/doc/workflow/award_emoji.png b/doc/workflow/award_emoji.png Binary files differindex 3408ed95841..481680af80c 100644 --- a/doc/workflow/award_emoji.png +++ b/doc/workflow/award_emoji.png diff --git a/doc/workflow/ci_mr.png b/doc/workflow/ci_mr.png Binary files differindex a577356f8e8..f8a7708643e 100644 --- a/doc/workflow/ci_mr.png +++ b/doc/workflow/ci_mr.png diff --git a/doc/workflow/close_issue_mr.png b/doc/workflow/close_issue_mr.png Binary files differindex a136d642e12..5e520240233 100644 --- a/doc/workflow/close_issue_mr.png +++ b/doc/workflow/close_issue_mr.png diff --git a/doc/workflow/environment_branches.png b/doc/workflow/environment_branches.png Binary files differindex ee893ced13b..13fb0478eaa 100644 --- a/doc/workflow/environment_branches.png +++ b/doc/workflow/environment_branches.png diff --git a/doc/workflow/forking/branch_select.png b/doc/workflow/forking/branch_select.png Binary files differindex 275f64d113b..7f19414f3a9 100644 --- a/doc/workflow/forking/branch_select.png +++ b/doc/workflow/forking/branch_select.png diff --git a/doc/workflow/forking/merge_request.png b/doc/workflow/forking/merge_request.png Binary files differindex 2dc00ed08a1..e2da42a2be7 100644 --- a/doc/workflow/forking/merge_request.png +++ b/doc/workflow/forking/merge_request.png diff --git a/doc/workflow/four_stages.png b/doc/workflow/four_stages.png Binary files differindex 2f444fc6f79..49413087dca 100644 --- a/doc/workflow/four_stages.png +++ b/doc/workflow/four_stages.png diff --git a/doc/workflow/git_pull.png b/doc/workflow/git_pull.png Binary files differindex 7d47064eb14..9a1fdf899bf 100644 --- a/doc/workflow/git_pull.png +++ b/doc/workflow/git_pull.png diff --git a/doc/workflow/gitdashflow.png b/doc/workflow/gitdashflow.png Binary files differindex f2f091dd10b..e456cf9309d 100644 --- a/doc/workflow/gitdashflow.png +++ b/doc/workflow/gitdashflow.png diff --git a/doc/workflow/github_flow.png b/doc/workflow/github_flow.png Binary files differindex 88addb623ee..b3fca97cc2d 100644 --- a/doc/workflow/github_flow.png +++ b/doc/workflow/github_flow.png diff --git a/doc/workflow/gitlab_flow.png b/doc/workflow/gitlab_flow.png Binary files differindex 1ea191a672b..d85d4ff374e 100644 --- a/doc/workflow/gitlab_flow.png +++ b/doc/workflow/gitlab_flow.png diff --git a/doc/workflow/good_commit.png b/doc/workflow/good_commit.png Binary files differindex 3737a026644..7958feea4d9 100644 --- a/doc/workflow/good_commit.png +++ b/doc/workflow/good_commit.png diff --git a/doc/workflow/groups/add_member_to_group.png b/doc/workflow/groups/add_member_to_group.png Binary files differindex fa340ce572f..6e3f660d2e4 100644 --- a/doc/workflow/groups/add_member_to_group.png +++ b/doc/workflow/groups/add_member_to_group.png diff --git a/doc/workflow/groups/group_dashboard.png b/doc/workflow/groups/group_dashboard.png Binary files differindex 7fc9048d74d..662c932e536 100644 --- a/doc/workflow/groups/group_dashboard.png +++ b/doc/workflow/groups/group_dashboard.png diff --git a/doc/workflow/groups/group_with_two_projects.png b/doc/workflow/groups/group_with_two_projects.png Binary files differindex 87242781e4f..dc3475949f5 100644 --- a/doc/workflow/groups/group_with_two_projects.png +++ b/doc/workflow/groups/group_with_two_projects.png diff --git a/doc/workflow/groups/max_access_level.png b/doc/workflow/groups/max_access_level.png Binary files differindex 71106a8a5a0..2855a514013 100644 --- a/doc/workflow/groups/max_access_level.png +++ b/doc/workflow/groups/max_access_level.png diff --git a/doc/workflow/groups/new_group_button.png b/doc/workflow/groups/new_group_button.png Binary files differindex 51e82798658..26136312c8f 100644 --- a/doc/workflow/groups/new_group_button.png +++ b/doc/workflow/groups/new_group_button.png diff --git a/doc/workflow/groups/new_group_form.png b/doc/workflow/groups/new_group_form.png Binary files differindex bf992c40bc2..dc50a069ef2 100644 --- a/doc/workflow/groups/new_group_form.png +++ b/doc/workflow/groups/new_group_form.png diff --git a/doc/workflow/groups/other_group_sees_shared_project.png b/doc/workflow/groups/other_group_sees_shared_project.png Binary files differindex cbf2c3c1fdc..2230720cecd 100644 --- a/doc/workflow/groups/other_group_sees_shared_project.png +++ b/doc/workflow/groups/other_group_sees_shared_project.png diff --git a/doc/workflow/groups/override_access_level.png b/doc/workflow/groups/override_access_level.png Binary files differindex f4225a63679..9d6aaf4c363 100644 --- a/doc/workflow/groups/override_access_level.png +++ b/doc/workflow/groups/override_access_level.png diff --git a/doc/workflow/groups/project_members_via_group.png b/doc/workflow/groups/project_members_via_group.png Binary files differindex b13cb1cfd95..58270936a0b 100644 --- a/doc/workflow/groups/project_members_via_group.png +++ b/doc/workflow/groups/project_members_via_group.png diff --git a/doc/workflow/groups/share_project_with_groups.png b/doc/workflow/groups/share_project_with_groups.png Binary files differindex a5dbc89fe90..5772d4deced 100644 --- a/doc/workflow/groups/share_project_with_groups.png +++ b/doc/workflow/groups/share_project_with_groups.png diff --git a/doc/workflow/groups/transfer_project.png b/doc/workflow/groups/transfer_project.png Binary files differindex 044fe10d073..0aef3ab3f0f 100644 --- a/doc/workflow/groups/transfer_project.png +++ b/doc/workflow/groups/transfer_project.png diff --git a/doc/workflow/img/award_emoji_select.png b/doc/workflow/img/award_emoji_select.png Binary files differindex fffdfedda5d..ad664c0aeff 100644 --- a/doc/workflow/img/award_emoji_select.png +++ b/doc/workflow/img/award_emoji_select.png diff --git a/doc/workflow/img/award_emoji_votes_least_popular.png b/doc/workflow/img/award_emoji_votes_least_popular.png Binary files differindex 2ef5be7154f..57d595d9602 100644 --- a/doc/workflow/img/award_emoji_votes_least_popular.png +++ b/doc/workflow/img/award_emoji_votes_least_popular.png diff --git a/doc/workflow/img/award_emoji_votes_most_popular.png b/doc/workflow/img/award_emoji_votes_most_popular.png Binary files differindex 5b089730d93..432bd09b8a7 100644 --- a/doc/workflow/img/award_emoji_votes_most_popular.png +++ b/doc/workflow/img/award_emoji_votes_most_popular.png diff --git a/doc/workflow/img/award_emoji_votes_sort_options.png b/doc/workflow/img/award_emoji_votes_sort_options.png Binary files differindex 9bbf3f82a0b..ae6e224b317 100644 --- a/doc/workflow/img/award_emoji_votes_sort_options.png +++ b/doc/workflow/img/award_emoji_votes_sort_options.png diff --git a/doc/workflow/img/cherry_pick_changes_commit.png b/doc/workflow/img/cherry_pick_changes_commit.png Binary files differindex ae91d2cae53..7fb68cc9e9b 100644 --- a/doc/workflow/img/cherry_pick_changes_commit.png +++ b/doc/workflow/img/cherry_pick_changes_commit.png diff --git a/doc/workflow/img/cherry_pick_changes_commit_modal.png b/doc/workflow/img/cherry_pick_changes_commit_modal.png Binary files differindex f502f87677a..5267e04562f 100644 --- a/doc/workflow/img/cherry_pick_changes_commit_modal.png +++ b/doc/workflow/img/cherry_pick_changes_commit_modal.png diff --git a/doc/workflow/img/cherry_pick_changes_mr.png b/doc/workflow/img/cherry_pick_changes_mr.png Binary files differindex 59c610e620b..975fb13e463 100644 --- a/doc/workflow/img/cherry_pick_changes_mr.png +++ b/doc/workflow/img/cherry_pick_changes_mr.png diff --git a/doc/workflow/img/cherry_pick_changes_mr_modal.png b/doc/workflow/img/cherry_pick_changes_mr_modal.png Binary files differindex 96a80f4726d..6c003bacbe3 100644 --- a/doc/workflow/img/cherry_pick_changes_mr_modal.png +++ b/doc/workflow/img/cherry_pick_changes_mr_modal.png diff --git a/doc/workflow/img/file_finder_find_button.png b/doc/workflow/img/file_finder_find_button.png Binary files differindex c5005d0d7ca..96e383f0213 100644 --- a/doc/workflow/img/file_finder_find_button.png +++ b/doc/workflow/img/file_finder_find_button.png diff --git a/doc/workflow/img/file_finder_find_file.png b/doc/workflow/img/file_finder_find_file.png Binary files differindex 58500f4c163..c6508514c76 100644 --- a/doc/workflow/img/file_finder_find_file.png +++ b/doc/workflow/img/file_finder_find_file.png diff --git a/doc/workflow/img/forking_workflow_choose_namespace.png b/doc/workflow/img/forking_workflow_choose_namespace.png Binary files differindex eefe5769554..1839d5e8be2 100644 --- a/doc/workflow/img/forking_workflow_choose_namespace.png +++ b/doc/workflow/img/forking_workflow_choose_namespace.png diff --git a/doc/workflow/img/forking_workflow_fork_button.png b/doc/workflow/img/forking_workflow_fork_button.png Binary files differindex 49e68d33e89..cc79d6fd40c 100644 --- a/doc/workflow/img/forking_workflow_fork_button.png +++ b/doc/workflow/img/forking_workflow_fork_button.png diff --git a/doc/workflow/img/forking_workflow_path_taken_error.png b/doc/workflow/img/forking_workflow_path_taken_error.png Binary files differindex 7a3139506fe..a859155aef0 100644 --- a/doc/workflow/img/forking_workflow_path_taken_error.png +++ b/doc/workflow/img/forking_workflow_path_taken_error.png diff --git a/doc/workflow/img/new_branch_from_issue.png b/doc/workflow/img/new_branch_from_issue.png Binary files differindex 394c139e17e..61acdd30ae9 100644 --- a/doc/workflow/img/new_branch_from_issue.png +++ b/doc/workflow/img/new_branch_from_issue.png diff --git a/doc/workflow/img/revert_changes_commit.png b/doc/workflow/img/revert_changes_commit.png Binary files differindex d84211e20db..e7194fc3504 100644 --- a/doc/workflow/img/revert_changes_commit.png +++ b/doc/workflow/img/revert_changes_commit.png diff --git a/doc/workflow/img/revert_changes_commit_modal.png b/doc/workflow/img/revert_changes_commit_modal.png Binary files differindex e94d151a2af..c660ec7eaec 100644 --- a/doc/workflow/img/revert_changes_commit_modal.png +++ b/doc/workflow/img/revert_changes_commit_modal.png diff --git a/doc/workflow/img/revert_changes_mr.png b/doc/workflow/img/revert_changes_mr.png Binary files differindex 7adad88463b..3002f0ac1c5 100644 --- a/doc/workflow/img/revert_changes_mr.png +++ b/doc/workflow/img/revert_changes_mr.png diff --git a/doc/workflow/img/revert_changes_mr_modal.png b/doc/workflow/img/revert_changes_mr_modal.png Binary files differindex 9da78f84828..c6aaeecc8a6 100644 --- a/doc/workflow/img/revert_changes_mr_modal.png +++ b/doc/workflow/img/revert_changes_mr_modal.png diff --git a/doc/workflow/img/todos_icon.png b/doc/workflow/img/todos_icon.png Binary files differindex a63bad0c258..bba77f88913 100644 --- a/doc/workflow/img/todos_icon.png +++ b/doc/workflow/img/todos_icon.png diff --git a/doc/workflow/img/todos_index.png b/doc/workflow/img/todos_index.png Binary files differindex 4ee18dd1285..f1438ef7355 100644 --- a/doc/workflow/img/todos_index.png +++ b/doc/workflow/img/todos_index.png diff --git a/doc/workflow/img/web_editor_new_branch_dropdown.png b/doc/workflow/img/web_editor_new_branch_dropdown.png Binary files differindex 009e4b05adf..a8e635d2faf 100644 --- a/doc/workflow/img/web_editor_new_branch_dropdown.png +++ b/doc/workflow/img/web_editor_new_branch_dropdown.png diff --git a/doc/workflow/img/web_editor_new_branch_page.png b/doc/workflow/img/web_editor_new_branch_page.png Binary files differindex dd6cfc6e7bb..7f36b7faf63 100644 --- a/doc/workflow/img/web_editor_new_branch_page.png +++ b/doc/workflow/img/web_editor_new_branch_page.png diff --git a/doc/workflow/img/web_editor_new_directory_dialog.png b/doc/workflow/img/web_editor_new_directory_dialog.png Binary files differindex 2c76f84f395..d16e3c67116 100644 --- a/doc/workflow/img/web_editor_new_directory_dialog.png +++ b/doc/workflow/img/web_editor_new_directory_dialog.png diff --git a/doc/workflow/img/web_editor_new_directory_dropdown.png b/doc/workflow/img/web_editor_new_directory_dropdown.png Binary files differindex cedf46aedfd..c8d77b16ee8 100644 --- a/doc/workflow/img/web_editor_new_directory_dropdown.png +++ b/doc/workflow/img/web_editor_new_directory_dropdown.png diff --git a/doc/workflow/img/web_editor_new_file_dropdown.png b/doc/workflow/img/web_editor_new_file_dropdown.png Binary files differindex 6e884f6504d..3fcb91c9b93 100644 --- a/doc/workflow/img/web_editor_new_file_dropdown.png +++ b/doc/workflow/img/web_editor_new_file_dropdown.png diff --git a/doc/workflow/img/web_editor_new_file_editor.png b/doc/workflow/img/web_editor_new_file_editor.png Binary files differindex c76473bcfa7..21c340b9288 100644 --- a/doc/workflow/img/web_editor_new_file_editor.png +++ b/doc/workflow/img/web_editor_new_file_editor.png diff --git a/doc/workflow/img/web_editor_new_push_widget.png b/doc/workflow/img/web_editor_new_push_widget.png Binary files differindex a2108735741..c7738a4c930 100644 --- a/doc/workflow/img/web_editor_new_push_widget.png +++ b/doc/workflow/img/web_editor_new_push_widget.png diff --git a/doc/workflow/img/web_editor_new_tag_dropdown.png b/doc/workflow/img/web_editor_new_tag_dropdown.png Binary files differindex 263dd635b95..ac7415009b3 100644 --- a/doc/workflow/img/web_editor_new_tag_dropdown.png +++ b/doc/workflow/img/web_editor_new_tag_dropdown.png diff --git a/doc/workflow/img/web_editor_new_tag_page.png b/doc/workflow/img/web_editor_new_tag_page.png Binary files differindex 64d7cd11ed1..231e1a13fc0 100644 --- a/doc/workflow/img/web_editor_new_tag_page.png +++ b/doc/workflow/img/web_editor_new_tag_page.png diff --git a/doc/workflow/img/web_editor_start_new_merge_request.png b/doc/workflow/img/web_editor_start_new_merge_request.png Binary files differindex be12a151cac..2755501dfd1 100644 --- a/doc/workflow/img/web_editor_start_new_merge_request.png +++ b/doc/workflow/img/web_editor_start_new_merge_request.png diff --git a/doc/workflow/img/web_editor_upload_file_dialog.png b/doc/workflow/img/web_editor_upload_file_dialog.png Binary files differindex 6dd2207bca0..9d6d8250bbe 100644 --- a/doc/workflow/img/web_editor_upload_file_dialog.png +++ b/doc/workflow/img/web_editor_upload_file_dialog.png diff --git a/doc/workflow/img/web_editor_upload_file_dropdown.png b/doc/workflow/img/web_editor_upload_file_dropdown.png Binary files differindex bf6528701b0..6b5205b05ec 100644 --- a/doc/workflow/img/web_editor_upload_file_dropdown.png +++ b/doc/workflow/img/web_editor_upload_file_dropdown.png diff --git a/doc/workflow/importing/bitbucket_importer/bitbucket_import_select_project.png b/doc/workflow/importing/bitbucket_importer/bitbucket_import_select_project.png Binary files differindex 0e08703f421..1a5661de75d 100644 --- a/doc/workflow/importing/bitbucket_importer/bitbucket_import_select_project.png +++ b/doc/workflow/importing/bitbucket_importer/bitbucket_import_select_project.png diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png Binary files differindex 205c515bd3f..fd7a4d3fabf 100644 --- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png +++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png Binary files differindex a1e348d46ad..fd1ba6f5884 100644 --- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png +++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png Binary files differindex ed362846909..186c1563951 100644 --- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png +++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png Binary files differindex d2fbd0267bd..2f84d3232f2 100644 --- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png +++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png Binary files differindex b1cc4b58525..652ca20b9ab 100644 --- a/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png +++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png diff --git a/doc/workflow/importing/gitlab_importer/importer.png b/doc/workflow/importing/gitlab_importer/importer.png Binary files differindex d2a286d8cac..35a7ddc8318 100644 --- a/doc/workflow/importing/gitlab_importer/importer.png +++ b/doc/workflow/importing/gitlab_importer/importer.png diff --git a/doc/workflow/importing/gitlab_importer/new_project_page.png b/doc/workflow/importing/gitlab_importer/new_project_page.png Binary files differindex 5e239208e1e..81074d2d016 100644 --- a/doc/workflow/importing/gitlab_importer/new_project_page.png +++ b/doc/workflow/importing/gitlab_importer/new_project_page.png diff --git a/doc/workflow/importing/img/import_projects_from_github_importer.png b/doc/workflow/importing/img/import_projects_from_github_importer.png Binary files differindex f744dc06f81..b6ed8dd692a 100644 --- a/doc/workflow/importing/img/import_projects_from_github_importer.png +++ b/doc/workflow/importing/img/import_projects_from_github_importer.png 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 Binary files differindex 86be35acb37..c8f35a50f48 100644 --- 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 diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md index a7dfac2c120..a2b2a4b88f9 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.
![New project page on GitLab](img/import_projects_from_github_new_project_page.png)
diff --git a/doc/workflow/merge_commits.png b/doc/workflow/merge_commits.png Binary files differindex 757b589d0db..8aa1587cde6 100644 --- a/doc/workflow/merge_commits.png +++ b/doc/workflow/merge_commits.png diff --git a/doc/workflow/merge_request.png b/doc/workflow/merge_request.png Binary files differindex fde3ff5c854..6aad1d82f6e 100644 --- a/doc/workflow/merge_request.png +++ b/doc/workflow/merge_request.png diff --git a/doc/workflow/merge_requests/commit_compare.png b/doc/workflow/merge_requests/commit_compare.png Binary files differindex dfd7ee220f0..0e4a2b23c04 100644 --- a/doc/workflow/merge_requests/commit_compare.png +++ b/doc/workflow/merge_requests/commit_compare.png diff --git a/doc/workflow/merge_requests/merge_request_diff.png b/doc/workflow/merge_requests/merge_request_diff.png Binary files differindex f368423c746..3ebbfb75ea3 100644 --- a/doc/workflow/merge_requests/merge_request_diff.png +++ b/doc/workflow/merge_requests/merge_request_diff.png diff --git a/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png b/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png Binary files differindex b2d03bb66f9..a0db535019c 100644 --- a/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png +++ b/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png diff --git a/doc/workflow/merge_when_build_succeeds/enable.png b/doc/workflow/merge_when_build_succeeds/enable.png Binary files differindex 633efa1246f..b86e6d7b3fd 100644 --- a/doc/workflow/merge_when_build_succeeds/enable.png +++ b/doc/workflow/merge_when_build_succeeds/enable.png diff --git a/doc/workflow/merge_when_build_succeeds/status.png b/doc/workflow/merge_when_build_succeeds/status.png Binary files differindex c856c7d14dc..f3ea61d8147 100644 --- a/doc/workflow/merge_when_build_succeeds/status.png +++ b/doc/workflow/merge_when_build_succeeds/status.png diff --git a/doc/workflow/messy_flow.png b/doc/workflow/messy_flow.png Binary files differindex 1addb95ca54..8d2c0dae8c2 100644 --- a/doc/workflow/messy_flow.png +++ b/doc/workflow/messy_flow.png diff --git a/doc/workflow/milestones/form.png b/doc/workflow/milestones/form.png Binary files differindex de44c1ffc1a..3965ca4d083 100644 --- a/doc/workflow/milestones/form.png +++ b/doc/workflow/milestones/form.png diff --git a/doc/workflow/milestones/group_form.png b/doc/workflow/milestones/group_form.png Binary files differindex 38862dcca68..ff20df8081f 100644 --- a/doc/workflow/milestones/group_form.png +++ b/doc/workflow/milestones/group_form.png diff --git a/doc/workflow/mr_inline_comments.png b/doc/workflow/mr_inline_comments.png Binary files differindex e851b95bcef..af7df3100d0 100644 --- a/doc/workflow/mr_inline_comments.png +++ b/doc/workflow/mr_inline_comments.png diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md index fe4485e148a..b4a9c2f3d3e 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 Binary files differindex 7c6857aad1a..d50757beffc 100644 --- a/doc/workflow/notifications/settings.png +++ b/doc/workflow/notifications/settings.png diff --git a/doc/workflow/production_branch.png b/doc/workflow/production_branch.png Binary files differindex 33fb26dd621..d88a3687151 100644 --- a/doc/workflow/production_branch.png +++ b/doc/workflow/production_branch.png diff --git a/doc/workflow/protected_branches/protected_branches1.png b/doc/workflow/protected_branches/protected_branches1.png Binary files differindex 5c2a3de5f70..bb3ab7d7913 100644 --- a/doc/workflow/protected_branches/protected_branches1.png +++ b/doc/workflow/protected_branches/protected_branches1.png diff --git a/doc/workflow/protected_branches/protected_branches2.png b/doc/workflow/protected_branches/protected_branches2.png Binary files differindex 2dca3541365..58ace31ac57 100644 --- a/doc/workflow/protected_branches/protected_branches2.png +++ b/doc/workflow/protected_branches/protected_branches2.png diff --git a/doc/workflow/rebase.png b/doc/workflow/rebase.png Binary files differindex ef82c834755..df353311fa0 100644 --- a/doc/workflow/rebase.png +++ b/doc/workflow/rebase.png diff --git a/doc/workflow/release_branches.png b/doc/workflow/release_branches.png Binary files differindex da7ae53413a..c2162248d25 100644 --- a/doc/workflow/release_branches.png +++ b/doc/workflow/release_branches.png diff --git a/doc/workflow/releases/new_tag.png b/doc/workflow/releases/new_tag.png Binary files differindex e2b64bfe17f..2456a8500f4 100644 --- a/doc/workflow/releases/new_tag.png +++ b/doc/workflow/releases/new_tag.png diff --git a/doc/workflow/releases/tags.png b/doc/workflow/releases/tags.png Binary files differindex aca91906c68..eeda967afd6 100644 --- a/doc/workflow/releases/tags.png +++ b/doc/workflow/releases/tags.png diff --git a/doc/workflow/remove_checkbox.png b/doc/workflow/remove_checkbox.png Binary files differindex 3e247d38155..3b0393deb0f 100644 --- a/doc/workflow/remove_checkbox.png +++ b/doc/workflow/remove_checkbox.png diff --git a/doc/workflow/share_with_group.png b/doc/workflow/share_with_group.png Binary files differindex a0ca6f14552..2c47625e29a 100644 --- a/doc/workflow/share_with_group.png +++ b/doc/workflow/share_with_group.png diff --git a/doc/workflow/shortcuts.png b/doc/workflow/shortcuts.png Binary files differindex 16be0413b64..a9b1c4b4dcc 100644 --- a/doc/workflow/shortcuts.png +++ b/doc/workflow/shortcuts.png diff --git a/doc/workflow/wip_merge_requests/blocked_accept_button.png b/doc/workflow/wip_merge_requests/blocked_accept_button.png Binary files differindex 4791e5de972..89c458aa8d9 100644 --- a/doc/workflow/wip_merge_requests/blocked_accept_button.png +++ b/doc/workflow/wip_merge_requests/blocked_accept_button.png diff --git a/doc/workflow/wip_merge_requests/mark_as_wip.png b/doc/workflow/wip_merge_requests/mark_as_wip.png Binary files differindex 8fa83a201ac..9c37354a653 100644 --- a/doc/workflow/wip_merge_requests/mark_as_wip.png +++ b/doc/workflow/wip_merge_requests/mark_as_wip.png diff --git a/doc/workflow/wip_merge_requests/unmark_as_wip.png b/doc/workflow/wip_merge_requests/unmark_as_wip.png Binary files differindex d45e68f31c5..31f7326beb0 100644 --- a/doc/workflow/wip_merge_requests/unmark_as_wip.png +++ b/doc/workflow/wip_merge_requests/unmark_as_wip.png diff --git a/features/dashboard/new_project.feature b/features/dashboard/new_project.feature index 56b4a639c01..8ddafb6a7ac 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 31f8924c38c..09373168dad 100644 --- a/features/steps/dashboard/new_project.rb +++ b/features/steps/dashboard/new_project.rb @@ -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 483370f41c6..4fa7d7c6567 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 0ead83d6937..6b56a77b832 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 edc08cf0986..ab3f0ca7aeb 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/entities.rb b/lib/api/entities.rb index 5a23a18fe9c..4e2a43e45e2 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 ab9b7c602b5..dbe5bb08d3f 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 1d361569d59..b32503e8516 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 7b91215d50b..b9773f98d75 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 81d66271136..d77a5e3ff09 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 5351272f42d..4042e9a4c25 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 2d6f34c9cd8..bf058241cda 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 37f4c34054f..c3064163e07 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 ab7b811c5d8..ad412f56cca 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 3e3986d6382..34e0143a82e 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/current_settings.rb b/lib/gitlab/current_settings.rb index 28c34429c1f..54b46e5d23f 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 d325eca6d99..043f10d96a9 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 2286ac8829c..730978d502b 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/key_fingerprint.rb b/lib/gitlab/key_fingerprint.rb index 8684b4636ea..b75ae512d92 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/o_auth/auth_hash.rb b/lib/gitlab/o_auth/auth_hash.rb index 36e5c2670bb..7d6911a1ab3 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/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 9ee72fde92f..b43ee5b3383 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 12d6ac45fb6..e9a4e37ec48 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 ab0028d6603..b7cbdc6cd78 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 4753f00c26a..dbdd4e977e8 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 352b566df24..fe43d40e6d2 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 c7596e7abcb..ffcc76e5498 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 b1648a4602a..c85ebdf8619 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 d0c019044b7..ab96b1d3593 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 c5666d49e61..21c0e5f1d41 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 Binary files differindex 7da5f23ed9b..05c8b0d0ccf 100644 --- a/public/apple-touch-icon-precomposed.png +++ b/public/apple-touch-icon-precomposed.png diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png Binary files differindex 7da5f23ed9b..05c8b0d0ccf 100644 --- a/public/apple-touch-icon.png +++ b/public/apple-touch-icon.png diff --git a/rubocop/cop/migration/add_index.rb b/rubocop/cop/migration/add_index.rb new file mode 100644 index 00000000000..d9247a1f7ea --- /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 00000000000..97ee8b11044 --- /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 00000000000..3160a784a04 --- /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 00000000000..7922e19768b --- /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 c55a3c28208..51d59526854 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 6be9489edb2..79b819a1377 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/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb index dbc1d829b67..f4e5c26b519 100644 --- a/spec/features/admin/admin_system_info_spec.rb +++ b/spec/features/admin/admin_system_info_spec.rb @@ -11,7 +11,7 @@ describe 'Admin System Info' do expect(page).to have_content 'CPU' expect(page).to have_content 'Memory' - expect(page).to have_content 'Disk' + expect(page).to have_content 'Disks' end end end diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 5065dfb849c..17df66e73b4 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 c5fb0fc783b..9d66f76ef58 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 Binary files differindex 87ce25e877a..1247f2fecd7 100644 --- a/spec/fixtures/dk.png +++ b/spec/fixtures/dk.png diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb new file mode 100644 index 00000000000..08a93503258 --- /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 09e0bbfd00b..604204cca0a 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 00000000000..5178bd130f4 --- /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 4bb149f25ff..14c8df954a6 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 8d6ce114aa9..a005b4990e7 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 fd869f48b5c..6e5ba211382 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 00000000000..004341ffd02 --- /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 7c21cbe96d9..3b023a35446 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/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb index 109522fa626..211ef68dfab 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/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 6727a83e58a..5ec5ab40b6f 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 795cf241278..e8b236426e9 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 c59dfea5c55..c4c107c9eea 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 d84f3e998f5..2ea1320267c 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 8154001cf46..97b28686d82 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 4e68ac5e63a..cbea407f9bf 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_spec.rb b/spec/models/project_spec.rb index d305cd9ff1e..42308035d8c 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 d8350000bf6..8ae083d7132 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/internal_spec.rb b/spec/requests/api/internal_spec.rb index 437c89c3577..fcea45f19ba 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 41b5ed9bc33..5c909d8b3b3 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 f756101c514..6629a5a65e2 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 afa89b84175..eca8ddd8ea4 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 f99ad046f0d..48d374883d7 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 a63656e6268..a4fcd44882d 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 4c5ced7e746..bd4dc6a0f79 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 068c9a1219c..d5d4d7c56ef 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 b43f38ef202..606da1b7605 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 426bf53f198..9f9ef20f99b 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -80,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 @@ -127,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 @@ -143,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 25da0917134..02308530d13 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 00000000000..cd18d19ef5e --- /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 b8e73682c91..20b1a343c27 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 4ef05eb29d2..5f762282b5e 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 |