diff options
168 files changed, 1131 insertions, 468 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 34348247e91..84f1f115b3c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -61,9 +61,10 @@ update-knapsack: - scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json - rm -f knapsack/*_node_*.json only: - - master - -# Execute all testing suites + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + - master@gitlab/gitlabhq + - master@gitlab/gitlab-ee .use-db: &use-db services: @@ -143,7 +144,10 @@ spinach 9 10: *spinach-knapsack image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.1-git-2.7-phantomjs-2.1" <<: *use-db only: - - master + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + - master@gitlab/gitlabhq + - master@gitlab/gitlab-ee cache: key: "ruby21" paths: @@ -286,7 +290,10 @@ bundler:audit: stage: test <<: *ruby-static-analysis only: - - master + - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + - master@gitlab/gitlabhq + - master@gitlab/gitlab-ee script: - "bundle exec bundle-audit check --update --ignore OSVDB-115941" @@ -297,6 +304,9 @@ migration paths: SETUP_DB: "false" only: - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee + - master@gitlab/gitlabhq + - master@gitlab/gitlab-ee script: - git checkout HEAD . - git fetch --tags diff --git a/CHANGELOG.md b/CHANGELOG.md index 86a37d5bdb1..fe686b9fe8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ entry. ## 8.14.0 (2016-11-22) +- Centralize LDAP config/filter logic. !6606 +- Show random messages when the To Do list is empty. !6818 (Josep Llaneras) +- Fix record not found error on NewNoteWorker processing. !6863 (Oswaldo Ferreira) +- Fix expanding a collapsed diff when converting a symlink to a regular file. !6953 +- Add link to build pipeline within individual build pages. !7082 +- Add api endpoint `/groups/owned`. !7103 (Borja Aparicio) +- Fix no "Register" tab if ldap auth is enabled (#24038). !7274 (Luc Didry) +- Added ability to throttle Sidekiq Jobs. !7292 +- Require projects before creating milestone. !7301 (gfyoung) +- Fix error when using invalid branch name when creating a new pipeline. !7324 +- Fix cache for commit status in commits list to respect branches. !7372 +- Removed gray button styling from todo buttons in sidebars. !7387 +- Fix project records with invalid visibility_level values. !7391 +- Use 'Forking in progress' title when appropriate. !7394 (Philip Karpiak) +- Fix error links in help index page. !7396 (Fu Xu) +- [Fix] Extra divider issue in dropdown. !7398 +- Project download buttons always show. !7405 (Philip Karpiak) +- Give search-input correct padding-right value. !7407 (Philip Karpiak) +- Remove additional padding on right-aligned items in MR widget. !7411 (Didem Acet) +- Fix issue causing Labels not to appear in sidebar on MR page. !7416 (Alex Sanford) +- Fix project Visibility Level selector not using default values. - Use separate email-token for incoming email and revert back the inactive feature. !5914 - Replace jQuery.timeago with timeago.js. !6274 (ClemMakesApps) - Add CI notifications. Who triggered a pipeline would receive an email after the pipeline is succeeded or failed. Users could also update notification settings accordingly. !6342 diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index e7aff2d0cec..9acff45de75 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -141,6 +141,10 @@ &.btn-save { @include btn-outline($white-light, $green-normal, $green-normal, $green-light, $white-light, $green-light); } + + &.btn-remove { + @include btn-outline($white-light, $red-normal, $red-normal, $red-light, $white-light, $red-light); + } } &.btn-gray { diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 5a34132112a..0e0673a72f6 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -63,6 +63,7 @@ header { &:focus, &:active { background-color: $background-color; + color: darken($gl-icon-color, 50%); } .fa-caret-down { @@ -152,7 +153,7 @@ header { padding-right: 20px; margin: 0; font-size: 19px; - max-width: 400px; + max-width: 385px; display: inline-block; line-height: $header-height; font-weight: normal; @@ -191,6 +192,10 @@ header { font-size: 10px; text-align: center; cursor: pointer; + + &:hover { + color: darken($color: $gl-text-color, $amount: 50%); + } } .project-item-select { @@ -218,6 +223,14 @@ header { } } +.page-sidebar-pinned.right-sidebar-expanded { + @media (max-width: $screen-lg-min) { + .header-content .title { + width: 300px; + } + } +} + @media (max-width: $screen-xs-max) { header .container-fluid { font-size: 18px; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index e0d00759c9c..8bf5edfde50 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -252,7 +252,7 @@ $award-emoji-new-btn-icon-color: #dcdcdc; */ $search-input-border-color: rgba(#4688f1, .8); $search-input-focus-shadow-color: $dropdown-input-focus-shadow; -$search-input-width: 244px; +$search-input-width: 220px; $location-badge-color: #aaa; $location-badge-bg: $gray-normal; $location-badge-active-bg: #4f91f8; diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 61fbd7425b7..83ffa0e1d39 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -84,7 +84,8 @@ font-weight: 600; } -.commit { +.commit, +.generic_commit_status { padding: 10px 0; position: relative; @@ -102,7 +103,6 @@ vertical-align: baseline; } - .avatar { margin-left: -46px; } diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 526e9ae5cdd..9bfa1c96a5d 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -141,6 +141,22 @@ ul.notes { } } +.page-sidebar-pinned.right-sidebar-expanded { + @media (max-width: $screen-lg-min) { + .note-header { + .note-headline-light { + display: block; + } + + .note-actions { + position: absolute; + right: 0; + top: 0; + } + } + } +} + // Diff code in discussion view .discussion-body .diff-file { .file-title { diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index bf3cb6e7ad9..881621a2655 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -109,10 +109,6 @@ float: none; } - .api { - color: $code-color; - } - .branch-commit { .branch-name { diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss index b4761df3f23..1a116f6a919 100644 --- a/app/assets/stylesheets/pages/search.scss +++ b/app/assets/stylesheets/pages/search.scss @@ -21,6 +21,11 @@ padding: 4px; width: $search-input-width; line-height: 24px; + + &:hover { + border-color: lighten($dropdown-input-focus-border, 20%); + box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%); + } } .location-text { @@ -28,10 +33,9 @@ } .search-input { - padding-right: 20px; border: none; font-size: 14px; - padding: 0; + padding: 0 20px 0 0; margin-left: 5px; line-height: 25px; width: 98%; @@ -153,6 +157,7 @@ width: 68%; } } + } .search-holder { @@ -229,4 +234,5 @@ &:focus { color: $gl-link-color; } + } diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index 4eca278599f..4b3c71874be 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -7,8 +7,8 @@ class HelpController < ApplicationController @help_index = File.read(Rails.root.join('doc', 'README.md')) # Prefix Markdown links with `help/` unless they already have been - # See http://rubular.com/r/nwwhzH6Z8X - @help_index.gsub!(/(\]\()(?!help\/)([^\)\(]+)(\))/, '\1help/\2\3') + # See http://rubular.com/r/ie2MlpdUMq + @help_index.gsub!(/(\]\()(\/?help\/)?([^\)\(]+\))/, '\1/help/\3') end def show diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 2de8ada3e29..6b9f37983c4 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -4,7 +4,7 @@ class Projects::BranchesController < Projects::ApplicationController # Authorize before_action :require_non_empty_project before_action :authorize_download_code! - before_action :authorize_push_code!, only: [:new, :create, :destroy] + before_action :authorize_push_code!, only: [:new, :create, :destroy, :destroy_all_merged] def index @sort = params[:sort].presence || sort_value_name @@ -62,6 +62,13 @@ class Projects::BranchesController < Projects::ApplicationController end end + def destroy_all_merged + DeleteMergedBranchesService.new(@project, current_user).async_execute + + redirect_to namespace_project_branches_path(@project.namespace, @project), + notice: 'Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.' + end + private def ref diff --git a/app/controllers/projects/lfs_api_controller.rb b/app/controllers/projects/lfs_api_controller.rb index ece49dcd922..2d493276941 100644 --- a/app/controllers/projects/lfs_api_controller.rb +++ b/app/controllers/projects/lfs_api_controller.rb @@ -31,10 +31,6 @@ class Projects::LfsApiController < Projects::GitHttpClientController private - def objects - @objects ||= (params[:objects] || []).to_a - end - def existing_oids @existing_oids ||= begin storage_project.lfs_objects.where(oid: objects.map { |o| o['oid'].to_s }).pluck(:oid) diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index cd4d778e508..92bac149313 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -3,7 +3,7 @@ module AuthHelper FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze def ldap_enabled? - Gitlab.config.ldap.enabled + Gitlab::LDAP::Config.enabled? end def omniauth_enabled? diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index bccf64d1aac..af9087d8326 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -82,6 +82,10 @@ module GitlabRoutingHelper namespace_project_merge_request_path(entity.project.namespace, entity.project, entity, *args) end + def pipeline_path(pipeline, *args) + namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, *args) + end + def milestone_path(entity, *args) namespace_project_milestone_path(entity.project.namespace, entity.project, entity, *args) end diff --git a/app/helpers/lfs_helper.rb b/app/helpers/lfs_helper.rb index d3966ba1f10..2425c3a8bc8 100644 --- a/app/helpers/lfs_helper.rb +++ b/app/helpers/lfs_helper.rb @@ -30,6 +30,10 @@ module LfsHelper ci? || lfs_deploy_token? || user_can_download_code? || build_can_download_code? end + def objects + @objects ||= (params[:objects] || []).to_a + end + def user_can_download_code? has_authentication_ability?(:download_code) && can?(user, :download_code, project) end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index d1e1b45ab43..bf463a3b6bb 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -203,6 +203,10 @@ class ApplicationSetting < ActiveRecord::Base ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url) end + def sidekiq_throttling_column_exists? + ActiveRecord::Base.connection.column_exists?(:application_settings, :sidekiq_throttling_enabled) + end + def domain_whitelist_raw self.domain_whitelist.join("\n") unless self.domain_whitelist.nil? end @@ -256,6 +260,12 @@ class ApplicationSetting < ActiveRecord::Base ensure_health_check_access_token! end + def sidekiq_throttling_enabled? + return false unless sidekiq_throttling_column_exists? + + sidekiq_throttling_enabled + end + private def check_repository_storages diff --git a/app/models/issue.rb b/app/models/issue.rb index adbca510ef7..4a4017003d8 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -266,7 +266,7 @@ class Issue < ActiveRecord::Base def as_json(options = {}) super(options).tap do |json| - json[:subscribed] = subscribed?(options[:user]) if options.has_key?(:user) + json[:subscribed] = subscribed?(options[:user]) if options.has_key?(:user) && options[:user] if options.has_key?(:labels) json[:labels] = labels.as_json( diff --git a/app/models/note.rb b/app/models/note.rb index 2d644b03e4d..9ff5e308ed2 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -7,6 +7,7 @@ class Note < ActiveRecord::Base include Importable include FasterCacheKeys include CacheMarkdownField + include AfterCommitQueue cache_markdown_field :note, pipeline: :note diff --git a/app/models/project.rb b/app/models/project.rb index 94aabafce20..bab2f0c53ca 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -35,6 +35,7 @@ class Project < ActiveRecord::Base default_value_for :builds_enabled, gitlab_config_features.builds default_value_for :wiki_enabled, gitlab_config_features.wiki default_value_for :snippets_enabled, gitlab_config_features.snippets + default_value_for :only_allow_merge_if_all_discussions_are_resolved, false after_create :ensure_dir_exist after_create :create_project_feature, unless: :project_feature @@ -1334,10 +1335,6 @@ class Project < ActiveRecord::Base end end - def only_allow_merge_if_all_discussions_are_resolved - super || false - end - private def pushes_since_gc_redis_key diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb index 34fd5a57b5e..5c53c8f1ee5 100644 --- a/app/models/project_feature.rb +++ b/app/models/project_feature.rb @@ -49,20 +49,14 @@ class ProjectFeature < ActiveRecord::Base end def builds_enabled? - return true unless builds_access_level - builds_access_level > DISABLED end def wiki_enabled? - return true unless wiki_access_level - wiki_access_level > DISABLED end def merge_requests_enabled? - return true unless merge_requests_access_level - merge_requests_access_level > DISABLED end diff --git a/app/services/delete_merged_branches_service.rb b/app/services/delete_merged_branches_service.rb new file mode 100644 index 00000000000..8b8deafedb7 --- /dev/null +++ b/app/services/delete_merged_branches_service.rb @@ -0,0 +1,18 @@ +require_relative 'base_service' + +class DeleteMergedBranchesService < BaseService + def async_execute + DeleteMergedBranchesWorker.perform_async(project.id, current_user.id) + end + + def execute + raise Gitlab::Access::AccessDeniedError unless can?(current_user, :push_code, project) + + branches = project.repository.branch_names + branches = branches.select { |branch| project.repository.merged_to_root_ref?(branch) } + + branches.each do |branch| + DeleteBranchService.new(project, current_user).execute(branch) + end + end +end diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb index 723cc0e6834..e338792412b 100644 --- a/app/services/notes/create_service.rb +++ b/app/services/notes/create_service.rb @@ -26,9 +26,12 @@ module Notes note.note = content end - if !only_commands && note.save + note.run_after_commit do # Finish the harder work in the background - NewNoteWorker.perform_in(2.seconds, note.id, params) + NewNoteWorker.perform_async(note.id) + end + + if !only_commands && note.save todo_service.new_note(note, current_user) end diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml index 5b2465e25ee..472d698486b 100644 --- a/app/views/dashboard/todos/index.html.haml +++ b/app/views/dashboard/todos/index.html.haml @@ -84,7 +84,7 @@ = render "shared/empty_states/todos_all_done.svg" - if todos_filter_empty? %h4.text-center - Good job! Looks like you don't have any todos left. + = Gitlab.config.gitlab.no_todos_messages.sample %p.text-center Are you looking for things to do? Take a look at = succeed "," do diff --git a/app/views/projects/boards/components/_sidebar.html.haml b/app/views/projects/boards/components/_sidebar.html.haml index f0c0c6953e0..2125c3387c4 100644 --- a/app/views/projects/boards/components/_sidebar.html.haml +++ b/app/views/projects/boards/components/_sidebar.html.haml @@ -1,5 +1,5 @@ %board-sidebar{ "inline-template" => true, - ":current-user" => "#{current_user.to_json(only: [:username, :id, :name], methods: [:avatar_url]) if current_user}" } + ":current-user" => "#{current_user ? current_user.to_json(only: [:username, :id, :name], methods: [:avatar_url]) : {}}" } %aside.right-sidebar.right-sidebar-expanded.issue-boards-sidebar{ "v-show" => "showSidebar" } .issuable-sidebar .block.issuable-sidebar-header diff --git a/app/views/projects/boards/components/sidebar/_assignee.html.haml b/app/views/projects/boards/components/sidebar/_assignee.html.haml index 604e13858d1..8fe1b832071 100644 --- a/app/views/projects/boards/components/sidebar/_assignee.html.haml +++ b/app/views/projects/boards/components/sidebar/_assignee.html.haml @@ -1,8 +1,8 @@ .block.assignee .title.hide-collapsed Assignee - = icon("spinner spin", class: "block-loading") - if can?(current_user, :admin_issue, @project) + = icon("spinner spin", class: "block-loading") = link_to "Edit", "#", class: "edit-link pull-right" .value.hide-collapsed %span.assign-yourself.no-value{ "v-if" => "!issue.assignee" } diff --git a/app/views/projects/boards/components/sidebar/_due_date.html.haml b/app/views/projects/boards/components/sidebar/_due_date.html.haml index c7da1d0d4ac..1a3b88e28c5 100644 --- a/app/views/projects/boards/components/sidebar/_due_date.html.haml +++ b/app/views/projects/boards/components/sidebar/_due_date.html.haml @@ -1,8 +1,8 @@ .block.due_date .title Due date - = icon("spinner spin", class: "block-loading") - if can?(current_user, :admin_issue, @project) + = icon("spinner spin", class: "block-loading") = link_to "Edit", "#", class: "edit-link pull-right" .value .value-content diff --git a/app/views/projects/boards/components/sidebar/_labels.html.haml b/app/views/projects/boards/components/sidebar/_labels.html.haml index ce68e5e1998..0f0a84c156d 100644 --- a/app/views/projects/boards/components/sidebar/_labels.html.haml +++ b/app/views/projects/boards/components/sidebar/_labels.html.haml @@ -1,8 +1,8 @@ .block.labels .title Labels - = icon("spinner spin", class: "block-loading") - if can?(current_user, :admin_issue, @project) + = icon("spinner spin", class: "block-loading") = link_to "Edit", "#", class: "edit-link pull-right" .value.issuable-show-labels %span.no-value{ "v-if" => "issue.labels && issue.labels.length === 0" } diff --git a/app/views/projects/boards/components/sidebar/_milestone.html.haml b/app/views/projects/boards/components/sidebar/_milestone.html.haml index 3cd20d1c0f7..008d1186478 100644 --- a/app/views/projects/boards/components/sidebar/_milestone.html.haml +++ b/app/views/projects/boards/components/sidebar/_milestone.html.haml @@ -1,8 +1,8 @@ .block.milestone .title Milestone - = icon("spinner spin", class: "block-loading") - if can?(current_user, :admin_issue, @project) + = icon("spinner spin", class: "block-loading") = link_to "Edit", "#", class: "edit-link pull-right" .value %span.no-value{ "v-if" => "!issue.milestone" } diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index 84f38575e84..2246316b540 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -26,6 +26,8 @@ = sort_title_oldest_updated - if can? current_user, :push_code, @project + = link_to namespace_project_merged_branches_path(@project.namespace, @project), class: 'btn btn-inverted btn-remove has-tooltip', title: "Delete all branches that are merged into '#{@project.repository.root_ref}'", method: :delete, data: { confirm: "Deleting the merged branches cannot be undone. Are you sure?", container: 'body' } do + Delete merged branches = link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do New branch diff --git a/app/views/projects/builds/_header.html.haml b/app/views/projects/builds/_header.html.haml index 3f2ce7377fd..9f69bd64f71 100644 --- a/app/views/projects/builds/_header.html.haml +++ b/app/views/projects/builds/_header.html.haml @@ -3,6 +3,9 @@ = ci_status_with_icon(@build.status) Build %strong ##{@build.id} + in pipeline + = link_to pipeline_path(@build.pipeline) do + %strong ##{@build.pipeline.id} for commit = link_to ci_status_path(@build.pipeline) do %strong= @build.pipeline.short_sha diff --git a/app/views/projects/builds/_table.html.haml b/app/views/projects/builds/_table.html.haml index 36294c89fa8..028664f5bba 100644 --- a/app/views/projects/builds/_table.html.haml +++ b/app/views/projects/builds/_table.html.haml @@ -10,6 +10,7 @@ %tr %th Status %th Build + %th Pipeline - if admin %th Project %th Runner @@ -19,6 +20,6 @@ %th Coverage %th - = render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: admin || project.build_coverage_enabled?, admin: admin } + = render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, pipeline_link: true, stage: true, allow_retry: true, coverage: admin || project.build_coverage_enabled?, admin: admin } = paginate builds, theme: 'gitlab' diff --git a/app/views/projects/buttons/_download.html.haml b/app/views/projects/buttons/_download.html.haml index 7e83a88913a..7b995bd8735 100644 --- a/app/views/projects/buttons/_download.html.haml +++ b/app/views/projects/buttons/_download.html.haml @@ -1,5 +1,5 @@ - if !project.empty_repo? && can?(current_user, :download_code, project) - %span{class: 'hidden-xs hidden-sm download-button'} + %span{class: 'download-button'} .dropdown.inline %button.btn{ 'data-toggle' => 'dropdown' } = icon('download') diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 94632056b15..8d9c15d0dc6 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -2,6 +2,7 @@ - ref = local_assigns.fetch(:ref, nil) - commit_sha = local_assigns.fetch(:commit_sha, nil) - retried = local_assigns.fetch(:retried, false) +- pipeline_link = local_assigns.fetch(:pipeline_link, false) - stage = local_assigns.fetch(:stage, false) - coverage = local_assigns.fetch(:coverage, false) - allow_retry = local_assigns.fetch(:allow_retry, false) @@ -51,6 +52,16 @@ - if build.manual? %span.label.label-info manual + - if pipeline_link + %td + = link_to pipeline_path(build.pipeline) do + %span.pipeline-id ##{build.pipeline.id} + %span by + - if build.pipeline.user + = user_avatar(user: build.pipeline.user, size: 20) + - else + %span.monospace API + - if admin %td - if build.project diff --git a/app/views/projects/commit/_ci_stage.html.haml b/app/views/projects/commit/_ci_stage.html.haml index 6bb900e3fc1..3a3d750439f 100644 --- a/app/views/projects/commit/_ci_stage.html.haml +++ b/app/views/projects/commit/_ci_stage.html.haml @@ -8,8 +8,8 @@ - if stage = stage.titleize - = render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true - = render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true - %tr - %td{colspan: 10} - + = render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, pipeline_link: false, allow_retry: true + = render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, pipeline_link: false, retried: true +%tr + %td{colspan: 10} + diff --git a/app/views/projects/diffs/_content.html.haml b/app/views/projects/diffs/_content.html.haml index c3d2f80544b..6120b2191dd 100644 --- a/app/views/projects/diffs/_content.html.haml +++ b/app/views/projects/diffs/_content.html.haml @@ -25,7 +25,7 @@ - elsif diff_file.renamed_file .nothing-here-block File moved - elsif blob.image? - - old_blob = diff_file.old_blob(diff_commit) + - old_blob = diff_file.old_blob(diff_file.old_content_commit || @base_commit) = render "projects/diffs/image", diff_file: diff_file, old_file: old_blob, file: blob - else .nothing-here-block No preview for this file type diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml index 80fe6be49b0..0b99e9f8756 100644 --- a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml +++ b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml @@ -15,6 +15,16 @@ - if defined?(retried) && retried = icon('warning', class: 'text-warning has-tooltip', title: 'Status was retried.') + - if defined?(pipeline_link) && pipeline_link + %td + = link_to pipeline_path(generic_commit_status.pipeline) do + %span.pipeline-id ##{generic_commit_status.pipeline.id} + %span by + - if generic_commit_status.pipeline.user + = user_avatar(user: generic_commit_status.pipeline.user, size: 20) + - else + %span.monospace API + - if defined?(commit_sha) && commit_sha %td = link_to generic_commit_status.short_sha, namespace_project_commit_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.sha), class: "monospace" diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 932603f03b0..0788924d44a 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -90,7 +90,8 @@ = f.label :visibility_level, class: 'label-light' do Visibility Level = link_to "(?)", help_page_path("public_access/public_access") - = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: @project.visibility_level, form_model: @project) + = render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project + = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4 = link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel' diff --git a/app/workers/delete_merged_branches_worker.rb b/app/workers/delete_merged_branches_worker.rb new file mode 100644 index 00000000000..f870da4ecfd --- /dev/null +++ b/app/workers/delete_merged_branches_worker.rb @@ -0,0 +1,20 @@ +class DeleteMergedBranchesWorker + include Sidekiq::Worker + include DedicatedSidekiqQueue + + def perform(project_id, user_id) + begin + project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + return + end + + user = User.find(user_id) + + begin + DeleteMergedBranchesService.new(project, user).execute + rescue Gitlab::Access::AccessDeniedError + return + end + end +end diff --git a/app/workers/new_note_worker.rb b/app/workers/new_note_worker.rb index c3e62bb88c0..66574d0fd01 100644 --- a/app/workers/new_note_worker.rb +++ b/app/workers/new_note_worker.rb @@ -2,10 +2,12 @@ class NewNoteWorker include Sidekiq::Worker include DedicatedSidekiqQueue - def perform(note_id, note_params) - note = Note.find(note_id) - - NotificationService.new.new_note(note) - Notes::PostProcessService.new(note).execute + def perform(note_id) + if note = Note.find_by(id: note_id) + NotificationService.new.new_note(note) + Notes::PostProcessService.new(note).execute + else + Rails.logger.error("NewNoteWorker: couldn't find note with ID=#{note_id}, skipping job") + end end end diff --git a/changelogs/unreleased/21076-deleted-merged-branches.yml b/changelogs/unreleased/21076-deleted-merged-branches.yml new file mode 100644 index 00000000000..b7fa7f14384 --- /dev/null +++ b/changelogs/unreleased/21076-deleted-merged-branches.yml @@ -0,0 +1,4 @@ +--- +title: Add button to delete all merged branches +merge_request: 6449 +author: Toon Claes diff --git a/changelogs/unreleased/22699-group-permssion-background-migration.yml b/changelogs/unreleased/22699-group-permssion-background-migration.yml deleted file mode 100644 index e8c221b6c42..00000000000 --- a/changelogs/unreleased/22699-group-permssion-background-migration.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix project records with invalid visibility_level values -merge_request: 7391 -author: diff --git a/changelogs/unreleased/24038-fix-no-register-pane-if-ldap.yml b/changelogs/unreleased/24038-fix-no-register-pane-if-ldap.yml deleted file mode 100644 index 53f418b6b18..00000000000 --- a/changelogs/unreleased/24038-fix-no-register-pane-if-ldap.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix no "Register" tab if ldap auth is enabled (#24038) -merge_request: 7274 -author: Luc Didry diff --git a/changelogs/unreleased/24048-dropdown-issue-with-devider.yml b/changelogs/unreleased/24048-dropdown-issue-with-devider.yml deleted file mode 100644 index b889da61957..00000000000 --- a/changelogs/unreleased/24048-dropdown-issue-with-devider.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "[Fix] Extra divider issue in dropdown" -merge_request: 7398 -author: diff --git a/changelogs/unreleased/24279-issue-merge-request-sidebar-todo-button-style-improvement.yml b/changelogs/unreleased/24279-issue-merge-request-sidebar-todo-button-style-improvement.yml deleted file mode 100644 index 72e7110d1b8..00000000000 --- a/changelogs/unreleased/24279-issue-merge-request-sidebar-todo-button-style-improvement.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Removed gray button styling from todo buttons in sidebars -merge_request: 7387 -author: diff --git a/changelogs/unreleased/24369-remove-additional-padding.yml b/changelogs/unreleased/24369-remove-additional-padding.yml deleted file mode 100644 index a6a0b248412..00000000000 --- a/changelogs/unreleased/24369-remove-additional-padding.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove additional padding on right-aligned items in MR widget. -merge_request: 7411 -author: Didem Acet diff --git a/changelogs/unreleased/24397-load-labels-on-mr-tabs.yml b/changelogs/unreleased/24397-load-labels-on-mr-tabs.yml deleted file mode 100644 index 6bfa7fa1a49..00000000000 --- a/changelogs/unreleased/24397-load-labels-on-mr-tabs.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix issue causing Labels not to appear in sidebar on MR page -merge_request: 7416 -author: Alex Sanford diff --git a/changelogs/unreleased/adam-fix-collapsed-diff-symlink-file-conversion.yml b/changelogs/unreleased/adam-fix-collapsed-diff-symlink-file-conversion.yml deleted file mode 100644 index c83558f33d1..00000000000 --- a/changelogs/unreleased/adam-fix-collapsed-diff-symlink-file-conversion.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix expanding a collapsed diff when converting a symlink to a regular file -merge_request: 6953 -author: diff --git a/changelogs/unreleased/feature-api_owned_resource.yml b/changelogs/unreleased/feature-api_owned_resource.yml deleted file mode 100644 index 9c270e4ecf4..00000000000 --- a/changelogs/unreleased/feature-api_owned_resource.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add api endpoint `/groups/owned` -merge_request: 7103 -author: Borja Aparicio diff --git a/changelogs/unreleased/fix-cache-for-commit-status.yml b/changelogs/unreleased/fix-cache-for-commit-status.yml deleted file mode 100644 index eb4e96e75ae..00000000000 --- a/changelogs/unreleased/fix-cache-for-commit-status.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix cache for commit status in commits list to respect branches -merge_request: 7372 -author: diff --git a/changelogs/unreleased/fix-error-when-invalid-branch-for-new-pipeline-used.yml b/changelogs/unreleased/fix-error-when-invalid-branch-for-new-pipeline-used.yml deleted file mode 100644 index ad6aa214f0f..00000000000 --- a/changelogs/unreleased/fix-error-when-invalid-branch-for-new-pipeline-used.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix error when using invalid branch name when creating a new pipeline -merge_request: 7324 -author: diff --git a/changelogs/unreleased/fix_saml_ldap_link.yml b/changelogs/unreleased/fix_saml_ldap_link.yml new file mode 100644 index 00000000000..3b6f26d610e --- /dev/null +++ b/changelogs/unreleased/fix_saml_ldap_link.yml @@ -0,0 +1,5 @@ +--- +title: Omniauth auto link LDAP user falls back to find by DN when user cannot be found + by UID +merge_request: 7002 +author: diff --git a/changelogs/unreleased/forking-in-progress-title.yml b/changelogs/unreleased/forking-in-progress-title.yml deleted file mode 100644 index 4b9684844b3..00000000000 --- a/changelogs/unreleased/forking-in-progress-title.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use 'Forking in progress' title when appropriate -merge_request: 7394 -author: Philip Karpiak diff --git a/changelogs/unreleased/milestone-project-require.yml b/changelogs/unreleased/milestone-project-require.yml deleted file mode 100644 index e43033541c7..00000000000 --- a/changelogs/unreleased/milestone-project-require.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Require projects before creating milestone. -merge_request: 7301 -author: gfyoung diff --git a/changelogs/unreleased/repository-name-emojis b/changelogs/unreleased/repository-name-emojis new file mode 100644 index 00000000000..fe52df8eedc --- /dev/null +++ b/changelogs/unreleased/repository-name-emojis @@ -0,0 +1,4 @@ +--- +title: Added ability to put emojis into repository name +merge_request: 7420 +author: Vincent Composieux diff --git a/changelogs/unreleased/sidekiq-job-throttling.yml b/changelogs/unreleased/sidekiq-job-throttling.yml deleted file mode 100644 index ec4e2051c7e..00000000000 --- a/changelogs/unreleased/sidekiq-job-throttling.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Added ability to throttle Sidekiq Jobs -merge_request: 7292 -author: diff --git a/changelogs/unreleased/stanhu-gitlab-ce-fix-error-500-with-mr-images.yml b/changelogs/unreleased/stanhu-gitlab-ce-fix-error-500-with-mr-images.yml new file mode 100644 index 00000000000..7ca0d5fb19e --- /dev/null +++ b/changelogs/unreleased/stanhu-gitlab-ce-fix-error-500-with-mr-images.yml @@ -0,0 +1,4 @@ +--- +title: Fix Error 500 when creating a merge request that contains an image that was deleted and added +merge_request: 7457 +author: diff --git a/config/database.yml.mysql b/config/database.yml.mysql index a99c50706c5..d9702870249 100644 --- a/config/database.yml.mysql +++ b/config/database.yml.mysql @@ -3,8 +3,8 @@ # production: adapter: mysql2 - encoding: utf8 - collation: utf8_general_ci + encoding: utf8mb4 + collation: utf8mb4_general_ci reconnect: false database: gitlabhq_production pool: 10 @@ -18,8 +18,8 @@ production: # development: adapter: mysql2 - encoding: utf8 - collation: utf8_general_ci + encoding: utf8mb4 + collation: utf8mb4_general_ci reconnect: false database: gitlabhq_development pool: 5 @@ -32,8 +32,8 @@ development: # Do not set this db to the same as development or production. test: &test adapter: mysql2 - encoding: utf8 - collation: utf8_general_ci + encoding: utf8mb4 + collation: utf8mb4_general_ci reconnect: false database: gitlabhq_test pool: 5 diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 9fec2ad6bf7..9ddd1554811 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -215,6 +215,7 @@ Settings.gitlab.default_projects_features['visibility_level'] = Settings.send( Settings.gitlab['domain_whitelist'] ||= [] Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab google_code fogbugz git gitlab_project] Settings.gitlab['trusted_proxies'] ||= [] +Settings.gitlab['no_todos_messages'] ||= YAML.load_file(Rails.root.join('config', 'no_todos_messages.yml')) # # CI diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index a0a8f88584c..f06c4d4ecf2 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -213,22 +213,9 @@ Devise.setup do |config| end if Gitlab::LDAP::Config.enabled? - Gitlab.config.ldap.servers.values.each do |server| - if server['allow_username_or_email_login'] - email_stripping_proc = ->(name) {name.gsub(/@.*\z/, '')} - else - email_stripping_proc = ->(name) {name} - end - - config.omniauth server['provider_name'], - host: server['host'], - base: server['base'], - uid: server['uid'], - port: server['port'], - method: server['method'], - bind_dn: server['bind_dn'], - password: server['password'], - name_proc: email_stripping_proc + Gitlab::LDAP::Config.providers.each do |provider| + ldap_config = Gitlab::LDAP::Config.new(provider) + config.omniauth(provider, ldap_config.omniauth_options) end end diff --git a/config/no_todos_messages.yml b/config/no_todos_messages.yml new file mode 100644 index 00000000000..8372fb4ebe9 --- /dev/null +++ b/config/no_todos_messages.yml @@ -0,0 +1,13 @@ +# When the Todos list on the user's dashboard becomes empty, one of the messages below shows up randomly. +# +# If you come up with a fun one, please feel free to contribute it to GitLab! +# https://about.gitlab.com/contributing/ + +--- +- Good job! Looks like you don't have any todos left. +- Coffee really tastes better without any todos left. +- Isn't an empty To Do list beautiful? +- Time for a rewarding coffee break +- Give yourself a pat on the back! +- High five! +- Hence forth you shall be known as 'Todo Destroyer'
\ No newline at end of file diff --git a/config/routes/project.rb b/config/routes/project.rb index 82defb0ba71..9cf8465dca8 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -125,6 +125,7 @@ resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: end resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } + delete :merged_branches, controller: 'branches', action: :destroy_all_merged resources :tags, only: [:index, :show, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } do resource :release, only: [:edit, :update] end diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 0aec8aedf72..f3531dd30a5 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -34,6 +34,7 @@ - [project_service, 1] - [clear_database_cache, 1] - [delete_user, 1] + - [delete_merged_branches, 1] - [expire_build_instance_artifacts, 1] - [group_destroy, 1] - [irker, 1] diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example index e5058cebce8..40a16a32359 100644 --- a/config/unicorn.rb.example +++ b/config/unicorn.rb.example @@ -44,7 +44,7 @@ listen "127.0.0.1:8080", :tcp_nopush => true # nuke workers after 30 seconds instead of 60 seconds (the default) # # NOTICE: git push over http depends on this value. -# If you want be able to push huge amount of data to git repository over http +# If you want to be able to push huge amount of data to git repository over http # you will have to increase this value too. # # Example of output if you try to push 1GB repo to GitLab over http. @@ -82,7 +82,7 @@ GC.respond_to?(:copy_on_write_friendly=) and check_client_connection false before_fork do |server, worker| - # the following is highly recomended for Rails + "preload_app true" + # the following is highly recommended for Rails + "preload_app true" # as there's no need for the master process to hold a connection defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md index 537f4f3501d..5602d70f1ef 100644 --- a/doc/administration/high_availability/nfs.md +++ b/doc/administration/high_availability/nfs.md @@ -76,7 +76,7 @@ configuration to move each data location to a subdirectory: user['home'] = '/gitlab-data/home' git_data_dir '/gitlab-data/git-data' gitlab_rails['shared_path'] = '/gitlab-data/shared' -gitlab_rails['uploads_directory'] = "/gitlab-data/uploads" +gitlab_rails['uploads_directory'] = '/gitlab-data/uploads' gitlab_ci['builds_directory'] = '/gitlab-data/builds' ``` diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md index bc424330656..8656b42f274 100644 --- a/doc/administration/high_availability/redis.md +++ b/doc/administration/high_availability/redis.md @@ -48,15 +48,15 @@ Redis. redis['password'] = 'Redis Password' ``` -1. Run `sudo gitlab-ctl reconfigure` to install and configure PostgreSQL. +1. Run `sudo touch /etc/gitlab/skip-auto-migrations` to prevent database migrations + from running on upgrade. Only the primary GitLab application server should + handle migrations. + +1. Run `sudo gitlab-ctl reconfigure` to install and configure Redis. > **Note**: This `reconfigure` step will result in some errors. That's OK - don't be alarmed. -1. Run `touch /etc/gitlab/skip-auto-migrations` to prevent database migrations - from running on upgrade. Only the primary GitLab application server should - handle migrations. - ## Experimental Redis Sentinel support > [Introduced][ce-1877] in GitLab 8.11. diff --git a/doc/api/branches.md b/doc/api/branches.md index 0b5f7778fc7..f68eeb9f86b 100644 --- a/doc/api/branches.md +++ b/doc/api/branches.md @@ -240,3 +240,21 @@ Example response: "branch_name": "newbranch" } ``` + +## Delete merged branches + +Will delete all branches that are merged into the project's default branch. + +``` +DELETE /projects/:id/repository/merged_branches +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer | yes | The ID of a project | + +It returns `200` to indicate deletion of all merged branches was started. + +```bash +curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/repository/merged_branches" +``` diff --git a/doc/development/README.md b/doc/development/README.md index 87306b1501d..f88456a7a7a 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -14,7 +14,7 @@ contributing to documentation. - [SQL Migration Style Guide](migration_style_guide.md) for creating safe SQL migrations - [Testing standards and style guidelines](testing.md) -- [UX guide](ux_guide/README.md) for building GitLab with existing CSS styles and elements +- [UX guide](ux_guide/index.md) for building GitLab with existing CSS styles and elements - [Frontend guidelines](frontend.md) - [SQL guidelines](sql.md) for working with SQL queries - [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md index 3f45a631b3a..1c549844ee1 100644 --- a/doc/gitlab-basics/create-project.md +++ b/doc/gitlab-basics/create-project.md @@ -14,8 +14,8 @@ There are two ways to create a new project in GitLab. 1. Fill out the information: - 1. "Project name" is the name of your project (you can't use spaces, but you - can use hyphens or underscores). + 1. "Project name" is the name of your project (you can't use special characters, + but you can use spaces, hyphens, underscores or even emojis). 1. The "Project description" is optional and will be shown in your project's dashboard so others can briefly understand what your project is about. 1. Select a [visibility level](../public_access/public_access.md). diff --git a/doc/integration/README.md b/doc/integration/README.md index c2fd299db07..ae4387e2577 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -44,11 +44,15 @@ This [resource](http://kb.kerio.com/product/kerio-connect/server-configuration/s has all the information you need to add a certificate to the main trusted chain. This [answer](http://superuser.com/questions/437330/how-do-you-add-a-certificate-authority-ca-to-ubuntu) -at SuperUser also has relevant information. +at Super User also has relevant information. **Omnibus Trusted Chain** -It is enough to concatenate the certificate to the main trusted certificate: +[Install the self signed certificate or custom certificate authorities](http://docs.gitlab.com/omnibus/common_installation_problems/README.html#using-self-signed-certificate-or-custom-certificate-authorities) +in to GitLab Omnibus. + +It is enough to concatenate the certificate to the main trusted certificate +however it may be overwritten during upgrades: ```bash cat jira.pem >> /opt/gitlab/embedded/ssl/certs/cacert.pem diff --git a/doc/user/markdown.md b/doc/user/markdown.md index 7a7a0b864bd..dbc7e0f14e3 100644 --- a/doc/user/markdown.md +++ b/doc/user/markdown.md @@ -590,7 +590,7 @@ Quote break. You can also use raw HTML in your Markdown, and it'll mostly work pretty well. -See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows `span` elements. +See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/1.11.0/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows `span` elements. ```no-highlight <dl> diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb index 87915b19480..ed723b94cfd 100644 --- a/lib/api/access_requests.rb +++ b/lib/api/access_requests.rb @@ -48,7 +48,7 @@ module API put ':id/access_requests/:user_id/approve' do source = find_source(source_type, params[:id]) - member = ::Members::ApproveAccessRequestService.new(source, current_user, declared(params)).execute + member = ::Members::ApproveAccessRequestService.new(source, current_user, declared_params).execute status :created present member.user, with: Entities::Member, member: member diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 21a106387f0..73aed624ea7 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -128,6 +128,18 @@ module API render_api_error!(result[:message], result[:return_code]) end end + + # Delete all merged branches + # + # Parameters: + # id (required) - The ID of a project + # Example Request: + # DELETE /projects/:id/repository/branches/delete_merged + delete ":id/repository/merged_branches" do + DeleteMergedBranchesService.new(user_project, current_user).async_execute + + status(200) + end end end end diff --git a/lib/api/broadcast_messages.rb b/lib/api/broadcast_messages.rb index fb2a4148011..b6281a7f0ac 100644 --- a/lib/api/broadcast_messages.rb +++ b/lib/api/broadcast_messages.rb @@ -36,8 +36,7 @@ module API optional :font, type: String, desc: 'Foreground color' end post do - create_params = declared(params, include_missing: false).to_h - message = BroadcastMessage.create(create_params) + message = BroadcastMessage.create(declared_params(include_missing: false)) if message.persisted? present message, with: Entities::BroadcastMessage @@ -73,9 +72,8 @@ module API end put ':id' do message = find_message - update_params = declared(params, include_missing: false).to_h - if message.update(update_params) + if message.update(declared_params(include_missing: false)) present message, with: Entities::BroadcastMessage else render_validation_error!(message) diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 2f2cf769481..f412e1da1bf 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -53,7 +53,7 @@ module API post ":id/repository/commits" do authorize! :push_code, user_project - attrs = declared(params) + attrs = declared_params attrs[:source_branch] = attrs[:branch_name] attrs[:target_branch] = attrs[:branch_name] attrs[:actions].map! do |action| diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb index 425df2c176a..85360730841 100644 --- a/lib/api/deploy_keys.rb +++ b/lib/api/deploy_keys.rb @@ -82,7 +82,7 @@ module API end post ":id/#{path}/:key_id/enable" do key = ::Projects::EnableDeployKeyService.new(user_project, - current_user, declared(params)).execute + current_user, declared_params).execute if key present key, with: Entities::SSHKey diff --git a/lib/api/environments.rb b/lib/api/environments.rb index 819f80d8365..00c901937b1 100644 --- a/lib/api/environments.rb +++ b/lib/api/environments.rb @@ -32,8 +32,7 @@ module API post ':id/environments' do authorize! :create_environment, user_project - create_params = declared(params, include_parent_namespaces: false).to_h - environment = user_project.environments.create(create_params) + environment = user_project.environments.create(declared_params) if environment.persisted? present environment, with: Entities::Environment @@ -55,8 +54,8 @@ module API authorize! :update_environment, user_project environment = user_project.environments.find(params[:environment_id]) - - update_params = declared(params, include_missing: false).extract!(:name, :external_url).to_h + + update_params = declared_params(include_missing: false).extract!(:name, :external_url) if environment.update(update_params) present environment, with: Entities::Environment else diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 3c9d7b1aaef..6998b6dc039 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -23,6 +23,11 @@ module API warden.try(:authenticate) if %w[GET HEAD].include?(env['REQUEST_METHOD']) end + def declared_params(options = {}) + options = { include_parent_namespaces: false }.merge(options) + declared(params, options).to_h.symbolize_keys + end + def find_user_by_private_token token = private_token return nil unless token.present? diff --git a/lib/api/labels.rb b/lib/api/labels.rb index 97218054f37..652786d4e3e 100644 --- a/lib/api/labels.rb +++ b/lib/api/labels.rb @@ -30,10 +30,7 @@ module API conflict!('Label already exists') if label priority = params.delete(:priority) - label_params = declared(params, - include_parent_namespaces: false, - include_missing: false).to_h - label = user_project.labels.create(label_params) + label = user_project.labels.create(declared_params(include_missing: false)) if label.valid? label.prioritize!(user_project, priority) if priority @@ -77,11 +74,9 @@ module API update_priority = params.key?(:priority) priority = params.delete(:priority) - label_params = declared(params, - include_parent_namespaces: false, - include_missing: false).to_h + label_params = declared_params(include_missing: false) # Rename new name to the actual label attribute name - label_params[:name] = label_params.delete('new_name') if label_params.key?('new_name') + label_params[:name] = label_params.delete(:new_name) if label_params.key?(:new_name) render_validation_error!(label) unless label.update(label_params) diff --git a/lib/api/members.rb b/lib/api/members.rb index b80818f0eb6..2d4d5cedf20 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -120,7 +120,7 @@ module API if member.nil? { message: "Access revoked", id: params[:user_id].to_i } else - ::Members::DestroyService.new(source, current_user, declared(params)).execute + ::Members::DestroyService.new(source, current_user, declared_params).execute present member.user, with: Entities::Member, member: member end diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 8984cf8cdcd..ba4a84275bc 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -62,9 +62,8 @@ module API end post ":id/milestones" do authorize! :admin_milestone, user_project - milestone_params = declared(params, include_parent_namespaces: false) - milestone = ::Milestones::CreateService.new(user_project, current_user, milestone_params).execute + milestone = ::Milestones::CreateService.new(user_project, current_user, declared_params).execute if milestone.valid? present milestone, with: Entities::Milestone @@ -86,9 +85,9 @@ module API end put ":id/milestones/:milestone_id" do authorize! :admin_milestone, user_project - milestone_params = declared(params, include_parent_namespaces: false, include_missing: false) + milestone = user_project.milestones.find(params.delete(:milestone_id)) - milestone = user_project.milestones.find(milestone_params.delete(:milestone_id)) + milestone_params = declared_params(include_missing: false) milestone = ::Milestones::UpdateService.new(user_project, current_user, milestone_params).execute(milestone) if milestone.valid? diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb index a70a7e71073..c5e9b3ad69b 100644 --- a/lib/api/notification_settings.rb +++ b/lib/api/notification_settings.rb @@ -33,10 +33,9 @@ module API begin notification_setting.transaction do new_notification_email = params.delete(:notification_email) - declared_params = declared(params, include_missing: false).to_h current_user.update(notification_email: new_notification_email) if new_notification_email - notification_setting.update(declared_params) + notification_setting.update(declared_params(include_missing: false)) end rescue ArgumentError => e # catch level enum error render_api_error! e.to_s, 400 @@ -81,9 +80,7 @@ module API notification_setting = current_user.notification_settings_for(source) begin - declared_params = declared(params, include_missing: false).to_h - - notification_setting.update(declared_params) + notification_setting.update(declared_params(include_missing: false)) rescue ArgumentError => e # catch level enum error render_api_error! e.to_s, 400 end diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb index eef343c2ac6..2b36ef7c426 100644 --- a/lib/api/project_hooks.rb +++ b/lib/api/project_hooks.rb @@ -51,8 +51,7 @@ module API use :project_hook_properties end post ":id/hooks" do - new_hook_params = declared(params, include_missing: false, include_parent_namespaces: false).to_h - hook = user_project.hooks.new(new_hook_params) + hook = user_project.hooks.new(declared_params(include_missing: false)) if hook.save present hook, with: Entities::ProjectHook @@ -71,12 +70,9 @@ module API use :project_hook_properties end put ":id/hooks/:hook_id" do - hook = user_project.hooks.find(params[:hook_id]) - - new_params = declared(params, include_missing: false, include_parent_namespaces: false).to_h - new_params.delete('hook_id') + hook = user_project.hooks.find(params.delete(:hook_id)) - if hook.update_attributes(new_params) + if hook.update_attributes(declared_params(include_missing: false)) present hook, with: Entities::ProjectHook else error!("Invalid url given", 422) if hook.errors[:url].present? diff --git a/lib/api/runners.rb b/lib/api/runners.rb index 84c19c432b0..b145cce7e3e 100644 --- a/lib/api/runners.rb +++ b/lib/api/runners.rb @@ -57,9 +57,7 @@ module API runner = get_runner(params.delete(:id)) authenticate_update_runner!(runner) - runner_params = declared(params, include_missing: false) - - if runner.update(runner_params) + if runner.update(declared_params(include_missing: false)) present runner, with: Entities::RunnerDetails, current_user: current_user else render_validation_error!(runner) diff --git a/lib/api/subscriptions.rb b/lib/api/subscriptions.rb index c49e2a21b82..00a79c24f96 100644 --- a/lib/api/subscriptions.rb +++ b/lib/api/subscriptions.rb @@ -9,23 +9,20 @@ module API 'labels' => proc { |id| find_project_label(id) }, } + params do + requires :id, type: String, desc: 'The ID of a project' + requires :subscribable_id, type: String, desc: 'The ID of a resource' + end resource :projects do subscribable_types.each do |type, finder| type_singularized = type.singularize - type_id_str = :"#{type_singularized}_id" entity_class = Entities.const_get(type_singularized.camelcase) - # Subscribe to a resource - # - # Parameters: - # id (required) - The ID of a project - # subscribable_id (required) - The ID of a resource - # Example Request: - # POST /projects/:id/labels/:subscribable_id/subscription - # POST /projects/:id/issues/:subscribable_id/subscription - # POST /projects/:id/merge_requests/:subscribable_id/subscription - post ":id/#{type}/:#{type_id_str}/subscription" do - resource = instance_exec(params[type_id_str], &finder) + desc 'Subscribe to a resource' do + success entity_class + end + post ":id/#{type}/:subscribable_id/subscription" do + resource = instance_exec(params[:subscribable_id], &finder) if resource.subscribed?(current_user) not_modified! @@ -35,17 +32,11 @@ module API end end - # Unsubscribe from a resource - # - # Parameters: - # id (required) - The ID of a project - # subscribable_id (required) - The ID of a resource - # Example Request: - # DELETE /projects/:id/labels/:subscribable_id/subscription - # DELETE /projects/:id/issues/:subscribable_id/subscription - # DELETE /projects/:id/merge_requests/:subscribable_id/subscription - delete ":id/#{type}/:#{type_id_str}/subscription" do - resource = instance_exec(params[type_id_str], &finder) + desc 'Unsubscribe from a resource' do + success entity_class + end + delete ":id/#{type}/:subscribable_id/subscription" do + resource = instance_exec(params[:subscribable_id], &finder) if !resource.subscribed?(current_user) not_modified! diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb index b6bfff9f20f..708ec8cfe70 100644 --- a/lib/api/system_hooks.rb +++ b/lib/api/system_hooks.rb @@ -27,7 +27,7 @@ module API optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook" end post do - hook = SystemHook.new declared(params, include_missing: false).to_h + hook = SystemHook.new(declared_params(include_missing: false)) if hook.save present hook, with: Entities::Hook diff --git a/lib/api/tags.rb b/lib/api/tags.rb index bf2a199ce21..cd33f9a9903 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -40,10 +40,9 @@ module API end post ':id/repository/tags' do authorize_push_project - create_params = declared(params) result = CreateTagService.new(user_project, current_user). - execute(create_params[:tag_name], create_params[:ref], create_params[:message], create_params[:release_description]) + execute(params[:tag_name], params[:ref], params[:message], params[:release_description]) if result[:status] == :success present result[:tag], diff --git a/lib/api/users.rb b/lib/api/users.rb index 298c401a816..aea328d2f8f 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -335,7 +335,7 @@ module API requires :id, type: String, desc: 'The user ID' end get ':id/events' do - user = User.find_by(id: declared(params).id) + user = User.find_by(id: params[:id]) not_found!('User') unless user events = user.events. diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 3e33c9399e2..fef652cb975 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -2,7 +2,7 @@ module Ci class GitlabCiYamlProcessor class ValidationError < StandardError; end - include Gitlab::Ci::Config::Node::LegacyValidationHelpers + include Gitlab::Ci::Config::Entry::LegacyValidationHelpers attr_reader :path, :cache, :stages, :jobs diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb index bbfa6cf7d05..06599238d22 100644 --- a/lib/gitlab/ci/config.rb +++ b/lib/gitlab/ci/config.rb @@ -13,7 +13,7 @@ module Gitlab def initialize(config) @config = Loader.new(config).load! - @global = Node::Global.new(@config) + @global = Entry::Global.new(@config) @global.compose! end diff --git a/lib/gitlab/ci/config/node/artifacts.rb b/lib/gitlab/ci/config/entry/artifacts.rb index 844bd2fe998..b756b0d4555 100644 --- a/lib/gitlab/ci/config/node/artifacts.rb +++ b/lib/gitlab/ci/config/entry/artifacts.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a configuration of job artifacts. # - class Artifacts < Entry + class Artifacts < Node include Validatable include Attributable diff --git a/lib/gitlab/ci/config/node/attributable.rb b/lib/gitlab/ci/config/entry/attributable.rb index 221b666f9f6..1c8b55ee4c4 100644 --- a/lib/gitlab/ci/config/node/attributable.rb +++ b/lib/gitlab/ci/config/entry/attributable.rb @@ -1,7 +1,7 @@ module Gitlab module Ci class Config - module Node + module Entry module Attributable extend ActiveSupport::Concern diff --git a/lib/gitlab/ci/config/node/boolean.rb b/lib/gitlab/ci/config/entry/boolean.rb index 84b03ee7832..f3357f85b99 100644 --- a/lib/gitlab/ci/config/node/boolean.rb +++ b/lib/gitlab/ci/config/entry/boolean.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a boolean value. # - class Boolean < Entry + class Boolean < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/cache.rb b/lib/gitlab/ci/config/entry/cache.rb index b4bda2841ac..7653cab668b 100644 --- a/lib/gitlab/ci/config/node/cache.rb +++ b/lib/gitlab/ci/config/entry/cache.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a cache configuration # - class Cache < Entry + class Cache < Node include Configurable ALLOWED_KEYS = %i[key untracked paths] @@ -14,13 +14,13 @@ module Gitlab validates :config, allowed_keys: ALLOWED_KEYS end - node :key, Node::Key, + entry :key, Entry::Key, description: 'Cache key used to define a cache affinity.' - node :untracked, Node::Boolean, + entry :untracked, Entry::Boolean, description: 'Cache all untracked files.' - node :paths, Node::Paths, + entry :paths, Entry::Paths, description: 'Specify which paths should be cached across builds.' end end diff --git a/lib/gitlab/ci/config/node/commands.rb b/lib/gitlab/ci/config/entry/commands.rb index d7657ae314b..65d19db249c 100644 --- a/lib/gitlab/ci/config/node/commands.rb +++ b/lib/gitlab/ci/config/entry/commands.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a job script. # - class Commands < Entry + class Commands < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/configurable.rb b/lib/gitlab/ci/config/entry/configurable.rb index 6b7ab2fdaf2..0f438faeda2 100644 --- a/lib/gitlab/ci/config/node/configurable.rb +++ b/lib/gitlab/ci/config/entry/configurable.rb @@ -1,7 +1,7 @@ module Gitlab module Ci class Config - module Node + module Entry ## # This mixin is responsible for adding DSL, which purpose is to # simplifly process of adding child nodes. @@ -48,8 +48,8 @@ module Gitlab private # rubocop:disable Lint/UselessAccessModifier - def node(key, node, metadata) - factory = Node::Factory.new(node) + def entry(key, entry, metadata) + factory = Entry::Factory.new(entry) .with(description: metadata[:description]) (@nodes ||= {}).merge!(key.to_sym => factory) diff --git a/lib/gitlab/ci/config/node/environment.rb b/lib/gitlab/ci/config/entry/environment.rb index 9a95ef43628..b7b4b91eb51 100644 --- a/lib/gitlab/ci/config/node/environment.rb +++ b/lib/gitlab/ci/config/entry/environment.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents an environment. # - class Environment < Entry + class Environment < Node include Validatable ALLOWED_KEYS = %i[name url action on_stop] diff --git a/lib/gitlab/ci/config/node/factory.rb b/lib/gitlab/ci/config/entry/factory.rb index 5387f29ad59..9f5e393d191 100644 --- a/lib/gitlab/ci/config/node/factory.rb +++ b/lib/gitlab/ci/config/entry/factory.rb @@ -1,15 +1,15 @@ module Gitlab module Ci class Config - module Node + module Entry ## - # Factory class responsible for fabricating node entry objects. + # Factory class responsible for fabricating entry objects. # class Factory class InvalidFactory < StandardError; end - def initialize(node) - @node = node + def initialize(entry) + @entry = entry @metadata = {} @attributes = {} end @@ -37,11 +37,11 @@ module Gitlab # See issue #18775. # if @value.nil? - Node::Unspecified.new( + Entry::Unspecified.new( fabricate_unspecified ) else - fabricate(@node, @value) + fabricate(@entry, @value) end end @@ -49,21 +49,21 @@ module Gitlab def fabricate_unspecified ## - # If node has a default value we fabricate concrete node + # If entry has a default value we fabricate concrete node # with default value. # - if @node.default.nil? - fabricate(Node::Undefined) + if @entry.default.nil? + fabricate(Entry::Undefined) else - fabricate(@node, @node.default) + fabricate(@entry, @entry.default) end end - def fabricate(node, value = nil) - node.new(value, @metadata).tap do |entry| - entry.key = @attributes[:key] - entry.parent = @attributes[:parent] - entry.description = @attributes[:description] + def fabricate(entry, value = nil) + entry.new(value, @metadata).tap do |node| + node.key = @attributes[:key] + node.parent = @attributes[:parent] + node.description = @attributes[:description] end end end diff --git a/lib/gitlab/ci/config/node/global.rb b/lib/gitlab/ci/config/entry/global.rb index 2a2943c9288..a4ec8f0ff2f 100644 --- a/lib/gitlab/ci/config/node/global.rb +++ b/lib/gitlab/ci/config/entry/global.rb @@ -1,36 +1,36 @@ module Gitlab module Ci class Config - module Node + module Entry ## - # This class represents a global entry - root node for entire + # This class represents a global entry - root Entry for entire # GitLab CI Configuration file. # - class Global < Entry + class Global < Node include Configurable - node :before_script, Node::Script, + entry :before_script, Entry::Script, description: 'Script that will be executed before each job.' - node :image, Node::Image, + entry :image, Entry::Image, description: 'Docker image that will be used to execute jobs.' - node :services, Node::Services, + entry :services, Entry::Services, description: 'Docker images that will be linked to the container.' - node :after_script, Node::Script, + entry :after_script, Entry::Script, description: 'Script that will be executed after each job.' - node :variables, Node::Variables, + entry :variables, Entry::Variables, description: 'Environment variables that will be used.' - node :stages, Node::Stages, + entry :stages, Entry::Stages, description: 'Configuration of stages for this pipeline.' - node :types, Node::Stages, + entry :types, Entry::Stages, description: 'Deprecated: stages for this pipeline.' - node :cache, Node::Cache, + entry :cache, Entry::Cache, description: 'Configure caching between build jobs.' helpers :before_script, :image, :services, :after_script, @@ -46,7 +46,7 @@ module Gitlab private def compose_jobs! - factory = Node::Factory.new(Node::Jobs) + factory = Entry::Factory.new(Entry::Jobs) .value(@config.except(*self.class.nodes.keys)) .with(key: :jobs, parent: self, description: 'Jobs definition for this pipeline') diff --git a/lib/gitlab/ci/config/node/hidden.rb b/lib/gitlab/ci/config/entry/hidden.rb index fe4ee8a7fc6..6fc3aa385bc 100644 --- a/lib/gitlab/ci/config/node/hidden.rb +++ b/lib/gitlab/ci/config/entry/hidden.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## - # Entry that represents a hidden CI/CD job. + # Entry that represents a hidden CI/CD key. # - class Hidden < Entry + class Hidden < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/image.rb b/lib/gitlab/ci/config/entry/image.rb index 5d3c7c5eab0..b5050257688 100644 --- a/lib/gitlab/ci/config/node/image.rb +++ b/lib/gitlab/ci/config/entry/image.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a Docker image. # - class Image < Entry + class Image < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/job.rb b/lib/gitlab/ci/config/entry/job.rb index 603334d6793..ab4ef333629 100644 --- a/lib/gitlab/ci/config/node/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a concrete CI/CD job. # - class Job < Entry + class Job < Node include Configurable include Attributable @@ -34,43 +34,43 @@ module Gitlab end end - node :before_script, Node::Script, + entry :before_script, Entry::Script, description: 'Global before script overridden in this job.' - node :script, Node::Commands, + entry :script, Entry::Commands, description: 'Commands that will be executed in this job.' - node :stage, Node::Stage, + entry :stage, Entry::Stage, description: 'Pipeline stage this job will be executed into.' - node :type, Node::Stage, + entry :type, Entry::Stage, description: 'Deprecated: stage this job will be executed into.' - node :after_script, Node::Script, + entry :after_script, Entry::Script, description: 'Commands that will be executed when finishing job.' - node :cache, Node::Cache, + entry :cache, Entry::Cache, description: 'Cache definition for this job.' - node :image, Node::Image, + entry :image, Entry::Image, description: 'Image that will be used to execute this job.' - node :services, Node::Services, + entry :services, Entry::Services, description: 'Services that will be used to execute this job.' - node :only, Node::Trigger, + entry :only, Entry::Trigger, description: 'Refs policy this job will be executed for.' - node :except, Node::Trigger, + entry :except, Entry::Trigger, description: 'Refs policy this job will be executed for.' - node :variables, Node::Variables, + entry :variables, Entry::Variables, description: 'Environment variables available for this job.' - node :artifacts, Node::Artifacts, + entry :artifacts, Entry::Artifacts, description: 'Artifacts configuration for this job.' - node :environment, Node::Environment, + entry :environment, Entry::Environment, description: 'Environment configuration for this job.' helpers :before_script, :script, :stage, :type, :after_script, diff --git a/lib/gitlab/ci/config/node/jobs.rb b/lib/gitlab/ci/config/entry/jobs.rb index d10e80d1a7d..5671a09480b 100644 --- a/lib/gitlab/ci/config/node/jobs.rb +++ b/lib/gitlab/ci/config/entry/jobs.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a set of jobs. # - class Jobs < Entry + class Jobs < Node include Validatable validations do @@ -29,9 +29,9 @@ module Gitlab def compose!(deps = nil) super do @config.each do |name, config| - node = hidden?(name) ? Node::Hidden : Node::Job + node = hidden?(name) ? Entry::Hidden : Entry::Job - factory = Node::Factory.new(node) + factory = Entry::Factory.new(node) .value(config || {}) .metadata(name: name) .with(key: name, parent: self, diff --git a/lib/gitlab/ci/config/node/key.rb b/lib/gitlab/ci/config/entry/key.rb index f8b461ca098..0e4c9fe6edc 100644 --- a/lib/gitlab/ci/config/node/key.rb +++ b/lib/gitlab/ci/config/entry/key.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a key. # - class Key < Entry + class Key < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/legacy_validation_helpers.rb b/lib/gitlab/ci/config/entry/legacy_validation_helpers.rb index 0c291efe6a5..f01975aab5c 100644 --- a/lib/gitlab/ci/config/node/legacy_validation_helpers.rb +++ b/lib/gitlab/ci/config/entry/legacy_validation_helpers.rb @@ -1,7 +1,7 @@ module Gitlab module Ci class Config - module Node + module Entry module LegacyValidationHelpers private diff --git a/lib/gitlab/ci/config/node/entry.rb b/lib/gitlab/ci/config/entry/node.rb index 8717eabf81e..5eef2868cd6 100644 --- a/lib/gitlab/ci/config/node/entry.rb +++ b/lib/gitlab/ci/config/entry/node.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Base abstract class for each configuration entry node. # - class Entry + class Node class InvalidError < StandardError; end attr_reader :config, :metadata @@ -21,7 +21,7 @@ module Gitlab end def [](key) - @entries[key] || Node::Undefined.new + @entries[key] || Entry::Undefined.new end def compose!(deps = nil) diff --git a/lib/gitlab/ci/config/node/paths.rb b/lib/gitlab/ci/config/entry/paths.rb index 3c6d3a52966..68dad161149 100644 --- a/lib/gitlab/ci/config/node/paths.rb +++ b/lib/gitlab/ci/config/entry/paths.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents an array of paths. # - class Paths < Entry + class Paths < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/script.rb b/lib/gitlab/ci/config/entry/script.rb index 39328f0fade..29ecd9995ca 100644 --- a/lib/gitlab/ci/config/node/script.rb +++ b/lib/gitlab/ci/config/entry/script.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a script. # - class Script < Entry + class Script < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/services.rb b/lib/gitlab/ci/config/entry/services.rb index 481e2b66adc..84f8ab780f5 100644 --- a/lib/gitlab/ci/config/node/services.rb +++ b/lib/gitlab/ci/config/entry/services.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a configuration of Docker services. # - class Services < Entry + class Services < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/stage.rb b/lib/gitlab/ci/config/entry/stage.rb index cbc97641f5a..b7afaba1de8 100644 --- a/lib/gitlab/ci/config/node/stage.rb +++ b/lib/gitlab/ci/config/entry/stage.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a stage for a job. # - class Stage < Entry + class Stage < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/stages.rb b/lib/gitlab/ci/config/entry/stages.rb index b1fe45357ff..ec187bd3732 100644 --- a/lib/gitlab/ci/config/node/stages.rb +++ b/lib/gitlab/ci/config/entry/stages.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a configuration for pipeline stages. # - class Stages < Entry + class Stages < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/trigger.rb b/lib/gitlab/ci/config/entry/trigger.rb index d8b31975088..28b0a9ffe01 100644 --- a/lib/gitlab/ci/config/node/trigger.rb +++ b/lib/gitlab/ci/config/entry/trigger.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents a trigger policy for the job. # - class Trigger < Entry + class Trigger < Node include Validatable validations do diff --git a/lib/gitlab/ci/config/node/undefined.rb b/lib/gitlab/ci/config/entry/undefined.rb index 33e78023539..b33b8238230 100644 --- a/lib/gitlab/ci/config/node/undefined.rb +++ b/lib/gitlab/ci/config/entry/undefined.rb @@ -1,13 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## - # This class represents an undefined node. + # This class represents an undefined entry. # - # Implements the Null Object pattern. - # - class Undefined < Entry + class Undefined < Node def initialize(*) super(nil) end diff --git a/lib/gitlab/ci/config/node/unspecified.rb b/lib/gitlab/ci/config/entry/unspecified.rb index a7d1f6131b8..fbb2551e870 100644 --- a/lib/gitlab/ci/config/node/unspecified.rb +++ b/lib/gitlab/ci/config/entry/unspecified.rb @@ -1,9 +1,9 @@ module Gitlab module Ci class Config - module Node + module Entry ## - # This class represents an unspecified entry node. + # This class represents an unspecified entry. # # It decorates original entry adding method that indicates it is # unspecified. diff --git a/lib/gitlab/ci/config/node/validatable.rb b/lib/gitlab/ci/config/entry/validatable.rb index 085e6e988d1..f7f1b111571 100644 --- a/lib/gitlab/ci/config/node/validatable.rb +++ b/lib/gitlab/ci/config/entry/validatable.rb @@ -1,13 +1,13 @@ module Gitlab module Ci class Config - module Node + module Entry module Validatable extend ActiveSupport::Concern class_methods do def validator - @validator ||= Class.new(Node::Validator).tap do |validator| + @validator ||= Class.new(Entry::Validator).tap do |validator| if defined?(@validations) @validations.each { |rules| validator.class_eval(&rules) } end diff --git a/lib/gitlab/ci/config/node/validator.rb b/lib/gitlab/ci/config/entry/validator.rb index 43c7e102b50..55343005fe3 100644 --- a/lib/gitlab/ci/config/node/validator.rb +++ b/lib/gitlab/ci/config/entry/validator.rb @@ -1,14 +1,14 @@ module Gitlab module Ci class Config - module Node + module Entry class Validator < SimpleDelegator include ActiveModel::Validations - include Node::Validators + include Entry::Validators - def initialize(node) - super(node) - @node = node + def initialize(entry) + super(entry) + @entry = entry end def messages @@ -30,7 +30,7 @@ module Gitlab def key_name if key.blank? - @node.class.name.demodulize.underscore.humanize + @entry.class.name.demodulize.underscore.humanize else key end diff --git a/lib/gitlab/ci/config/node/validators.rb b/lib/gitlab/ci/config/entry/validators.rb index e20908ad3cb..8632dd0e233 100644 --- a/lib/gitlab/ci/config/node/validators.rb +++ b/lib/gitlab/ci/config/entry/validators.rb @@ -1,7 +1,7 @@ module Gitlab module Ci class Config - module Node + module Entry module Validators class AllowedKeysValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) diff --git a/lib/gitlab/ci/config/node/variables.rb b/lib/gitlab/ci/config/entry/variables.rb index 5f813f81f55..c3b0e651c3a 100644 --- a/lib/gitlab/ci/config/node/variables.rb +++ b/lib/gitlab/ci/config/entry/variables.rb @@ -1,11 +1,11 @@ module Gitlab module Ci class Config - module Node + module Entry ## # Entry that represents environment variables. # - class Variables < Entry + class Variables < Node include Validatable validations do diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 3a651ef318a..c6bb8f9c8ed 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -24,7 +24,7 @@ module Gitlab end def sidekiq_throttling_enabled? - current_application_settings.sidekiq_throttling_enabled + current_application_settings.sidekiq_throttling_enabled? end def fake_application_settings diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 5110bfbf898..c6bf25b5874 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -55,6 +55,12 @@ module Gitlab repository.commit(deleted_file ? old_ref : new_ref) end + def old_content_commit + return unless diff_refs + + repository.commit(old_ref) + end + def old_ref diff_refs.try(:base_sha) end @@ -111,13 +117,10 @@ module Gitlab diff_lines.count(&:removed?) end - def old_blob(commit = content_commit) + def old_blob(commit = old_content_commit) return unless commit - parent_id = commit.parent_id - return unless parent_id - - repository.blob_at(parent_id, old_path) + repository.blob_at(commit.id, old_path) end def blob(commit = content_commit) diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb index 8b38cfaefb6..7b05290e5cc 100644 --- a/lib/gitlab/ldap/adapter.rb +++ b/lib/gitlab/ldap/adapter.rb @@ -89,9 +89,7 @@ module Gitlab end def user_filter(filter = nil) - if config.user_filter.present? - user_filter = Net::LDAP::Filter.construct(config.user_filter) - end + user_filter = config.constructed_user_filter if config.user_filter.present? if user_filter && filter Net::LDAP::Filter.join(filter, user_filter) diff --git a/lib/gitlab/ldap/authentication.rb b/lib/gitlab/ldap/authentication.rb index bad683c6511..4745311402c 100644 --- a/lib/gitlab/ldap/authentication.rb +++ b/lib/gitlab/ldap/authentication.rb @@ -54,11 +54,9 @@ module Gitlab # Apply LDAP user filter if present if config.user_filter.present? - filter = Net::LDAP::Filter.join( - filter, - Net::LDAP::Filter.construct(config.user_filter) - ) + filter = Net::LDAP::Filter.join(filter, config.constructed_user_filter) end + filter end diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 6ea069d26df..de52ef3fc65 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -13,7 +13,7 @@ module Gitlab end def self.providers - servers.map {|server| server['provider_name'] } + servers.map { |server| server['provider_name'] } end def self.valid_provider?(provider) @@ -38,13 +38,31 @@ module Gitlab end def adapter_options - { - host: options['host'], - port: options['port'], - encryption: encryption - }.tap do |options| - options.merge!(auth_options) if has_auth? + opts = base_options.merge( + encryption: encryption, + ) + + opts.merge!(auth_options) if has_auth? + + opts + end + + def omniauth_options + opts = base_options.merge( + base: base, + method: options['method'], + filter: omniauth_user_filter, + name_proc: name_proc + ) + + if has_auth? + opts.merge!( + bind_dn: options['bind_dn'], + password: options['password'] + ) end + + opts end def base @@ -68,6 +86,10 @@ module Gitlab options['user_filter'] end + def constructed_user_filter + @constructed_user_filter ||= Net::LDAP::Filter.construct(user_filter) + end + def group_base options['group_base'] end @@ -96,8 +118,27 @@ module Gitlab options['password'] || options['bind_dn'] end + def allow_username_or_email_login + options['allow_username_or_email_login'] + end + + def name_proc + if allow_username_or_email_login + Proc.new { |name| name.gsub(/@.*\z/, '') } + else + Proc.new { |name| name } + end + end + protected + def base_options + { + host: options['host'], + port: options['port'] + } + end + def base_config Gitlab.config.ldap end @@ -126,6 +167,16 @@ module Gitlab } } end + + def omniauth_user_filter + uid_filter = Net::LDAP::Filter.eq(uid, '%{username}') + + if user_filter.present? + Net::LDAP::Filter.join(uid_filter, constructed_user_filter).to_s + else + uid_filter.to_s + end + end end end end diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb index 0a91d3918d5..a8b4dc2a83f 100644 --- a/lib/gitlab/o_auth/user.rb +++ b/lib/gitlab/o_auth/user.rb @@ -102,6 +102,8 @@ module Gitlab Gitlab::LDAP::Config.providers.each do |provider| adapter = Gitlab::LDAP::Adapter.new(provider) @ldap_person = Gitlab::LDAP::Person.find_by_uid(auth_hash.uid, adapter) + # The `uid` might actually be a DN. Try it next. + @ldap_person ||= Gitlab::LDAP::Person.find_by_dn(auth_hash.uid, adapter) break if @ldap_person end @ldap_person diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index cb1659f9cee..155ca47e04c 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -26,12 +26,12 @@ module Gitlab end def project_name_regex - @project_name_regex ||= /\A[\p{Alnum}_][\p{Alnum}\p{Pd}_\. ]*\z/.freeze + @project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9c0}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9c0}_\. ]*\z/.freeze end def project_name_regex_message - "can contain only letters, digits, '_', '.', dash and space. " \ - "It must start with letter, digit or '_'." + "can contain only letters, digits, emojis, '_', '.', dash, space. " \ + "It must start with letter, digit, emoji or '_'." end def project_path_regex diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index 33c75e7584f..6fc6ea95e13 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -7,6 +7,40 @@ describe HelpController do sign_in(user) end + describe 'GET #index' do + context 'when url prefixed without /help/' do + it 'has correct url prefix' do + stub_readme("[API](api/README.md)") + get :index + expect(assigns[:help_index]).to eq '[API](/help/api/README.md)' + end + end + + context 'when url prefixed with help/' do + it 'will be an absolute path' do + stub_readme("[API](help/api/README.md)") + get :index + expect(assigns[:help_index]).to eq '[API](/help/api/README.md)' + end + end + + context 'when url prefixed with help' do + it 'will be an absolute path' do + stub_readme("[API](helpful_hints/README.md)") + get :index + expect(assigns[:help_index]).to eq '[API](/help/helpful_hints/README.md)' + end + end + + context 'when url prefixed with /help/' do + it 'will not be changed' do + stub_readme("[API](/help/api/README.md)") + get :index + expect(assigns[:help_index]).to eq '[API](/help/api/README.md)' + end + end + end + describe 'GET #show' do context 'for Markdown formats' do context 'when requested file exists' do @@ -72,4 +106,8 @@ describe HelpController do end end end + + def stub_readme(content) + allow(File).to receive(:read).and_return(content) + end end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index 644de308c64..f7cf006efd6 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -1,13 +1,13 @@ require 'spec_helper' describe Projects::BranchesController do - let(:project) { create(:project) } - let(:user) { create(:user) } + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:developer) { create(:user) } before do - sign_in(user) - project.team << [user, :master] + project.team << [user, :developer] allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz']) allow(project).to receive(:tags).and_return(['v1.0.0', 'v2.0.0']) @@ -19,6 +19,8 @@ describe Projects::BranchesController do context "on creation of a new branch" do before do + sign_in(user) + post :create, namespace_id: project.namespace.to_param, project_id: project.to_param, @@ -68,6 +70,10 @@ describe Projects::BranchesController do let(:branch) { "1-feature-branch" } let!(:issue) { create(:issue, project: project) } + before do + sign_in(user) + end + it 'redirects' do post :create, namespace_id: project.namespace.to_param, @@ -94,6 +100,10 @@ describe Projects::BranchesController do describe "POST destroy with HTML format" do render_views + before do + sign_in(user) + end + it 'returns 303' do post :destroy, format: :html, @@ -109,6 +119,8 @@ describe Projects::BranchesController do render_views before do + sign_in(user) + post :destroy, format: :js, id: branch, @@ -139,4 +151,42 @@ describe Projects::BranchesController do it { expect(response).to have_http_status(404) } end end + + describe "DELETE destroy_all_merged" do + def destroy_all_merged + delete :destroy_all_merged, + namespace_id: project.namespace.to_param, + project_id: project.to_param + end + + context 'when user is allowed to push' do + before do + sign_in(user) + end + + it 'redirects to branches' do + destroy_all_merged + + expect(response).to redirect_to namespace_project_branches_path(project.namespace, project) + end + + it 'starts worker to delete merged branches' do + expect_any_instance_of(DeleteMergedBranchesService).to receive(:async_execute) + + destroy_all_merged + end + end + + context 'when user is not allowed to push' do + before do + sign_in(developer) + end + + it 'responds with status 404' do + destroy_all_merged + + expect(response).to have_http_status(404) + end + end + end end diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 6cb8753e8fc..4aa84fb65d9 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -659,6 +659,10 @@ describe 'Issue Boards', feature: true, js: true do wait_for_vue_resource end + it 'displays lists' do + expect(page).to have_selector('.board') + end + it 'does not show create new list' do expect(page).not_to have_selector('.js-new-board-list') end diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index c68e1ea4af9..584574cc91a 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -67,4 +67,14 @@ feature 'Create New Merge Request', feature: true, js: true do expect(page).to have_content('Source branch "non-exist-source" does not exist') expect(page).to have_content('Target branch "non-exist-target" does not exist') end + + context 'when a branch contains commits that both delete and add the same image' do + it 'renders the diff successfully' do + visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_branch: 'master', source_branch: 'deleted-image-test' }) + + click_link "Changes" + + expect(page).to have_content "6049019_460s.jpg" + end + end end diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb new file mode 100644 index 00000000000..abfc46601fb --- /dev/null +++ b/spec/features/projects/new_project_spec.rb @@ -0,0 +1,19 @@ +require "spec_helper" + +feature "New project", feature: true do + context "Visibility level selector" do + let(:user) { create(:admin) } + + before { login_as(user) } + + Gitlab::VisibilityLevel.options.each do |key, level| + it "sets selector to #{key}" do + stub_application_setting(default_project_visibility: level) + + visit new_project_path + + expect(find_field("project_visibility_level_#{level}")).to be_checked + end + end + end +end diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb index 3de25d7af7d..bf60cca4ea4 100644 --- a/spec/features/projects/project_settings_spec.rb +++ b/spec/features/projects/project_settings_spec.rb @@ -18,7 +18,7 @@ describe 'Edit Project Settings', feature: true do click_button 'Save changes' expect(page).to have_field 'project_name_edit', with: 'foo&bar' - expect(page).to have_content "Name can contain only letters, digits, '_', '.', dash and space. It must start with letter, digit or '_'." + expect(page).to have_content "Name can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'." expect(page).to have_button 'Save changes' end end @@ -34,8 +34,21 @@ describe 'Edit Project Settings', feature: true do expect(page).to have_field 'Project name', with: 'foo&bar' expect(page).to have_field 'Path', with: 'foo&bar' - expect(page).to have_content "Name can contain only letters, digits, '_', '.', dash and space. It must start with letter, digit or '_'." + expect(page).to have_content "Name can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'." expect(page).to have_content "Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'" end end + + describe 'Rename repository name with emojis' do + it 'shows error for invalid project name' do + visit edit_namespace_project_path(project.namespace, project) + + fill_in 'Project name', with: '🚀 foo bar ☁️' + + click_button 'Rename project' + + expect(page).to have_field 'Project name', with: '🚀 foo bar ☁️' + expect(page).not_to have_content "Name can contain only letters, digits, emojis '_', '.', dash and space. It must start with letter, digit, emoji or '_'." + end + end end diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb index 3ae83ac082d..88eabea7e3a 100644 --- a/spec/features/todos/todos_spec.rb +++ b/spec/features/todos/todos_spec.rb @@ -44,7 +44,7 @@ describe 'Dashboard Todos', feature: true do end it 'shows "All done" message' do - expect(page).to have_content("Good job! Looks like you don't have any todos left.") + expect(page).to have_selector('.todos-all-done', count: 1) end end @@ -64,7 +64,7 @@ describe 'Dashboard Todos', feature: true do end it 'shows "All done" message' do - expect(page).to have_content("Good job! Looks like you don't have any todos left.") + expect(page).to have_selector('.todos-all-done', count: 1) end end end @@ -152,7 +152,7 @@ describe 'Dashboard Todos', feature: true do within('.todos-pending-count') { expect(page).to have_content '0' } expect(page).to have_content 'To do 0' expect(page).to have_content 'Done 0' - expect(page).to have_content "Good job! Looks like you don't have any todos left." + expect(page).to have_selector('.todos-all-done', count: 1) end end end diff --git a/spec/lib/gitlab/ci/config/node/artifacts_spec.rb b/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb index c09a0a9c793..5c31423fdee 100644 --- a/spec/lib/gitlab/ci/config/node/artifacts_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Artifacts do +describe Gitlab::Ci::Config::Entry::Artifacts do let(:entry) { described_class.new(config) } describe 'validation' do diff --git a/spec/lib/gitlab/ci/config/node/attributable_spec.rb b/spec/lib/gitlab/ci/config/entry/attributable_spec.rb index 24d9daafd88..fde03c51e2c 100644 --- a/spec/lib/gitlab/ci/config/node/attributable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/attributable_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Attributable do +describe Gitlab::Ci::Config::Entry::Attributable do let(:node) { Class.new } let(:instance) { node.new } diff --git a/spec/lib/gitlab/ci/config/node/boolean_spec.rb b/spec/lib/gitlab/ci/config/entry/boolean_spec.rb index deafa8bf8a7..5f067cad93c 100644 --- a/spec/lib/gitlab/ci/config/node/boolean_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/boolean_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Boolean do +describe Gitlab::Ci::Config::Entry::Boolean do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb index e251210949c..70a327c5183 100644 --- a/spec/lib/gitlab/ci/config/node/cache_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Cache do +describe Gitlab::Ci::Config::Entry::Cache do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/commands_spec.rb b/spec/lib/gitlab/ci/config/entry/commands_spec.rb index e373c40706f..b8b0825a1c7 100644 --- a/spec/lib/gitlab/ci/config/node/commands_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/commands_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Commands do +describe Gitlab::Ci::Config::Entry::Commands do let(:entry) { described_class.new(config) } context 'when entry config value is an array' do diff --git a/spec/lib/gitlab/ci/config/entry/configurable_spec.rb b/spec/lib/gitlab/ci/config/entry/configurable_spec.rb new file mode 100644 index 00000000000..ae7e628b5b5 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/configurable_spec.rb @@ -0,0 +1,67 @@ +require 'spec_helper' + +describe Gitlab::Ci::Config::Entry::Configurable do + let(:entry) { Class.new } + + before do + entry.include(described_class) + end + + describe 'validations' do + let(:validator) { entry.validator.new(instance) } + + before do + entry.class_eval do + attr_reader :config + + def initialize(config) + @config = config + end + end + + validator.validate + end + + context 'when entry validator is invalid' do + let(:instance) { entry.new('ls') } + + it 'returns invalid validator' do + expect(validator).to be_invalid + end + end + + context 'when entry instance is valid' do + let(:instance) { entry.new(key: 'value') } + + it 'returns valid validator' do + expect(validator).to be_valid + end + end + end + + describe 'configured entries' do + before do + entry.class_eval do + entry :object, Object, description: 'test object' + end + end + + describe '.nodes' do + it 'has valid nodes' do + expect(entry.nodes).to include :object + end + + it 'creates a node factory' do + expect(entry.nodes[:object]) + .to be_an_instance_of Gitlab::Ci::Config::Entry::Factory + end + + it 'returns a duplicated factory object' do + first_factory = entry.nodes[:object] + second_factory = entry.nodes[:object] + + expect(first_factory).not_to be_equal(second_factory) + end + end + end +end diff --git a/spec/lib/gitlab/ci/config/node/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb index df925ff1afd..d97806295fb 100644 --- a/spec/lib/gitlab/ci/config/node/environment_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Environment do +describe Gitlab::Ci::Config::Entry::Environment do let(:entry) { described_class.new(config) } before { entry.compose! } diff --git a/spec/lib/gitlab/ci/config/node/factory_spec.rb b/spec/lib/gitlab/ci/config/entry/factory_spec.rb index a699089c563..00dad5d9591 100644 --- a/spec/lib/gitlab/ci/config/node/factory_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/factory_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Factory do +describe Gitlab::Ci::Config::Entry::Factory do describe '#create!' do - let(:factory) { described_class.new(node) } - let(:node) { Gitlab::Ci::Config::Node::Script } + let(:factory) { described_class.new(entry) } + let(:entry) { Gitlab::Ci::Config::Entry::Script } context 'when setting a concrete value' do it 'creates entry with valid value' do @@ -54,7 +54,7 @@ describe Gitlab::Ci::Config::Node::Factory do context 'when not setting a value' do it 'raises error' do expect { factory.create! }.to raise_error( - Gitlab::Ci::Config::Node::Factory::InvalidFactory + Gitlab::Ci::Config::Entry::Factory::InvalidFactory ) end end @@ -66,12 +66,12 @@ describe Gitlab::Ci::Config::Node::Factory do .create! expect(entry) - .to be_an_instance_of Gitlab::Ci::Config::Node::Unspecified + .to be_an_instance_of Gitlab::Ci::Config::Entry::Unspecified end end context 'when passing metadata' do - let(:node) { spy('node') } + let(:entry) { spy('entry') } it 'passes metadata as a parameter' do factory @@ -79,7 +79,7 @@ describe Gitlab::Ci::Config::Node::Factory do .metadata(some: 'hash') .create! - expect(node).to have_received(:new) + expect(entry).to have_received(:new) .with('some value', { some: 'hash' }) end end diff --git a/spec/lib/gitlab/ci/config/node/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb index 12232ff7e2f..c7726adfd27 100644 --- a/spec/lib/gitlab/ci/config/node/global_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Global do +describe Gitlab::Ci::Config::Entry::Global do let(:global) { described_class.new(hash) } describe '.nodes' do @@ -40,9 +40,9 @@ describe Gitlab::Ci::Config::Node::Global do it 'creates node object using valid class' do expect(global.descendants.first) - .to be_an_instance_of Gitlab::Ci::Config::Node::Script + .to be_an_instance_of Gitlab::Ci::Config::Entry::Script expect(global.descendants.second) - .to be_an_instance_of Gitlab::Ci::Config::Node::Image + .to be_an_instance_of Gitlab::Ci::Config::Entry::Image end it 'sets correct description for nodes' do @@ -181,7 +181,7 @@ describe Gitlab::Ci::Config::Node::Global do it 'contains unspecified nodes' do expect(global.descendants.first) - .to be_an_instance_of Gitlab::Ci::Config::Node::Unspecified + .to be_an_instance_of Gitlab::Ci::Config::Entry::Unspecified end end @@ -284,7 +284,7 @@ describe Gitlab::Ci::Config::Node::Global do context 'when node exists' do it 'returns correct entry' do expect(global[:cache]) - .to be_an_instance_of Gitlab::Ci::Config::Node::Cache + .to be_an_instance_of Gitlab::Ci::Config::Entry::Cache expect(global[:jobs][:rspec][:script].value).to eq ['ls'] end end diff --git a/spec/lib/gitlab/ci/config/node/hidden_spec.rb b/spec/lib/gitlab/ci/config/entry/hidden_spec.rb index 61e2a554419..459362761e6 100644 --- a/spec/lib/gitlab/ci/config/node/hidden_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/hidden_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Hidden do +describe Gitlab::Ci::Config::Entry::Hidden do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb index d11bb39f328..3c99cb0a1ee 100644 --- a/spec/lib/gitlab/ci/config/node/image_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Image do +describe Gitlab::Ci::Config::Entry::Image do let(:entry) { described_class.new(config) } describe 'validation' do diff --git a/spec/lib/gitlab/ci/config/node/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index 91f676dae03..c05711b6338 100644 --- a/spec/lib/gitlab/ci/config/node/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Job do +describe Gitlab::Ci::Config::Entry::Job do let(:entry) { described_class.new(config, name: :rspec) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb index 929809339ef..aaebf783962 100644 --- a/spec/lib/gitlab/ci/config/node/jobs_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Jobs do +describe Gitlab::Ci::Config::Entry::Jobs do let(:entry) { described_class.new(config) } describe 'validations' do @@ -74,9 +74,9 @@ describe Gitlab::Ci::Config::Node::Jobs do it 'creates valid descendant nodes' do expect(entry.descendants.count).to eq 3 expect(entry.descendants.first(2)) - .to all(be_an_instance_of(Gitlab::Ci::Config::Node::Job)) + .to all(be_an_instance_of(Gitlab::Ci::Config::Entry::Job)) expect(entry.descendants.last) - .to be_an_instance_of(Gitlab::Ci::Config::Node::Hidden) + .to be_an_instance_of(Gitlab::Ci::Config::Entry::Hidden) end end diff --git a/spec/lib/gitlab/ci/config/node/key_spec.rb b/spec/lib/gitlab/ci/config/entry/key_spec.rb index 8cda43173fe..a55e5b4b8ac 100644 --- a/spec/lib/gitlab/ci/config/node/key_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/key_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Key do +describe Gitlab::Ci::Config::Entry::Key do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/paths_spec.rb b/spec/lib/gitlab/ci/config/entry/paths_spec.rb index 6fd744b3975..e60c9aaf661 100644 --- a/spec/lib/gitlab/ci/config/node/paths_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/paths_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Paths do +describe Gitlab::Ci::Config::Entry::Paths do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/script_spec.rb b/spec/lib/gitlab/ci/config/entry/script_spec.rb index 219a7e981d3..aa99cee2690 100644 --- a/spec/lib/gitlab/ci/config/node/script_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/script_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Script do +describe Gitlab::Ci::Config::Entry::Script do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/services_spec.rb b/spec/lib/gitlab/ci/config/entry/services_spec.rb index be0fe46befd..66fad3b6b16 100644 --- a/spec/lib/gitlab/ci/config/node/services_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/services_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Services do +describe Gitlab::Ci::Config::Entry::Services do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/stage_spec.rb b/spec/lib/gitlab/ci/config/entry/stage_spec.rb index fb9ec70762a..70c8a0a355a 100644 --- a/spec/lib/gitlab/ci/config/node/stage_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/stage_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Stage do +describe Gitlab::Ci::Config::Entry::Stage do let(:stage) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/stages_spec.rb b/spec/lib/gitlab/ci/config/entry/stages_spec.rb index 1a3818d8997..182c8d867c7 100644 --- a/spec/lib/gitlab/ci/config/node/stages_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/stages_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Stages do +describe Gitlab::Ci::Config::Entry::Stages do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/trigger_spec.rb b/spec/lib/gitlab/ci/config/entry/trigger_spec.rb index a4a3e36754e..e4ee44f1274 100644 --- a/spec/lib/gitlab/ci/config/node/trigger_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/trigger_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Trigger do +describe Gitlab::Ci::Config::Entry::Trigger do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/undefined_spec.rb b/spec/lib/gitlab/ci/config/entry/undefined_spec.rb index 6bde8602963..fdf48d84192 100644 --- a/spec/lib/gitlab/ci/config/node/undefined_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/undefined_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Undefined do +describe Gitlab::Ci::Config::Entry::Undefined do let(:entry) { described_class.new } describe '#leaf?' do diff --git a/spec/lib/gitlab/ci/config/node/unspecified_spec.rb b/spec/lib/gitlab/ci/config/entry/unspecified_spec.rb index ba3ceef24ce..66f88fa35b6 100644 --- a/spec/lib/gitlab/ci/config/node/unspecified_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/unspecified_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Unspecified do +describe Gitlab::Ci::Config::Entry::Unspecified do let(:unspecified) { described_class.new(entry) } let(:entry) { spy('Entry') } diff --git a/spec/lib/gitlab/ci/config/node/validatable_spec.rb b/spec/lib/gitlab/ci/config/entry/validatable_spec.rb index 64b77fd6e03..d1856801827 100644 --- a/spec/lib/gitlab/ci/config/node/validatable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/validatable_spec.rb @@ -1,15 +1,15 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Validatable do - let(:node) { Class.new } +describe Gitlab::Ci::Config::Entry::Validatable do + let(:entry) { Class.new } before do - node.include(described_class) + entry.include(described_class) end describe '.validator' do before do - node.class_eval do + entry.class_eval do attr_accessor :test_attribute validations do @@ -19,34 +19,34 @@ describe Gitlab::Ci::Config::Node::Validatable do end it 'returns validator' do - expect(node.validator.superclass) - .to be Gitlab::Ci::Config::Node::Validator + expect(entry.validator.superclass) + .to be Gitlab::Ci::Config::Entry::Validator end it 'returns only one validator to mitigate leaks' do - expect { node.validator }.not_to change { node.validator } + expect { entry.validator }.not_to change { entry.validator } end - context 'when validating node instance' do - let(:node_instance) { node.new } + context 'when validating entry instance' do + let(:entry_instance) { entry.new } context 'when attribute is valid' do before do - node_instance.test_attribute = 'valid' + entry_instance.test_attribute = 'valid' end it 'instance of validator is valid' do - expect(node.validator.new(node_instance)).to be_valid + expect(entry.validator.new(entry_instance)).to be_valid end end context 'when attribute is not valid' do before do - node_instance.test_attribute = nil + entry_instance.test_attribute = nil end it 'instance of validator is invalid' do - expect(node.validator.new(node_instance)).to be_invalid + expect(entry.validator.new(entry_instance)).to be_invalid end end end diff --git a/spec/lib/gitlab/ci/config/node/validator_spec.rb b/spec/lib/gitlab/ci/config/entry/validator_spec.rb index 090fd63b844..ad7e6f07d3c 100644 --- a/spec/lib/gitlab/ci/config/node/validator_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/validator_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Validator do +describe Gitlab::Ci::Config::Entry::Validator do let(:validator) { Class.new(described_class) } let(:validator_instance) { validator.new(node) } let(:node) { spy('node') } diff --git a/spec/lib/gitlab/ci/config/node/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/variables_spec.rb index 4b6d971ec71..58327d08904 100644 --- a/spec/lib/gitlab/ci/config/node/variables_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/variables_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Config::Node::Variables do +describe Gitlab::Ci::Config::Entry::Variables do let(:entry) { described_class.new(config) } describe 'validations' do diff --git a/spec/lib/gitlab/ci/config/node/configurable_spec.rb b/spec/lib/gitlab/ci/config/node/configurable_spec.rb deleted file mode 100644 index c468ecf957b..00000000000 --- a/spec/lib/gitlab/ci/config/node/configurable_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Ci::Config::Node::Configurable do - let(:node) { Class.new } - - before do - node.include(described_class) - end - - describe 'validations' do - let(:validator) { node.validator.new(instance) } - - before do - node.class_eval do - attr_reader :config - - def initialize(config) - @config = config - end - end - - validator.validate - end - - context 'when node validator is invalid' do - let(:instance) { node.new('ls') } - - it 'returns invalid validator' do - expect(validator).to be_invalid - end - end - - context 'when node instance is valid' do - let(:instance) { node.new(key: 'value') } - - it 'returns valid validator' do - expect(validator).to be_valid - end - end - end - - describe 'configured nodes' do - before do - node.class_eval do - node :object, Object, description: 'test object' - end - end - - describe '.nodes' do - it 'has valid nodes' do - expect(node.nodes).to include :object - end - - it 'creates a node factory' do - expect(node.nodes[:object]) - .to be_an_instance_of Gitlab::Ci::Config::Node::Factory - end - - it 'returns a duplicated factory object' do - first_factory = node.nodes[:object] - second_factory = node.nodes[:object] - - expect(first_factory).not_to be_equal(second_factory) - end - end - end -end diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index 0650cb291e5..38475792d93 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -46,4 +46,28 @@ describe Gitlab::Diff::File, lib: true do expect(diff_file.collapsed?).to eq(false) end end + + describe '#old_content_commit' do + it 'returns base commit' do + old_content_commit = diff_file.old_content_commit + + expect(old_content_commit.id).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') + end + end + + describe '#old_blob' do + it 'returns blob of commit of base commit' do + old_data = diff_file.old_blob.data + + expect(old_data).to include('raise "System commands must be given as an array of strings"') + end + end + + describe '#blob' do + it 'returns blob of new commit' do + data = diff_file.blob.data + + expect(data).to include('raise RuntimeError, "System commands must be given as an array of strings"') + end + end end diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index f5ebe703083..1a6803e01c3 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -19,6 +19,87 @@ describe Gitlab::LDAP::Config, lib: true do end end + describe '#adapter_options' do + it 'constructs basic options' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 386, + 'method' => 'plain' + } + ) + + expect(config.adapter_options).to eq( + host: 'ldap.example.com', + port: 386, + encryption: nil + ) + end + + it 'includes authentication options when auth is configured' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'method' => 'ssl', + 'bind_dn' => 'uid=admin,dc=example,dc=com', + 'password' => 'super_secret' + } + ) + + expect(config.adapter_options).to eq( + host: 'ldap.example.com', + port: 686, + encryption: :simple_tls, + auth: { + method: :simple, + username: 'uid=admin,dc=example,dc=com', + password: 'super_secret' + } + ) + end + end + + describe '#omniauth_options' do + it 'constructs basic options' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 386, + 'base' => 'ou=users,dc=example,dc=com', + 'method' => 'plain', + 'uid' => 'uid' + } + ) + + expect(config.omniauth_options).to include( + host: 'ldap.example.com', + port: 386, + base: 'ou=users,dc=example,dc=com', + method: 'plain', + filter: '(uid=%{username})' + ) + expect(config.omniauth_options.keys).not_to include(:bind_dn, :password) + end + + it 'includes authentication options when auth is configured' do + stub_ldap_config( + options: { + 'uid' => 'sAMAccountName', + 'user_filter' => '(memberOf=cn=group1,ou=groups,dc=example,dc=com)', + 'bind_dn' => 'uid=admin,dc=example,dc=com', + 'password' => 'super_secret' + } + ) + + expect(config.omniauth_options).to include( + filter: '(&(sAMAccountName=%{username})(memberOf=cn=group1,ou=groups,dc=example,dc=com))', + bind_dn: 'uid=admin,dc=example,dc=com', + password: 'super_secret' + ) + end + end + describe '#has_auth?' do it 'is true when password is set' do stub_ldap_config( diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 78c669e8fa5..fc9e1cb430a 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -137,11 +137,12 @@ describe Gitlab::OAuth::User, lib: true do allow(ldap_user).to receive(:username) { uid } allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] } allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' } - allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) end context "and no account for the LDAP user" do it "creates a user with dual LDAP and omniauth identities" do + allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) + oauth_user.save expect(gl_user).to be_valid @@ -159,6 +160,8 @@ describe Gitlab::OAuth::User, lib: true do context "and LDAP user has an account already" do let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'ldapmain', username: 'john') } it "adds the omniauth identity to the LDAP account" do + allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) + oauth_user.save expect(gl_user).to be_valid @@ -172,6 +175,24 @@ describe Gitlab::OAuth::User, lib: true do ]) end end + + context 'when an LDAP person is not found by uid' do + it 'tries to find an LDAP person by DN and adds the omniauth identity to the user' do + allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil) + allow(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(ldap_user) + + oauth_user.save + + identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } } + expect(identities_as_hash) + .to match_array( + [ + { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' }, + { provider: 'twitter', extern_uid: uid } + ] + ) + end + end end context "and no corresponding LDAP person" do diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index 1711096f4bd..8f605757186 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -299,4 +299,20 @@ describe API::API, api: true do expect(json_response['message']).to eq('Cannot remove HEAD branch') end end + + describe "DELETE /projects/:id/repository/merged_branches" do + before do + allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true) + end + + it 'returns 200' do + delete api("/projects/#{project.id}/repository/merged_branches", user) + expect(response).to have_http_status(200) + end + + it 'returns a 403 error if guest' do + delete api("/projects/#{project.id}/repository/merged_branches", user2) + expect(response).to have_http_status(403) + end + end end diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/delete_merged_branches_service_spec.rb new file mode 100644 index 00000000000..181488e89c7 --- /dev/null +++ b/spec/services/delete_merged_branches_service_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe DeleteMergedBranchesService, services: true do + subject(:service) { described_class.new(project, project.owner) } + + let(:project) { create(:project) } + + context '#execute' do + context 'unprotected branches' do + before do + service.execute + end + + it 'deletes a branch that was merged' do + expect(project.repository.branch_names).not_to include('improve/awesome') + end + + it 'keeps branch that is unmerged' do + expect(project.repository.branch_names).to include('feature') + end + + it 'keeps "master"' do + expect(project.repository.branch_names).to include('master') + end + end + + context 'protected branches' do + before do + create(:protected_branch, name: 'improve/awesome', project: project) + service.execute + end + + it 'keeps protected branch' do + expect(project.repository.branch_names).to include('improve/awesome') + end + end + + context 'user without rights' do + let(:user) { create(:user) } + + it 'cannot execute' do + expect { described_class.new(project, user).execute }.to raise_error(Gitlab::Access::AccessDeniedError) + end + end + end + + context '#async_execute' do + it 'calls DeleteMergedBranchesWorker async' do + expect(DeleteMergedBranchesWorker).to receive(:perform_async) + + service.async_execute + end + end +end diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index 93885c84dc3..25804696d2e 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -14,12 +14,41 @@ describe Notes::CreateService, services: true do end context "valid params" do - before do - @note = Notes::CreateService.new(project, user, opts).execute + it 'returns a valid note' do + note = Notes::CreateService.new(project, user, opts).execute + + expect(note).to be_valid + end + + it 'returns a persisted note' do + note = Notes::CreateService.new(project, user, opts).execute + + expect(note).to be_persisted + end + + it 'note has valid content' do + note = Notes::CreateService.new(project, user, opts).execute + + expect(note.note).to eq(opts[:note]) end - it { expect(@note).to be_valid } - it { expect(@note.note).to eq(opts[:note]) } + it 'TodoService#new_note is called' do + note = build(:note) + allow(project).to receive_message_chain(:notes, :new).with(opts) { note } + + expect_any_instance_of(TodoService).to receive(:new_note).with(note, user) + + Notes::CreateService.new(project, user, opts).execute + end + + it 'enqueues NewNoteWorker' do + note = build(:note, id: 999) + allow(project).to receive_message_chain(:notes, :new).with(opts) { note } + + expect(NewNoteWorker).to receive(:perform_async).with(note.id) + + Notes::CreateService.new(project, user, opts).execute + end end describe 'note with commands' do diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 103f7542286..4cf81be3adc 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -35,6 +35,7 @@ module TestEnv 'conflict-missing-side' => 'eb227b3', 'conflict-non-utf8' => 'd0a293c', 'conflict-too-large' => '39fa04f', + 'deleted-image-test' => '6c17798' } # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily diff --git a/spec/views/projects/builds/_build.html.haml_spec.rb b/spec/views/projects/builds/_build.html.haml_spec.rb new file mode 100644 index 00000000000..e141a117731 --- /dev/null +++ b/spec/views/projects/builds/_build.html.haml_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe 'projects/ci/builds/_build' do + include Devise::Test::ControllerHelpers + + let(:project) { create(:project) } + let(:pipeline) { create(:ci_empty_pipeline, id: 1337, project: project, sha: project.commit.id) } + let(:build) { create(:ci_build, pipeline: pipeline, stage: 'test', stage_idx: 1, name: 'rspec 0:2', status: :pending) } + + before do + controller.prepend_view_path('app/views/projects') + allow(view).to receive(:can?).and_return(true) + end + + it 'won\'t include a column with a link to its pipeline by default' do + render partial: 'projects/ci/builds/build', locals: { build: build } + + expect(rendered).not_to have_link('#1337') + expect(rendered).not_to have_text('#1337 by API') + end + + it 'can include a column with a link to its pipeline' do + render partial: 'projects/ci/builds/build', locals: { build: build, pipeline_link: true } + + expect(rendered).to have_link('#1337') + expect(rendered).to have_text('#1337 by API') + end +end diff --git a/spec/views/projects/builds/_generic_commit_status.html.haml_spec.rb b/spec/views/projects/builds/_generic_commit_status.html.haml_spec.rb new file mode 100644 index 00000000000..49b20e5b36b --- /dev/null +++ b/spec/views/projects/builds/_generic_commit_status.html.haml_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe 'projects/generic_commit_statuses/_generic_commit_status.html.haml' do + include Devise::Test::ControllerHelpers + + let(:project) { create(:project) } + let(:pipeline) { create(:ci_empty_pipeline, id: 1337, project: project, sha: project.commit.id) } + let(:generic_commit_status) { create(:generic_commit_status, pipeline: pipeline, stage: 'external', name: 'jenkins', stage_idx: 3) } + + before do + controller.prepend_view_path('app/views/projects') + allow(view).to receive(:can?).and_return(true) + end + + it 'won\'t include a column with a link to its pipeline by default' do + render partial: 'projects/generic_commit_statuses/generic_commit_status', locals: { generic_commit_status: generic_commit_status } + + expect(rendered).not_to have_link('#1337') + expect(rendered).not_to have_text('#1337 by API') + end + + it 'can include a column with a link to its pipeline' do + render partial: 'projects/generic_commit_statuses/generic_commit_status', locals: { generic_commit_status: generic_commit_status, pipeline_link: true } + + expect(rendered).to have_link('#1337') + expect(rendered).to have_text('#1337 by API') + end +end diff --git a/spec/workers/delete_merged_branches_worker_spec.rb b/spec/workers/delete_merged_branches_worker_spec.rb new file mode 100644 index 00000000000..d9497bd486c --- /dev/null +++ b/spec/workers/delete_merged_branches_worker_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe DeleteMergedBranchesWorker do + subject(:worker) { described_class.new } + + let(:project) { create(:project) } + + describe "#perform" do + it "calls DeleteMergedBranchesService" do + expect_any_instance_of(DeleteMergedBranchesService).to receive(:execute).and_return(true) + + worker.perform(project.id, project.owner.id) + end + + it "returns false when project was not found" do + expect(worker.perform('unknown', project.owner.id)).to be_falsy + end + end +end diff --git a/spec/workers/new_note_worker_spec.rb b/spec/workers/new_note_worker_spec.rb new file mode 100644 index 00000000000..8fdbb35afd0 --- /dev/null +++ b/spec/workers/new_note_worker_spec.rb @@ -0,0 +1,49 @@ +require "spec_helper" + +describe NewNoteWorker do + context 'when Note found' do + let(:note) { create(:note) } + + it "calls NotificationService#new_note" do + expect_any_instance_of(NotificationService).to receive(:new_note).with(note) + + described_class.new.perform(note.id) + end + + it "calls Notes::PostProcessService#execute" do + notes_post_process_service = double(Notes::PostProcessService) + allow(Notes::PostProcessService).to receive(:new).with(note) { notes_post_process_service } + + expect(notes_post_process_service).to receive(:execute) + + described_class.new.perform(note.id) + end + end + + context 'when Note not found' do + let(:unexistent_note_id) { 999 } + + it 'logs NewNoteWorker process skipping' do + expect(Rails.logger).to receive(:error). + with("NewNoteWorker: couldn't find note with ID=999, skipping job") + + described_class.new.perform(unexistent_note_id) + end + + it 'does not raise errors' do + expect { described_class.new.perform(unexistent_note_id) }.not_to raise_error + end + + it "does not call NotificationService#new_note" do + expect_any_instance_of(NotificationService).not_to receive(:new_note) + + described_class.new.perform(unexistent_note_id) + end + + it "does not call Notes::PostProcessService#execute" do + expect_any_instance_of(Notes::PostProcessService).not_to receive(:execute) + + described_class.new.perform(unexistent_note_id) + end + end +end |