diff options
297 files changed, 2005 insertions, 1144 deletions
diff --git a/.eslintrc b/.eslintrc index 3e07edbccfe..44ad6a4896c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,6 +6,7 @@ }, "extends": "airbnb-base", "globals": { + "__webpack_public_path__": true, "_": false, "gl": false, "gon": false, diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ecedd44c89..d32b6989388 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,180 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 9.5.1 (2017-08-23) + +- [FIXED] Fix merge request pipeline status when pipeline has errors. !13664 +- [FIXED] Commit rows would occasionally render with the wrong language. +- [FIXED] Fix caching of future broadcast messages. +- [FIXED] Only require Sidekiq throttling library when enabled, to reduce cache misses. +- Raise Housekeeping timeout to 24 hours. !13719 + +## 9.5.0 (2017-08-22) + +- [FIXED] Fix timeouts when creating projects in groups with many members. !13508 +- [FIXED] Improve API pagination headers when no record found. !13629 (Jordan Patterson) +- [FIXED] Fix deleting GitLab Pages files when a project is removed. !13631 +- [FIXED] Fix commit list not loading the correct page when scrolling. +- [OTHER] Cache the number of forks of a project. !13535 +- GPG signed commits integration. !9546 (Alexis Reigel) +- Alert the user if a Wiki page changed while they were editing it in order to prevent overwriting changes. !9707 (Hiroyuki Sato) +- Add custom linter for inline JavaScript to haml_lint. !9742 (winniehell) +- Add /shrug and /tableflip commands. !10068 (Alex Ives) +- Allow wiki pages to be renamed in the UI. !10069 (wendy0402) +- Insert user name directly without encoding. !10085 (Nathan Neulinger <nneul@neulinger.org>) +- Avoid plucking Todo ids in TodoService. !10845 +- Handle errors while a project is being deleted asynchronously. !11088 +- Decrease ABC threshold to 56.96. !11227 (Maxim Rydkin) +- Remove Mattermost team when deleting a group. !11362 +- Block access to failing repository storage. !11449 +- Add coordinator url to admin area runner page. !11603 +- Allow testing any events for project hooks and system hooks. !11728 (Alexander Randa (@randaalex)) +- Disallow running the pipeline if ref is protected and user cannot merge the branch or create the tag. !11910 +- Remove project_key from the Jira configuration. !12050 +- Add CSRF token verification to API. !12154 (Vitaliy @blackst0ne Klachkov) +- Fixes needed when GitLab sign-in is not enabled. !12491 (Robin Bobbitt) +- Lazy load images for better Frontend performance. !12503 +- Replaces dashboard/event_filters.feature spinach with rspec. !12651 (Alexander Randa (@randaalex)) +- Toggle import description with import_sources_enabled. !12691 (Brianna Kicia) +- Bump scss-lint to 0.54.0. !12733 (Takuya Noguchi) +- Enable SpaceAfterComma in scss-lint. !12734 (Takuya Noguchi) +- Remove CSS for nprogress removed. !12737 (Takuya Noguchi) +- Enable UnnecessaryParentReference in scss-lint. !12738 (Takuya Noguchi) +- Extract "@request.env[devise.mapping] = Devise.mappings[:user]" to a test helper. !12742 (Jacopo Beschi @jacopo-beschi) +- Enable ImportPath in scss-lint. !12749 (Takuya Noguchi) +- Enable PropertySpelling in scss-lint. !12752 (Takuya Noguchi) +- Add API for protected branches to allow for wildcard matching and no access restrictions. !12756 (Eric Yu) +- refactor initializations in dropzone_input.js. !12768 (Brandon Everett) +- Improve CSS for global nav dropdown UI. !12772 (Takuya Noguchi) +- Remove public/ci/favicon.ico. !12803 (Takuya Noguchi) +- Enable DeclarationOrder in scss-lint. !12805 (Takuya Noguchi) +- Increase width of dropdown menus automatically. !12809 (Thomas Wucher) +- Enable BangFormat in scss-lint [ci skip]. !12815 (Takuya Noguchi) +- Added /duplicate quick action to close a duplicate issue. !12845 (Ryan Scott) +- Make all application-settings accessible through the API. !12851 +- Remove Inactive Personal Access Tokens list from Access Tokens page. !12866 +- Replaces dashboard/dashboard.feature spinach with rspec. !12876 (Alexander Randa (@randaalex)) +- Reduce memory usage of the GitHub importer. !12886 +- Bump fog-core to 1.44.3 and fog providers' plugins to latest. !12897 (Takuya Noguchi) +- Use only CSS to truncate commit message in blame. !12900 (Takuya Noguchi) +- Protect manual actions against protected tag too. !12908 +- Allow to configure automatic retry of a failed CI/CD job. !12909 +- Remove help message about prioritized labels for non-members. !12912 (Takuya Noguchi) +- Add link to doc/api/ci/lint.md. !12914 (Takuya Noguchi) +- Add RequestCache which makes caching with RequestStore easier. !12920 +- Free up some top level words, reject top level groups named like files in the public folder. !12932 +- Extend API for Group Secret Variable. !12936 +- Hide description about protected branches to non-member. !12945 (Takuya Noguchi) +- Support custom directory in gitlab:backup:create task. !12984 (Markus Koller) +- Raise guessed encoding confidence threshold to 50. !12990 +- Add author_id & assignee_id param to /issues API. !13004 +- Fix today day highlight in calendar. !13048 +- Prevent LDAP login callback from being called with a GET request. !13059 +- Add top-level merge_requests API endpoint. !13060 +- Handle maximum pages artifacts size correctly. !13072 +- Enable gitaly_post_upload_pack by default. !13078 +- Add Prometheus metrics exporter to Sidekiq. !13082 +- Fix improperly skipped backups of wikis. !13096 +- Projects can be created from templates. !13108 +- Fix the /projects/:id/repository/branches endpoint to handle dots in the branch name when the project full path contains a `/`. !13115 +- Fix project logos that are not centered vertically on list pages. !13124 (Florian Lemaitre) +- Derive project path from import URL. !13131 +- Fix deletion of deploy keys linked to other projects. !13162 +- repository archive download url now ends with selected file extension. !13178 (haseebeqx) +- Show auto-generated avatars for Groups without avatars. !13188 +- Allow any logged in users to read_users_list even if it's restricted. !13201 +- Unlock stuck merge request and set the proper state. !13207 +- Fix timezone inconsistencies in user contribution graph. !13208 +- Fix Issue board when using Ruby 2.4. !13220 +- Don't rename namespace called system when upgrading from 9.1.x to 9.5. !13228 +- Fix encoding error for WebHook logging. !13230 (Alexander Randa (@randaalex)) +- Uniquify reserved word usernames on OAuth user creation. !13244 (Robin Bobbitt) +- Expose target_iid in Events API. !13247 (sue445) +- Add star for action scope, in order to delete image from registry. !13248 (jean) +- Make Delete Merged Branches handle wildcard protected branches correctly. !13251 +- Fix an order of operations for CI connection error message in merge request widget. !13252 +- Don't send rejection mails for all auto-generated mails. !13254 +- Expose noteable_iid in Note. !13265 (sue445) +- Fix pipeline_schedules pages when active schedule has an abnormal state. !13286 +- Move some code from services to workers in order to improve performance. !13326 +- Fix destroy of case-insensitive conflicting redirects. !13357 +- Fix the /projects/:id/repository/tags endpoint to handle dots in the tag name when the project full path contains a `/`. !13368 +- Fix the /projects/:id/repository/commits endpoint to handle dots in the ref name when the project full path contains a `/`. !13370 +- Project pending delete no longer return 500 error in admins projects view. !13389 +- Use full path of user's avatar in webhooks. !13401 (Vitaliy @blackst0ne Klachkov) +- Make GPGME temporary directory handling thread safe. !13481 (Alexis Reigel) +- Add support for kube_namespace in Metrics queries. !16169 +- Fix bar chart does not display label at 0 hour. !35136 (Jason Dai) +- Use project_ref_path to create the link to a branch to fix links that 404. +- Declare related resources into V4 API entities. +- Add Slack and JIRA services counts to Usage Data. +- Prevent web hook and project service background jobs from going to the dead jobs queue. +- Display specific error message when JIRA test fails. +- clean up merge request widget UI. +- Associate Issues tab only with internal issues tracker. +- Remove events column from notification settings table. +- Clarifies and rearranges the input variables on the kubernetes integration page and adjusts the docs slightly to meet the same order. +- Respect blockquote line breaks in markdown. +- Update confidential issue UI - add confidential visibility and settings to sidebar. +- Add icons to contextual sidebars. +- Make contextual sidebar collapsible. +- Update Pipeline's badge count in Merge Request and Commits view to match real-time content. +- Added link to the MR widget that directs to the monitoring dashboard. +- Use jQuery to control scroll behavior in job log for cross browser consistency. +- move edit comment button outside of dropdown. +- Updates vue resource and code according to breaking changes. +- Add GitHub imported projects count to usage data. +- Rename about to overview for group and project page. +- Prevent disabled pagination button to be clicked. +- Remove coffee-rails gem. (Takuya Noguchi) +- Remove net-ssh gem. (Takuya Noguchi) +- Bump rubocop to 0.49.1 and rubocop-rspec to 1.15.1. (Takuya Noguchi) +- improve file upload/replace experience. +- allow closing Cycle Analytics intro box in firefox. +- Fix label creation from new list for subgroup projects. +- fix transient js error in rspec tests. +- fix jump to next discussion button. +- Fix translations for Star/Unstar in JS file. +- Improve mobile sidebar. +- Rename Pipelines tab to CI / CD in new navigation. +- Fix display of new diff comments after changing b between diff views. +- Store & use ConvDev percentages returned by the Version app. +- Fixes new issue button for failed job returning 404. +- Align OR separator to center in new project page. +- Add filtered search to group issue dashboard. +- Cache Appearance instances in Redis. +- Fixed breadcrumbs title aggressively collapsing. +- Better caching and indexing of broadcast messages. +- Moved diff changed files into a dropdown. +- Improve performance of large (initial) push into default branch. +- Improve performance of checking for projects on the projects dashboard. +- Eager load project creators for project dashboards. +- Modify if condition to be more readable. +- Fix links to group milestones from issue and merge request sidebar. +- Remove hidden symlinks from project import files. +- Fixed sign-in restrictions buttons not toggling active state. +- Fix replying to commit comments on merge requests created from forks. +- Support Markdown references, autocomplete, and quick actions for group milestones. +- Cache recent projects for group-level new resource creation. +- Fix API responses when dealing with txt files. +- Fix project milestones import when projects belongs to a group. +- Fix Mattermost integration. +- Memoize the number of personal projects a user has to reduce COUNT queries. +- Merge issuable "reopened" state into "opened". +- Migrate events into a new format to reduce the storage necessary and improve performance. +- MR branch link now links to tree instead of commits. +- Use Prev/Next pagination for exploring projects. +- Pass before_script and script as-is preserving arrays. +- Change project FK migration to skip existing FKs. +- Remove redundant query when retrieving the most recent push of a user. +- Re-organise "issues" indexes for faster ordering. +- Disallow Git URLs that include a username or hostname beginning with a non-alphanumeric character. +- Fix search box losing focus when typing. +- Add structured logging for Rails processes. +- Skip oAuth authorization for trusted applications. +- Use a specialized class for querying events to improve performance. +- Update build badges to be pipeline badges and display passing instead of success. + ## 9.4.5 (2017-08-14) - Fix deletion of deploy keys linked to other projects. !13162 @@ -396,12 +396,12 @@ gem 'net-ssh', '~> 4.1.0' # Required for ED25519 SSH host key support group :ed25519 do gem 'rbnacl-libsodium' - gem 'rbnacl', '~> 3.2' + gem 'rbnacl', '~> 4.0' gem 'bcrypt_pbkdf', '~> 1.0' end # Gitaly GRPC client -gem 'gitaly', '~> 0.29.0' +gem 'gitaly', '~> 0.30.0' gem 'toml-rb', '~> 0.3.15', require: false diff --git a/Gemfile.lock b/Gemfile.lock index ec8349cd1df..7d3c53ee010 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -203,7 +203,7 @@ GEM multi_json fast_gettext (1.4.0) ffaker (2.4.0) - ffi (1.9.10) + ffi (1.9.18) flay (2.8.1) erubis (~> 2.7.0) path_expander (~> 1.0) @@ -275,7 +275,7 @@ GEM po_to_json (>= 1.0.0) rails (>= 3.2.0) gherkin-ruby (0.3.2) - gitaly (0.29.0) + gitaly (0.30.0) google-protobuf (~> 3.1) grpc (~> 1.0) github-linguist (4.7.6) @@ -682,7 +682,7 @@ GEM rake (12.0.0) rblineprof (0.3.6) debugger-ruby_core_source (~> 1.3) - rbnacl (3.4.0) + rbnacl (4.0.2) ffi rbnacl-libsodium (1.0.11) rbnacl (>= 3.0.1) @@ -1019,7 +1019,7 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.2.0) - gitaly (~> 0.29.0) + gitaly (~> 0.30.0) github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.5.1) @@ -1107,7 +1107,7 @@ DEPENDENCIES rainbow (~> 2.2) raindrops (~> 0.18) rblineprof (~> 0.3.6) - rbnacl (~> 3.2) + rbnacl (~> 4.0) rbnacl-libsodium rdoc (~> 4.2) re2 (~> 1.1.1) @@ -1 +1 @@ -9.5.0-pre +9.6.0-pre diff --git a/app/assets/javascripts/repo/monaco_loader.js b/app/assets/javascripts/repo/monaco_loader.js index ad1370a7730..af83a1ec0b4 100644 --- a/app/assets/javascripts/repo/monaco_loader.js +++ b/app/assets/javascripts/repo/monaco_loader.js @@ -1,13 +1,11 @@ -/* eslint-disable no-underscore-dangle, camelcase */ -/* global __webpack_public_path__ */ - import monacoContext from 'monaco-editor/dev/vs/loader'; monacoContext.require.config({ paths: { - vs: `${__webpack_public_path__}monaco-editor/vs`, + vs: `${__webpack_public_path__}monaco-editor/vs`, // eslint-disable-line camelcase }, }); +// eslint-disable-next-line no-underscore-dangle window.__monaco_context__ = monacoContext; export default monacoContext.require; diff --git a/app/assets/javascripts/webpack.js b/app/assets/javascripts/webpack.js index 9a9cf395fb8..ced847294ae 100644 --- a/app/assets/javascripts/webpack.js +++ b/app/assets/javascripts/webpack.js @@ -5,5 +5,5 @@ */ if (gon && gon.webpack_public_path) { - __webpack_public_path__ = gon.webpack_public_path; // eslint-disable-line + __webpack_public_path__ = gon.webpack_public_path; // eslint-disable-line camelcase } diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 0bd84c9e08c..d13f9996518 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -13,6 +13,9 @@ img { /*max-width: 100%;*/ margin: 0 0 8px; + } + + img.lazy { min-width: 200px; min-height: 100px; background-color: $gray-lightest; diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 46fbfe5f91e..d0d11b4d71c 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -286,6 +286,9 @@ .gpg-status-box { + padding: 2px 10px; + margin-right: $gl-padding; + &:empty { display: none; } @@ -314,7 +317,6 @@ &.valid { svg { border: 1px solid $brand-success; - fill: $brand-success; } } @@ -322,7 +324,6 @@ &.invalid { svg { border: 1px solid $common-gray-light; - fill: $common-gray-light; } } diff --git a/app/controllers/admin/logs_controller.rb b/app/controllers/admin/logs_controller.rb index b999018dde4..bdc4332ae69 100644 --- a/app/controllers/admin/logs_controller.rb +++ b/app/controllers/admin/logs_controller.rb @@ -1,2 +1,11 @@ class Admin::LogsController < Admin::ApplicationController + def show + @loggers = [ + Gitlab::AppLogger, + Gitlab::GitLogger, + Gitlab::EnvironmentLogger, + Gitlab::SidekiqLogger, + Gitlab::RepositoryCheckLogger + ] + end end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index f76b3f69e9e..994e736d66e 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -26,6 +26,13 @@ class GroupsController < Groups::ApplicationController def new @group = Group.new + + if params[:parent_id].present? + parent = Group.find_by(id: params[:parent_id]) + if can?(current_user, :create_subgroup, parent) + @group.parent = parent + end + end end def create diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index d54a1111f11..daa5c88aae0 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -4,7 +4,6 @@ class Projects::ServicesController < Projects::ApplicationController # Authorize before_action :authorize_admin_project! before_action :service, only: [:edit, :update, :test] - before_action :update_service, only: [:update, :test] respond_to :html @@ -14,6 +13,8 @@ class Projects::ServicesController < Projects::ApplicationController end def update + @service.attributes = service_params[:service] + if @service.save(context: :manual_change) redirect_to(project_settings_integrations_path(@project), notice: success_message) else @@ -24,7 +25,7 @@ class Projects::ServicesController < Projects::ApplicationController def test message = {} - if @service.can_test? + if @service.can_test? && @service.update_attributes(service_params[:service]) data = @service.test_data(project, current_user) outcome = @service.test(data) @@ -50,10 +51,6 @@ class Projects::ServicesController < Projects::ApplicationController end end - def update_service - @service.assign_attributes(service_params[:service]) - end - def service @service ||= @project.find_or_initialize_service(params[:id]) end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 150188f0b65..3b76da238e0 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -116,6 +116,7 @@ module ApplicationSettingsHelper :email_author_in_body, :enabled_git_access_protocol, :gravatar_enabled, + :hashed_storage_enabled, :help_page_hide_commercial_content, :help_page_support_url, :help_page_text, diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index 4b51269533c..a4c226a6aad 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -12,11 +12,18 @@ module AvatarsHelper avatar_size = options[:size] || 16 user_name = options[:user].try(:name) || options[:user_name] avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size) - data_attributes = { container: 'body' } + has_tooltip = options[:has_tooltip].nil? ? true : options[:has_tooltip] + data_attributes = {} + css_class = %W[avatar s#{avatar_size}].push(*options[:css_class]) + + if has_tooltip + css_class.push('has-tooltip') + data_attributes = { container: 'body' } + end image_tag( avatar_url, - class: %W[avatar has-tooltip s#{avatar_size}].push(*options[:css_class]), + class: css_class, alt: "#{user_name}'s avatar", title: user_name, data: data_attributes, diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 72e26b64e60..9651f9733f9 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -114,7 +114,7 @@ module CommitsHelper end def commit_signature_badge_classes(additional_classes) - %w(btn status-box gpg-status-box) + Array(additional_classes) + %w(btn gpg-status-box) + Array(additional_classes) end protected diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index c6f98e7e782..b331693c789 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -181,6 +181,7 @@ module EventsHelper end def event_commit_title(message) + message ||= '' (message.split("\n").first || "").truncate(70) rescue "--broken encoding" diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb index 3692bcc680d..fdc5a2adea0 100644 --- a/app/models/broadcast_message.rb +++ b/app/models/broadcast_message.rb @@ -19,11 +19,21 @@ class BroadcastMessage < ActiveRecord::Base after_commit :flush_redis_cache def self.current - Rails.cache.fetch(CACHE_KEY) do - where('ends_at > :now AND starts_at <= :now', now: Time.zone.now) - .reorder(id: :asc) - .to_a - end + messages = Rails.cache.fetch(CACHE_KEY) { current_and_future_messages.to_a } + + return messages if messages.empty? + + now_or_future = messages.select(&:now_or_future?) + + # If there are cached entries but none are to be displayed we'll purge the + # cache so we don't keep running this code all the time. + Rails.cache.delete(CACHE_KEY) if now_or_future.empty? + + now_or_future.select(&:now?) + end + + def self.current_and_future_messages + where('ends_at > :now', now: Time.zone.now).reorder(id: :asc) end def active? @@ -38,6 +48,18 @@ class BroadcastMessage < ActiveRecord::Base ends_at < Time.zone.now end + def now? + (starts_at..ends_at).cover?(Time.zone.now) + end + + def future? + starts_at > Time.zone.now + end + + def now_or_future? + now? || future? + end + def flush_redis_cache Rails.cache.delete(CACHE_KEY) end diff --git a/app/models/concerns/storage/legacy_project.rb b/app/models/concerns/storage/legacy_project.rb deleted file mode 100644 index 815db712285..00000000000 --- a/app/models/concerns/storage/legacy_project.rb +++ /dev/null @@ -1,76 +0,0 @@ -module Storage - module LegacyProject - extend ActiveSupport::Concern - - def disk_path - full_path - end - - def ensure_storage_path_exist - gitlab_shell.add_namespace(repository_storage_path, namespace.full_path) - end - - def rename_repo - path_was = previous_changes['path'].first - old_path_with_namespace = File.join(namespace.full_path, path_was) - new_path_with_namespace = File.join(namespace.full_path, path) - - Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}" - - if has_container_registry_tags? - Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!" - - # we currently doesn't support renaming repository if it contains images in container registry - raise StandardError.new('Project cannot be renamed, because images are present in its container registry') - end - - expire_caches_before_rename(old_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(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") - send_move_instructions(old_path_with_namespace) - expires_full_path_cache - - @old_path_with_namespace = old_path_with_namespace - - SystemHooksService.new.execute_hooks_for(self, :rename) - - @repository = nil - rescue => e - Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}" - # Returning false does not rollback after_* transaction but gives - # us information about failing some of tasks - false - end - else - Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}" - - # if we cannot move namespace directory we should rollback - # db changes in order to prevent out of sync between db and fs - raise StandardError.new('repository cannot be renamed') - end - - Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}" - - Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path) - Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path) - end - - def create_repository(force: false) - # Forked import is handled asynchronously - return if forked? && !force - - if gitlab_shell.add_repository(repository_storage_path, path_with_namespace) - repository.after_create - true - else - errors.add(:base, 'Failed to create repository via gitlab-shell') - false - end - end - end -end diff --git a/app/models/event.rb b/app/models/event.rb index 15ee170ca75..996768a267b 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -406,7 +406,7 @@ class Event < ActiveRecord::Base def body? if push? - push_with_commits? || rm_ref? + push_with_commits? elsif note? true else diff --git a/app/models/issue.rb b/app/models/issue.rb index 043da9967a1..b9aa937d2f9 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -50,7 +50,10 @@ class Issue < ActiveRecord::Base scope :preload_associations, -> { preload(:labels, project: :namespace) } + scope :public_only, -> { where(confidential: false) } + after_save :expire_etag_cache + after_commit :update_project_counter_caches, on: :destroy attr_spammable :title, spam_title: true attr_spammable :description, spam_description: true @@ -266,6 +269,10 @@ class Issue < ActiveRecord::Base end end + def update_project_counter_caches + Projects::OpenIssuesCountService.new(project).refresh_cache + end + private # Returns `true` if the given User can read the current Issue. diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index f028d2395c1..dde43e94cb5 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -31,6 +31,7 @@ class MergeRequest < ActiveRecord::Base after_create :ensure_merge_request_diff, unless: :importing? after_update :reload_diff_if_branch_changed + after_commit :update_project_counter_caches, on: :destroy # When this attribute is true some MR validation is ignored # It allows us to close or modify broken merge requests @@ -936,6 +937,10 @@ class MergeRequest < ActiveRecord::Base true end + def update_project_counter_caches + Projects::OpenMergeRequestsCountService.new(target_project).refresh_cache + end + private def write_ref diff --git a/app/models/project.rb b/app/models/project.rb index be248bc99e1..3118a480f7b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -17,7 +17,6 @@ class Project < ActiveRecord::Base include ProjectFeaturesCompatibility include SelectForProjectAuthorization include Routable - include Storage::LegacyProject extend Gitlab::ConfigHelper @@ -25,6 +24,7 @@ class Project < ActiveRecord::Base NUMBER_OF_PERMITTED_BOARDS = 1 UNKNOWN_IMPORT_URL = 'http://unknown.git'.freeze + LATEST_STORAGE_VERSION = 1 cache_markdown_field :description, pipeline: :description @@ -32,6 +32,8 @@ class Project < ActiveRecord::Base :merge_requests_enabled?, :issues_enabled?, to: :project_feature, allow_nil: true + delegate :base_dir, :disk_path, :ensure_storage_path_exists, to: :storage + default_value_for :archived, false default_value_for :visibility_level, gitlab_config_features.visibility_level default_value_for :container_registry_enabled, gitlab_config_features.container_registry @@ -44,32 +46,24 @@ class Project < ActiveRecord::Base default_value_for :snippets_enabled, gitlab_config_features.snippets default_value_for :only_allow_merge_if_all_discussions_are_resolved, false - after_create :ensure_storage_path_exist - after_create :create_project_feature, unless: :project_feature - after_save :update_project_statistics, if: :namespace_id_changed? + add_authentication_token_field :runners_token + before_save :ensure_runners_token - # set last_activity_at to the same as created_at + after_save :update_project_statistics, if: :namespace_id_changed? + after_create :create_project_feature, unless: :project_feature after_create :set_last_activity_at - def set_last_activity_at - update_column(:last_activity_at, self.created_at) - end - after_create :set_last_repository_updated_at - def set_last_repository_updated_at - update_column(:last_repository_updated_at, self.created_at) - end + after_update :update_forks_visibility_level before_destroy :remove_private_deploy_keys after_destroy -> { run_after_commit { remove_pages } } - # update visibility_level of forks - after_update :update_forks_visibility_level - after_validation :check_pending_delete - # Legacy Storage specific hooks - - after_save :ensure_storage_path_exist, if: :namespace_id_changed? + # Storage specific hooks + after_initialize :use_hashed_storage + after_create :ensure_storage_path_exists + after_save :ensure_storage_path_exists, if: :namespace_id_changed? acts_as_taggable @@ -238,9 +232,6 @@ class Project < ActiveRecord::Base presence: true, inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } } - add_authentication_token_field :runners_token - before_save :ensure_runners_token - mount_uploader :avatar, AvatarUploader has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent @@ -487,6 +478,10 @@ class Project < ActiveRecord::Base @repository ||= Repository.new(full_path, self, disk_path: disk_path) end + def reload_repository! + @repository = nil + end + def container_registry_url if Gitlab.config.registry.enabled "#{Gitlab.config.registry.host_port}/#{full_path.downcase}" @@ -1004,6 +999,19 @@ class Project < ActiveRecord::Base end end + def create_repository(force: false) + # Forked import is handled asynchronously + return if forked? && !force + + if gitlab_shell.add_repository(repository_storage_path, disk_path) + repository.after_create + true + else + errors.add(:base, 'Failed to create repository via gitlab-shell') + false + end + end + def hook_attrs(backward: true) attrs = { name: name, @@ -1086,6 +1094,7 @@ class Project < ActiveRecord::Base !!repository.exists? end + # update visibility_level of forks def update_forks_visibility_level return unless visibility_level < visibility_level_was @@ -1158,7 +1167,11 @@ class Project < ActiveRecord::Base end def open_issues_count - issues.opened.count + Projects::OpenIssuesCountService.new(self).count + end + + def open_merge_requests_count + Projects::OpenMergeRequestsCountService.new(self).count end def visibility_level_allowed_as_fork?(level = self.visibility_level) @@ -1213,7 +1226,8 @@ class Project < ActiveRecord::Base end def pages_path - File.join(Settings.pages.path, disk_path) + # TODO: when we migrate Pages to work with new storage types, change here to use disk_path + File.join(Settings.pages.path, full_path) end def public_pages_path @@ -1252,6 +1266,50 @@ class Project < ActiveRecord::Base end end + def rename_repo + new_full_path = build_full_path + + Rails.logger.error "Attempting to rename #{full_path_was} -> #{new_full_path}" + + if has_container_registry_tags? + Rails.logger.error "Project #{full_path_was} cannot be renamed because container registry tags are present!" + + # we currently doesn't support renaming repository if it contains images in container registry + raise StandardError.new('Project cannot be renamed, because images are present in its container registry') + end + + expire_caches_before_rename(full_path_was) + + if storage.rename_repo + Gitlab::AppLogger.info "Project was renamed: #{full_path_was} -> #{new_full_path}" + rename_repo_notify! + after_rename_repo + else + Rails.logger.error "Repository could not be renamed: #{full_path_was} -> #{new_full_path}" + + # if we cannot move namespace directory we should rollback + # db changes in order to prevent out of sync between db and fs + raise StandardError.new('repository cannot be renamed') + end + end + + def rename_repo_notify! + send_move_instructions(full_path_was) + expires_full_path_cache + + self.old_path_with_namespace = full_path_was + SystemHooksService.new.execute_hooks_for(self, :rename) + + reload_repository! + end + + def after_rename_repo + path_before_change = previous_changes['path'].first + + Gitlab::UploadsTransfer.new.rename_project(path_before_change, self.path, namespace.full_path) + Gitlab::PagesTransfer.new.rename_project(path_before_change, self.path, namespace.full_path) + end + def running_or_pending_build_count(force: false) Rails.cache.fetch(['projects', id, 'running_or_pending_build_count'], force: force) do builds.running_or_pending.count(:all) @@ -1410,6 +1468,10 @@ class Project < ActiveRecord::Base end end + def full_path_was + File.join(namespace.full_path, previous_changes['path'].first) + end + alias_method :name_with_namespace, :full_name alias_method :human_name, :full_name # @deprecated cannot remove yet because it has an index with its name in elasticsearch @@ -1419,8 +1481,36 @@ class Project < ActiveRecord::Base Projects::ForksCountService.new(self).count end + def legacy_storage? + self.storage_version.nil? + end + private + def storage + @storage ||= + if self.storage_version && self.storage_version >= 1 + Storage::HashedProject.new(self) + else + Storage::LegacyProject.new(self) + end + end + + def use_hashed_storage + if self.new_record? && current_application_settings.hashed_storage_enabled + self.storage_version = LATEST_STORAGE_VERSION + end + end + + # set last_activity_at to the same as created_at + def set_last_activity_at + update_column(:last_activity_at, self.created_at) + end + + def set_last_repository_updated_at + update_column(:last_repository_updated_at, self.created_at) + end + def cross_namespace_reference?(from) case from when Project diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb index dee99bbb859..8ba07173c74 100644 --- a/app/models/project_services/kubernetes_service.rb +++ b/app/models/project_services/kubernetes_service.rb @@ -24,6 +24,8 @@ class KubernetesService < DeploymentService validates :token end + before_validation :enforce_namespace_to_lower_case + validates :namespace, allow_blank: true, length: 1..63, @@ -207,4 +209,8 @@ class KubernetesService < DeploymentService max_session_time: current_application_settings.terminal_max_session_time } end + + def enforce_namespace_to_lower_case + self.namespace = self.namespace&.downcase + end end diff --git a/app/models/storage/hashed_project.rb b/app/models/storage/hashed_project.rb new file mode 100644 index 00000000000..fae1b64961a --- /dev/null +++ b/app/models/storage/hashed_project.rb @@ -0,0 +1,42 @@ +module Storage + class HashedProject + attr_accessor :project + delegate :gitlab_shell, :repository_storage_path, to: :project + + ROOT_PATH_PREFIX = '@hashed'.freeze + + def initialize(project) + @project = project + end + + # Base directory + # + # @return [String] directory where repository is stored + def base_dir + "#{ROOT_PATH_PREFIX}/#{disk_hash[0..1]}/#{disk_hash[2..3]}" if disk_hash + end + + # Disk path is used to build repository and project's wiki path on disk + # + # @return [String] combination of base_dir and the repository own name without `.git` or `.wiki.git` extensions + def disk_path + "#{base_dir}/#{disk_hash}" if disk_hash + end + + def ensure_storage_path_exists + gitlab_shell.add_namespace(repository_storage_path, base_dir) + end + + def rename_repo + true + end + + private + + # Generates the hash for the project path and name on disk + # If you need to refer to the repository on disk, use the `#disk_path` + def disk_hash + @disk_hash ||= Digest::SHA2.hexdigest(project.id.to_s) if project.id + end + end +end diff --git a/app/models/storage/legacy_project.rb b/app/models/storage/legacy_project.rb new file mode 100644 index 00000000000..9d9e5e1d352 --- /dev/null +++ b/app/models/storage/legacy_project.rb @@ -0,0 +1,51 @@ +module Storage + class LegacyProject + attr_accessor :project + delegate :namespace, :gitlab_shell, :repository_storage_path, to: :project + + def initialize(project) + @project = project + end + + # Base directory + # + # @return [String] directory where repository is stored + def base_dir + namespace.full_path + end + + # Disk path is used to build repository and project's wiki path on disk + # + # @return [String] combination of base_dir and the repository own name without `.git` or `.wiki.git` extensions + def disk_path + project.full_path + end + + def ensure_storage_path_exists + return unless namespace + + gitlab_shell.add_namespace(repository_storage_path, base_dir) + end + + def rename_repo + new_full_path = project.build_full_path + + if gitlab_shell.mv_repository(repository_storage_path, project.full_path_was, new_full_path) + # 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(repository_storage_path, "#{project.full_path_was}.wiki", "#{new_full_path}.wiki") + return true + rescue => e + Rails.logger.error "Exception renaming #{project.full_path_was} -> #{new_full_path}: #{e}" + # Returning false does not rollback after_* transaction but gives + # us information about failing some of tasks + return false + end + end + + false + end + end +end diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index 6defab75fce..8ada661e571 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -13,6 +13,8 @@ class GroupPolicy < BasePolicy condition(:master) { access_level >= GroupMember::MASTER } condition(:reporter) { access_level >= GroupMember::REPORTER } + condition(:nested_groups_supported, scope: :global) { Group.supports_nested_groups? } + condition(:has_projects) do GroupProjectsFinder.new(group: @subject, current_user: @user).execute.any? end @@ -42,7 +44,7 @@ class GroupPolicy < BasePolicy enable :change_visibility_level end - rule { owner & can_create_group }.enable :create_subgroup + rule { owner & can_create_group & nested_groups_supported }.enable :create_subgroup rule { public_group | logged_in_viewable }.enable :view_globally diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb index c4e9b8fd8e0..c7c27621085 100644 --- a/app/services/groups/create_service.rb +++ b/app/services/groups/create_service.rb @@ -13,9 +13,9 @@ module Groups return @group end - if @group.parent && !can?(current_user, :admin_group, @group.parent) + if @group.parent && !can?(current_user, :create_subgroup, @group.parent) @group.parent = nil - @group.errors.add(:parent_id, 'manage access required to create subgroup') + @group.errors.add(:parent_id, 'You don’t have permission to create a subgroup in this group.') return @group end diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb index f565612a89d..e3f9d9ee95d 100644 --- a/app/services/groups/destroy_service.rb +++ b/app/services/groups/destroy_service.rb @@ -13,7 +13,7 @@ module Groups # Execute the destruction of the models immediately to ensure atomic cleanup. # Skip repository removal because we remove directory with namespace # that contain all these repositories - ::Projects::DestroyService.new(project, current_user, skip_repo: true).execute + ::Projects::DestroyService.new(project, current_user, skip_repo: project.legacy_storage?).execute end group.children.each do |group| diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb new file mode 100644 index 00000000000..8d793f5c02e --- /dev/null +++ b/app/services/groups/nested_create_service.rb @@ -0,0 +1,45 @@ +module Groups + class NestedCreateService < Groups::BaseService + attr_reader :group_path + + def initialize(user, params) + @current_user, @params = user, params.dup + + @group_path = @params.delete(:group_path) + end + + def execute + return nil unless group_path + + if group = Group.find_by_full_path(group_path) + return group + end + + create_group_path + end + + private + + def create_group_path + group_path_segments = group_path.split('/') + + last_group = nil + partial_path_segments = [] + while subgroup_name = group_path_segments.shift + partial_path_segments << subgroup_name + partial_path = partial_path_segments.join('/') + + new_params = params.reverse_merge( + path: subgroup_name, + name: subgroup_name, + parent: last_group + ) + new_params[:visibility_level] ||= Gitlab::CurrentSettings.current_application_settings.default_group_visibility + + last_group = Group.find_by_full_path(partial_path) || Groups::CreateService.new(current_user, new_params).execute + end + + last_group + end + end +end diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 4a4f2b91182..1486db046b5 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -192,6 +192,8 @@ class IssuableBaseService < BaseService def after_create(issuable) # To be overridden by subclasses + + issuable.update_project_counter_caches end def before_update(issuable) @@ -200,6 +202,8 @@ class IssuableBaseService < BaseService def after_update(issuable) # To be overridden by subclasses + + issuable.update_project_counter_caches end def update(issuable) diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb index 234fcbede03..0307634c0b6 100644 --- a/app/services/issues/create_service.rb +++ b/app/services/issues/create_service.rb @@ -27,6 +27,8 @@ module Issues todo_service.new_issue(issuable, current_user) user_agent_detail_service.create resolve_discussions_with_issue(issuable) + + super end def resolve_discussions_with_issue(issue) diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb index 194413bf321..3d53fe0646b 100644 --- a/app/services/merge_requests/create_service.rb +++ b/app/services/merge_requests/create_service.rb @@ -28,6 +28,8 @@ module MergeRequests todo_service.new_merge_request(issuable, current_user) issuable.cache_merge_request_closes_issues!(current_user) update_merge_requests_head_pipeline(issuable) + + super end private diff --git a/app/services/projects/count_service.rb b/app/services/projects/count_service.rb new file mode 100644 index 00000000000..5e633c37bf8 --- /dev/null +++ b/app/services/projects/count_service.rb @@ -0,0 +1,43 @@ +module Projects + # Base class for the various service classes that count project data (e.g. + # issues or forks). + class CountService + def initialize(project) + @project = project + end + + def relation_for_count + raise( + NotImplementedError, + '"relation_for_count" must be implemented and return an ActiveRecord::Relation' + ) + end + + def count + Rails.cache.fetch(cache_key) { uncached_count } + end + + def refresh_cache + Rails.cache.write(cache_key, uncached_count) + end + + def uncached_count + relation_for_count.count + end + + def delete_cache + Rails.cache.delete(cache_key) + end + + def cache_key_name + raise( + NotImplementedError, + '"cache_key_name" must be implemented and return a String' + ) + end + + def cache_key + ['projects', @project.id, cache_key_name] + end + end +end diff --git a/app/services/projects/forks_count_service.rb b/app/services/projects/forks_count_service.rb index e2e2b1da91d..3a0fa84b868 100644 --- a/app/services/projects/forks_count_service.rb +++ b/app/services/projects/forks_count_service.rb @@ -1,30 +1,12 @@ module Projects # Service class for getting and caching the number of forks of a project. - class ForksCountService - def initialize(project) - @project = project + class ForksCountService < CountService + def relation_for_count + @project.forks end - def count - Rails.cache.fetch(cache_key) { uncached_count } - end - - def refresh_cache - Rails.cache.write(cache_key, uncached_count) - end - - def delete_cache - Rails.cache.delete(cache_key) - end - - private - - def uncached_count - @project.forks.count - end - - def cache_key - ['projects', @project.id, 'forks_count'] + def cache_key_name + 'forks_count' end end end diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb index 4b8946f8ee2..d66ef676088 100644 --- a/app/services/projects/housekeeping_service.rb +++ b/app/services/projects/housekeeping_service.rb @@ -9,7 +9,8 @@ module Projects class HousekeepingService < BaseService include Gitlab::CurrentSettings - LEASE_TIMEOUT = 3600 + # Timeout set to 24h + LEASE_TIMEOUT = 86400 class LeaseTaken < StandardError def to_s diff --git a/app/services/projects/open_issues_count_service.rb b/app/services/projects/open_issues_count_service.rb new file mode 100644 index 00000000000..3c0d186a73c --- /dev/null +++ b/app/services/projects/open_issues_count_service.rb @@ -0,0 +1,15 @@ +module Projects + # Service class for counting and caching the number of open issues of a + # project. + class OpenIssuesCountService < CountService + def relation_for_count + # We don't include confidential issues in this number since this would + # expose the number of confidential issues to non project members. + @project.issues.opened.public_only + end + + def cache_key_name + 'open_issues_count' + end + end +end diff --git a/app/services/projects/open_merge_requests_count_service.rb b/app/services/projects/open_merge_requests_count_service.rb new file mode 100644 index 00000000000..2a90f78b90d --- /dev/null +++ b/app/services/projects/open_merge_requests_count_service.rb @@ -0,0 +1,13 @@ +module Projects + # Service class for counting and caching the number of open merge requests of + # a project. + class OpenMergeRequestsCountService < CountService + def relation_for_count + @project.merge_requests.opened + end + + def cache_key_name + 'open_merge_requests_count' + end + end +end diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb index 9d7237c2fbb..8e20de8dfa5 100644 --- a/app/services/users/destroy_service.rb +++ b/app/services/users/destroy_service.rb @@ -35,16 +35,18 @@ module Users Groups::DestroyService.new(group, current_user).execute end + namespace = user.namespace + namespace.prepare_for_destroy + user.personal_projects.each do |project| # Skip repository removal because we remove directory with namespace # that contain all this repositories - ::Projects::DestroyService.new(project, current_user, skip_repo: true).execute + ::Projects::DestroyService.new(project, current_user, skip_repo: project.legacy_storage?).execute end MigrateToGhostUserService.new(user).execute unless options[:hard_delete] # Destroy the namespace after destroying the user since certain methods may depend on the namespace existing - namespace = user.namespace user_data = user.destroy namespace.really_destroy! diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index dc585054316..959af5c0d13 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -493,6 +493,16 @@ %fieldset %legend Repository Storage .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :hashed_storage_enabled do + = f.check_box :hashed_storage_enabled + Create new projects using hashed storage paths + .help-block + Enable immutable, hash-based paths and repository names to store repositories on disk. This prevents + repositories from having to be moved or renamed when the Project URL changes and may improve disk I/O performance. + %em (EXPERIMENTAL) + .form-group = f.label :repository_storages, 'Storage paths for new projects', class: 'control-label col-sm-2' .col-sm-10 = f.select :repository_storages, repository_storages_options_for_select, {include_hidden: false}, multiple: true, class: 'form-control' @@ -501,6 +511,7 @@ = succeed "." do = link_to "repository storages documentation", help_page_path("administration/repository_storages") + %fieldset %legend Repository Checks .form-group diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 487f1cf5c4f..ee87f25a225 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -1,25 +1,21 @@ - @no_container = true - page_title "Logs" -- loggers = [Gitlab::GitLogger, Gitlab::AppLogger, - Gitlab::EnvironmentLogger, Gitlab::SidekiqLogger, - Gitlab::RepositoryCheckLogger] = render 'admin/monitoring/head' %div{ class: container_class } %ul.nav-links.log-tabs - - loggers.each do |klass| - %li{ class: active_when(klass == Gitlab::GitLogger) }> - = link_to klass::file_name, "##{klass::file_name_noext}", - 'data-toggle' => 'tab' + - @loggers.each do |klass| + %li{ class: active_when(klass == @loggers.first) }> + = link_to klass.file_name, "##{klass.file_name_noext}", data: { toggle: 'tab' } .row-content-block To prevent performance issues admin logs output the last 2000 lines .tab-content - - loggers.each do |klass| - .tab-pane{ class: active_when(klass == Gitlab::GitLogger), id: klass::file_name_noext } + - @loggers.each do |klass| + .tab-pane{ class: active_when(klass == @loggers.first), id: klass.file_name_noext } .file-holder#README .js-file-title.file-title %i.fa.fa-file - = klass::file_name + = klass.file_name .pull-right = link_to '#', class: 'log-bottom' do %i.fa.fa-arrow-down diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml index bf655f9d21a..e3c5fd55f08 100644 --- a/app/views/events/_event_push.atom.haml +++ b/app/views/events/_event_push.atom.haml @@ -5,9 +5,10 @@ %i at = event.created_at.to_s(:short) - %blockquote= markdown(escape_once(event.commit_title), pipeline: :atom, project: event.project, author: event.author) - - if event.commits_count > 1 - %p - %i - \... and - = pluralize(event.commits_count - 1, "more commit") + - unless event.rm_ref? + %blockquote= markdown(escape_once(event.commit_title), pipeline: :atom, project: event.project, author: event.author) + - if event.commits_count > 1 + %p + %i + \... and + = pluralize(event.commits_count - 1, "more commit") diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml index 973c652ad88..53ebdd6d2ff 100644 --- a/app/views/events/event/_push.html.haml +++ b/app/views/events/event/_push.html.haml @@ -41,7 +41,3 @@ %li.commits-stat = link_to create_mr_path(project.default_branch, event.ref_name, project) do Create Merge Request -- elsif event.rm_ref? - .event-body - %ul.well-list.event_commits - = render "events/commit", project: project, event: event diff --git a/app/views/import/gitlab_projects/new.html.haml b/app/views/import/gitlab_projects/new.html.haml index 008e8287aa3..5d68e1e2156 100644 --- a/app/views/import/gitlab_projects/new.html.haml +++ b/app/views/import/gitlab_projects/new.html.haml @@ -25,7 +25,7 @@ = hidden_field_tag :namespace_id, value: current_user.namespace_id .form-group.col-xs-12.col-sm-6.project-path = label_tag :path, 'Project name', class: 'label-light' - = text_field_tag :path, nil, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, autofocus: true, required: true + = text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, autofocus: true, required: true .row .form-group.col-md-12 @@ -33,7 +33,6 @@ .row .form-group.col-sm-12 = hidden_field_tag :namespace_id, @namespace.id - = hidden_field_tag :path, @path = label_tag :file, 'GitLab project export', class: 'label-light' .form-group = file_field_tag :file, class: '' diff --git a/app/views/layouts/nav/_new_project_sidebar.html.haml b/app/views/layouts/nav/_new_project_sidebar.html.haml index 0ef81375c3a..81c84756ff8 100644 --- a/app/views/layouts/nav/_new_project_sidebar.html.haml +++ b/app/views/layouts/nav/_new_project_sidebar.html.haml @@ -86,7 +86,8 @@ %span.nav-item-name Issues - if @project.issues_enabled? - %span.badge.count.issue_counter= number_with_delimiter(IssuesFinder.new(current_user, project_id: @project.id).execute.opened.count) + %span.badge.count.issue_counter + = number_with_delimiter(@project.open_issues_count) %ul.sidebar-sub-level-items = nav_link(controller: :issues) do @@ -116,7 +117,8 @@ = custom_icon('mr_bold') %span.nav-item-name Merge Requests - %span.badge.count.merge_counter.js-merge-counter= number_with_delimiter(MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.count) + %span.badge.count.merge_counter.js-merge-counter + = number_with_delimiter(@project.open_merge_requests_count) - if project_nav_tab? :pipelines = nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :environments, :artifacts]) do diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 924cd2e9681..b88465848e3 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -28,7 +28,8 @@ %span Issues - if @project.issues_enabled? - %span.badge.count.issue_counter= number_with_delimiter(issuables_count_for_state(:issues, :opened, finder: IssuesFinder.new(current_user, project_id: @project.id))) + %span.badge.count.issue_counter + = number_with_delimiter(@project.open_issues_count) - if project_nav_tab? :merge_requests - controllers = [:merge_requests, 'projects/merge_requests/conflicts'] @@ -37,7 +38,8 @@ = link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do %span Merge Requests - %span.badge.count.merge_counter.js-merge-counter= number_with_delimiter(issuables_count_for_state(:merge_requests, :opened, finder: MergeRequestsFinder.new(current_user, project_id: @project.id))) + %span.badge.count.merge_counter.js-merge-counter + = number_with_delimiter(@project.open_merge_requests_count) - if project_nav_tab? :pipelines = nav_link(controller: [:pipelines, :builds, :environments, :artifacts]) do diff --git a/app/views/projects/_project_templates.html.haml b/app/views/projects/_project_templates.html.haml index 97cf13df070..5638b7da1b0 100644 --- a/app/views/projects/_project_templates.html.haml +++ b/app/views/projects/_project_templates.html.haml @@ -1,6 +1,6 @@ .project-templates-buttons.import-buttons{ data: { toggle: "buttons" } } .btn.blank-option.active - %input{ type: "radio", autocomplete: "off", name: "project_templates", id: "blank", checked: "true" } + %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: "blank", checked: "true", value: "" } = icon('file-o', class: 'btn-template-icon') Blank - Gitlab::ProjectTemplate.all.each do |template| diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 7e8a5a38086..1214aabe837 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -37,14 +37,14 @@ .commit-actions.hidden-xs - - if commit.status(ref) - = render_commit_status(commit, ref: ref) - - if request.xhr? = render partial: 'projects/commit/signature', object: commit.signature - else = render partial: 'projects/commit/ajax_signature', locals: { commit: commit } + - if commit.status(ref) + = render_commit_status(commit, ref: ref) + = link_to commit.short_id, project_commit_path(project, commit), class: "commit-sha btn btn-transparent" = clipboard_button(text: commit.id, title: _("Copy commit SHA to clipboard")) = link_to_browse_code(project, commit) diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 6178abe9160..9e26bdecd31 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -202,8 +202,6 @@ .sub-section.rename-respository %h4.warning-title Rename repository - %p - Export this project with all its related data in order to move your project to a new GitLab instance. Once the export is finished, you can import the file from the "New Project" page. = render 'projects/errors' = form_for([@project.namespace.becomes(Namespace), @project]) do |f| .form-group.project_name_holder diff --git a/app/views/shared/_group_form.html.haml b/app/views/shared/_group_form.html.haml index 8d5b5129454..2e1bd5a088c 100644 --- a/app/views/shared/_group_form.html.haml +++ b/app/views/shared/_group_form.html.haml @@ -1,6 +1,6 @@ - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('group') -- parent = GroupFinder.new(current_user).execute(id: params[:parent_id] || @group.parent_id) +- parent = @group.parent - group_path = root_url - group_path << parent.full_path + '/' if parent @@ -13,13 +13,12 @@ %span>= root_url - if parent %strong= parent.full_path + '/' + = f.hidden_field :parent_id = f.text_field :path, placeholder: 'open-source', class: 'form-control', autofocus: local_assigns[:autofocus] || false, required: true, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, title: 'Please choose a group path with no special characters.', "data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}" - - if parent - = f.hidden_field :parent_id, value: parent.id - if @group.persisted? .alert.alert-warning.prepend-top-10 diff --git a/app/views/shared/icons/_icon_arrow_circle_o_right.svg b/app/views/shared/icons/_icon_arrow_circle_o_right.svg index 5e45c6c15ce..29bdc8e5754 100644 --- a/app/views/shared/icons/_icon_arrow_circle_o_right.svg +++ b/app/views/shared/icons/_icon_arrow_circle_o_right.svg @@ -1 +1,2 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14"><g fill-rule="evenodd"><path fill-rule="nonzero" d="m0 7c0-3.866 3.142-7 7-7 3.866 0 7 3.142 7 7 0 3.866-3.142 7-7 7-3.866 0-7-3.142-7-7m1 0c0 3.309 2.69 6 6 6 3.309 0 6-2.69 6-6 0-3.309-2.69-6-6-6-3.309 0-6 2.69-6 6"/><path d="m7 6h-2.702c-.154 0-.298.132-.298.295v1.41c0 .164.133.295.298.295h2.702v1.694c0 .18.095.209.213.09l2.539-2.568c.115-.116.118-.312 0-.432l-2.539-2.568c-.115-.116-.213-.079-.213.09v1.694"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 6h-7a2 2 0 1 0 0 4h7v2.586a1 1 0 0 0 1.707.707l4.586-4.586a1 1 0 0 0 0-1.414l-4.586-4.586a1 1 0 0 0 -1.707.707z" fill-rule="evenodd"/></svg> + diff --git a/app/views/shared/icons/_icon_check_square_o.svg b/app/views/shared/icons/_icon_check_square_o.svg index 3dfbfc8c0e9..05ed4d715d5 100644 --- a/app/views/shared/icons/_icon_check_square_o.svg +++ b/app/views/shared/icons/_icon_check_square_o.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1472 930v318q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q63 0 117 25 15 7 18 23 3 17-9 29l-49 49q-10 10-23 10-3 0-9-2-23-6-45-6h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113v-254q0-13 9-22l64-64q10-10 23-10 6 0 12 3 20 8 20 29zm231-489l-814 814q-24 24-57 24t-57-24l-430-430q-24-24-24-57t24-57l110-110q24-24 57-24t57 24l263 263 647-647q24-24 57-24t57 24l110 110q24 24 24 57t-24 57z"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></svg> + diff --git a/app/views/shared/icons/_icon_clock_o.svg b/app/views/shared/icons/_icon_clock_o.svg index 8ddce62614c..9787ff6cb9e 100644 --- a/app/views/shared/icons/_icon_clock_o.svg +++ b/app/views/shared/icons/_icon_clock_o.svg @@ -1 +1 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1024 544v448q0 14-9 23t-23 9h-320q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h224v-352q0-14 9-23t23-9h64q14 0 23 9t9 23zm416 352q0-148-73-273t-198-198-273-73-273 73-198 198-73 273 73 273 198 198 273 73 273-73 198-198 73-273zm224 0q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M9 7h1c.552 0 1 .448 1 1s-.448 1-1 1H8c-.276 0-.526-.112-.707-.293S7 8.277 7 8V5c0-.552.448-1 1-1s1 .448 1 1zm-1 9c-4.418 0-8-3.582-8-8s3.582-8 8-8 8 3.582 8 8-3.582 8-8 8zm0-2c3.314 0 6-2.686 6-6s-2.686-6-6-6-6 2.686-6 6 2.686 6 6 6z"/></svg> diff --git a/app/views/shared/icons/_icon_clone.svg b/app/views/shared/icons/_icon_clone.svg index ccc897aa98f..faba51b5797 100644 --- a/app/views/shared/icons/_icon_clone.svg +++ b/app/views/shared/icons/_icon_clone.svg @@ -1,3 +1,2 @@ -<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14"> -<path d="M13 12.75v-8.5q0-0.102-0.074-0.176t-0.176-0.074h-8.5q-0.102 0-0.176 0.074t-0.074 0.176v8.5q0 0.102 0.074 0.176t0.176 0.074h8.5q0.102 0 0.176-0.074t0.074-0.176zM14 4.25v8.5q0 0.516-0.367 0.883t-0.883 0.367h-8.5q-0.516 0-0.883-0.367t-0.367-0.883v-8.5q0-0.516 0.367-0.883t0.883-0.367h8.5q0.516 0 0.883 0.367t0.367 0.883zM11 1.25v1.25h-1v-1.25q0-0.102-0.074-0.176t-0.176-0.074h-8.5q-0.102 0-0.176 0.074t-0.074 0.176v8.5q0 0.102 0.074 0.176t0.176 0.074h1.25v1h-1.25q-0.516 0-0.883-0.367t-0.367-0.883v-8.5q0-0.516 0.367-0.883t0.883-0.367h8.5q0.516 0 0.883 0.367t0.367 0.883z"></path> -</svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M10.874 2H12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-2c-.918 0-1.74-.413-2.29-1.063a3.987 3.987 0 0 0 1.988-.984A1 1 0 0 0 10 14h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-1V3c0-.345-.044-.68-.126-1zM4 0h3a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4z"/></svg> + diff --git a/app/views/shared/icons/_icon_code_fork.svg b/app/views/shared/icons/_icon_code_fork.svg index 5a0df2eee19..968e0ad3b2b 100644 --- a/app/views/shared/icons/_icon_code_fork.svg +++ b/app/views/shared/icons/_icon_code_fork.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M672 1472q0-40-28-68t-68-28-68 28-28 68 28 68 68 28 68-28 28-68zm0-1152q0-40-28-68t-68-28-68 28-28 68 28 68 68 28 68-28 28-68zm640 128q0-40-28-68t-68-28-68 28-28 68 28 68 68 28 68-28 28-68zm96 0q0 52-26 96.5t-70 69.5q-2 287-226 414-68 38-203 81-128 40-169.5 71t-41.5 100v26q44 25 70 69.5t26 96.5q0 80-56 136t-136 56-136-56-56-136q0-52 26-96.5t70-69.5v-820q-44-25-70-69.5t-26-96.5q0-80 56-136t136-56 136 56 56 136q0 52-26 96.5t-70 69.5v497q54-26 154-57 55-17 87.5-29.5t70.5-31 59-39.5 40.5-51 28-69.5 8.5-91.5q-44-25-70-69.5t-26-96.5q0-80 56-136t136-56 136 56 56 136z"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M6 11.978v.29a2 2 0 1 1-2 0V3.732a2 2 0 1 1 2 0v3.849c.592-.491 1.31-.854 2.15-1.081 1.308-.353 1.875-.882 1.893-1.743a2 2 0 1 1 2.002-.051C12.053 6.54 10.857 7.84 8.67 8.43 7.056 8.867 6.195 9.98 6 11.978zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm6 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></svg> + diff --git a/app/views/shared/icons/_icon_comment_o.svg b/app/views/shared/icons/_icon_comment_o.svg index b99bd5f42c8..050d7356f54 100644 --- a/app/views/shared/icons/_icon_comment_o.svg +++ b/app/views/shared/icons/_icon_comment_o.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M896 384q-204 0-381.5 69.5t-282 187.5-104.5 255q0 112 71.5 213.5t201.5 175.5l87 50-27 96q-24 91-70 172 152-63 275-171l43-38 57 6q69 8 130 8 204 0 381.5-69.5t282-187.5 104.5-255-104.5-255-282-187.5-381.5-69.5zm896 512q0 174-120 321.5t-326 233-450 85.5q-70 0-145-8-198 175-460 242-49 14-114 22h-5q-15 0-27-10.5t-16-27.5v-1q-3-4-.5-12t2-10 4.5-9.5l6-9 7-8.5 8-9q7-8 31-34.5t34.5-38 31-39.5 32.5-51 27-59 26-76q-157-89-247.5-220t-90.5-281q0-174 120-321.5t326-233 450-85.5 450 85.5 326 233 120 321.5z"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.707 15.707c-.63.63-1.707.184-1.707-.707v-12a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1 -3 3h-7.586zm.293-3.121 2.293-2.293a1 1 0 0 1 .707-.293h8a1 1 0 0 0 1-1v-6a1 1 0 0 0 -1-1h-10a1 1 0 0 0 -1 1z"/></svg> + diff --git a/app/views/shared/icons/_icon_commit.svg b/app/views/shared/icons/_icon_commit.svg index 7e9c0ded04e..6060d2e2aa4 100644 --- a/app/views/shared/icons/_icon_commit.svg +++ b/app/views/shared/icons/_icon_commit.svg @@ -1 +1,2 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 18" enable-background="new 0 0 36 18"><path d="m34 7h-7.2c-.9-4-4.5-7-8.8-7s-7.9 3-8.8 7h-7.2c-1.1 0-2 .9-2 2 0 1.1.9 2 2 2h7.2c.9 4 4.5 7 8.8 7s7.9-3 8.8-7h7.2c1.1 0 2-.9 2-2 0-1.1-.9-2-2-2m-16 7c-2.8 0-5-2.2-5-5s2.2-5 5-5 5 2.2 5 5-2.2 5-5 5"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3.876-1.008a4.002 4.002 0 0 1-7.752 0A1.01 1.01 0 0 1 4 9H1a1 1 0 1 1 0-2h3c.042 0 .083.003.124.008a4.002 4.002 0 0 1 7.752 0A1.01 1.01 0 0 1 12 7h3a1 1 0 0 1 0 2h-3a1.01 1.01 0 0 1-.124-.008z"/></svg> + diff --git a/app/views/shared/icons/_icon_edit.svg b/app/views/shared/icons/_icon_edit.svg index cd4e34147e1..1c10ef138b5 100644 --- a/app/views/shared/icons/_icon_edit.svg +++ b/app/views/shared/icons/_icon_edit.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M888 1184l116-116-152-152-116 116v56h96v96h56zm440-720q-16-16-33 1l-350 350q-17 17-1 33t33-1l350-350q17-17 1-33zm80 594v190q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q63 0 117 25 15 7 18 23 3 17-9 29l-49 49q-14 14-32 8-23-6-45-6h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113v-126q0-13 9-22l64-64q15-15 35-7t20 29zm-96-738l288 288-672 672h-288v-288zm444 132l-92 92-288-288 92-92q28-28 68-28t68 28l152 152q28 28 28 68t-28 68z"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.436 1.413 1.415 1.414a1 1 0 0 1 0 1.414l-10.316 10.315a1 1 0 0 1 -.703.293l-2.407.008-.008-2.421a1 1 0 0 1 .293-.71l10.312-10.314a1 1 0 0 1 1.414 0zm-9.608 12.436 10.315-10.315-1.413-1.414-10.313 10.312.005 1.422zm7.486-10.313 1.414 1.414-7.778 7.778-1.407.007-.007-1.421zm1.414-1.415 1.414 1.415-.707.707-1.414-1.415z"/></svg> + diff --git a/app/views/shared/icons/_icon_eye.svg b/app/views/shared/icons/_icon_eye.svg index 2e2ae67142f..9fea9841eb3 100644 --- a/app/views/shared/icons/_icon_eye.svg +++ b/app/views/shared/icons/_icon_eye.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1664 960q-152-236-381-353 61 104 61 225 0 185-131.5 316.5t-316.5 131.5-316.5-131.5-131.5-316.5q0-121 61-225-229 117-381 353 133 205 333.5 326.5t434.5 121.5 434.5-121.5 333.5-326.5zm-720-384q0-20-14-34t-34-14q-125 0-214.5 89.5t-89.5 214.5q0 20 14 34t34 14 34-14 14-34q0-86 61-147t147-61q20 0 34-14t14-34zm848 384q0 34-20 69-140 230-376.5 368.5t-499.5 138.5-499.5-139-376.5-368q-20-35-20-69t20-69q140-229 376.5-368t499.5-139 499.5 139 376.5 368q20 35 20 69z"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M8 14C4.816 14 2.253 12.284.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2s5.747 1.716 7.607 5.019a2 2 0 0 1 0 1.962C13.747 12.284 11.184 14 8 14zm0-2c2.41 0 4.338-1.29 5.864-4C12.338 5.29 10.411 4 8 4 5.59 4 3.662 5.29 2.136 8 3.662 10.71 5.589 12 8 12zm0-1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm1-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></svg> + diff --git a/app/views/shared/icons/_icon_eye_slash.svg b/app/views/shared/icons/_icon_eye_slash.svg index a16c5dcb24b..45c06b3495d 100644 --- a/app/views/shared/icons/_icon_eye_slash.svg +++ b/app/views/shared/icons/_icon_eye_slash.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M555 1335l78-141q-87-63-136-159t-49-203q0-121 61-225-229 117-381 353 167 258 427 375zm389-759q0-20-14-34t-34-14q-125 0-214.5 89.5t-89.5 214.5q0 20 14 34t34 14 34-14 14-34q0-86 61-147t147-61q20 0 34-14t14-34zm363-191q0 7-1 9-105 188-315 566t-316 567l-49 89q-10 16-28 16-12 0-134-70-16-10-16-28 0-12 44-87-143-65-263.5-173t-208.5-245q-20-31-20-69t20-69q153-235 380-371t496-136q89 0 180 17l54-97q10-16 28-16 5 0 18 6t31 15.5 33 18.5 31.5 18.5 19.5 11.5q16 10 16 27zm37 447q0 139-79 253.5t-209 164.5l280-502q8 45 8 84zm448 128q0 35-20 69-39 64-109 145-150 172-347.5 267t-419.5 95l74-132q212-18 392.5-137t301.5-307q-115-179-282-294l63-112q95 64 182.5 153t144.5 184q20 34 20 69z"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M13.618 2.62L1.62 14.619a1 1 0 0 1-.985-1.668l1.525-1.526C1.516 10.742.926 9.927.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2c1.074 0 2.076.195 3.006.58l.944-.944a1 1 0 0 1 1.668.985zM8.068 11a3 3 0 0 0 2.931-2.932l-2.931 2.931zm-3.02-2.462a3 3 0 0 1 3.49-3.49l.884-.884A6.044 6.044 0 0 0 8 4C5.59 4 3.662 5.29 2.136 8c.445.79.924 1.46 1.439 2.011l1.473-1.473zm.421 5.06l1.658-1.658c.283.04.575.06.873.06 2.41 0 4.338-1.29 5.864-4a11.023 11.023 0 0 0-1.133-1.664l1.418-1.418a12.799 12.799 0 0 1 1.458 2.1 2 2 0 0 1 0 1.963C13.747 12.284 11.184 14 8 14a7.883 7.883 0 0 1-2.53-.402z"/></svg> + diff --git a/app/views/shared/icons/_icon_merged.svg b/app/views/shared/icons/_icon_merged.svg index 43d591daefa..77d170b2491 100644 --- a/app/views/shared/icons/_icon_merged.svg +++ b/app/views/shared/icons/_icon_merged.svg @@ -1 +1,2 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="m2 3c.552 0 1-.448 1-1 0-.552-.448-1-1-1-.552 0-1 .448-1 1 0 .552.448 1 1 1m.761.85c.154 2.556 1.987 4.692 4.45 5.255.328-.655 1.01-1.105 1.789-1.105 1.105 0 2 .895 2 2 0 1.105-.895 2-2 2-.89 0-1.645-.582-1.904-1.386-1.916-.376-3.548-1.5-4.596-3.044v4.493c.863.222 1.5 1.01 1.5 1.937 0 1.105-.895 2-2 2-1.105 0-2-.895-2-2 0-.74.402-1.387 1-1.732v-8.535c-.598-.346-1-.992-1-1.732 0-1.105.895-2 2-2 1.105 0 2 .895 2 2 0 .835-.512 1.551-1.239 1.85m6.239 7.15c.552 0 1-.448 1-1 0-.552-.448-1-1-1-.552 0-1 .448-1 1 0 .552.448 1 1 1m-7 4c.552 0 1-.448 1-1 0-.552-.448-1-1-1-.552 0-1 .448-1 1 0 .552.448 1 1 1" transform="translate(3)"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M11 12.268V5a1 1 0 0 0-1-1v1a.5.5 0 0 1-.8.4l-2.667-2a.5.5 0 0 1 0-.8L9.2.6a.5.5 0 0 1 .8.4v1a3 3 0 0 1 3 3v7.268a2 2 0 1 1-2 0zm-6 0a2 2 0 1 1-2 0V4.732a2 2 0 1 1 2 0v7.536zM4 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></svg> + diff --git a/app/views/shared/icons/_icon_pencil.svg b/app/views/shared/icons/_icon_pencil.svg index a3b48404f87..bcde54bd1e1 100644 --- a/app/views/shared/icons/_icon_pencil.svg +++ b/app/views/shared/icons/_icon_pencil.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M13.02 1.293l1.414 1.414a1 1 0 0 1 0 1.414L4.119 14.436a1 1 0 0 1-.704.293l-2.407.008L1 12.316a1 1 0 0 1 .293-.71L11.605 1.292a1 1 0 0 1 1.414 0zm-1.416 1.415l-.707.707L12.31 4.83l.707-.707-1.414-1.415zM3.411 13.73l1.123-1.122H3.12v-1.415L2 12.312l.005 1.422 1.406-.005z"/></svg> + diff --git a/app/views/shared/icons/_icon_random.svg b/app/views/shared/icons/_icon_random.svg index 763bd2d3dd8..74c1c903657 100644 --- a/app/views/shared/icons/_icon_random.svg +++ b/app/views/shared/icons/_icon_random.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M666 481q-60 92-137 273-22-45-37-72.5t-40.5-63.5-51-56.5-63-35-81.5-14.5h-224q-14 0-23-9t-9-23v-192q0-14 9-23t23-9h224q250 0 410 225zm1126 799q0 14-9 23l-320 320q-9 9-23 9-13 0-22.5-9.5t-9.5-22.5v-192q-32 0-85 .5t-81 1-73-1-71-5-64-10.5-63-18.5-58-28.5-59-40-55-53.5-56-69.5q59-93 136-273 22 45 37 72.5t40.5 63.5 51 56.5 63 35 81.5 14.5h256v-192q0-14 9-23t23-9q12 0 24 10l319 319q9 9 9 23zm0-896q0 14-9 23l-320 320q-9 9-23 9-13 0-22.5-9.5t-9.5-22.5v-192h-256q-48 0-87 15t-69 45-51 61.5-45 77.5q-32 62-78 171-29 66-49.5 111t-54 105-64 100-74 83-90 68.5-106.5 42-128 16.5h-224q-14 0-23-9t-9-23v-192q0-14 9-23t23-9h224q48 0 87-15t69-45 51-61.5 45-77.5q32-62 78-171 29-66 49.5-111t54-105 64-100 74-83 90-68.5 106.5-42 128-16.5h256v-192q0-14 9-23t23-9q12 0 24 10l319 319q9 9 9 23z"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586zM5 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></svg> + diff --git a/app/views/shared/icons/_icon_status_closed.svg b/app/views/shared/icons/_icon_status_closed.svg index de448ee1194..dc39223e721 100644 --- a/app/views/shared/icons/_icon_status_closed.svg +++ b/app/views/shared/icons/_icon_status_closed.svg @@ -1 +1 @@ -<svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path d="M0 7c0-3.866 3.142-7 7-7 3.866 0 7 3.142 7 7 0 3.866-3.142 7-7 7-3.866 0-7-3.142-7-7z"/><path d="M1 7c0 3.309 2.69 6 6 6 3.309 0 6-2.69 6-6 0-3.309-2.69-6-6-6-3.309 0-6 2.69-6 6z" fill="#FFF"/><rect x="3.36" y="6.16" width="7.28" height="1.68" rx=".84"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.83c.39-.39 1.024-.39 1.414 0 .39.392.39 1.025 0 1.416l-3.535 3.535c-.196.195-.452.293-.707.293-.256 0-.512-.097-.708-.292l-2.12-2.12c-.39-.392-.39-1.025 0-1.415s1.023-.39 1.413 0zM8 16c-4.418 0-8-3.582-8-8s3.582-8 8-8 8 3.582 8 8-3.582 8-8 8zm0-2c3.314 0 6-2.686 6-6s-2.686-6-6-6-6 2.686-6 6 2.686 6 6 6z"/></svg> diff --git a/app/views/shared/icons/_icon_tags.svg b/app/views/shared/icons/_icon_tags.svg index fc5acc89c5e..d36ea022f92 100644 --- a/app/views/shared/icons/_icon_tags.svg +++ b/app/views/shared/icons/_icon_tags.svg @@ -1 +1,2 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M384 448q0-53-37.5-90.5t-90.5-37.5-90.5 37.5-37.5 90.5 37.5 90.5 90.5 37.5 90.5-37.5 37.5-90.5zm1067 576q0 53-37 90l-491 492q-39 37-91 37-53 0-90-37l-715-716q-38-37-64.5-101t-26.5-117v-416q0-52 38-90t90-38h416q53 0 117 26.5t102 64.5l715 714q37 39 37 91zm384 0q0 53-37 90l-491 492q-39 37-91 37-36 0-59-14t-53-45l470-470q37-37 37-90 0-52-37-91l-715-714q-38-38-102-64.5t-117-26.5h224q53 0 117 26.5t102 64.5l715 714q37 39 37 91z"/></svg> +<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m7.222.222c1.657 0 3 1.343 3 3v8.327c0 .631-.298 1.226-.805 1.603l-3 2.237c-.709.529-1.682.529-2.391 0l-3-2.237c-.506-.377-.805-.972-.805-1.603v-8.327c0-1.657 1.343-3 3-3h4m-5 3v8.08c0 .158.075.306.201.401l2.5 1.864c.177.132.42.132.598 0l2.5-1.864c.127-.094.201-.243.201-.401v-8.08c0-.552-.448-1-1-1h-4c-.552 0-1 .448-1 1m2.778 7.778c-.552 0-1-.448-1-1s .448-1 1-1 1 .448 1 1-.448 1-1 1" transform="matrix(-.70711 .70711 -.70711 -.70711 17.05 9.767)"/></svg> + diff --git a/app/views/shared/icons/_icon_user.svg b/app/views/shared/icons/_icon_user.svg index 9b8cd74d62b..6e7406f7eac 100644 --- a/app/views/shared/icons/_icon_user.svg +++ b/app/views/shared/icons/_icon_user.svg @@ -1 +1 @@ -<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1600 1405q0 120-73 189.5t-194 69.5h-874q-121 0-194-69.5t-73-189.5q0-53 3.5-103.5t14-109 26.5-108.5 43-97.5 62-81 85.5-53.5 111.5-20q9 0 42 21.5t74.5 48 108 48 133.5 21.5 133.5-21.5 108-48 74.5-48 42-21.5q61 0 111.5 20t85.5 53.5 62 81 43 97.5 26.5 108.5 14 109 3.5 103.5zm-320-893q0 159-112.5 271.5t-271.5 112.5-271.5-112.5-112.5-271.5 112.5-271.5 271.5-112.5 271.5 112.5 112.5 271.5z"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 7C6.343 7 5 5.657 5 4s1.343-3 3-3 3 1.343 3 3-1.343 3-3 3zm0 8c-6.888 0-6.976-.78-6.976-2.52S2.144 8 8 8s6.976 2.692 6.976 4.48S14.888 15 8 15z" fill-rule="evenodd"/></svg> diff --git a/app/views/shared/issuable/_user_dropdown_item.html.haml b/app/views/shared/issuable/_user_dropdown_item.html.haml index c18e4975bb8..48d04678d47 100644 --- a/app/views/shared/issuable/_user_dropdown_item.html.haml +++ b/app/views/shared/issuable/_user_dropdown_item.html.haml @@ -4,7 +4,7 @@ %li.filter-dropdown-item{ class: ('js-current-user' if user == current_user) } %button.btn.btn-link.dropdown-user{ type: :button } .avatar-container.s40 - = user_avatar_without_link(user: user, lazy: avatar[:lazy], url: avatar[:url], size: 40).gsub('/images/{{avatar_url}}','{{avatar_url}}').html_safe + = user_avatar_without_link(user: user, lazy: avatar[:lazy], url: avatar[:url], size: 40, has_tooltip: false).gsub('/images/{{avatar_url}}','{{avatar_url}}').html_safe .dropdown-user-details %span = user.name diff --git a/app/workers/authorized_projects_worker.rb b/app/workers/authorized_projects_worker.rb index 13207a8bc71..be4c77503bb 100644 --- a/app/workers/authorized_projects_worker.rb +++ b/app/workers/authorized_projects_worker.rb @@ -4,18 +4,25 @@ class AuthorizedProjectsWorker # Schedules multiple jobs and waits for them to be completed. def self.bulk_perform_and_wait(args_list) - job_ids = bulk_perform_async(args_list) + waiter = Gitlab::JobWaiter.new(args_list.size) - Gitlab::JobWaiter.new(job_ids).wait + # Point all the bulk jobs at the same JobWaiter. Converts, [[1], [2], [3]] + # into [[1, "key"], [2, "key"], [3, "key"]] + waiting_args_list = args_list.map { |args| args << waiter.key } + bulk_perform_async(waiting_args_list) + + waiter.wait end def self.bulk_perform_async(args_list) Sidekiq::Client.push_bulk('class' => self, 'queue' => sidekiq_options['queue'], 'args' => args_list) end - def perform(user_id) + def perform(user_id, notify_key = nil) user = User.find_by(id: user_id) user&.refresh_authorized_projects + ensure + Gitlab::JobWaiter.notify(notify_key, jid) if notify_key end end diff --git a/app/workers/namespaceless_project_destroy_worker.rb b/app/workers/namespaceless_project_destroy_worker.rb index a9073742ff7..1cfb0be759e 100644 --- a/app/workers/namespaceless_project_destroy_worker.rb +++ b/app/workers/namespaceless_project_destroy_worker.rb @@ -18,7 +18,8 @@ class NamespacelessProjectDestroyWorker rescue ActiveRecord::RecordNotFound return end - return unless project.namespace_id.nil? # Reject doing anything for projects that *do* have a namespace + + return if project.namespace # Reject doing anything for projects that *do* have a namespace project.team.truncate diff --git a/changelogs/unreleased/10085-stop-encoding-user-name.yml b/changelogs/unreleased/10085-stop-encoding-user-name.yml deleted file mode 100644 index 8fab474e047..00000000000 --- a/changelogs/unreleased/10085-stop-encoding-user-name.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Insert user name directly without encoding" -merge_request: 10085 -author: Nathan Neulinger <nneul@neulinger.org> diff --git a/changelogs/unreleased/13247-api_project_events_target_iid.yml b/changelogs/unreleased/13247-api_project_events_target_iid.yml deleted file mode 100644 index 08a31039f77..00000000000 --- a/changelogs/unreleased/13247-api_project_events_target_iid.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Expose target_iid in Events API -merge_request: 13247 -author: sue445 diff --git a/changelogs/unreleased/13265-project_events_noteable_iid.yml b/changelogs/unreleased/13265-project_events_noteable_iid.yml deleted file mode 100644 index 54d538bb548..00000000000 --- a/changelogs/unreleased/13265-project_events_noteable_iid.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Expose noteable_iid in Note -merge_request: 13265 -author: sue445 diff --git a/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml b/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml deleted file mode 100644 index c8c2bb3eb4c..00000000000 --- a/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Alert the user if a Wiki page changed while they were editing it in order to prevent overwriting changes. -merge_request: 9707 -author: Hiroyuki Sato diff --git a/changelogs/unreleased/19629-remove-inactive-tokens-list.yml b/changelogs/unreleased/19629-remove-inactive-tokens-list.yml deleted file mode 100644 index 414e3d49e29..00000000000 --- a/changelogs/unreleased/19629-remove-inactive-tokens-list.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove Inactive Personal Access Tokens list from Access Tokens page -merge_request: 12866 -author: diff --git a/changelogs/unreleased/20817-please-add-coordinator-url-to-admin-area-runner-page.yml b/changelogs/unreleased/20817-please-add-coordinator-url-to-admin-area-runner-page.yml deleted file mode 100644 index c4c3fc7ceb2..00000000000 --- a/changelogs/unreleased/20817-please-add-coordinator-url-to-admin-area-runner-page.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add coordinator url to admin area runner page -merge_request: 11603 -author: diff --git a/changelogs/unreleased/22600-related-resources-uris-using-grape-source-helpers.yml b/changelogs/unreleased/22600-related-resources-uris-using-grape-source-helpers.yml deleted file mode 100644 index 837a34bd067..00000000000 --- a/changelogs/unreleased/22600-related-resources-uris-using-grape-source-helpers.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Declare related resources into V4 API entities -merge_request: -author: diff --git a/changelogs/unreleased/23036-replace-dashboard-event-filters-spinach.yml b/changelogs/unreleased/23036-replace-dashboard-event-filters-spinach.yml deleted file mode 100644 index 807cd097178..00000000000 --- a/changelogs/unreleased/23036-replace-dashboard-event-filters-spinach.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Replaces dashboard/event_filters.feature spinach with rspec -merge_request: 12651 -author: Alexander Randa (@randaalex) diff --git a/changelogs/unreleased/23036-replace-dashboard-spinach.yml b/changelogs/unreleased/23036-replace-dashboard-spinach.yml deleted file mode 100644 index b3197c4cfa6..00000000000 --- a/changelogs/unreleased/23036-replace-dashboard-spinach.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Replaces dashboard/dashboard.feature spinach with rspec -merge_request: 12876 -author: Alexander Randa (@randaalex) diff --git a/changelogs/unreleased/26372-duplicate-issue-slash-command.yml b/changelogs/unreleased/26372-duplicate-issue-slash-command.yml deleted file mode 100644 index 3108344e0bf..00000000000 --- a/changelogs/unreleased/26372-duplicate-issue-slash-command.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Added /duplicate quick action to close a duplicate issue -merge_request: 12845 -author: Ryan Scott diff --git a/changelogs/unreleased/27616-fix-contributions-graph-utc-offset-mysql.yml b/changelogs/unreleased/27616-fix-contributions-graph-utc-offset-mysql.yml deleted file mode 100644 index 1b3c3b8538d..00000000000 --- a/changelogs/unreleased/27616-fix-contributions-graph-utc-offset-mysql.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix timezone inconsistencies in user contribution graph -merge_request: 13208 -author: diff --git a/changelogs/unreleased/28202_decrease_abc_threshold_step2.yml b/changelogs/unreleased/28202_decrease_abc_threshold_step2.yml deleted file mode 100644 index b8f30b52b18..00000000000 --- a/changelogs/unreleased/28202_decrease_abc_threshold_step2.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Decrease ABC threshold to 56.96 -merge_request: 11227 -author: Maxim Rydkin diff --git a/changelogs/unreleased/28283-uuid-storage.yml b/changelogs/unreleased/28283-uuid-storage.yml new file mode 100644 index 00000000000..283e06d4b7f --- /dev/null +++ b/changelogs/unreleased/28283-uuid-storage.yml @@ -0,0 +1,4 @@ +--- +title: Hashed Storage support for Repositories (EXPERIMENTAL) +merge_request: 13246 +author: diff --git a/changelogs/unreleased/28472-ignore-auto-generated-mails.yml b/changelogs/unreleased/28472-ignore-auto-generated-mails.yml deleted file mode 100644 index af63b43e62e..00000000000 --- a/changelogs/unreleased/28472-ignore-auto-generated-mails.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't send rejection mails for all auto-generated mails -merge_request: 13254 -author: diff --git a/changelogs/unreleased/29289-project-destroy-clean-up-after-failure.yml b/changelogs/unreleased/29289-project-destroy-clean-up-after-failure.yml deleted file mode 100644 index 488b37ac37f..00000000000 --- a/changelogs/unreleased/29289-project-destroy-clean-up-after-failure.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Handle errors while a project is being deleted asynchronously. -merge_request: 11088 -author: diff --git a/changelogs/unreleased/29385-add_shrug_command.yml b/changelogs/unreleased/29385-add_shrug_command.yml deleted file mode 100644 index 14b8f486d5c..00000000000 --- a/changelogs/unreleased/29385-add_shrug_command.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add /shrug and /tableflip commands -merge_request: 10068 -author: Alex Ives diff --git a/changelogs/unreleased/29901-refactor-initialization-dropzone_input-js.yml b/changelogs/unreleased/29901-refactor-initialization-dropzone_input-js.yml deleted file mode 100644 index 8850422fc88..00000000000 --- a/changelogs/unreleased/29901-refactor-initialization-dropzone_input-js.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: refactor initializations in dropzone_input.js -merge_request: 12768 -author: Brandon Everett diff --git a/changelogs/unreleased/30634-protected-pipeline.yml b/changelogs/unreleased/30634-protected-pipeline.yml deleted file mode 100644 index e46538e5b46..00000000000 --- a/changelogs/unreleased/30634-protected-pipeline.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disallow running the pipeline if ref is protected and user cannot merge the - branch or create the tag -merge_request: 11910 -author: diff --git a/changelogs/unreleased/31129-jira-project-key-elim.yml b/changelogs/unreleased/31129-jira-project-key-elim.yml deleted file mode 100644 index bfa0e99f250..00000000000 --- a/changelogs/unreleased/31129-jira-project-key-elim.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove project_key from the Jira configuration -merge_request: 12050 -author: diff --git a/changelogs/unreleased/31207-clean-locked-merge-requests.yml b/changelogs/unreleased/31207-clean-locked-merge-requests.yml deleted file mode 100644 index 1f52987baef..00000000000 --- a/changelogs/unreleased/31207-clean-locked-merge-requests.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Unlock stuck merge request and set the proper state -merge_request: 13207 -author: diff --git a/changelogs/unreleased/31533-usage-data-projects-stats.yml b/changelogs/unreleased/31533-usage-data-projects-stats.yml deleted file mode 100644 index 11bb6118337..00000000000 --- a/changelogs/unreleased/31533-usage-data-projects-stats.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add Slack and JIRA services counts to Usage Data -merge_request: -author: diff --git a/changelogs/unreleased/31571-don-t-let-webhooks-jobs-go-to-the-dead-jobs-queue.yml b/changelogs/unreleased/31571-don-t-let-webhooks-jobs-go-to-the-dead-jobs-queue.yml deleted file mode 100644 index 69900f0b314..00000000000 --- a/changelogs/unreleased/31571-don-t-let-webhooks-jobs-go-to-the-dead-jobs-queue.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevent web hook and project service background jobs from going to the dead - jobs queue -merge_request: -author: diff --git a/changelogs/unreleased/32483-jira-error.yml b/changelogs/unreleased/32483-jira-error.yml deleted file mode 100644 index 1c530ca5e0f..00000000000 --- a/changelogs/unreleased/32483-jira-error.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Display specific error message when JIRA test fails -merge_request: -author: diff --git a/changelogs/unreleased/32844-issuables-performance.yml b/changelogs/unreleased/32844-issuables-performance.yml deleted file mode 100644 index e9b21c1aa45..00000000000 --- a/changelogs/unreleased/32844-issuables-performance.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Move some code from services to workers in order to improve performance -merge_request: 13326 -author: diff --git a/changelogs/unreleased/33095-mr-widget-ui.yml b/changelogs/unreleased/33095-mr-widget-ui.yml deleted file mode 100644 index 9ce3086df27..00000000000 --- a/changelogs/unreleased/33095-mr-widget-ui.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: clean up merge request widget UI -merge_request: -author: diff --git a/changelogs/unreleased/33097-issue-tracker.yml b/changelogs/unreleased/33097-issue-tracker.yml deleted file mode 100644 index 0b13f7165db..00000000000 --- a/changelogs/unreleased/33097-issue-tracker.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Associate Issues tab only with internal issues tracker -merge_request: -author: diff --git a/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml b/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml deleted file mode 100644 index 88cfb99a73e..00000000000 --- a/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add CSRF token verification to API -merge_request: 12154 -author: Vitaliy @blackst0ne Klachkov diff --git a/changelogs/unreleased/33620-remove-events-from-notification_settings.yml b/changelogs/unreleased/33620-remove-events-from-notification_settings.yml deleted file mode 100644 index f5f3ef3fb82..00000000000 --- a/changelogs/unreleased/33620-remove-events-from-notification_settings.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove events column from notification settings table -merge_request: -author: diff --git a/changelogs/unreleased/33741-clarify-k8s-service-keys.yml b/changelogs/unreleased/33741-clarify-k8s-service-keys.yml deleted file mode 100644 index 91142a0d580..00000000000 --- a/changelogs/unreleased/33741-clarify-k8s-service-keys.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Clarifies and rearranges the input variables on the kubernetes integration - page and adjusts the docs slightly to meet the same order -merge_request: !12188 -author: diff --git a/changelogs/unreleased/33770-respect-blockquote-line-breaks.yml b/changelogs/unreleased/33770-respect-blockquote-line-breaks.yml deleted file mode 100644 index 3a45ad88270..00000000000 --- a/changelogs/unreleased/33770-respect-blockquote-line-breaks.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Respect blockquote line breaks in markdown -merge_request: -author: diff --git a/changelogs/unreleased/33874_confi.yml b/changelogs/unreleased/33874_confi.yml deleted file mode 100644 index 940753d9aaa..00000000000 --- a/changelogs/unreleased/33874_confi.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update confidential issue UI - add confidential visibility and settings to - sidebar -merge_request: -author: diff --git a/changelogs/unreleased/34027-add-icons-to-sidebar.yml b/changelogs/unreleased/34027-add-icons-to-sidebar.yml deleted file mode 100644 index f5b50ca1dee..00000000000 --- a/changelogs/unreleased/34027-add-icons-to-sidebar.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add icons to contextual sidebars -merge_request: -author: diff --git a/changelogs/unreleased/34028-collapse-sidebar.yml b/changelogs/unreleased/34028-collapse-sidebar.yml deleted file mode 100644 index 468212240ac..00000000000 --- a/changelogs/unreleased/34028-collapse-sidebar.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make contextual sidebar collapsible -merge_request: -author: diff --git a/changelogs/unreleased/34075-pipelines-count-mt.yml b/changelogs/unreleased/34075-pipelines-count-mt.yml deleted file mode 100644 index 3846e7b06a4..00000000000 --- a/changelogs/unreleased/34075-pipelines-count-mt.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update Pipeline's badge count in Merge Request and Commits view to match real-time - content -merge_request: -author: diff --git a/changelogs/unreleased/34110-memory-usage-notice-doesn-t-link-anywhere.yml b/changelogs/unreleased/34110-memory-usage-notice-doesn-t-link-anywhere.yml deleted file mode 100644 index 1911705dd2b..00000000000 --- a/changelogs/unreleased/34110-memory-usage-notice-doesn-t-link-anywhere.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Added link to the MR widget that directs to the monitoring dashboard -merge_request: -author: diff --git a/changelogs/unreleased/34339-user_avatar-url-in-push-event-webhook-json-payload-is-relative-should-be-absolute.yml b/changelogs/unreleased/34339-user_avatar-url-in-push-event-webhook-json-payload-is-relative-should-be-absolute.yml deleted file mode 100644 index 13f28da8577..00000000000 --- a/changelogs/unreleased/34339-user_avatar-url-in-push-event-webhook-json-payload-is-relative-should-be-absolute.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use full path of user's avatar in webhooks -merge_request: 13401 -author: Vitaliy @blackst0ne Klachkov diff --git a/changelogs/unreleased/34361-lazy-load-images-on-the-frontend.yml b/changelogs/unreleased/34361-lazy-load-images-on-the-frontend.yml deleted file mode 100644 index d188a558d38..00000000000 --- a/changelogs/unreleased/34361-lazy-load-images-on-the-frontend.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Lazy load images for better Frontend performance -merge_request: 12503 -author: diff --git a/changelogs/unreleased/34519-extend-api-group-secret-variable.yml b/changelogs/unreleased/34519-extend-api-group-secret-variable.yml deleted file mode 100644 index e0b625c392f..00000000000 --- a/changelogs/unreleased/34519-extend-api-group-secret-variable.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Extend API for Group Secret Variable -merge_request: 12936 -author: diff --git a/changelogs/unreleased/34527-make-edit-comment-button-always-available-outside-of-dropdown.yml b/changelogs/unreleased/34527-make-edit-comment-button-always-available-outside-of-dropdown.yml deleted file mode 100644 index 08171f6bcec..00000000000 --- a/changelogs/unreleased/34527-make-edit-comment-button-always-available-outside-of-dropdown.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: move edit comment button outside of dropdown -merge_request: -author: diff --git a/changelogs/unreleased/34533-speed-up-group-project-authorizations.yml b/changelogs/unreleased/34533-speed-up-group-project-authorizations.yml deleted file mode 100644 index ddaaf4a2507..00000000000 --- a/changelogs/unreleased/34533-speed-up-group-project-authorizations.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix timeouts when creating projects in groups with many members -merge_request: 13508 -author: -type: fixed diff --git a/changelogs/unreleased/34534-update-vue-resource.yml b/changelogs/unreleased/34534-update-vue-resource.yml deleted file mode 100644 index 2d0af0c9bfe..00000000000 --- a/changelogs/unreleased/34534-update-vue-resource.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Updates vue resource and code according to breaking changes -merge_request: -author: diff --git a/changelogs/unreleased/34549-extract-devise-mappings-into-helper.yml b/changelogs/unreleased/34549-extract-devise-mappings-into-helper.yml deleted file mode 100644 index e843bbac239..00000000000 --- a/changelogs/unreleased/34549-extract-devise-mappings-into-helper.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Extract "@request.env[devise.mapping] = Devise.mappings[:user]" to a test helper -merge_request: 12742 -author: Jacopo Beschi @jacopo-beschi diff --git a/changelogs/unreleased/34563-usage-ping-github.yml b/changelogs/unreleased/34563-usage-ping-github.yml deleted file mode 100644 index 3ab982beea3..00000000000 --- a/changelogs/unreleased/34563-usage-ping-github.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add GitHub imported projects count to usage data -merge_request: -author: diff --git a/changelogs/unreleased/34764-rename-to-overview.yml b/changelogs/unreleased/34764-rename-to-overview.yml deleted file mode 100644 index 5b9643285b7..00000000000 --- a/changelogs/unreleased/34764-rename-to-overview.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Rename about to overview for group and project page -merge_request: -author: diff --git a/changelogs/unreleased/34810-vue-pagination.yml b/changelogs/unreleased/34810-vue-pagination.yml deleted file mode 100644 index 5cd03518a98..00000000000 --- a/changelogs/unreleased/34810-vue-pagination.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Prevent disabled pagination button to be clicked -merge_request: -author: diff --git a/changelogs/unreleased/34831-remove-coffee-rails-gem.yml b/changelogs/unreleased/34831-remove-coffee-rails-gem.yml deleted file mode 100644 index b555f112b8d..00000000000 --- a/changelogs/unreleased/34831-remove-coffee-rails-gem.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove coffee-rails gem -merge_request: -author: Takuya Noguchi diff --git a/changelogs/unreleased/34858-bump-scss-lint-to-0-54-0.yml b/changelogs/unreleased/34858-bump-scss-lint-to-0-54-0.yml deleted file mode 100644 index e6cd834aed2..00000000000 --- a/changelogs/unreleased/34858-bump-scss-lint-to-0-54-0.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Bump scss-lint to 0.54.0 -merge_request: 12733 -author: Takuya Noguchi diff --git a/changelogs/unreleased/34867-remove-net-ssh-gem.yml b/changelogs/unreleased/34867-remove-net-ssh-gem.yml deleted file mode 100644 index f5648d62467..00000000000 --- a/changelogs/unreleased/34867-remove-net-ssh-gem.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove net-ssh gem -merge_request: -author: Takuya Noguchi diff --git a/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml b/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml deleted file mode 100644 index 0eb2d069719..00000000000 --- a/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Bump rubocop to 0.49.1 and rubocop-rspec to 1.15.1 -merge_request: -author: Takuya Noguchi diff --git a/changelogs/unreleased/34921-global-dropdown-ui-improvement.yml b/changelogs/unreleased/34921-global-dropdown-ui-improvement.yml deleted file mode 100644 index 6a17353ba3f..00000000000 --- a/changelogs/unreleased/34921-global-dropdown-ui-improvement.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve CSS for global nav dropdown UI -merge_request: 12772 -author: Takuya Noguchi diff --git a/changelogs/unreleased/34927-protect-manual-actions-on-tags.yml b/changelogs/unreleased/34927-protect-manual-actions-on-tags.yml deleted file mode 100644 index d996ae2826a..00000000000 --- a/changelogs/unreleased/34927-protect-manual-actions-on-tags.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Protect manual actions against protected tag too -merge_request: 12908 -author: diff --git a/changelogs/unreleased/34978-remove-public-ci-favicon-ico.yml b/changelogs/unreleased/34978-remove-public-ci-favicon-ico.yml deleted file mode 100644 index 25cc8b5e45f..00000000000 --- a/changelogs/unreleased/34978-remove-public-ci-favicon-ico.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove public/ci/favicon.ico -merge_request: 12803 -author: Takuya Noguchi diff --git a/changelogs/unreleased/35044-projects-logo-are-not-centered-vertically-on-projects-page.yml b/changelogs/unreleased/35044-projects-logo-are-not-centered-vertically-on-projects-page.yml deleted file mode 100644 index 9de4dbefd35..00000000000 --- a/changelogs/unreleased/35044-projects-logo-are-not-centered-vertically-on-projects-page.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix project logos that are not centered vertically on list pages -merge_request: 13124 -author: Florian Lemaitre diff --git a/changelogs/unreleased/35072-fix-pages-delete.yml b/changelogs/unreleased/35072-fix-pages-delete.yml deleted file mode 100644 index 21af2bde201..00000000000 --- a/changelogs/unreleased/35072-fix-pages-delete.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix deleting GitLab Pages files when a project is removed -merge_request: 13631 -author: -type: fixed diff --git a/changelogs/unreleased/35098-raise-encoding-confidence-threshold.yml b/changelogs/unreleased/35098-raise-encoding-confidence-threshold.yml deleted file mode 100644 index 3cdb3011f5b..00000000000 --- a/changelogs/unreleased/35098-raise-encoding-confidence-threshold.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Raise guessed encoding confidence threshold to 50 -merge_request: 12990 -author: diff --git a/changelogs/unreleased/35136-barchart-not-display-label-at-0-hour.yml b/changelogs/unreleased/35136-barchart-not-display-label-at-0-hour.yml deleted file mode 100644 index ea8f31cca9d..00000000000 --- a/changelogs/unreleased/35136-barchart-not-display-label-at-0-hour.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix bar chart does not display label at 0 hour -merge_request: 35136 -author: Jason Dai diff --git a/changelogs/unreleased/35155-upgrade-fog-core-to-1-44-3-and-its-providers-to-the-latest.yml b/changelogs/unreleased/35155-upgrade-fog-core-to-1-44-3-and-its-providers-to-the-latest.yml deleted file mode 100644 index 9d9558347ba..00000000000 --- a/changelogs/unreleased/35155-upgrade-fog-core-to-1-44-3-and-its-providers-to-the-latest.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Bump fog-core to 1.44.3 and fog providers' plugins to latest -merge_request: 12897 -author: Takuya Noguchi diff --git a/changelogs/unreleased/35163-url-in-commit-message-can-be-broken-in-blame.yml b/changelogs/unreleased/35163-url-in-commit-message-can-be-broken-in-blame.yml deleted file mode 100644 index 4fd60a79782..00000000000 --- a/changelogs/unreleased/35163-url-in-commit-message-can-be-broken-in-blame.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use only CSS to truncate commit message in blame -merge_request: 12900 -author: Takuya Noguchi diff --git a/changelogs/unreleased/35164-cycle-analytics-firefox.yml b/changelogs/unreleased/35164-cycle-analytics-firefox.yml deleted file mode 100644 index 0b7115136ca..00000000000 --- a/changelogs/unreleased/35164-cycle-analytics-firefox.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: allow closing Cycle Analytics intro box in firefox -merge_request: -author: diff --git a/changelogs/unreleased/35181-cannot-create-label-from-board-page.yml b/changelogs/unreleased/35181-cannot-create-label-from-board-page.yml deleted file mode 100644 index 4afe603720d..00000000000 --- a/changelogs/unreleased/35181-cannot-create-label-from-board-page.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix label creation from new list for subgroup projects -merge_request: -author: diff --git a/changelogs/unreleased/35191-prioritized-labels-for-non-member.yml b/changelogs/unreleased/35191-prioritized-labels-for-non-member.yml deleted file mode 100644 index fbe55d4c2b0..00000000000 --- a/changelogs/unreleased/35191-prioritized-labels-for-non-member.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove help message about prioritized labels for non-members -merge_request: 12912 -author: Takuya Noguchi diff --git a/changelogs/unreleased/35204-doc-api-ci-lint-typo.yml b/changelogs/unreleased/35204-doc-api-ci-lint-typo.yml deleted file mode 100644 index 45b6c57579b..00000000000 --- a/changelogs/unreleased/35204-doc-api-ci-lint-typo.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add link to doc/api/ci/lint.md -merge_request: 12914 -author: Takuya Noguchi diff --git a/changelogs/unreleased/35225-transient-poll.yml b/changelogs/unreleased/35225-transient-poll.yml deleted file mode 100644 index 59e2e738c7b..00000000000 --- a/changelogs/unreleased/35225-transient-poll.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: fix transient js error in rspec tests -merge_request: -author: diff --git a/changelogs/unreleased/35253-desc-protected-branches-for-non-member.yml b/changelogs/unreleased/35253-desc-protected-branches-for-non-member.yml deleted file mode 100644 index 9b2a66da1c3..00000000000 --- a/changelogs/unreleased/35253-desc-protected-branches-for-non-member.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Hide description about protected branches to non-member -merge_request: 12945 -author: Takuya Noguchi diff --git a/changelogs/unreleased/35391-fix-star-i18n-in-js.yml b/changelogs/unreleased/35391-fix-star-i18n-in-js.yml deleted file mode 100644 index a6fd4dc89fd..00000000000 --- a/changelogs/unreleased/35391-fix-star-i18n-in-js.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix translations for Star/Unstar in JS file -merge_request: -author: diff --git a/changelogs/unreleased/35408-group-auto-avatars.yml b/changelogs/unreleased/35408-group-auto-avatars.yml deleted file mode 100644 index 77b644a7f94..00000000000 --- a/changelogs/unreleased/35408-group-auto-avatars.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Show auto-generated avatars for Groups without avatars -merge_request: 13188 -author: diff --git a/changelogs/unreleased/35483-improve-mobile-sidebar.yml b/changelogs/unreleased/35483-improve-mobile-sidebar.yml deleted file mode 100644 index eb3dab1da9e..00000000000 --- a/changelogs/unreleased/35483-improve-mobile-sidebar.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve mobile sidebar -merge_request: -author: diff --git a/changelogs/unreleased/35659-rename-pipeline.yml b/changelogs/unreleased/35659-rename-pipeline.yml deleted file mode 100644 index 0fe211868e4..00000000000 --- a/changelogs/unreleased/35659-rename-pipeline.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Rename Pipelines tab to CI / CD in new navigation -merge_request: -author: diff --git a/changelogs/unreleased/35695-comment-appears-in-a-wrong-place-after-changing-diff-view-to-inline.yml b/changelogs/unreleased/35695-comment-appears-in-a-wrong-place-after-changing-diff-view-to-inline.yml deleted file mode 100644 index 1c9ad20bc95..00000000000 --- a/changelogs/unreleased/35695-comment-appears-in-a-wrong-place-after-changing-diff-view-to-inline.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix display of new diff comments after changing b between diff views -merge_request: -author: diff --git a/changelogs/unreleased/35761-convdev-perc.yml b/changelogs/unreleased/35761-convdev-perc.yml deleted file mode 100644 index 319c4d18219..00000000000 --- a/changelogs/unreleased/35761-convdev-perc.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Store & use ConvDev percentages returned by the Version app -merge_request: -author: diff --git a/changelogs/unreleased/35769-fix-ruby-2-4-compatibility.yml b/changelogs/unreleased/35769-fix-ruby-2-4-compatibility.yml deleted file mode 100644 index ac480993d85..00000000000 --- a/changelogs/unreleased/35769-fix-ruby-2-4-compatibility.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix Issue board when using Ruby 2.4 -merge_request: 13220 -author: diff --git a/changelogs/unreleased/35815-webhook-log-encoding-error.yml b/changelogs/unreleased/35815-webhook-log-encoding-error.yml deleted file mode 100644 index 76ec235086c..00000000000 --- a/changelogs/unreleased/35815-webhook-log-encoding-error.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix encoding error for WebHook logging -merge_request: 13230 -author: Alexander Randa (@randaalex) diff --git a/changelogs/unreleased/35845-improve-subgroup-creation-permissions.yml b/changelogs/unreleased/35845-improve-subgroup-creation-permissions.yml new file mode 100644 index 00000000000..eac8dbe23c2 --- /dev/null +++ b/changelogs/unreleased/35845-improve-subgroup-creation-permissions.yml @@ -0,0 +1,5 @@ +--- +title: Improves subgroup creation permissions +merge_request: 13418 +author: +type: bugifx diff --git a/changelogs/unreleased/36185-or-separator.yml b/changelogs/unreleased/36185-or-separator.yml deleted file mode 100644 index 4e46e60ea1b..00000000000 --- a/changelogs/unreleased/36185-or-separator.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Align OR separator to center in new project page -merge_request: -author: diff --git a/changelogs/unreleased/3686_make_tarball_download_url.yml b/changelogs/unreleased/3686_make_tarball_download_url.yml deleted file mode 100644 index 4e75e52e3ac..00000000000 --- a/changelogs/unreleased/3686_make_tarball_download_url.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: repository archive download url now ends with selected file extension -merge_request: 13178 -author: haseebeqx diff --git a/changelogs/unreleased/5971-webhook-testing.yml b/changelogs/unreleased/5971-webhook-testing.yml deleted file mode 100644 index 58233091977..00000000000 --- a/changelogs/unreleased/5971-webhook-testing.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow testing any events for project hooks and system hooks -merge_request: 11728 -author: Alexander Randa (@randaalex) diff --git a/changelogs/unreleased/add-filtered-search-group-issues-ce.yml b/changelogs/unreleased/add-filtered-search-group-issues-ce.yml deleted file mode 100644 index f83f4173890..00000000000 --- a/changelogs/unreleased/add-filtered-search-group-issues-ce.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add filtered search to group issue dashboard -merge_request: -author: diff --git a/changelogs/unreleased/add-star-for-action-scope.yml b/changelogs/unreleased/add-star-for-action-scope.yml deleted file mode 100644 index a8119a01ec4..00000000000 --- a/changelogs/unreleased/add-star-for-action-scope.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add star for action scope, in order to delete image from registry -merge_request: 13248 -author: jean diff --git a/changelogs/unreleased/appearances-caching-and-schema.yml b/changelogs/unreleased/appearances-caching-and-schema.yml deleted file mode 100644 index 5743f6e0f2d..00000000000 --- a/changelogs/unreleased/appearances-caching-and-schema.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Cache Appearance instances in Redis -merge_request: -author: diff --git a/changelogs/unreleased/artifacts-download-dropdown-menu-is-too-narrow.yml b/changelogs/unreleased/artifacts-download-dropdown-menu-is-too-narrow.yml deleted file mode 100644 index 7d47c60e262..00000000000 --- a/changelogs/unreleased/artifacts-download-dropdown-menu-is-too-narrow.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Increase width of dropdown menus automatically -merge_request: 12809 -author: Thomas Wucher diff --git a/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml b/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml deleted file mode 100644 index 988fdacb5fd..00000000000 --- a/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed breadcrumbs title aggressively collapsing -merge_request: -author: diff --git a/changelogs/unreleased/broadcast-messages-cache.yml b/changelogs/unreleased/broadcast-messages-cache.yml deleted file mode 100644 index a3c9e1ff465..00000000000 --- a/changelogs/unreleased/broadcast-messages-cache.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Better caching and indexing of broadcast messages -merge_request: -author: diff --git a/changelogs/unreleased/bump-omniauth-ldap-gem-version.yml b/changelogs/unreleased/bump-omniauth-ldap-gem-version.yml deleted file mode 100644 index 42e1c9e8f83..00000000000 --- a/changelogs/unreleased/bump-omniauth-ldap-gem-version.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Prevent LDAP login callback from being called with a GET request -merge_request: 13059 -author: diff --git a/changelogs/unreleased/bvl-add-all-settings-to-api.yml b/changelogs/unreleased/bvl-add-all-settings-to-api.yml deleted file mode 100644 index bfaf237a21c..00000000000 --- a/changelogs/unreleased/bvl-add-all-settings-to-api.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make all application-settings accessible through the API -merge_request: 12851 -author: diff --git a/changelogs/unreleased/bvl-free-unused-names.yml b/changelogs/unreleased/bvl-free-unused-names.yml deleted file mode 100644 index 53acb95e5bb..00000000000 --- a/changelogs/unreleased/bvl-free-unused-names.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Free up some top level words, reject top level groups named like files in the - public folder -merge_request: 12932 -author: diff --git a/changelogs/unreleased/bvl-improve-bare-project-import.yml b/changelogs/unreleased/bvl-improve-bare-project-import.yml new file mode 100644 index 00000000000..74c1da4ea40 --- /dev/null +++ b/changelogs/unreleased/bvl-improve-bare-project-import.yml @@ -0,0 +1,6 @@ +--- +title: 'Improve bare project import: Allow subgroups, take default visibility level + into account' +merge_request: 13670 +author: +type: fixed diff --git a/changelogs/unreleased/bvl-nfs-circuitbreaker.yml b/changelogs/unreleased/bvl-nfs-circuitbreaker.yml deleted file mode 100644 index 151854ed31f..00000000000 --- a/changelogs/unreleased/bvl-nfs-circuitbreaker.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Block access to failing repository storage -merge_request: 11449 -author: diff --git a/changelogs/unreleased/bvl-rollback-renamed-system-namespace.yml b/changelogs/unreleased/bvl-rollback-renamed-system-namespace.yml deleted file mode 100644 index a24cc7a1c43..00000000000 --- a/changelogs/unreleased/bvl-rollback-renamed-system-namespace.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't rename namespace called system when upgrading from 9.1.x to 9.5 -merge_request: 13228 -author: diff --git a/changelogs/unreleased/cache-issue-and-mr-counts.yml b/changelogs/unreleased/cache-issue-and-mr-counts.yml new file mode 100644 index 00000000000..fe3fe3be976 --- /dev/null +++ b/changelogs/unreleased/cache-issue-and-mr-counts.yml @@ -0,0 +1,5 @@ +--- +title: Cache the number of open issues and merge requests +merge_request: +author: +type: other diff --git a/changelogs/unreleased/commits-list-page-limit.yml b/changelogs/unreleased/commits-list-page-limit.yml deleted file mode 100644 index 2fd54c5960a..00000000000 --- a/changelogs/unreleased/commits-list-page-limit.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix commit list not loading the correct page when scrolling -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/diff-changed-files-dropdown.yml b/changelogs/unreleased/diff-changed-files-dropdown.yml deleted file mode 100644 index 2d2a26ffea2..00000000000 --- a/changelogs/unreleased/diff-changed-files-dropdown.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Moved diff changed files into a dropdown -merge_request: -author: diff --git a/changelogs/unreleased/dm-commit-cache-i18n.yml b/changelogs/unreleased/dm-commit-cache-i18n.yml deleted file mode 100644 index d47226fd408..00000000000 --- a/changelogs/unreleased/dm-commit-cache-i18n.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Commit rows would occasionally render with the wrong language -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/dm-large-push-performance.yml b/changelogs/unreleased/dm-large-push-performance.yml deleted file mode 100644 index f5fe1bd3b28..00000000000 --- a/changelogs/unreleased/dm-large-push-performance.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve performance of large (initial) push into default branch -merge_request: -author: diff --git a/changelogs/unreleased/dm-ldap-adapter-attributes.yml b/changelogs/unreleased/dm-ldap-adapter-attributes.yml new file mode 100644 index 00000000000..edd68ef08e7 --- /dev/null +++ b/changelogs/unreleased/dm-ldap-adapter-attributes.yml @@ -0,0 +1,6 @@ +--- +title: Fix signing in using LDAP when attribute mapping uses simple strings instead + of arrays +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/dont-use-limit-offset-when-counting-projects.yml b/changelogs/unreleased/dont-use-limit-offset-when-counting-projects.yml deleted file mode 100644 index 8ecea635ce5..00000000000 --- a/changelogs/unreleased/dont-use-limit-offset-when-counting-projects.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Improve performance of checking for projects on the projects dashboard" -merge_request: -author: diff --git a/changelogs/unreleased/dz-fix-calendar-today.yml b/changelogs/unreleased/dz-fix-calendar-today.yml deleted file mode 100644 index 5320d8b26b5..00000000000 --- a/changelogs/unreleased/dz-fix-calendar-today.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix today day highlight in calendar -merge_request: 13048 -author: diff --git a/changelogs/unreleased/eager-load-project-creators-for-project-dashboards.yml b/changelogs/unreleased/eager-load-project-creators-for-project-dashboards.yml deleted file mode 100644 index e550e0b2f44..00000000000 --- a/changelogs/unreleased/eager-load-project-creators-for-project-dashboards.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Eager load project creators for project dashboards -merge_request: -author: diff --git a/changelogs/unreleased/enable-scss-lint-bang-format.yml b/changelogs/unreleased/enable-scss-lint-bang-format.yml deleted file mode 100644 index 0b73760198e..00000000000 --- a/changelogs/unreleased/enable-scss-lint-bang-format.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Enable BangFormat in scss-lint [ci skip] -merge_request: 12815 -author: Takuya Noguchi diff --git a/changelogs/unreleased/enable-scss-lint-declaration-order.yml b/changelogs/unreleased/enable-scss-lint-declaration-order.yml deleted file mode 100644 index 7ac2f55592e..00000000000 --- a/changelogs/unreleased/enable-scss-lint-declaration-order.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Enable DeclarationOrder in scss-lint -merge_request: 12805 -author: Takuya Noguchi diff --git a/changelogs/unreleased/enable-scss-lint-import-path.yml b/changelogs/unreleased/enable-scss-lint-import-path.yml deleted file mode 100644 index d158cf5b5f3..00000000000 --- a/changelogs/unreleased/enable-scss-lint-import-path.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Enable ImportPath in scss-lint -merge_request: 12749 -author: Takuya Noguchi diff --git a/changelogs/unreleased/enable-scss-lint-property-spelling.yml b/changelogs/unreleased/enable-scss-lint-property-spelling.yml deleted file mode 100644 index c5a5a4dddb6..00000000000 --- a/changelogs/unreleased/enable-scss-lint-property-spelling.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Enable PropertySpelling in scss-lint -merge_request: 12752 -author: Takuya Noguchi diff --git a/changelogs/unreleased/enable-scss-lint-space-after-comma.yml b/changelogs/unreleased/enable-scss-lint-space-after-comma.yml deleted file mode 100644 index 210f34fbb87..00000000000 --- a/changelogs/unreleased/enable-scss-lint-space-after-comma.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Enable SpaceAfterComma in scss-lint -merge_request: 12734 -author: Takuya Noguchi diff --git a/changelogs/unreleased/enable-scss-lint-unnecessary-parent-reference.yml b/changelogs/unreleased/enable-scss-lint-unnecessary-parent-reference.yml deleted file mode 100644 index 59d5df56525..00000000000 --- a/changelogs/unreleased/enable-scss-lint-unnecessary-parent-reference.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Enable UnnecessaryParentReference in scss-lint -merge_request: 12738 -author: Takuya Noguchi diff --git a/changelogs/unreleased/ericy_ts-protected_branches_api.yml b/changelogs/unreleased/ericy_ts-protected_branches_api.yml deleted file mode 100644 index 4cd275c5e8f..00000000000 --- a/changelogs/unreleased/ericy_ts-protected_branches_api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add API for protected branches to allow for wildcard matching and no access - restrictions -merge_request: 12756 -author: Eric Yu diff --git a/changelogs/unreleased/feature-backup-custom-path.yml b/changelogs/unreleased/feature-backup-custom-path.yml deleted file mode 100644 index 1c5f25b3ee5..00000000000 --- a/changelogs/unreleased/feature-backup-custom-path.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Support custom directory in gitlab:backup:create task -merge_request: 12984 -author: Markus Koller diff --git a/changelogs/unreleased/feature-gb-auto-retry-failed-ci-job.yml b/changelogs/unreleased/feature-gb-auto-retry-failed-ci-job.yml deleted file mode 100644 index bdafc5929c0..00000000000 --- a/changelogs/unreleased/feature-gb-auto-retry-failed-ci-job.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow to configure automatic retry of a failed CI/CD job -merge_request: 12909 -author: diff --git a/changelogs/unreleased/feature-gpg-signed-commits.yml b/changelogs/unreleased/feature-gpg-signed-commits.yml deleted file mode 100644 index 99bc5a309ef..00000000000 --- a/changelogs/unreleased/feature-gpg-signed-commits.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: GPG signed commits integration -merge_request: 9546 -author: Alexis Reigel diff --git a/changelogs/unreleased/fix-500-error-when-rendering-avatar-for-deleted-project-creator.yml b/changelogs/unreleased/fix-500-error-when-rendering-avatar-for-deleted-project-creator.yml deleted file mode 100644 index be6f1ea00fb..00000000000 --- a/changelogs/unreleased/fix-500-error-when-rendering-avatar-for-deleted-project-creator.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Modify if condition to be more readable -merge_request: -author: diff --git a/changelogs/unreleased/fix-gb-fix-head-pipeline-when-pipeline-has-errors.yml b/changelogs/unreleased/fix-gb-fix-head-pipeline-when-pipeline-has-errors.yml deleted file mode 100644 index ede8031a501..00000000000 --- a/changelogs/unreleased/fix-gb-fix-head-pipeline-when-pipeline-has-errors.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix merge request pipeline status when pipeline has errors -merge_request: 13664 -author: -type: fixed diff --git a/changelogs/unreleased/fix-gb-handle-max-pages-artifacts-size-correctly.yml b/changelogs/unreleased/fix-gb-handle-max-pages-artifacts-size-correctly.yml deleted file mode 100644 index 3d9592bbf2a..00000000000 --- a/changelogs/unreleased/fix-gb-handle-max-pages-artifacts-size-correctly.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Handle maximum pages artifacts size correctly -merge_request: 13072 -author: diff --git a/changelogs/unreleased/fix-import-fork-mr.yml b/changelogs/unreleased/fix-import-fork-mr.yml new file mode 100644 index 00000000000..4e9cf7faae8 --- /dev/null +++ b/changelogs/unreleased/fix-import-fork-mr.yml @@ -0,0 +1,5 @@ +--- +title: Fix Import/Export issue to do with fork merge requests +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix-import-symbolink-links.yml b/changelogs/unreleased/fix-import-symbolink-links.yml deleted file mode 100644 index 36e73821bdc..00000000000 --- a/changelogs/unreleased/fix-import-symbolink-links.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove hidden symlinks from project import files -merge_request: -author: diff --git a/changelogs/unreleased/fix-push-events-branch-removals.yml b/changelogs/unreleased/fix-push-events-branch-removals.yml new file mode 100644 index 00000000000..71f368db296 --- /dev/null +++ b/changelogs/unreleased/fix-push-events-branch-removals.yml @@ -0,0 +1,5 @@ +--- +title: Fix display of push events for removed refs +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix-replying-to-commit-comment-in-mr-from-fork.yml b/changelogs/unreleased/fix-replying-to-commit-comment-in-mr-from-fork.yml deleted file mode 100644 index f4136460626..00000000000 --- a/changelogs/unreleased/fix-replying-to-commit-comment-in-mr-from-fork.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix replying to commit comments on merge requests created from forks -merge_request: -author: diff --git a/changelogs/unreleased/fix-thread-safe-gpgme-tmp-directory.yml b/changelogs/unreleased/fix-thread-safe-gpgme-tmp-directory.yml deleted file mode 100644 index 66b5b6b4f47..00000000000 --- a/changelogs/unreleased/fix-thread-safe-gpgme-tmp-directory.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make GPGME temporary directory handling thread safe -merge_request: 13481 -author: Alexis Reigel diff --git a/changelogs/unreleased/fixes-for-internal-auth-disabled.yml b/changelogs/unreleased/fixes-for-internal-auth-disabled.yml deleted file mode 100644 index 188d2770455..00000000000 --- a/changelogs/unreleased/fixes-for-internal-auth-disabled.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes needed when GitLab sign-in is not enabled -merge_request: 12491 -author: Robin Bobbitt diff --git a/changelogs/unreleased/forks-count-cache.yml b/changelogs/unreleased/forks-count-cache.yml deleted file mode 100644 index da8c53c2abd..00000000000 --- a/changelogs/unreleased/forks-count-cache.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Cache the number of forks of a project -merge_request: 13535 -author: -type: other diff --git a/changelogs/unreleased/github.yml b/changelogs/unreleased/github.yml deleted file mode 100644 index 585b9b13b65..00000000000 --- a/changelogs/unreleased/github.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Reduce memory usage of the GitHub importer -merge_request: 12886 -author: diff --git a/changelogs/unreleased/group-milestone-references-system-notes.yml b/changelogs/unreleased/group-milestone-references-system-notes.yml deleted file mode 100644 index 58215352305..00000000000 --- a/changelogs/unreleased/group-milestone-references-system-notes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Support Markdown references, autocomplete, and quick actions for group milestones -merge_request: -author: diff --git a/changelogs/unreleased/group-new-issue.yml b/changelogs/unreleased/group-new-issue.yml deleted file mode 100644 index 5480a44526b..00000000000 --- a/changelogs/unreleased/group-new-issue.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Cache recent projects for group-level new resource creation. -merge_request: !13058 -author: diff --git a/changelogs/unreleased/handle-reserved-words-for-oauth-usernames.yml b/changelogs/unreleased/handle-reserved-words-for-oauth-usernames.yml deleted file mode 100644 index 0d64844a2b8..00000000000 --- a/changelogs/unreleased/handle-reserved-words-for-oauth-usernames.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Uniquify reserved word usernames on OAuth user creation -merge_request: 13244 -author: Robin Bobbitt diff --git a/changelogs/unreleased/issue_31790.yml b/changelogs/unreleased/issue_31790.yml deleted file mode 100644 index df02cad423a..00000000000 --- a/changelogs/unreleased/issue_31790.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix API responses when dealing with txt files -merge_request: -author: diff --git a/changelogs/unreleased/issue_35580.yml b/changelogs/unreleased/issue_35580.yml deleted file mode 100644 index 3a94e771e25..00000000000 --- a/changelogs/unreleased/issue_35580.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix project milestones import when projects belongs to a group -merge_request: -author: diff --git a/changelogs/unreleased/memoize-user-personal-projects-count.yml b/changelogs/unreleased/memoize-user-personal-projects-count.yml deleted file mode 100644 index 3839a97f185..00000000000 --- a/changelogs/unreleased/memoize-user-personal-projects-count.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Memoize the number of personal projects a user has to reduce COUNT queries -merge_request: -author: diff --git a/changelogs/unreleased/merge-issuable-reopened-into-opened-state.yml b/changelogs/unreleased/merge-issuable-reopened-into-opened-state.yml deleted file mode 100644 index 5d7af8971e5..00000000000 --- a/changelogs/unreleased/merge-issuable-reopened-into-opened-state.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Merge issuable "reopened" state into "opened" -merge_request: -author: diff --git a/changelogs/unreleased/migrate-events-into-a-new-format.yml b/changelogs/unreleased/migrate-events-into-a-new-format.yml deleted file mode 100644 index 8a29f75323f..00000000000 --- a/changelogs/unreleased/migrate-events-into-a-new-format.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Migrate events into a new format to reduce the storage necessary and improve performance -merge_request: -author: diff --git a/changelogs/unreleased/mk-fix-wiki-backup.yml b/changelogs/unreleased/mk-fix-wiki-backup.yml deleted file mode 100644 index ba9c1e85955..00000000000 --- a/changelogs/unreleased/mk-fix-wiki-backup.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix improperly skipped backups of wikis. -merge_request: 13096 -author: diff --git a/changelogs/unreleased/mr-branch-link-use-tree.yml b/changelogs/unreleased/mr-branch-link-use-tree.yml deleted file mode 100644 index f4c4d9f5082..00000000000 --- a/changelogs/unreleased/mr-branch-link-use-tree.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: MR branch link now links to tree instead of commits -merge_request: -author: diff --git a/changelogs/unreleased/only-limit-fetch-when-requested.yml b/changelogs/unreleased/only-limit-fetch-when-requested.yml deleted file mode 100644 index d9acdf56511..00000000000 --- a/changelogs/unreleased/only-limit-fetch-when-requested.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Only require Sidekiq throttling library when enabled, to reduce cache misses -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/pagination-projects-explore.yml b/changelogs/unreleased/pagination-projects-explore.yml deleted file mode 100644 index dc9c4218793..00000000000 --- a/changelogs/unreleased/pagination-projects-explore.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use Prev/Next pagination for exploring projects -merge_request: -author: diff --git a/changelogs/unreleased/pass-before-script-as-is.yml b/changelogs/unreleased/pass-before-script-as-is.yml deleted file mode 100644 index ac6513dcff6..00000000000 --- a/changelogs/unreleased/pass-before-script-as-is.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Pass before_script and script as-is preserving arrays -merge_request: -author: diff --git a/changelogs/unreleased/pawel-add-sidekiq-metrics-endpoint-32145.yml b/changelogs/unreleased/pawel-add-sidekiq-metrics-endpoint-32145.yml deleted file mode 100644 index 71eabdc16d2..00000000000 --- a/changelogs/unreleased/pawel-add-sidekiq-metrics-endpoint-32145.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add Prometheus metrics exporter to Sidekiq -merge_request: 13082 -author: diff --git a/changelogs/unreleased/pawel-add_more_variables_to_additional_metrics-35267.yml b/changelogs/unreleased/pawel-add_more_variables_to_additional_metrics-35267.yml deleted file mode 100644 index c1e831306df..00000000000 --- a/changelogs/unreleased/pawel-add_more_variables_to_additional_metrics-35267.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add support for kube_namespace in Metrics queries -merge_request: 16169 -author: diff --git a/changelogs/unreleased/post-upload-pack-opt-out.yml b/changelogs/unreleased/post-upload-pack-opt-out.yml deleted file mode 100644 index 302a99795a0..00000000000 --- a/changelogs/unreleased/post-upload-pack-opt-out.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Enable gitaly_post_upload_pack by default -merge_request: 13078 -author: diff --git a/changelogs/unreleased/rc-fix-branches-api-endpoint.yml b/changelogs/unreleased/rc-fix-branches-api-endpoint.yml deleted file mode 100644 index b36663bbe91..00000000000 --- a/changelogs/unreleased/rc-fix-branches-api-endpoint.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix the /projects/:id/repository/branches endpoint to handle dots in the branch - name when the project full path contains a `/` -merge_request: 13115 -author: diff --git a/changelogs/unreleased/rc-fix-commits-api.yml b/changelogs/unreleased/rc-fix-commits-api.yml deleted file mode 100644 index 215429eaf6b..00000000000 --- a/changelogs/unreleased/rc-fix-commits-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix the /projects/:id/repository/commits endpoint to handle dots in the ref - name when the project full path contains a `/` -merge_request: 13370 -author: diff --git a/changelogs/unreleased/rc-fix-tags-api.yml b/changelogs/unreleased/rc-fix-tags-api.yml deleted file mode 100644 index 0a7dd5ca6ab..00000000000 --- a/changelogs/unreleased/rc-fix-tags-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix the /projects/:id/repository/tags endpoint to handle dots in the tag name - when the project full path contains a `/` -merge_request: 13368 -author: diff --git a/changelogs/unreleased/rd-fix-broken-configuration-for-some-integrations.yml b/changelogs/unreleased/rd-fix-broken-configuration-for-some-integrations.yml new file mode 100644 index 00000000000..00528397d64 --- /dev/null +++ b/changelogs/unreleased/rd-fix-broken-configuration-for-some-integrations.yml @@ -0,0 +1,5 @@ +--- +title: Testing of some integrations were broken due to missing ServiceHook record. +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/remove-nprogress-gleaning.yml b/changelogs/unreleased/remove-nprogress-gleaning.yml deleted file mode 100644 index 78e4dc82dd4..00000000000 --- a/changelogs/unreleased/remove-nprogress-gleaning.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove CSS for nprogress removed -merge_request: 12737 -author: Takuya Noguchi diff --git a/changelogs/unreleased/remove-redundant-query-when-retrieving-recent-pushes.yml b/changelogs/unreleased/remove-redundant-query-when-retrieving-recent-pushes.yml deleted file mode 100644 index 83934217e6a..00000000000 --- a/changelogs/unreleased/remove-redundant-query-when-retrieving-recent-pushes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove redundant query when retrieving the most recent push of a user -merge_request: -author: diff --git a/changelogs/unreleased/reorganise-issues-indexes-for-sorting.yml b/changelogs/unreleased/reorganise-issues-indexes-for-sorting.yml deleted file mode 100644 index 5bfe55e562f..00000000000 --- a/changelogs/unreleased/reorganise-issues-indexes-for-sorting.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Re-organise "issues" indexes for faster ordering -merge_request: -author: diff --git a/changelogs/unreleased/replace_spinach_spec_browse_files.yml b/changelogs/unreleased/replace_spinach_spec_browse_files.yml deleted file mode 100644 index 7380d39fa9f..00000000000 --- a/changelogs/unreleased/replace_spinach_spec_browse_files.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Replace 'browse_files.feature' spinach test with an rspec analog -merge_request: 12251 -author: @blackst0ne diff --git a/changelogs/unreleased/request-store-wrap.yml b/changelogs/unreleased/request-store-wrap.yml deleted file mode 100644 index 8017054b77b..00000000000 --- a/changelogs/unreleased/request-store-wrap.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add RequestCache which makes caching with RequestStore easier -merge_request: 12920 -author: diff --git a/changelogs/unreleased/restrict-haml-javascript.yml b/changelogs/unreleased/restrict-haml-javascript.yml deleted file mode 100644 index 3d0a52f416d..00000000000 --- a/changelogs/unreleased/restrict-haml-javascript.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add custom linter for inline JavaScript to haml_lint -merge_request: 9742 -author: winniehell diff --git a/changelogs/unreleased/rs-alphanumeric-ssh-params.yml b/changelogs/unreleased/rs-alphanumeric-ssh-params.yml deleted file mode 100644 index 426b01cafad..00000000000 --- a/changelogs/unreleased/rs-alphanumeric-ssh-params.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disallow Git URLs that include a username or hostname beginning with a non-alphanumeric - character -merge_request: -author: diff --git a/changelogs/unreleased/sh-structured-logging.yml b/changelogs/unreleased/sh-structured-logging.yml deleted file mode 100644 index d89eb93f689..00000000000 --- a/changelogs/unreleased/sh-structured-logging.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add structured logging for Rails processes -merge_request: -author: diff --git a/changelogs/unreleased/skip-oauth-authorization-for-trusted-applications.yml b/changelogs/unreleased/skip-oauth-authorization-for-trusted-applications.yml deleted file mode 100644 index 7b4ae355978..00000000000 --- a/changelogs/unreleased/skip-oauth-authorization-for-trusted-applications.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Skip oAuth authorization for trusted applications -merge_request: -author: diff --git a/changelogs/unreleased/tc-api-root-merge-requests.yml b/changelogs/unreleased/tc-api-root-merge-requests.yml deleted file mode 100644 index 17456f943eb..00000000000 --- a/changelogs/unreleased/tc-api-root-merge-requests.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add top-level merge_requests API endpoint -merge_request: 13060 -author: diff --git a/changelogs/unreleased/tc-git-tower-pagination-links.yml b/changelogs/unreleased/tc-git-tower-pagination-links.yml deleted file mode 100644 index b99ef8c3c4c..00000000000 --- a/changelogs/unreleased/tc-git-tower-pagination-links.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve API pagination headers when no record found -merge_request: 13629 -author: Jordan Patterson -type: fixed diff --git a/changelogs/unreleased/tc-issue-api-assignee.yml b/changelogs/unreleased/tc-issue-api-assignee.yml deleted file mode 100644 index 8d6360d5baf..00000000000 --- a/changelogs/unreleased/tc-issue-api-assignee.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add author_id & assignee_id param to /issues API -merge_request: 13004 -author: diff --git a/changelogs/unreleased/tc-no-todo-service-select.yml b/changelogs/unreleased/tc-no-todo-service-select.yml deleted file mode 100644 index ddcae334aa7..00000000000 --- a/changelogs/unreleased/tc-no-todo-service-select.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Avoid plucking Todo ids in TodoService -merge_request: 10845 -author: diff --git a/changelogs/unreleased/tc-remove-nonexisting-namespace-pending-delete-projects.yml b/changelogs/unreleased/tc-remove-nonexisting-namespace-pending-delete-projects.yml new file mode 100644 index 00000000000..218336df5d2 --- /dev/null +++ b/changelogs/unreleased/tc-remove-nonexisting-namespace-pending-delete-projects.yml @@ -0,0 +1,5 @@ +--- +title: Migration to remove pending delete projects with non-existing namespace +merge_request: 13598 +author: +type: other diff --git a/changelogs/unreleased/toggle-new-project-import-description.yml b/changelogs/unreleased/toggle-new-project-import-description.yml deleted file mode 100644 index 8f0d09e0540..00000000000 --- a/changelogs/unreleased/toggle-new-project-import-description.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Toggle import description with import_sources_enabled -merge_request: 12691 -author: Brianna Kicia
\ No newline at end of file diff --git a/changelogs/unreleased/use-a-specialized-class-for-querying-events.yml b/changelogs/unreleased/use-a-specialized-class-for-querying-events.yml deleted file mode 100644 index 6c1ec10aa12..00000000000 --- a/changelogs/unreleased/use-a-specialized-class-for-querying-events.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use a specialized class for querying events to improve performance -merge_request: -author: diff --git a/changelogs/unreleased/wiki_title.yml b/changelogs/unreleased/wiki_title.yml deleted file mode 100644 index 3ef5fa2969b..00000000000 --- a/changelogs/unreleased/wiki_title.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow wiki pages to be renamed in the UI -merge_request: 10069 -author: wendy0402 diff --git a/changelogs/unreleased/winh-derive-project-name.yml b/changelogs/unreleased/winh-derive-project-name.yml deleted file mode 100644 index 2244d21d768..00000000000 --- a/changelogs/unreleased/winh-derive-project-name.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Derive project path from import URL -merge_request: 13131 -author: diff --git a/changelogs/unreleased/zj-delete-mm-team.yml b/changelogs/unreleased/zj-delete-mm-team.yml deleted file mode 100644 index f0c782c4566..00000000000 --- a/changelogs/unreleased/zj-delete-mm-team.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove Mattermost team when deleting a group -merge_request: 11362 -author: diff --git a/changelogs/unreleased/zj-fix-fe-blank-button.yml b/changelogs/unreleased/zj-fix-fe-blank-button.yml new file mode 100644 index 00000000000..2165d4186c1 --- /dev/null +++ b/changelogs/unreleased/zj-fix-fe-blank-button.yml @@ -0,0 +1,5 @@ +--- +title: Fix new project form not resetting the template value +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/zj-pipeline-badge-improvements.yml b/changelogs/unreleased/zj-pipeline-badge-improvements.yml deleted file mode 100644 index 735192ede2d..00000000000 --- a/changelogs/unreleased/zj-pipeline-badge-improvements.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Update build badges to be pipeline badges and display passing instead of success -merge_request: -author: diff --git a/changelogs/unreleased/zj-project-templates.yml b/changelogs/unreleased/zj-project-templates.yml deleted file mode 100644 index ab6e0f2d5f2..00000000000 --- a/changelogs/unreleased/zj-project-templates.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Projects can be created from templates -merge_request: 13108 -author: diff --git a/config/initializers/workhorse_multipart.rb b/config/initializers/workhorse_multipart.rb index 064e5964f09..4196e3a8f61 100644 --- a/config/initializers/workhorse_multipart.rb +++ b/config/initializers/workhorse_multipart.rb @@ -10,10 +10,8 @@ end # module Gitlab module StrongParameterScalars - GITLAB_PERMITTED_SCALAR_TYPES = [::UploadedFile].freeze - def permitted_scalar?(value) - super || GITLAB_PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) } + super || value.is_a?(::UploadedFile) end end end diff --git a/config/karma.config.js b/config/karma.config.js index 2f571978e08..e459f5cdac3 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -8,6 +8,7 @@ if (webpackConfig.plugins) { webpackConfig.plugins = webpackConfig.plugins.filter(function (plugin) { return !( plugin instanceof webpack.optimize.CommonsChunkPlugin || + plugin instanceof webpack.optimize.ModuleConcatenationPlugin || plugin instanceof webpack.DefinePlugin ); }); diff --git a/db/migrate/20170802013652_add_storage_fields_to_project.rb b/db/migrate/20170802013652_add_storage_fields_to_project.rb new file mode 100644 index 00000000000..c2381a9d0b2 --- /dev/null +++ b/db/migrate/20170802013652_add_storage_fields_to_project.rb @@ -0,0 +1,16 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddStorageFieldsToProject < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def up + add_column :projects, :storage_version, :integer, limit: 2 + end + + def down + remove_column :projects, :storage_version + end +end diff --git a/db/migrate/20170807071105_add_hashed_storage_to_settings.rb b/db/migrate/20170807071105_add_hashed_storage_to_settings.rb new file mode 100644 index 00000000000..0846557add8 --- /dev/null +++ b/db/migrate/20170807071105_add_hashed_storage_to_settings.rb @@ -0,0 +1,18 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddHashedStorageToSettings < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default :application_settings, :hashed_storage_enabled, :boolean, default: false + end + + def down + remove_columns :application_settings, :hashed_storage_enabled + end +end diff --git a/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb b/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb new file mode 100644 index 00000000000..3f085c17133 --- /dev/null +++ b/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb @@ -0,0 +1,54 @@ +# Follow up of CleanupNamespacelessPendingDeleteProjects and it cleans +# all projects with `pending_delete = true` and for which the +# namespace no longer exists. +class CleanupNonexistingNamespacePendingDeleteProjects < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + class Project < ActiveRecord::Base + self.table_name = 'projects' + + include ::EachBatch + end + + class Namespace < ActiveRecord::Base + self.table_name = 'namespaces' + end + + def up + find_projects.each_batch do |batch| + args = batch.pluck(:id).map { |id| [id] } + + NamespacelessProjectDestroyWorker.bulk_perform_async(args) + end + end + + def down + # NOOP + end + + private + + def find_projects + projects = Project.arel_table + namespaces = Namespace.arel_table + + namespace_query = namespaces.project(1) + .where(namespaces[:id].eq(projects[:namespace_id])) + .exists.not + + # SELECT "projects"."id" + # FROM "projects" + # WHERE "projects"."pending_delete" = 't' + # AND (NOT (EXISTS + # (SELECT 1 + # FROM "namespaces" + # WHERE "namespaces"."id" = "projects"."namespace_id"))) + Project.where(projects[:pending_delete].eq(true)) + .where(namespace_query) + .select(:id) + end +end diff --git a/db/schema.rb b/db/schema.rb index c31bff3a8f2..cd488630237 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -128,6 +128,7 @@ ActiveRecord::Schema.define(version: 20170820100558) do t.integer "performance_bar_allowed_group_id" t.boolean "password_authentication_enabled" t.boolean "project_export_enabled", default: true, null: false + t.boolean "hashed_storage_enabled", default: false, null: false end create_table "audit_events", force: :cascade do |t| @@ -1208,6 +1209,7 @@ ActiveRecord::Schema.define(version: 20170820100558) do t.datetime "last_repository_updated_at" t.string "ci_config_path" t.text "delete_error" + t.integer "storage_version", limit: 2 end add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree diff --git a/doc/development/licensing.md b/doc/development/licensing.md index 1f115059fb8..2b16dfe0e7c 100644 --- a/doc/development/licensing.md +++ b/doc/development/licensing.md @@ -66,7 +66,7 @@ Libraries with the following licenses are unacceptable for use: ## Requesting Approval for Licenses -Libraries that are not listed in the [Acceptable Licenses][Acceptable-Licenses] or [Unacceptable Licenses][Unacceptable-Licenses] list can be submitted to the legal team for review. Please create an issue in the [Organization Repository][Org-Repo] and cc `@gl-legal`. After a decision has been made, the original requestor is responsible for updating this document. +Libraries that are not listed in the [Acceptable Licenses][Acceptable-Licenses] or [Unacceptable Licenses][Unacceptable-Licenses] list can be submitted to the legal team for review. Please email `legal@gitlab.com` with the details. After a decision has been made, the original requestor is responsible for updating this document. ## Notes diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md index 0fad181f59e..81057736e3a 100644 --- a/doc/install/kubernetes/gitlab_chart.md +++ b/doc/install/kubernetes/gitlab_chart.md @@ -428,6 +428,13 @@ ingress: ## Installing GitLab using the Helm Chart > You may see a temporary error message `SchedulerPredicates failed due to PersistentVolumeClaim is not bound` while storage provisions. Once the storage provisions, the pods will automatically restart. This may take a couple minutes depending on your cloud provider. If the error persists, please review the [prerequisites](#prerequisites) to ensure you have enough RAM, CPU, and storage. +Ensure the GitLab repo has been added and re-initialize Helm: + +```bash +helm repo add gitlab https://charts.gitlab.io +helm init +``` + Once you [have configured](#configuration) GitLab in your `values.yml` file, run the following: diff --git a/doc/install/kubernetes/gitlab_omnibus.md b/doc/install/kubernetes/gitlab_omnibus.md index bd3a85272d0..05e0a59ffeb 100644 --- a/doc/install/kubernetes/gitlab_omnibus.md +++ b/doc/install/kubernetes/gitlab_omnibus.md @@ -126,14 +126,23 @@ Let's Encrypt limits a single TLD to five certificate requests within a single w ## Installing GitLab using the Helm Chart > You may see a temporary error message `SchedulerPredicates failed due to PersistentVolumeClaim is not bound` while storage provisions. Once the storage provisions, the pods will automatically restart. This may take a couple minutes depending on your cloud provider. If the error persists, please review the [prerequisites](#prerequisites) to ensure you have enough RAM, CPU, and storage. -Once you have reviewed the [configuration settings](#configuring-and-installing-gitlab) and [added the Helm repository](index.md#add-the-gitlab-helm-repository), you can install the chart. We recommending saving your configuration options in a `values.yaml` file for easier upgrades in the future. +Ensure the GitLab repo has been added and re-initialize Helm: + +```bash +helm repo add gitlab https://charts.gitlab.io +helm init +``` + +Once you have reviewed the [configuration settings](#configuring-and-installing-gitlab) you can install the chart. We recommending saving your configuration options in a `values.yaml` file for easier upgrades in the future. For example: + ```bash helm install --name gitlab -f values.yaml gitlab/gitlab-omnibus ``` or passing them on the command line: + ```bash helm install --name gitlab --set baseDomain=gitlab.io,baseIP=1.1.1.1,gitlab=ee,gitlabEELicense=$LICENSE,legoEmail=email@gitlab.com gitlab/gitlab-omnibus ``` diff --git a/doc/install/kubernetes/gitlab_runner_chart.md b/doc/install/kubernetes/gitlab_runner_chart.md index b0fe91d6337..51f94a33109 100644 --- a/doc/install/kubernetes/gitlab_runner_chart.md +++ b/doc/install/kubernetes/gitlab_runner_chart.md @@ -190,6 +190,13 @@ certsSecretName: <SECRET NAME> ## Installing GitLab Runner using the Helm Chart +Ensure the GitLab repo has been added and re-initialize Helm: + +```bash +helm repo add gitlab https://charts.gitlab.io +helm init +``` + Once you [have configured](#configuration) GitLab Runner in your `values.yml` file, run the following: diff --git a/doc/install/kubernetes/index.md b/doc/install/kubernetes/index.md index 3608aa6b2d6..eb98dc06a18 100644 --- a/doc/install/kubernetes/index.md +++ b/doc/install/kubernetes/index.md @@ -35,12 +35,14 @@ helm init ## Using the GitLab Helm Charts -GitLab makes available three Helm Charts: an easy to use bundled chart, and a specific chart for GitLab itself and the Runner. +GitLab makes available three Helm Charts. -- [gitlab-omnibus](gitlab_omnibus.md): The easiest way to get started. Includes everything needed to run GitLab, including: a Runner, Container Registry, automatic SSL, and an Ingress. +- [gitlab-omnibus](gitlab_omnibus.md): **Recommended** and the easiest way to get started. Includes everything needed to run GitLab, including: a [Runner](https://docs.gitlab.com/runner/), [Container Registry](https://docs.gitlab.com/ee/user/project/container_registry.html#gitlab-container-registry), [automatic SSL](https://github.com/kubernetes/charts/tree/master/stable/kube-lego), and an [Ingress](https://github.com/kubernetes/ingress/tree/master/controllers/nginx). - [gitlab](gitlab_chart.md): Just the GitLab service, with optional Postgres and Redis. - [gitlab-runner](gitlab_runner_chart.md): GitLab Runner, to process CI jobs. +We are also working on a new set of [cloud native Charts](https://gitlab.com/charts/helm.gitlab.io) which will eventually replace these. + [chart]: https://github.com/kubernetes/charts [helm-quick]: https://github.com/kubernetes/helm/blob/master/docs/quickstart.md [helm]: https://github.com/kubernetes/helm/blob/master/README.md diff --git a/doc/user/project/merge_requests/img/merge_request_diff_file_navigation.png b/doc/user/project/merge_requests/img/merge_request_diff_file_navigation.png Binary files differnew file mode 100644 index 00000000000..9b8aee47411 --- /dev/null +++ b/doc/user/project/merge_requests/img/merge_request_diff_file_navigation.png diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 285c40729fe..26c6277d33a 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -137,6 +137,14 @@ have been marked as a **Work In Progress**. [Learn more about settings a merge request as "Work In Progress".](work_in_progress_merge_requests.md) +## Merge request diff file navigation + +The diff view has a persistent dropdown for file navigation. As you scroll through +diffs with a large number of files and/or many changes in those files, you can +easily jump to any changed file through the dropdown navigation. + +![Merge request diff file navigation](img/merge_request_diff_file_navigation.png) + ## Ignore whitespace changes in Merge Request diff view If you click the **Hide whitespace changes** button, you can see the diff diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index 88821ae56e0..4e92be85110 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -75,7 +75,7 @@ module Backup path_to_project_repo = path_to_repo(project) path_to_project_bundle = path_to_bundle(project) - project.ensure_storage_path_exist + project.ensure_storage_path_exists cmd = if File.exist?(path_to_project_bundle) %W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_project_bundle} #{path_to_project_repo}) diff --git a/lib/github/import.rb b/lib/github/import.rb index 4cc01593ef4..7b848081e85 100644 --- a/lib/github/import.rb +++ b/lib/github/import.rb @@ -107,7 +107,7 @@ module Github # this means that repo has wiki enabled, but have no pages. So, # we can skip the import. if e.message !~ /repository not exported/ - errors(:wiki, wiki_url, e.message) + error(:wiki, wiki_url, e.message) end end diff --git a/lib/gitlab/bare_repository_importer.rb b/lib/gitlab/bare_repository_importer.rb new file mode 100644 index 00000000000..9323bfc7fb2 --- /dev/null +++ b/lib/gitlab/bare_repository_importer.rb @@ -0,0 +1,96 @@ +module Gitlab + class BareRepositoryImporter + NoAdminError = Class.new(StandardError) + + def self.execute + Gitlab.config.repositories.storages.each do |storage_name, repository_storage| + git_base_path = repository_storage['path'] + repos_to_import = Dir.glob(git_base_path + '/**/*.git') + + repos_to_import.each do |repo_path| + if repo_path.end_with?('.wiki.git') + log " * Skipping wiki repo" + next + end + + log "Processing #{repo_path}".color(:yellow) + + repo_relative_path = repo_path[repository_storage['path'].length..-1] + .sub(/^\//, '') # Remove leading `/` + .sub(/\.git$/, '') # Remove `.git` at the end + new(storage_name, repo_relative_path).create_project_if_needed + end + end + end + + attr_reader :storage_name, :full_path, :group_path, :project_path, :user + delegate :log, to: :class + + def initialize(storage_name, repo_path) + @storage_name = storage_name + @full_path = repo_path + + unless @user = User.admins.order_id_asc.first + raise NoAdminError.new('No admin user found to import repositories') + end + + @group_path, @project_path = File.split(repo_path) + @group_path = nil if @group_path == '.' + end + + def create_project_if_needed + if project = Project.find_by_full_path(full_path) + log " * #{project.name} (#{full_path}) exists" + return project + end + + create_project + end + + private + + def create_project + group = find_or_create_group + + project_params = { + name: project_path, + path: project_path, + repository_storage: storage_name, + namespace_id: group&.id + } + + project = Projects::CreateService.new(user, project_params).execute + + if project.persisted? + log " * Created #{project.name} (#{full_path})".color(:green) + ProjectCacheWorker.perform_async(project.id) + else + log " * Failed trying to create #{project.name} (#{full_path})".color(:red) + log " Errors: #{project.errors.messages}".color(:red) + end + + project + end + + def find_or_create_group + return nil unless group_path + + if namespace = Namespace.find_by_full_path(group_path) + log " * Namespace #{group_path} exists.".color(:green) + return namespace + end + + log " * Creating Group: #{group_path}" + Groups::NestedCreateService.new(user, group_path: group_path).execute + end + + # This is called from within a rake task only used by Admins, so allow writing + # to STDOUT + # + # rubocop:disable Rails/Output + def self.log(message) + puts message + end + # rubocop:enable Rails/Output + end +end diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index a499bbc6266..5ee6669050c 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -271,7 +271,13 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/324 def to_diff - rugged_diff_from_parent.patch + Gitlab::GitalyClient.migrate(:commit_patch) do |is_enabled| + if is_enabled + @repository.gitaly_commit_client.patch(id) + else + rugged_diff_from_parent.patch + end + end end # Returns a diff object for the changes from this commit's first parent. diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index 2d58fb0186e..57f42bd35ee 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -175,8 +175,8 @@ module Gitlab def raw_blame(revision, path) request = Gitaly::RawBlameRequest.new( repository: @gitaly_repo, - revision: revision, - path: path + revision: GitalyClient.encode(revision), + path: GitalyClient.encode(path) ) response = GitalyClient.call(@repository.storage, :commit_service, :raw_blame, request) @@ -194,6 +194,16 @@ module Gitlab response.commit end + def patch(revision) + request = Gitaly::CommitPatchRequest.new( + repository: @gitaly_repo, + revision: GitalyClient.encode(revision) + ) + response = GitalyClient.call(@repository.storage, :diff_service, :commit_patch, request) + + response.sum(&:data) + end + private def commit_diff_request_params(commit, options = {}) diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 9d9ebcb389a..e5d4bb686e7 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -98,6 +98,7 @@ excluded_attributes: - :last_activity_at - :last_repository_updated_at - :last_repository_check_at + - :storage_version snippets: - :expired_at merge_request_diff: @@ -133,5 +134,7 @@ methods: - :utf8_diff merge_requests: - :diff_head_sha + - :source_branch_sha + - :target_branch_sha project: - :description_html diff --git a/lib/gitlab/import_export/merge_request_parser.rb b/lib/gitlab/import_export/merge_request_parser.rb index c20adc20bfd..81a213e8321 100644 --- a/lib/gitlab/import_export/merge_request_parser.rb +++ b/lib/gitlab/import_export/merge_request_parser.rb @@ -30,7 +30,7 @@ module Gitlab end def branch_exists?(branch_name) - @project.repository.branch_exists?(branch_name) + @project.repository.raw.branch_exists?(branch_name) end def fork_merge_request? diff --git a/lib/gitlab/job_waiter.rb b/lib/gitlab/job_waiter.rb index 208f0e1bbea..4d6bbda15f3 100644 --- a/lib/gitlab/job_waiter.rb +++ b/lib/gitlab/job_waiter.rb @@ -1,12 +1,31 @@ module Gitlab # JobWaiter can be used to wait for a number of Sidekiq jobs to complete. + # + # Its use requires the cooperation of the sidekiq jobs themselves. Set up the + # waiter, then start the jobs, passing them its `key`. Their `perform` methods + # should look like: + # + # def perform(args, notify_key) + # # do work + # ensure + # ::Gitlab::JobWaiter.notify(notify_key, jid) + # end + # + # The JobWaiter blocks popping items from a Redis array. All the sidekiq jobs + # push to that array when done. Once the waiter has popped `count` items, it + # knows all the jobs are done. class JobWaiter - # The sleep interval between checking keys, in seconds. - INTERVAL = 0.1 + def self.notify(key, jid) + Gitlab::Redis::SharedState.with { |redis| redis.lpush(key, jid) } + end + + attr_reader :key, :jobs_remaining, :finished - # jobs - The job IDs to wait for. - def initialize(jobs) - @jobs = jobs + # jobs_remaining - the number of jobs left to wait for + def initialize(jobs_remaining) + @key = "gitlab:job_waiter:#{SecureRandom.uuid}" + @jobs_remaining = jobs_remaining + @finished = [] end # Waits for all the jobs to be completed. @@ -15,13 +34,33 @@ module Gitlab # ensures we don't indefinitely block a caller in case a job takes # long to process, or is never processed. def wait(timeout = 10) - start = Time.current + deadline = Time.now.utc + timeout + + Gitlab::Redis::SharedState.with do |redis| + # Fallback key expiry: allow a long grace period to reduce the chance of + # a job pushing to an expired key and recreating it + redis.expire(key, [timeout * 2, 10.minutes.to_i].max) + + while jobs_remaining > 0 + # Redis will not take fractional seconds. Prefer waiting too long over + # not waiting long enough + seconds_left = (deadline - Time.now.utc).ceil - while (Time.current - start) <= timeout - break if SidekiqStatus.all_completed?(@jobs) + # Redis interprets 0 as "wait forever", so skip the final `blpop` call + break if seconds_left <= 0 - sleep(INTERVAL) # to not overload Redis too much. + list, jid = redis.blpop(key, timeout: seconds_left) + break unless list && jid # timed out + + @finished << jid + @jobs_remaining -= 1 + end + + # All jobs have finished, so expire the key immediately + redis.expire(key, 0) if jobs_remaining == 0 end + + finished end end end diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb index 8867a91c244..cd7e4ca7b7e 100644 --- a/lib/gitlab/ldap/adapter.rb +++ b/lib/gitlab/ldap/adapter.rb @@ -73,7 +73,7 @@ module Gitlab private def user_options(field, value, limit) - options = { attributes: user_attributes } + options = { attributes: Gitlab::LDAP::Person.ldap_attributes(config).compact.uniq } options[:size] = limit if limit if field.to_sym == :dn @@ -99,10 +99,6 @@ module Gitlab filter end end - - def user_attributes - %W(#{config.uid} cn dn) + config.attributes['username'] + config.attributes['email'] - end end end end diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb index e138b466a34..4d6f8ac79de 100644 --- a/lib/gitlab/ldap/person.rb +++ b/lib/gitlab/ldap/person.rb @@ -21,6 +21,15 @@ module Gitlab adapter.dn_matches_filter?(dn, AD_USER_DISABLED) end + def self.ldap_attributes(config) + [ + 'dn', # Used in `dn` + config.uid, # Used in `uid` + *config.attributes['name'], # Used in `name` + *config.attributes['email'] # Used in `email` + ] + end + def initialize(entry, provider) Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" } @entry = entry diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb index 59b21149a9a..6bffd410ed0 100644 --- a/lib/gitlab/logger.rb +++ b/lib/gitlab/logger.rb @@ -14,13 +14,9 @@ module Gitlab def self.read_latest path = Rails.root.join("log", file_name) - self.build unless File.exist?(path) - tail_output, _ = Gitlab::Popen.popen(%W(tail -n 2000 #{path})) - tail_output.split("\n") - end - def self.read_latest_for(filename) - path = Rails.root.join("log", filename) + return [] unless File.readable?(path) + tail_output, _ = Gitlab::Popen.popen(%W(tail -n 2000 #{path})) tail_output.split("\n") end diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index 1adc5ec952a..58f6245579a 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -53,7 +53,8 @@ module Gitlab end def kubernetes_namespace_regex_message - "can contain only letters, digits or '-', and cannot start or end with '-'" + "can contain only lowercase letters, digits, and '-'. " \ + "Must start with a letter, and cannot end with '-'" end def environment_slug_regex diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index 48bd9139ce8..d227a0c8bdb 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -9,71 +9,16 @@ namespace :gitlab do # * The project owner will set to the first administator of the system # * Existing projects will be skipped # + # desc "GitLab | Import bare repositories from repositories -> storages into GitLab project instance" task repos: :environment do - Gitlab.config.repositories.storages.each_value do |repository_storage| - git_base_path = repository_storage['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] = '' - - path = repo_path.sub(/\.git$/, '') - group_name, name = File.split(path) - group_name = nil if group_name == '.' - - puts "Processing #{repo_path}".color(:yellow) - - if path.end_with?('.wiki') - puts " * Skipping wiki repo" - next - end - - project = Project.find_by_full_path(path) - - if project - puts " * #{project.name} (#{repo_path}) exists" - else - user = User.admins.reorder("id").first - - 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) - end - end - # set project group - project_params[:namespace_id] = group.id - end - - project = Projects::CreateService.new(user, project_params).execute + if Project.current_application_settings.hashed_storage_enabled + puts 'Cannot import repositories when Hashed Storage is enabled'.color(:red) - if project.persisted? - puts " * Created #{project.name} (#{repo_path})".color(:green) - ProjectCacheWorker.perform_async(project.id) - else - puts " * Failed trying to create #{project.name} (#{repo_path})".color(:red) - puts " Errors: #{project.errors.messages}".color(:red) - end - end - end + exit 1 end - puts "Done!".color(:green) + Gitlab::BareRepositoryImporter.execute end end end diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake index 96b8f59242c..1206302cb76 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/import.rake @@ -72,23 +72,7 @@ class GithubImport return @current_user.namespace if names == @current_user.namespace_path return @current_user.namespace unless @current_user.can_create_group? - full_path_namespace = Namespace.find_by_full_path(names) - - return full_path_namespace if full_path_namespace - - names.split('/').inject(nil) do |parent, name| - begin - namespace = Group.create!(name: name, - path: name, - owner: @current_user, - parent: parent) - namespace.add_owner(@current_user) - - namespace - rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid - Namespace.where(parent: parent).find_by_path_or_name(name) - end - end + Groups::NestedCreateService.new(@current_user, group_path: names).execute end def full_path_namespace(names) diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index 4e9b0c09ff2..efba9cc7306 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -10,9 +10,6 @@ describe Projects::ServicesController do before do sign_in(user) project.team << [user, :master] - - controller.instance_variable_set(:@project, project) - controller.instance_variable_set(:@service, service) end describe '#test' do @@ -20,7 +17,7 @@ describe Projects::ServicesController do it 'renders 404' do allow_any_instance_of(Service).to receive(:can_test?).and_return(false) - put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id + put :test, namespace_id: project.namespace, project_id: project, id: service.to_param expect(response).to have_http_status(404) end @@ -36,7 +33,7 @@ describe Projects::ServicesController do it 'returns success' do allow_any_instance_of(MicrosoftTeams::Notifier).to receive(:ping).and_return(true) - put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id + put :test, namespace_id: project.namespace, project_id: project, id: service.to_param expect(response.status).to eq(200) end @@ -45,7 +42,7 @@ describe Projects::ServicesController do it 'returns success' do expect(HipChat::Client).to receive(:new).with('hipchat_token_p', anything).and_return(hipchat_client) - put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: service_params + put :test, namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params expect(response.status).to eq(200) end @@ -54,17 +51,42 @@ describe Projects::ServicesController do it 'returns success' do expect(HipChat::Client).to receive(:new).with('hipchat_token_p', anything).and_return(hipchat_client) - put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: service_params + put :test, namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params expect(response.status).to eq(200) end + + context 'when service is configured for the first time' do + before do + allow_any_instance_of(ServiceHook).to receive(:execute).and_return(true) + end + + it 'persist the object' do + do_put + + expect(BuildkiteService.first).to be_present + end + + it 'creates the ServiceHook object' do + do_put + + expect(BuildkiteService.first.service_hook).to be_present + end + + def do_put + put :test, namespace_id: project.namespace, + project_id: project, + id: 'buildkite', + service: { 'active' => '1', 'push_events' => '1', token: 'token', 'project_url' => 'http://test.com' } + end + end end context 'failure' do it 'returns success status code and the error message' do expect(HipChat::Client).to receive(:new).with('hipchat_token_p', anything).and_raise('Bad test') - put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: service_params + put :test, namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params expect(response.status).to eq(200) expect(JSON.parse(response.body)) @@ -77,7 +99,7 @@ describe Projects::ServicesController do context 'when param `active` is set to true' do it 'activates the service and redirects to integrations paths' do put :update, - namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: { active: true } + namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: true } expect(response).to redirect_to(project_settings_integrations_path(project)) expect(flash[:notice]).to eq 'HipChat activated.' @@ -87,7 +109,7 @@ describe Projects::ServicesController do context 'when param `active` is set to false' do it 'does not activate the service but saves the settings' do put :update, - namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: { active: false } + namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: false } expect(flash[:notice]).to eq 'HipChat settings saved, but not activated.' end diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 4a2034b31b3..9ebda0ba03b 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -81,6 +81,10 @@ FactoryGirl.define do archived true end + trait :hashed do + storage_version Project::LATEST_STORAGE_VERSION + end + trait :access_requestable do request_access_enabled true end diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index 2cd06258e22..e1c74a24890 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -74,7 +74,7 @@ feature 'Top Plus Menu', :js do expect(page).to have_content('Title') end - scenario 'Click on New subgroup shows new group page' do + scenario 'Click on New subgroup shows new group page', :nested_groups do visit group_path(group) click_topmenuitem("New subgroup") diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index e59a484d992..20f9818b08b 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -104,18 +104,15 @@ feature 'Group' do end context 'as group owner' do - let(:user) { create(:user) } + it 'creates a nested group' do + user = create(:user) - before do group.add_owner(user) sign_out(:user) sign_in(user) visit subgroups_group_path(group) click_link 'New Subgroup' - end - - it 'creates a nested group' do fill_in 'Group path', with: 'bar' click_button 'Create group' @@ -123,6 +120,16 @@ feature 'Group' do expect(page).to have_content("Group 'bar' was successfully created.") end end + + context 'when nested group feature is disabled' do + it 'renders 404' do + allow(Group).to receive(:supports_nested_groups?).and_return(false) + + visit subgroups_group_path(group) + + expect(page.status_code).to eq(404) + end + end end it 'checks permissions to avoid exposing groups by parent_id' do diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index 6a324d32ca7..9f2c86923b7 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -3,11 +3,13 @@ require 'spec_helper' feature 'Import/Export - project import integration test', js: true do include Select2Helper + let(:user) { create(:user) } let(:file) { File.join(Rails.root, 'spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') } let(:export_path) { "#{Dir.tmpdir}/import_file_spec" } background do allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) + gitlab_sign_in(user) end after do @@ -18,57 +20,67 @@ feature 'Import/Export - project import integration test', js: true do let(:user) { create(:admin) } let!(:namespace) { create(:namespace, name: "asd", owner: user) } - before do - gitlab_sign_in(user) - end + context 'prefilled the path' do + scenario 'user imports an exported project successfully' do + visit new_project_path - scenario 'user imports an exported project successfully' do - visit new_project_path + select2(namespace.id, from: '#project_namespace_id') + fill_in :project_path, with: 'test-project-path', visible: true + click_link 'GitLab export' - select2(namespace.id, from: '#project_namespace_id') - fill_in :project_path, with: 'test-project-path', visible: true - click_link 'GitLab export' + expect(page).to have_content('Import an exported GitLab project') + expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&path=test-project-path") + expect(Gitlab::ImportExport).to receive(:import_upload_path).with(filename: /\A\h{32}_test-project-path\z/).and_call_original - expect(page).to have_content('Import an exported GitLab project') - expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&path=test-project-path") - expect(Gitlab::ImportExport).to receive(:import_upload_path).with(filename: /\A\h{32}_test-project-path\z/).and_call_original + attach_file('file', file) - attach_file('file', file) + expect { click_on 'Import project' }.to change { Project.count }.by(1) - expect { click_on 'Import project' }.to change { Project.count }.from(0).to(1) - - project = Project.last - expect(project).not_to be_nil - expect(project.issues).not_to be_empty - expect(project.merge_requests).not_to be_empty - expect(project_hook_exists?(project)).to be true - expect(wiki_exists?(project)).to be true - expect(project.import_status).to eq('finished') + project = Project.last + expect(project).not_to be_nil + expect(project.issues).not_to be_empty + expect(project.merge_requests).not_to be_empty + expect(project_hook_exists?(project)).to be true + expect(wiki_exists?(project)).to be true + expect(project.import_status).to eq('finished') + end end - scenario 'invalid project' do - project = create(:project, namespace: namespace) + context 'path is not prefilled' do + scenario 'user imports an exported project successfully' do + visit new_project_path + click_link 'GitLab export' - visit new_project_path + fill_in :path, with: 'test-project-path', visible: true + attach_file('file', file) - select2(namespace.id, from: '#project_namespace_id') - fill_in :project_path, with: project.name, visible: true - click_link 'GitLab export' - attach_file('file', file) - click_on 'Import project' + expect { click_on 'Import project' }.to change { Project.count }.by(1) - page.within('.flash-container') do - expect(page).to have_content('Project could not be imported') + project = Project.last + expect(project).not_to be_nil + expect(page).to have_content("Project 'test-project-path' is being imported") end end end - context 'when limited to the default user namespace' do - let(:user) { create(:user) } - before do - gitlab_sign_in(user) + scenario 'invalid project' do + namespace = create(:namespace, name: "asd", owner: user) + project = create(:project, namespace: namespace) + + visit new_project_path + + select2(namespace.id, from: '#project_namespace_id') + fill_in :project_path, with: project.name, visible: true + click_link 'GitLab export' + attach_file('file', file) + click_on 'Import project' + + page.within('.flash-container') do + expect(page).to have_content('Project could not be imported') end + end + context 'when limited to the default user namespace' do scenario 'passes correct namespace ID in the URL' do visit new_project_path diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb index d16fcf21e45..4632c679972 100644 --- a/spec/helpers/avatars_helper_spec.rb +++ b/spec/helpers/avatars_helper_spec.rb @@ -28,7 +28,7 @@ describe AvatarsHelper do it 'displays user avatar' do is_expected.to eq image_tag( LazyImageTagHelper.placeholder_image, - class: 'avatar has-tooltip s16 lazy', + class: 'avatar s16 has-tooltip lazy', alt: "#{user.name}'s avatar", title: user.name, data: { container: 'body', src: avatar_icon(user, 16) } @@ -41,7 +41,7 @@ describe AvatarsHelper do it 'uses provided css_class' do is_expected.to eq image_tag( LazyImageTagHelper.placeholder_image, - class: "avatar has-tooltip s16 #{options[:css_class]} lazy", + class: "avatar s16 #{options[:css_class]} has-tooltip lazy", alt: "#{user.name}'s avatar", title: user.name, data: { container: 'body', src: avatar_icon(user, 16) } @@ -55,7 +55,7 @@ describe AvatarsHelper do it 'uses provided size' do is_expected.to eq image_tag( LazyImageTagHelper.placeholder_image, - class: "avatar has-tooltip s#{options[:size]} lazy", + class: "avatar s#{options[:size]} has-tooltip lazy", alt: "#{user.name}'s avatar", title: user.name, data: { container: 'body', src: avatar_icon(user, options[:size]) } @@ -69,7 +69,7 @@ describe AvatarsHelper do it 'uses provided url' do is_expected.to eq image_tag( LazyImageTagHelper.placeholder_image, - class: 'avatar has-tooltip s16 lazy', + class: 'avatar s16 has-tooltip lazy', alt: "#{user.name}'s avatar", title: user.name, data: { container: 'body', src: options[:url] } @@ -77,6 +77,36 @@ describe AvatarsHelper do end end + context 'with has_tooltip parameter' do + context 'with has_tooltip set to true' do + let(:options) { { user: user, has_tooltip: true } } + + it 'adds has-tooltip' do + is_expected.to eq image_tag( + LazyImageTagHelper.placeholder_image, + class: 'avatar s16 has-tooltip lazy', + alt: "#{user.name}'s avatar", + title: user.name, + data: { container: 'body', src: avatar_icon(user, 16) } + ) + end + end + + context 'with has_tooltip set to false' do + let(:options) { { user: user, has_tooltip: false } } + + it 'does not add has-tooltip or data container' do + is_expected.to eq image_tag( + LazyImageTagHelper.placeholder_image, + class: 'avatar s16 lazy', + alt: "#{user.name}'s avatar", + title: user.name, + data: { src: avatar_icon(user, 16) } + ) + end + end + end + context 'with user_name parameter' do let(:options) { { user_name: 'Tinky Winky', user_email: 'no@f.un' } } @@ -86,7 +116,7 @@ describe AvatarsHelper do it 'prefers user parameter' do is_expected.to eq image_tag( LazyImageTagHelper.placeholder_image, - class: 'avatar has-tooltip s16 lazy', + class: 'avatar s16 has-tooltip lazy', alt: "#{user.name}'s avatar", title: user.name, data: { container: 'body', src: avatar_icon(user, 16) } @@ -97,7 +127,7 @@ describe AvatarsHelper do it 'uses user_name and user_email parameter if user is not present' do is_expected.to eq image_tag( LazyImageTagHelper.placeholder_image, - class: 'avatar has-tooltip s16 lazy', + class: 'avatar s16 has-tooltip lazy', alt: "#{options[:user_name]}'s avatar", title: options[:user_name], data: { container: 'body', src: avatar_icon(options[:user_email], 16) } diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index 4b72dbb7964..d5536fcb22b 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -106,5 +106,9 @@ describe EventsHelper do it "handles empty strings" do expect(helper.event_commit_title("")).to eq("") end + + it 'handles nil values' do + expect(helper.event_commit_title(nil)).to eq('') + end end end diff --git a/spec/javascripts/repo/monaco_loader_spec.js b/spec/javascripts/repo/monaco_loader_spec.js index be6e779c50f..887a80160fc 100644 --- a/spec/javascripts/repo/monaco_loader_spec.js +++ b/spec/javascripts/repo/monaco_loader_spec.js @@ -1,17 +1,13 @@ -/* global __webpack_public_path__ */ import monacoContext from 'monaco-editor/dev/vs/loader'; +import monacoLoader from '~/repo/monaco_loader'; describe('MonacoLoader', () => { it('calls require.config and exports require', () => { - spyOn(monacoContext.require, 'config'); - - const monacoLoader = require('~/repo/monaco_loader'); // eslint-disable-line global-require - - expect(monacoContext.require.config).toHaveBeenCalledWith({ + expect(monacoContext.require.getConfig()).toEqual(jasmine.objectContaining({ paths: { vs: `${__webpack_public_path__}monaco-editor/vs`, // eslint-disable-line camelcase }, - }); - expect(monacoLoader.default).toBe(monacoContext.require); + })); + expect(monacoLoader).toBe(monacoContext.require); }); }); diff --git a/spec/lib/gitlab/bare_repository_importer_spec.rb b/spec/lib/gitlab/bare_repository_importer_spec.rb new file mode 100644 index 00000000000..892f2dafc96 --- /dev/null +++ b/spec/lib/gitlab/bare_repository_importer_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe Gitlab::BareRepositoryImporter, repository: true do + subject(:importer) { described_class.new('default', project_path) } + let(:project_path) { 'a-group/a-sub-group/a-project' } + let!(:admin) { create(:admin) } + + before do + allow(described_class).to receive(:log) + end + + describe '.execute' do + it 'creates a project for a repository in storage' do + FileUtils.mkdir_p(File.join(TestEnv.repos_path, "#{project_path}.git")) + fake_importer = double + + expect(described_class).to receive(:new).with('default', project_path) + .and_return(fake_importer) + expect(fake_importer).to receive(:create_project_if_needed) + + described_class.execute + end + + it 'skips wiki repos' do + FileUtils.mkdir_p(File.join(TestEnv.repos_path, 'the-group', 'the-project.wiki.git')) + + expect(described_class).to receive(:log).with(' * Skipping wiki repo') + expect(described_class).not_to receive(:new) + + described_class.execute + end + end + + describe '#initialize' do + context 'without admin users' do + let(:admin) { nil } + + it 'raises an error' do + expect { importer }.to raise_error(Gitlab::BareRepositoryImporter::NoAdminError) + end + end + end + + describe '#create_project_if_needed' do + it 'starts an import for a project that did not exist' do + expect(importer).to receive(:create_project) + + importer.create_project_if_needed + end + + it 'skips importing when the project already exists' do + group = create(:group, path: 'a-group') + subgroup = create(:group, path: 'a-sub-group', parent: group) + project = create(:project, path: 'a-project', namespace: subgroup) + + expect(importer).not_to receive(:create_project) + expect(importer).to receive(:log).with(" * #{project.name} (a-group/a-sub-group/a-project) exists") + + importer.create_project_if_needed + end + + it 'creates a project with the correct path in the database' do + importer.create_project_if_needed + + expect(Project.find_by_full_path(project_path)).not_to be_nil + end + end +end diff --git a/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb b/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb index 12366151f44..c708b15853a 100644 --- a/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb +++ b/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Git::Storage::ForkedStorageCheck, skip_database_cleaner: true do +describe Gitlab::Git::Storage::ForkedStorageCheck, broken_storage: true, skip_database_cleaner: true do let(:existing_path) do existing_path = TestEnv.repos_path FileUtils.mkdir_p(existing_path) diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb index 2eaf4222964..f32fe5d8150 100644 --- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb @@ -140,4 +140,29 @@ describe Gitlab::GitalyClient::CommitService do described_class.new(repository).find_commit(revision) end end + + describe '#patch' do + let(:request) do + Gitaly::CommitPatchRequest.new( + repository: repository_message, revision: revision + ) + end + let(:response) { [double(data: "my "), double(data: "diff")] } + + subject { described_class.new(repository).patch(revision) } + + it 'sends an RPC request' do + expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_patch) + .with(request, kind_of(Hash)).and_return([]) + + subject + end + + it 'concatenates the responses data' do + allow_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_patch) + .with(request, kind_of(Hash)).and_return(response) + + expect(subject).to eq("my diff") + end + end end diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 4e631e13410..331b7cf2fea 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -2522,7 +2522,7 @@ "id": 27, "target_branch": "feature", "source_branch": "feature_conflict", - "source_project_id": 5, + "source_project_id": 999, "author_id": 1, "assignee_id": null, "title": "MR1", @@ -2536,6 +2536,9 @@ "position": 0, "updated_by_id": null, "merge_error": null, + "diff_head_sha": "HEAD", + "source_branch_sha": "ABCD", + "target_branch_sha": "DCBA", "merge_params": { "force_remove_source_branch": null }, diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 956f1d56eb4..c10427d798f 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -10,6 +10,13 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do @shared = Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') allow(@shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/') @project = create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') + + allow(@project.repository).to receive(:fetch_ref).and_return(true) + allow(@project.repository.raw).to receive(:rugged_branch_exists?).and_return(false) + + expect_any_instance_of(Gitlab::Git::Repository).to receive(:create_branch).with('feature', 'DCBA') + allow_any_instance_of(Gitlab::Git::Repository).to receive(:create_branch) + project_tree_restorer = described_class.new(user: @user, shared: @shared, project: @project) @restored_project_json = project_tree_restorer.restore end diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index a278f89c1a1..065b0ec6658 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -11,6 +11,8 @@ describe Gitlab::ImportExport::ProjectTreeSaver do before do project.team << [user, :master] allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) + allow_any_instance_of(MergeRequest).to receive(:source_branch_sha).and_return('ABCD') + allow_any_instance_of(MergeRequest).to receive(:target_branch_sha).and_return('DCBA') end after do @@ -43,6 +45,14 @@ describe Gitlab::ImportExport::ProjectTreeSaver do expect(saved_project_json['merge_requests'].first['milestone']).not_to be_empty end + it 'has merge request\'s source branch SHA' do + expect(saved_project_json['merge_requests'].first['source_branch_sha']).to eq('ABCD') + end + + it 'has merge request\'s target branch SHA' do + expect(saved_project_json['merge_requests'].first['target_branch_sha']).to eq('DCBA') + end + it 'has events' do expect(saved_project_json['merge_requests'].first['milestone']['events']).not_to be_empty end diff --git a/spec/lib/gitlab/job_waiter_spec.rb b/spec/lib/gitlab/job_waiter_spec.rb index 6186cec2689..b0b4fdc09bc 100644 --- a/spec/lib/gitlab/job_waiter_spec.rb +++ b/spec/lib/gitlab/job_waiter_spec.rb @@ -1,30 +1,39 @@ require 'spec_helper' describe Gitlab::JobWaiter do - describe '#wait' do - let(:waiter) { described_class.new(%w(a)) } - it 'returns when all jobs have been completed' do - expect(Gitlab::SidekiqStatus).to receive(:all_completed?).with(%w(a)) - .and_return(true) + describe '.notify' do + it 'pushes the jid to the named queue' do + key = 'gitlab:job_waiter:foo' + jid = 1 - expect(waiter).not_to receive(:sleep) + redis = double('redis') + expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis) + expect(redis).to receive(:lpush).with(key, jid) - waiter.wait + described_class.notify(key, jid) end + end + + describe '#wait' do + let(:waiter) { described_class.new(2) } - it 'sleeps between checking the job statuses' do - expect(Gitlab::SidekiqStatus).to receive(:all_completed?) - .with(%w(a)) - .and_return(false, true) + it 'returns when all jobs have been completed' do + described_class.notify(waiter.key, 'a') + described_class.notify(waiter.key, 'b') - expect(waiter).to receive(:sleep).with(described_class::INTERVAL) + result = nil + expect { Timeout.timeout(1) { result = waiter.wait(2) } }.not_to raise_error - waiter.wait + expect(result).to contain_exactly('a', 'b') end - it 'returns when timing out' do - expect(waiter).not_to receive(:sleep) - waiter.wait(0) + it 'times out if not all jobs complete' do + described_class.notify(waiter.key, 'a') + + result = nil + expect { Timeout.timeout(2) { result = waiter.wait(1) } }.not_to raise_error + + expect(result).to contain_exactly('a') end end end diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb index d17d440d833..d9ddb4326be 100644 --- a/spec/lib/gitlab/ldap/adapter_spec.rb +++ b/spec/lib/gitlab/ldap/adapter_spec.rb @@ -16,7 +16,7 @@ describe Gitlab::LDAP::Adapter do expect(adapter).to receive(:ldap_search) do |arg| expect(arg[:filter].to_s).to eq('(uid=johndoe)') expect(arg[:base]).to eq('dc=example,dc=com') - expect(arg[:attributes]).to match(%w{uid cn dn uid userid sAMAccountName mail email userPrincipalName}) + expect(arg[:attributes]).to match(%w{dn uid cn mail email userPrincipalName}) end.and_return({}) adapter.users('uid', 'johndoe') @@ -26,7 +26,7 @@ describe Gitlab::LDAP::Adapter do expect(adapter).to receive(:ldap_search).with( base: 'uid=johndoe,ou=users,dc=example,dc=com', scope: Net::LDAP::SearchScope_BaseObject, - attributes: %w{uid cn dn uid userid sAMAccountName mail email userPrincipalName}, + attributes: %w{dn uid cn mail email userPrincipalName}, filter: nil ).and_return({}) @@ -63,7 +63,7 @@ describe Gitlab::LDAP::Adapter do it 'uses the right uid attribute when non-default' do stub_ldap_config(uid: 'sAMAccountName') expect(adapter).to receive(:ldap_search).with( - hash_including(attributes: %w{sAMAccountName cn dn uid userid sAMAccountName mail email userPrincipalName}) + hash_including(attributes: %w{dn sAMAccountName cn mail email userPrincipalName}) ).and_return({}) adapter.users('sAMAccountName', 'johndoe') diff --git a/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb b/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb index 12cac1d033d..b47f3314926 100644 --- a/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb +++ b/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb @@ -4,7 +4,7 @@ require Rails.root.join('db', 'post_migrate', '20170502101023_cleanup_namespacel describe CleanupNamespacelessPendingDeleteProjects do before do # Stub after_save callbacks that will fail when Project has no namespace - allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil) + allow_any_instance_of(Project).to receive(:ensure_storage_path_exists).and_return(nil) allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil) end diff --git a/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb b/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb new file mode 100644 index 00000000000..7879105a334 --- /dev/null +++ b/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb') + +describe CleanupNonexistingNamespacePendingDeleteProjects do + before do + # Stub after_save callbacks that will fail when Project has invalid namespace + allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil) + allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil) + end + + describe '#up' do + set(:some_project) { create(:project) } + + it 'only cleans up when namespace does not exist' do + create(:project, pending_delete: true) + project = build(:project, pending_delete: true, namespace: nil, namespace_id: Namespace.maximum(:id).to_i.succ) + project.save(validate: false) + + expect(NamespacelessProjectDestroyWorker).to receive(:bulk_perform_async).with([[project.id]]) + + described_class.new.up + end + + it 'does nothing when no pending delete projects without namespace found' do + create(:project, pending_delete: true, namespace: create(:namespace)) + + expect(NamespacelessProjectDestroyWorker).not_to receive(:bulk_perform_async) + + described_class.new.up + end + end +end diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb index 3369aef1d3e..461e754dc1f 100644 --- a/spec/models/broadcast_message_spec.rb +++ b/spec/models/broadcast_message_spec.rb @@ -53,6 +53,29 @@ describe BroadcastMessage do 2.times { described_class.current } end + + it 'includes messages that need to be displayed in the future' do + create(:broadcast_message) + + future = create( + :broadcast_message, + starts_at: Time.now + 10.minutes, + ends_at: Time.now + 20.minutes + ) + + expect(described_class.current.length).to eq(1) + + Timecop.travel(future.starts_at) do + expect(described_class.current.length).to eq(2) + end + end + + it 'does not clear the cache if only a future message should be displayed' do + create(:broadcast_message, :future) + + expect(Rails.cache).not_to receive(:delete) + expect(described_class.current.length).to eq(0) + end end describe '#active?' do diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index ff3224dd298..f55c161c821 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -304,6 +304,50 @@ describe Event do end end + describe '#body?' do + let(:push_event) do + event = build(:push_event) + + allow(event).to receive(:push?).and_return(true) + + event + end + + it 'returns true for a push event with commits' do + allow(push_event).to receive(:push_with_commits?).and_return(true) + + expect(push_event).to be_body + end + + it 'returns false for a push event without a valid commit range' do + allow(push_event).to receive(:push_with_commits?).and_return(false) + + expect(push_event).not_to be_body + end + + it 'returns true for a Note event' do + event = build(:event) + + allow(event).to receive(:note?).and_return(true) + + expect(event).to be_body + end + + it 'returns true if the target responds to #title' do + event = build(:event) + + allow(event).to receive(:target).and_return(double(:target, title: 'foo')) + + expect(event).to be_body + end + + it 'returns false for a regular event without a target' do + event = build(:event) + + expect(event).not_to be_body + end + end + def create_push_event(project, user) event = create(:push_event, project: project, author: user) diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 9203f6562f2..de86788d142 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -751,4 +751,22 @@ describe Issue do end end end + + describe 'removing an issue' do + it 'refreshes the number of open issues of the project' do + project = subject.project + + expect { subject.destroy } + .to change { project.open_issues_count }.from(1).to(0) + end + end + + describe '.public_only' do + it 'only returns public issues' do + public_issue = create(:issue) + create(:issue, confidential: true) + + expect(described_class.public_only).to eq([public_issue]) + end + end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 026bdbd26d1..1c72513520d 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1692,4 +1692,13 @@ describe MergeRequest do expect(subject.ref_fetched?).to be_falsey end end + + describe 'removing a merge request' do + it 'refreshes the number of open merge requests of the target project' do + project = subject.target_project + + expect { subject.destroy } + .to change { project.open_merge_requests_count }.from(1).to(0) + end + end end diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 55b96a0c12e..b1743cd608e 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -38,7 +38,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do 'a' * 63 => true, 'a' * 64 => false, 'a.b' => false, - 'a*b' => false + 'a*b' => false, + 'FOO' => true }.each do |namespace, validity| it "validates #{namespace} as #{validity ? 'valid' : 'invalid'}" do subject.namespace = namespace diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 5e60511f3a8..2e613c44357 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1251,60 +1251,6 @@ describe Project do end end - describe '#rename_repo' do - let(:project) { create(:project, :repository) } - let(:gitlab_shell) { Gitlab::Shell.new } - - before do - # Project#gitlab_shell returns a new instance of Gitlab::Shell on every - # call. This makes testing a bit easier. - allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) - allow(project).to receive(:previous_changes).and_return('path' => ['foo']) - end - - it 'renames a repository' do - stub_container_registry_config(enabled: false) - - expect(gitlab_shell).to receive(:mv_repository) - .ordered - .with(project.repository_storage_path, "#{project.namespace.full_path}/foo", "#{project.full_path}") - .and_return(true) - - expect(gitlab_shell).to receive(:mv_repository) - .ordered - .with(project.repository_storage_path, "#{project.namespace.full_path}/foo.wiki", "#{project.full_path}.wiki") - .and_return(true) - - expect_any_instance_of(SystemHooksService) - .to receive(:execute_hooks_for) - .with(project, :rename) - - expect_any_instance_of(Gitlab::UploadsTransfer) - .to receive(:rename_project) - .with('foo', project.path, project.namespace.full_path) - - expect(project).to receive(:expire_caches_before_rename) - - expect(project).to receive(:expires_full_path_cache) - - project.rename_repo - end - - context 'container registry with images' do - let(:container_repository) { create(:container_repository) } - - before do - stub_container_registry_config(enabled: true) - stub_container_registry_tags(repository: :any, tags: ['tag']) - project.container_repositories << container_repository - end - - subject { project.rename_repo } - - it { expect {subject}.to raise_error(StandardError) } - end - end - describe '#expire_caches_before_rename' do let(:project) { create(:project, :repository) } let(:repo) { double(:repo, exists?: true) } @@ -2367,4 +2313,181 @@ describe Project do expect(project.forks_count).to eq(1) end end + + context 'legacy storage' do + let(:project) { create(:project, :repository) } + let(:gitlab_shell) { Gitlab::Shell.new } + + before do + allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) + end + + describe '#base_dir' do + it 'returns base_dir based on namespace only' do + expect(project.base_dir).to eq(project.namespace.full_path) + end + end + + describe '#disk_path' do + it 'returns disk_path based on namespace and project path' do + expect(project.disk_path).to eq("#{project.namespace.full_path}/#{project.path}") + end + end + + describe '#ensure_storage_path_exists' do + it 'delegates to gitlab_shell to ensure namespace is created' do + expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, project.base_dir) + + project.ensure_storage_path_exists + end + end + + describe '#legacy_storage?' do + it 'returns true when storage_version is nil' do + project = build(:project) + + expect(project.legacy_storage?).to be_truthy + end + end + + describe '#rename_repo' do + before do + # Project#gitlab_shell returns a new instance of Gitlab::Shell on every + # call. This makes testing a bit easier. + allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) + allow(project).to receive(:previous_changes).and_return('path' => ['foo']) + end + + it 'renames a repository' do + stub_container_registry_config(enabled: false) + + expect(gitlab_shell).to receive(:mv_repository) + .ordered + .with(project.repository_storage_path, "#{project.namespace.full_path}/foo", "#{project.full_path}") + .and_return(true) + + expect(gitlab_shell).to receive(:mv_repository) + .ordered + .with(project.repository_storage_path, "#{project.namespace.full_path}/foo.wiki", "#{project.full_path}.wiki") + .and_return(true) + + expect_any_instance_of(SystemHooksService) + .to receive(:execute_hooks_for) + .with(project, :rename) + + expect_any_instance_of(Gitlab::UploadsTransfer) + .to receive(:rename_project) + .with('foo', project.path, project.namespace.full_path) + + expect(project).to receive(:expire_caches_before_rename) + + expect(project).to receive(:expires_full_path_cache) + + project.rename_repo + end + + context 'container registry with images' do + let(:container_repository) { create(:container_repository) } + + before do + stub_container_registry_config(enabled: true) + stub_container_registry_tags(repository: :any, tags: ['tag']) + project.container_repositories << container_repository + end + + subject { project.rename_repo } + + it { expect { subject }.to raise_error(StandardError) } + end + end + + describe '#pages_path' do + it 'returns a path where pages are stored' do + expect(project.pages_path).to eq(File.join(Settings.pages.path, project.namespace.full_path, project.path)) + end + end + end + + context 'hashed storage' do + let(:project) { create(:project, :repository) } + let(:gitlab_shell) { Gitlab::Shell.new } + let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } + + before do + stub_application_setting(hashed_storage_enabled: true) + allow(Digest::SHA2).to receive(:hexdigest) { hash } + allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) + end + + describe '#base_dir' do + it 'returns base_dir based on hash of project id' do + expect(project.base_dir).to eq('@hashed/6b/86') + end + end + + describe '#disk_path' do + it 'returns disk_path based on hash of project id' do + hashed_path = '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' + + expect(project.disk_path).to eq(hashed_path) + end + end + + describe '#ensure_storage_path_exists' do + it 'delegates to gitlab_shell to ensure namespace is created' do + expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, '@hashed/6b/86') + + project.ensure_storage_path_exists + end + end + + describe '#rename_repo' do + before do + # Project#gitlab_shell returns a new instance of Gitlab::Shell on every + # call. This makes testing a bit easier. + allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) + allow(project).to receive(:previous_changes).and_return('path' => ['foo']) + end + + it 'renames a repository' do + stub_container_registry_config(enabled: false) + + expect(gitlab_shell).not_to receive(:mv_repository) + + expect_any_instance_of(SystemHooksService) + .to receive(:execute_hooks_for) + .with(project, :rename) + + expect_any_instance_of(Gitlab::UploadsTransfer) + .to receive(:rename_project) + .with('foo', project.path, project.namespace.full_path) + + expect(project).to receive(:expire_caches_before_rename) + + expect(project).to receive(:expires_full_path_cache) + + project.rename_repo + end + + context 'container registry with images' do + let(:container_repository) { create(:container_repository) } + + before do + stub_container_registry_config(enabled: true) + stub_container_registry_tags(repository: :any, tags: ['tag']) + project.container_repositories << container_repository + end + + subject { project.rename_repo } + + it { expect { subject }.to raise_error(StandardError) } + end + end + + describe '#pages_path' do + it 'returns a path where pages are stored' do + expect(project.pages_path).to eq(File.join(Settings.pages.path, project.namespace.full_path, project.path)) + end + end + end end diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index b17a93e3fbe..7f832bfa563 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -105,6 +105,8 @@ describe GroupPolicy do let(:current_user) { owner } it do + allow(Group).to receive(:supports_nested_groups?).and_return(true) + expect_allowed(:read_group) expect_allowed(*reporter_permissions) expect_allowed(*master_permissions) @@ -116,6 +118,8 @@ describe GroupPolicy do let(:current_user) { admin } it do + allow(Group).to receive(:supports_nested_groups?).and_return(true) + expect_allowed(:read_group) expect_allowed(*reporter_permissions) expect_allowed(*master_permissions) @@ -123,6 +127,36 @@ describe GroupPolicy do end end + describe 'when nested group support feature is disabled' do + before do + allow(Group).to receive(:supports_nested_groups?).and_return(false) + end + + context 'admin' do + let(:current_user) { admin } + + it 'allows every owner permission except creating subgroups' do + create_subgroup_permission = [:create_subgroup] + updated_owner_permissions = owner_permissions - create_subgroup_permission + + expect_disallowed(*create_subgroup_permission) + expect_allowed(*updated_owner_permissions) + end + end + + context 'owner' do + let(:current_user) { owner } + + it 'allows every owner permission except creating subgroups' do + create_subgroup_permission = [:create_subgroup] + updated_owner_permissions = owner_permissions - create_subgroup_permission + + expect_disallowed(*create_subgroup_permission) + expect_allowed(*updated_owner_permissions) + end + end + end + describe 'private nested group use the highest access level from the group and inherited permissions', :nested_groups do let(:nested_group) { create(:group, :private, parent: group) } @@ -199,6 +233,8 @@ describe GroupPolicy do let(:current_user) { owner } it do + allow(Group).to receive(:supports_nested_groups?).and_return(true) + expect_allowed(:read_group) expect_allowed(*reporter_permissions) expect_allowed(*master_permissions) diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb index b2175717a70..10dda45d2a1 100644 --- a/spec/services/groups/create_service_spec.rb +++ b/spec/services/groups/create_service_spec.rb @@ -22,7 +22,7 @@ describe Groups::CreateService, '#execute' do end end - describe 'creating subgroup' do + describe 'creating subgroup', :nested_groups do let!(:group) { create(:group) } let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) } @@ -32,12 +32,24 @@ describe Groups::CreateService, '#execute' do end it { is_expected.to be_persisted } + + context 'when nested groups feature is disabled' do + it 'does not save group and returns an error' do + allow(Group).to receive(:supports_nested_groups?).and_return(false) + + is_expected.not_to be_persisted + expect(subject.errors[:parent_id]).to include('You don’t have permission to create a subgroup in this group.') + expect(subject.parent_id).to be_nil + end + end end context 'as guest' do it 'does not save group and returns an error' do + allow(Group).to receive(:supports_nested_groups?).and_return(true) + is_expected.not_to be_persisted - expect(subject.errors[:parent_id].first).to eq('manage access required to create subgroup') + expect(subject.errors[:parent_id].first).to eq('You don’t have permission to create a subgroup in this group.') expect(subject.parent_id).to be_nil end end diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb index 1b2ce3cd03e..ac4b9c02ba7 100644 --- a/spec/services/groups/destroy_service_spec.rb +++ b/spec/services/groups/destroy_service_spec.rb @@ -8,8 +8,8 @@ describe Groups::DestroyService do let!(:nested_group) { create(:group, parent: group) } let!(:project) { create(:project, namespace: group) } let!(:notification_setting) { create(:notification_setting, source: group)} - let!(:gitlab_shell) { Gitlab::Shell.new } - let!(:remove_path) { group.path + "+#{group.id}+deleted" } + let(:gitlab_shell) { Gitlab::Shell.new } + let(:remove_path) { group.path + "+#{group.id}+deleted" } before do group.add_user(user, Gitlab::Access::OWNER) @@ -134,4 +134,26 @@ describe Groups::DestroyService do it_behaves_like 'group destruction', false end + + describe 'repository removal' do + before do + destroy_group(group, user, false) + end + + context 'legacy storage' do + let!(:project) { create(:project, :empty_repo, namespace: group) } + + it 'removes repository' do + expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_falsey + end + end + + context 'hashed storage' do + let!(:project) { create(:project, :hashed, :empty_repo, namespace: group) } + + it 'removes repository' do + expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_falsey + end + end + end end diff --git a/spec/services/groups/nested_create_service_spec.rb b/spec/services/groups/nested_create_service_spec.rb new file mode 100644 index 00000000000..c1526456bac --- /dev/null +++ b/spec/services/groups/nested_create_service_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe Groups::NestedCreateService do + let(:user) { create(:user) } + let(:params) { { group_path: 'a-group/a-sub-group' } } + + subject(:service) { described_class.new(user, params) } + + describe "#execute" do + it 'returns the group if it already existed' do + parent = create(:group, path: 'a-group', owner: user) + child = create(:group, path: 'a-sub-group', parent: parent, owner: user) + + expect(service.execute).to eq(child) + end + + it 'reuses a parent if it already existed' do + parent = create(:group, path: 'a-group') + parent.add_owner(user) + + expect(service.execute.parent).to eq(parent) + end + + it 'creates group and subgroup in the database' do + service.execute + + parent = Group.find_by_full_path('a-group') + child = parent.children.find_by(path: 'a-sub-group') + + expect(parent).not_to be_nil + expect(child).not_to be_nil + end + + it 'creates the group with correct visibility level' do + allow(Gitlab::CurrentSettings.current_application_settings) + .to receive(:default_group_visibility) { Gitlab::VisibilityLevel::INTERNAL } + + group = service.execute + + expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) + end + + context 'adding a visibility level ' do + let(:params) { { group_path: 'a-group/a-sub-group', visibility_level: Gitlab::VisibilityLevel::PRIVATE } } + + it 'overwrites the visibility level' do + group = service.execute + + expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + end + end +end diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb index a03f68434de..171f70c32a8 100644 --- a/spec/services/issues/close_service_spec.rb +++ b/spec/services/issues/close_service_spec.rb @@ -42,6 +42,11 @@ describe Issues::CloseService do service.execute(issue) end + it 'refreshes the number of open issues' do + expect { service.execute(issue) } + .to change { project.open_issues_count }.from(1).to(0) + end + it 'invalidates counter cache for assignees' do expect_any_instance_of(User).to receive(:invalidate_issue_cache_counts) diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index 9b2d9e79f4f..78b11cd7991 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -35,6 +35,10 @@ describe Issues::CreateService do expect(issue.due_date).to eq Date.tomorrow end + it 'refreshes the number of open issues' do + expect { issue }.to change { project.open_issues_count }.from(0).to(1) + end + context 'when current user cannot admin issues in the project' do let(:guest) { create(:user) } diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb index 205e9ebd237..48fc98b3b2f 100644 --- a/spec/services/issues/reopen_service_spec.rb +++ b/spec/services/issues/reopen_service_spec.rb @@ -34,6 +34,13 @@ describe Issues::ReopenService do described_class.new(project, user).execute(issue) end + it 'refreshes the number of opened issues' do + service = described_class.new(project, user) + + expect { service.execute(issue) } + .to change { project.open_issues_count }.from(0).to(1) + end + context 'when issue is not confidential' do it 'executes issue hooks' do expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks) diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb index 04bf267d167..7e65369762c 100644 --- a/spec/services/merge_requests/close_service_spec.rb +++ b/spec/services/merge_requests/close_service_spec.rb @@ -52,6 +52,13 @@ describe MergeRequests::CloseService do end end + it 'refreshes the number of open merge requests for a valid MR' do + service = described_class.new(project, user, {}) + + expect { service.execute(merge_request) } + .to change { project.open_merge_requests_count }.from(1).to(0) + end + context 'current user is not authorized to close merge request' do before do perform_enqueued_jobs do diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index a1f3bec42cc..d6409c0d625 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -18,31 +18,35 @@ describe MergeRequests::CreateService do end let(:service) { described_class.new(project, user, opts) } + let(:merge_request) { service.execute } before do project.team << [user, :master] project.team << [assignee, :developer] allow(service).to receive(:execute_hooks) - - @merge_request = service.execute end it 'creates an MR' do - expect(@merge_request).to be_valid - expect(@merge_request.title).to eq('Awesome merge_request') - expect(@merge_request.assignee).to be_nil - expect(@merge_request.merge_params['force_remove_source_branch']).to eq('1') + expect(merge_request).to be_valid + expect(merge_request.title).to eq('Awesome merge_request') + expect(merge_request.assignee).to be_nil + expect(merge_request.merge_params['force_remove_source_branch']).to eq('1') end it 'executes hooks with default action' do - expect(service).to have_received(:execute_hooks).with(@merge_request) + expect(service).to have_received(:execute_hooks).with(merge_request) + end + + it 'refreshes the number of open merge requests' do + expect { service.execute } + .to change { project.open_merge_requests_count }.from(0).to(1) end it 'does not creates todos' do attributes = { project: project, - target_id: @merge_request.id, - target_type: @merge_request.class.name + target_id: merge_request.id, + target_type: merge_request.class.name } expect(Todo.where(attributes).count).to be_zero @@ -51,8 +55,8 @@ describe MergeRequests::CreateService do it 'creates exactly 1 create MR event' do attributes = { action: Event::CREATED, - target_id: @merge_request.id, - target_type: @merge_request.class.name + target_id: merge_request.id, + target_type: merge_request.class.name } expect(Event.where(attributes).count).to eq(1) @@ -69,15 +73,15 @@ describe MergeRequests::CreateService do } end - it { expect(@merge_request.assignee).to eq assignee } + it { expect(merge_request.assignee).to eq assignee } it 'creates a todo for new assignee' do attributes = { project: project, author: user, user: assignee, - target_id: @merge_request.id, - target_type: @merge_request.class.name, + target_id: merge_request.id, + target_type: merge_request.class.name, action: Todo::ASSIGNED, state: :pending } diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb index f02af0c582e..fa652611c6b 100644 --- a/spec/services/merge_requests/reopen_service_spec.rb +++ b/spec/services/merge_requests/reopen_service_spec.rb @@ -47,6 +47,13 @@ describe MergeRequests::ReopenService do end end + it 'refreshes the number of open merge requests for a valid MR' do + service = described_class.new(project, user, {}) + + expect { service.execute(merge_request) } + .to change { project.open_merge_requests_count }.from(0).to(1) + end + context 'current user is not authorized to reopen merge request' do before do perform_enqueued_jobs do diff --git a/spec/services/projects/count_service_spec.rb b/spec/services/projects/count_service_spec.rb new file mode 100644 index 00000000000..79b01e7620e --- /dev/null +++ b/spec/services/projects/count_service_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe Projects::CountService do + let(:project) { build(:project, id: 1) } + let(:service) { described_class.new(project) } + + describe '#relation_for_count' do + it 'raises NotImplementedError' do + expect { service.relation_for_count }.to raise_error(NotImplementedError) + end + end + + describe '#count' do + before do + allow(service).to receive(:cache_key_name).and_return('count_service') + end + + it 'returns the number of rows' do + allow(service).to receive(:uncached_count).and_return(1) + + expect(service.count).to eq(1) + end + + it 'caches the number of rows', :use_clean_rails_memory_store_caching do + expect(service).to receive(:uncached_count).once.and_return(1) + + 2.times do + expect(service.count).to eq(1) + end + end + end + + describe '#refresh_cache', :use_clean_rails_memory_store_caching do + before do + allow(service).to receive(:cache_key_name).and_return('count_service') + end + + it 'refreshes the cache' do + expect(service).to receive(:uncached_count).once.and_return(1) + + service.refresh_cache + + expect(service.count).to eq(1) + end + end + + describe '#delete_cache', :use_clean_rails_memory_store_caching do + before do + allow(service).to receive(:cache_key_name).and_return('count_service') + end + + it 'removes the cache' do + expect(service).to receive(:uncached_count).twice.and_return(1) + + service.count + service.delete_cache + service.count + end + end + + describe '#cache_key_name' do + it 'raises NotImplementedError' do + expect { service.cache_key_name }.to raise_error(NotImplementedError) + end + end + + describe '#cache_key' do + it 'returns the cache key as an Array' do + allow(service).to receive(:cache_key_name).and_return('count_service') + expect(service.cache_key).to eq(['projects', 1, 'count_service']) + end + end +end diff --git a/spec/services/projects/forks_count_service_spec.rb b/spec/services/projects/forks_count_service_spec.rb index cf299c5d09b..9f8e7ee18a8 100644 --- a/spec/services/projects/forks_count_service_spec.rb +++ b/spec/services/projects/forks_count_service_spec.rb @@ -1,40 +1,14 @@ require 'spec_helper' describe Projects::ForksCountService do - let(:project) { build(:project, id: 42) } - let(:service) { described_class.new(project) } - describe '#count' do it 'returns the number of forks' do - allow(service).to receive(:uncached_count).and_return(1) - - expect(service.count).to eq(1) - end - - it 'caches the forks count', :use_clean_rails_memory_store_caching do - expect(service).to receive(:uncached_count).once.and_return(1) + project = build(:project, id: 42) + service = described_class.new(project) - 2.times { service.count } - end - end - - describe '#refresh_cache', :use_clean_rails_memory_store_caching do - it 'refreshes the cache' do - expect(service).to receive(:uncached_count).once.and_return(1) - - service.refresh_cache + allow(service).to receive(:uncached_count).and_return(1) expect(service.count).to eq(1) end end - - describe '#delete_cache', :use_clean_rails_memory_store_caching do - it 'removes the cache' do - expect(service).to receive(:uncached_count).twice.and_return(1) - - service.count - service.delete_cache - service.count - end - end end diff --git a/spec/services/projects/open_issues_count_service_spec.rb b/spec/services/projects/open_issues_count_service_spec.rb new file mode 100644 index 00000000000..f964f9972cd --- /dev/null +++ b/spec/services/projects/open_issues_count_service_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe Projects::OpenIssuesCountService do + describe '#count' do + it 'returns the number of open issues' do + project = create(:project) + create(:issue, :opened, project: project) + + expect(described_class.new(project).count).to eq(1) + end + + it 'does not include confidential issues in the issue count' do + project = create(:project) + + create(:issue, :opened, project: project) + create(:issue, :opened, confidential: true, project: project) + + expect(described_class.new(project).count).to eq(1) + end + end +end diff --git a/spec/services/projects/open_merge_requests_count_service_spec.rb b/spec/services/projects/open_merge_requests_count_service_spec.rb new file mode 100644 index 00000000000..9f49b9ec6a2 --- /dev/null +++ b/spec/services/projects/open_merge_requests_count_service_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe Projects::OpenMergeRequestsCountService do + describe '#count' do + it 'returns the number of open merge requests' do + project = create(:project) + create(:merge_request, + :opened, + source_project: project, + target_project: project) + + expect(described_class.new(project).count).to eq(1) + end + end +end diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb index a82567f6f43..58a5bede3de 100644 --- a/spec/services/users/destroy_service_spec.rb +++ b/spec/services/users/destroy_service_spec.rb @@ -4,9 +4,10 @@ describe Users::DestroyService do describe "Deletes a user and all their personal projects" do let!(:user) { create(:user) } let!(:admin) { create(:admin) } - let!(:namespace) { create(:namespace, owner: user) } + let!(:namespace) { user.namespace } let!(:project) { create(:project, namespace: namespace) } let(:service) { described_class.new(admin) } + let(:gitlab_shell) { Gitlab::Shell.new } context 'no options are given' do it 'deletes the user' do @@ -14,7 +15,7 @@ describe Users::DestroyService do expect { user_data['email'].to eq(user.email) } expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound) - expect { Namespace.with_deleted.find(user.namespace.id) }.to raise_error(ActiveRecord::RecordNotFound) + expect { Namespace.with_deleted.find(namespace.id) }.to raise_error(ActiveRecord::RecordNotFound) end it 'will delete the project' do @@ -165,5 +166,27 @@ describe Users::DestroyService do expect(Issue.exists?(issue.id)).to be_falsy end end + + describe "user personal's repository removal" do + before do + Sidekiq::Testing.inline! { service.execute(user) } + end + + context 'legacy storage' do + let!(:project) { create(:project, :empty_repo, namespace: user.namespace) } + + it 'removes repository' do + expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_falsey + end + end + + context 'hashed storage' do + let!(:project) { create(:project, :empty_repo, :hashed, namespace: user.namespace) } + + it 'removes repository' do + expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_falsey + end + end + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c10197ff651..ff1754fbe7e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -105,6 +105,18 @@ RSpec.configure do |config| reset_delivered_emails! end + # Stub the `ForkedStorageCheck.storage_available?` method unless + # `:broken_storage` metadata is defined + # + # This check can be slow and is unnecessary in a test environment where we + # know the storage is available, because we create it at runtime + config.before(:example) do |example| + unless example.metadata[:broken_storage] + allow(Gitlab::Git::Storage::ForkedStorageCheck) + .to receive(:storage_available?).and_return(true) + end + end + config.around(:each, :use_clean_rails_memory_store_caching) do |example| caching_store = Rails.cache Rails.cache = ActiveSupport::Cache::MemoryStore.new diff --git a/spec/workers/authorized_projects_worker_spec.rb b/spec/workers/authorized_projects_worker_spec.rb index 03b9b99e263..f8385ae7c72 100644 --- a/spec/workers/authorized_projects_worker_spec.rb +++ b/spec/workers/authorized_projects_worker_spec.rb @@ -29,21 +29,27 @@ describe AuthorizedProjectsWorker do end describe '#perform' do - subject { described_class.new } + let(:user) { create(:user) } - it "refreshes user's authorized projects" do - user = create(:user) + subject(:job) { described_class.new } + it "refreshes user's authorized projects" do expect_any_instance_of(User).to receive(:refresh_authorized_projects) - subject.perform(user.id) + job.perform(user.id) + end + + it 'notifies the JobWaiter when done if the key is provided' do + expect(Gitlab::JobWaiter).to receive(:notify).with('notify-key', job.jid) + + job.perform(user.id, 'notify-key') end context "when the user is not found" do it "does nothing" do expect_any_instance_of(User).not_to receive(:refresh_authorized_projects) - subject.perform(-1) + job.perform(-1) end end end diff --git a/spec/workers/namespaceless_project_destroy_worker_spec.rb b/spec/workers/namespaceless_project_destroy_worker_spec.rb index f2706254284..20cf580af8a 100644 --- a/spec/workers/namespaceless_project_destroy_worker_spec.rb +++ b/spec/workers/namespaceless_project_destroy_worker_spec.rb @@ -5,7 +5,7 @@ describe NamespacelessProjectDestroyWorker do before do # Stub after_save callbacks that will fail when Project has no namespace - allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil) + allow_any_instance_of(Project).to receive(:ensure_storage_path_exists).and_return(nil) allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil) end @@ -75,5 +75,19 @@ describe NamespacelessProjectDestroyWorker do end end end + + context 'project has non-existing namespace' do + let!(:project) do + project = build(:project, namespace_id: Namespace.maximum(:id).to_i.succ) + project.save(validate: false) + project + end + + it 'deletes the project' do + subject.perform(project.id) + + expect(Project.unscoped.all).not_to include(project) + end + end end end |