diff options
116 files changed, 594 insertions, 460 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a31817e2b8d..15d9117976a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -195,6 +195,10 @@ entry. - Added type to CHANGELOG entries. (Jacopo Beschi @jacopo-beschi) - [BUGIFX] Improves subgroup creation permissions. !13418 +## 9.5.7 (2017-10-03) + +- Fix gitlab rake:import:repos task. + ## 9.5.6 (2017-09-29) - [FIXED] Fix MR ready to merge buttons/controls at mobile breakpoint. !14242 diff --git a/app/assets/javascripts/locale/index.js b/app/assets/javascripts/locale/index.js index af718e894cf..ce05b3eabec 100644 --- a/app/assets/javascripts/locale/index.js +++ b/app/assets/javascripts/locale/index.js @@ -1,30 +1,12 @@ import Jed from 'jed'; - import sprintf from './sprintf'; -/** - This is required to require all the translation folders in the current directory - this saves us having to do this manually & keep up to date with new languages -**/ -function requireAll(requireContext) { return requireContext.keys().map(requireContext); } - -const allLocales = requireAll(require.context('./', true, /^(?!.*(?:index.js$)).*\.js$/)); -const locales = allLocales.reduce((d, obj) => { - const data = d; - const localeKey = Object.keys(obj)[0]; - - data[localeKey] = obj[localeKey]; - - return data; -}, {}); - const langAttribute = document.querySelector('html').getAttribute('lang'); const lang = (langAttribute || 'en').replace(/-/g, '_'); -const locale = new Jed(locales[lang]); +const locale = new Jed(window.translations || {}); /** Translates `text` - @param text The text to be translated @returns {String} The translated text **/ diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index 0db2abe507d..af0658eb668 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -127,6 +127,21 @@ import IssuablesHelper from './helpers/issuables_helper'; $el.text(gl.text.addDelimiter(count)); }; + MergeRequest.prototype.hideCloseButton = function() { + const el = document.querySelector('.merge-request .issuable-actions'); + const closeDropdownItem = el.querySelector('li.close-item'); + if (closeDropdownItem) { + closeDropdownItem.classList.add('hidden'); + // Selects the next dropdown item + el.querySelector('li.report-item').click(); + } else { + // No dropdown just hide the Close button + el.querySelector('.btn-close').classList.add('hidden'); + } + // Dropdown for mobile screen + el.querySelector('li.js-close-item').classList.add('hidden'); + }; + return MergeRequest; })(); }).call(window); diff --git a/app/assets/javascripts/project_fork.js b/app/assets/javascripts/project_fork.js index 68cf47fd54e..65d46fa9a73 100644 --- a/app/assets/javascripts/project_fork.js +++ b/app/assets/javascripts/project_fork.js @@ -1,8 +1,7 @@ export default () => { - $('.fork-thumbnail a').on('click', function forkThumbnailClicked() { + $('.js-fork-thumbnail').on('click', function forkThumbnailClicked() { if ($(this).hasClass('disabled')) return false; - $('.fork-namespaces').hide(); - return $('.save-project-loader').show(); + return $('.js-fork-content').toggle(); }); }; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js index f83d3ca00dd..0c48a484fe8 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js @@ -156,6 +156,7 @@ export default { eventHub.$emit('FetchActionsContent'); if (window.mergeRequest) { window.mergeRequest.updateStatusText('status-box-open', 'status-box-merged', 'Merged'); + window.mergeRequest.hideCloseButton(); window.mergeRequest.decreaseCounter(); } stopPolling(); diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss index bdcbd4021b3..f1aedc227f3 100644 --- a/app/assets/stylesheets/framework/avatar.scss +++ b/app/assets/stylesheets/framework/avatar.scss @@ -23,6 +23,7 @@ &.s60 { @include avatar-size(60px, 12px); } &.s70 { @include avatar-size(70px, 14px); } &.s90 { @include avatar-size(90px, 15px); } + &.s100 { @include avatar-size(100px, 15px); } &.s110 { @include avatar-size(110px, 15px); } &.s140 { @include avatar-size(140px, 15px); } &.s160 { @include avatar-size(160px, 20px); } @@ -78,6 +79,7 @@ &.s60 { font-size: 32px; line-height: 58px; } &.s70 { font-size: 34px; line-height: 70px; } &.s90 { font-size: 36px; line-height: 88px; } + &.s100 { font-size: 36px; line-height: 98px; } &.s110 { font-size: 40px; line-height: 108px; font-weight: $gl-font-weight-normal; } &.s140 { font-size: 72px; line-height: 138px; } &.s160 { font-size: 96px; line-height: 158px; } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 1f7b6703909..a086c11324d 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -499,73 +499,56 @@ a.deploy-project-label { } } -.fork-namespaces { - .row { - -webkit-flex-wrap: wrap; - display: -webkit-flex; - display: flex; - flex-wrap: wrap; - justify-content: flex-start; +.fork-thumbnail { + height: 200px; + width: calc((100% / 2) - #{$gl-padding * 2}); - .fork-thumbnail { - border-radius: $border-radius-base; - background-color: $white-light; - border: 1px solid $border-white-light; - height: 202px; - margin: $gl-padding; - text-align: center; - width: 169px; + @media (min-width: $screen-md-min) { + width: calc((100% / 4) - #{$gl-padding * 2}); + } - &:hover:not(.disabled), - &.forked { - background-color: $row-hover; - border-color: $row-hover-border; - } + @media (min-width: $screen-lg-min) { + width: calc((100% / 5) - #{$gl-padding * 2}); + } - .no-avatar { - width: 100px; - height: 100px; - background-color: $gray-light; - border: 1px solid $white-normal; - margin: 0 auto; - border-radius: 50%; - - i { - font-size: 100px; - color: $white-normal; - } - } + &:hover:not(.disabled), + &.forked { + background-color: $row-hover; + border-color: $row-hover-border; + } - a { - display: block; - width: 100%; - height: 100%; - padding-top: $gl-padding; - color: $gl-text-color; - - &.disabled { - opacity: .3; - cursor: not-allowed; - - &:hover { - text-decoration: none; - } - } - - .caption { - min-height: 30px; - padding: $gl-padding 0; - } - } + .avatar-container, + .identicon { + float: none; + margin-left: auto; + margin-right: auto; + } - img { - border-radius: 50%; - max-width: 100px; - } + a { + display: block; + width: 100%; + height: 100%; + padding-top: $gl-padding; + text-decoration: none; + + &.disabled { + opacity: .3; + cursor: not-allowed; } } } +.fork-thumbnail-container { + display: flex; + flex-wrap: wrap; + margin-left: -$gl-padding; + margin-right: -$gl-padding; + + > h5 { + width: 100%; + } +} + .project-template, .project-import { .form-group { diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb index c1cc509a748..4146deefa89 100644 --- a/app/controllers/profiles/personal_access_tokens_controller.rb +++ b/app/controllers/profiles/personal_access_tokens_controller.rb @@ -1,6 +1,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController def index set_index_vars + @personal_access_token = finder.build end def create @@ -40,7 +41,6 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController def set_index_vars @scopes = Gitlab::Auth.available_scopes - @personal_access_token = finder.build @inactive_personal_access_tokens = finder(state: 'inactive').execute @active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at) end diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index a9cce578366..7f03ce07dec 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -9,7 +9,7 @@ class Projects::BranchesController < Projects::ApplicationController def index @sort = params[:sort].presence || sort_value_recently_updated - @branches = BranchesFinder.new(@repository, params).execute + @branches = BranchesFinder.new(@repository, params.merge(sort: @sort)).execute @branches = Kaminari.paginate_array(@branches).page(params[:page]) respond_to do |format| diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index b331693c789..fd88e0d794a 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -1,13 +1,15 @@ module EventsHelper ICON_NAMES_BY_EVENT_TYPE = { - 'pushed to' => 'icon_commit', - 'pushed new' => 'icon_commit', - 'created' => 'icon_status_open', - 'opened' => 'icon_status_open', - 'closed' => 'icon_status_closed', - 'accepted' => 'icon_code_fork', - 'commented on' => 'icon_comment_o', - 'deleted' => 'icon_trash_o' + 'pushed to' => 'commit', + 'pushed new' => 'commit', + 'created' => 'status_open', + 'opened' => 'status_open', + 'closed' => 'status_closed', + 'accepted' => 'fork', + 'commented on' => 'comment', + 'deleted' => 'remove', + 'imported' => 'import', + 'joined' => 'users' }.freeze def link_to_author(event, self_added: false) @@ -197,7 +199,7 @@ module EventsHelper def icon_for_event(note) icon_name = ICON_NAMES_BY_EVENT_TYPE[note] - custom_icon(icon_name) if icon_name + sprite_icon(icon_name) if icon_name end def icon_for_profile_event(event) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 3cb6913549d..0ba00d447e8 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -560,14 +560,20 @@ class MergeRequest < ActiveRecord::Base commits_for_notes_limit = 100 commit_ids = commit_shas.take(commits_for_notes_limit) - Note.where( - "(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" + - "((project_id = :source_project_id OR project_id = :target_project_id) AND noteable_type = 'Commit' AND commit_id IN (:commit_ids))", - mr_id: id, - commit_ids: commit_ids, - target_project_id: target_project_id, - source_project_id: source_project_id - ) + commit_notes = Note + .except(:order) + .where(project_id: [source_project_id, target_project_id]) + .where(noteable_type: 'Commit', commit_id: commit_ids) + + # We're using a UNION ALL here since this results in better performance + # compared to using OR statements. We're using UNION ALL since the queries + # used won't produce any duplicates (e.g. a note for a commit can't also be + # a note for an MR). + union = Gitlab::SQL::Union + .new([notes, commit_notes], remove_duplicates: false) + .to_sql + + Note.from("(#{union}) #{Note.table_name}") end alias_method :discussion_notes, :related_notes diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb index 1f9d712ef84..cfcb03138b7 100644 --- a/app/models/personal_access_token.rb +++ b/app/models/personal_access_token.rb @@ -17,6 +17,8 @@ class PersonalAccessToken < ActiveRecord::Base validates :scopes, presence: true validate :validate_scopes + after_initialize :set_default_scopes, if: :persisted? + def revoke! update!(revoked: true) end @@ -32,4 +34,8 @@ class PersonalAccessToken < ActiveRecord::Base errors.add :scopes, "can only contain available scopes" end end + + def set_default_scopes + self.scopes = Gitlab::Auth::DEFAULT_SCOPES if self.scopes.empty? + end end diff --git a/app/models/repository.rb b/app/models/repository.rb index d47dc9a05cd..d725c65081d 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -989,7 +989,7 @@ class Repository end def create_ref(ref, ref_path) - fetch_ref(path_to_repo, ref, ref_path) + raw_repository.write_ref(ref_path, ref) end def ls_files(ref) diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index e3a9e99250e..0d5350f873b 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -37,9 +37,9 @@ - if content_for?(:library_javascripts) = yield :library_javascripts + = javascript_include_tag asset_path("locale/#{I18n.locale.to_s || I18n.default_locale.to_s}/app.js") = webpack_bundle_tag "webpack_runtime" = webpack_bundle_tag "common" - = webpack_bundle_tag "locale" = webpack_bundle_tag "main" = webpack_bundle_tag "raven" if current_application_settings.clientside_sentry_enabled = webpack_bundle_tag "test" if Rails.env.test? diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml index 906774a21e3..e9613534dde 100644 --- a/app/views/projects/forks/new.html.haml +++ b/app/views/projects/forks/new.html.haml @@ -9,50 +9,36 @@ %br Forking a repository allows you to make changes without affecting the original project. .col-lg-9 - .fork-namespaces - - if @namespaces.present? - %label.label-light - %span - Click to fork the project - - @namespaces.in_groups_of(6, false) do |group| - .row - - group.each do |namespace| - - avatar = namespace_icon(namespace, 100) - - if fork = namespace.find_fork_of(@project) - .fork-thumbnail.forked - = link_to project_path(fork) do - - if /no_((\w*)_)*avatar/.match(avatar) - .no-avatar - = icon 'question' - - else - = image_tag avatar - .caption - = namespace.human_name - - else - - can_create_project = current_user.can?(:create_projects, namespace) - .fork-thumbnail{ class: ("disabled" unless can_create_project) } - = link_to project_forks_path(@project, namespace_key: namespace.id), - method: "POST", - class: ("disabled has-tooltip" unless can_create_project), - title: (_('You have reached your project limit') unless can_create_project) do - - if /no_((\w*)_)*avatar/.match(avatar) - .no-avatar - = icon 'question' - - else - = image_tag avatar - .caption - = namespace.human_name - - else - %label.label-light - %span - No available namespaces to fork the project. - %br - %small - You must have permission to create a project in a namespace before forking. + - if @namespaces.present? + .fork-thumbnail-container.js-fork-content + %h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default + Click to fork the project + - @namespaces.each do |namespace| + - avatar = namespace_icon(namespace, 100) + - can_create_project = current_user.can?(:create_projects, namespace) + - forked_project = namespace.find_fork_of(@project) + - fork_path = forked_project ? project_path(forked_project) : project_forks_path(@project, namespace_key: namespace.id) + .bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default{ class: [("disabled" unless can_create_project), ("forked" if forked_project)] } + = link_to fork_path, + method: "POST", + class: [("js-fork-thumbnail" unless forked_project), ("disabled has-tooltip" unless can_create_project)], + title: (_('You have reached your project limit') unless can_create_project) do + - if /no_((\w*)_)*avatar/.match(avatar) + = project_identicon(namespace, class: "avatar s100 identicon") + - else + .avatar-container.s100 + = image_tag(avatar, class: "avatar s100") + %h5.prepend-top-default + = namespace.human_name + - else + %strong + No available namespaces to fork the project. + %p.prepend-top-default + You must have permission to create a project in a namespace before forking. - .save-project-loader.hide - .center - %h2 - %i.fa.fa-spinner.fa-spin - Forking repository - %p Please wait a moment, this page will automatically refresh when ready. + .save-project-loader.hide.js-fork-content + %h2.text-center + = icon('spinner spin') + Forking repository + %p.text-center + Please wait a moment, this page will automatically refresh when ready. diff --git a/app/views/projects/merge_requests/_mr_title.html.haml b/app/views/projects/merge_requests/_mr_title.html.haml index f3c44c94a5c..9ff85c2ee4c 100644 --- a/app/views/projects/merge_requests/_mr_title.html.haml +++ b/app/views/projects/merge_requests/_mr_title.html.haml @@ -29,7 +29,7 @@ - unless current_user == @merge_request.author %li= link_to 'Report abuse', new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request)) - if can_update_merge_request - %li{ class: merge_request_button_visibility(@merge_request, true) } + %li{ class: [merge_request_button_visibility(@merge_request, true), 'js-close-item'] } = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, title: 'Close merge request' %li{ class: merge_request_button_visibility(@merge_request, false) } = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request' diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index b842fd57cf3..c0b1c62e8ef 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -23,7 +23,7 @@ - disabled_class = 'disabled' - disabled_title = @service.disabled_title - = link_to 'Cancel', project_settings_integrations_path(@project), class: 'btn btn-cancel' + = link_to 'Cancel', project_settings_integrations_path(@project), class: 'btn btn-cancel' - if lookup_context.template_exists?('show', "projects/services/#{@service.to_param}", true) %hr diff --git a/app/views/shared/_personal_access_tokens_form.html.haml b/app/views/shared/_personal_access_tokens_form.html.haml index e415ec64c38..b8b1f4ca42f 100644 --- a/app/views/shared/_personal_access_tokens_form.html.haml +++ b/app/views/shared/_personal_access_tokens_form.html.haml @@ -1,9 +1,9 @@ - type = impersonation ? "impersonation" : "personal access" %h5.prepend-top-0 - Add a #{type} Token + Add a #{type} token %p.profile-settings-content - Pick a name for the application, and we'll give you a unique #{type} Token. + Pick a name for the application, and we'll give you a unique #{type} token. = form_for token, url: path, method: :post, html: { class: 'js-requires-input' } do |f| diff --git a/changelogs/unreleased/26890-fix-default-branches-sorting.yml b/changelogs/unreleased/26890-fix-default-branches-sorting.yml new file mode 100644 index 00000000000..cf7060190b3 --- /dev/null +++ b/changelogs/unreleased/26890-fix-default-branches-sorting.yml @@ -0,0 +1,5 @@ +--- +title: Fix the default branches sorting to actually be 'Last updated' +merge_request: 14295 +author: +type: fixed diff --git a/changelogs/unreleased/36742-hide-close-mr-button-on-merge.yml b/changelogs/unreleased/36742-hide-close-mr-button-on-merge.yml new file mode 100644 index 00000000000..3d3efcdbcc6 --- /dev/null +++ b/changelogs/unreleased/36742-hide-close-mr-button-on-merge.yml @@ -0,0 +1,5 @@ +--- +title: Hide close MR button after merge without reloading page +merge_request: 14122 +author: Jacopo Beschi @jacopo-beschi +type: added diff --git a/changelogs/unreleased/dm-pat-revoke.yml b/changelogs/unreleased/dm-pat-revoke.yml new file mode 100644 index 00000000000..32ac66056d5 --- /dev/null +++ b/changelogs/unreleased/dm-pat-revoke.yml @@ -0,0 +1,5 @@ +--- +title: Set default scope on PATs that don't have one set to allow them to be revoked +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix-edit-project-service-cancel-button-position.yml b/changelogs/unreleased/fix-edit-project-service-cancel-button-position.yml new file mode 100644 index 00000000000..efb993eff71 --- /dev/null +++ b/changelogs/unreleased/fix-edit-project-service-cancel-button-position.yml @@ -0,0 +1,5 @@ +--- +title: Fix edit project service cancel button position +merge_request: 14596 +author: Matt Coleman +type: fixed diff --git a/changelogs/unreleased/merge-request-notes-performance.yml b/changelogs/unreleased/merge-request-notes-performance.yml new file mode 100644 index 00000000000..6cf7a5047df --- /dev/null +++ b/changelogs/unreleased/merge-request-notes-performance.yml @@ -0,0 +1,5 @@ +--- +title: Use a UNION ALL for getting merge request notes +merge_request: +author: +type: other diff --git a/config/application.rb b/config/application.rb index 30117b6a98e..ca2ab83becc 100644 --- a/config/application.rb +++ b/config/application.rb @@ -105,6 +105,7 @@ module Gitlab config.assets.precompile << "lib/ace.js" config.assets.precompile << "vendor/assets/fonts/*" config.assets.precompile << "test.css" + config.assets.precompile << "locale/**/app.js" # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index c5c50c216e1..88771c5f5bb 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -499,6 +499,8 @@ production: &base # Gitaly settings gitaly: + # Path to the directory containing Gitaly client executables. + client_path: /home/git/gitaly # Default Gitaly authentication token. Can be overriden per storage. Can # be left blank when Gitaly is running locally on a Unix socket, which # is the normal way to deploy Gitaly. @@ -664,7 +666,7 @@ test: gitaly_address: unix:tmp/tests/gitaly/gitaly.socket gitaly: - enabled: true + client_path: tmp/tests/gitaly token: secret backup: path: tmp/tests/backups diff --git a/config/initializers/gettext_rails_i18n_patch.rb b/config/initializers/gettext_rails_i18n_patch.rb index 377e5104f9d..49551319435 100644 --- a/config/initializers/gettext_rails_i18n_patch.rb +++ b/config/initializers/gettext_rails_i18n_patch.rb @@ -39,3 +39,17 @@ module GettextI18nRailsJs end end end + +class PoToJson + # This is required to modify the JS locale file output to our import needs + # Overwrites: https://github.com/webhippie/po_to_json/blob/master/lib/po_to_json.rb#L46 + def generate_for_jed(language, overwrite = {}) + @options = parse_options(overwrite.merge(language: language)) + @parsed ||= inject_meta(parse_document) + + generated = build_json_for(build_jed_for(@parsed)) + [ + "window.translations = #{generated};" + ].join(" ") + end +end diff --git a/config/webpack.config.js b/config/webpack.config.js index 2eb4444916b..c515a170d2d 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -123,10 +123,6 @@ var config = { } }, { - test: /locale\/\w+\/(.*)\.js$/, - loader: 'exports-loader?locales', - }, - { test: /monaco-editor\/\w+\/vs\/loader\.js$/, use: [ { loader: 'exports-loader', options: 'l.global' }, @@ -224,7 +220,7 @@ var config = { // create cacheable common library bundles new webpack.optimize.CommonsChunkPlugin({ - names: ['main', 'locale', 'common', 'webpack_runtime'], + names: ['main', 'common', 'webpack_runtime'], }), // enable scope hoisting diff --git a/db/migrate/20150827121444_add_fast_forward_option_to_project.rb b/db/migrate/20150827121444_add_fast_forward_option_to_project.rb index 014f5b2f372..6f22641077d 100644 --- a/db/migrate/20150827121444_add_fast_forward_option_to_project.rb +++ b/db/migrate/20150827121444_add_fast_forward_option_to_project.rb @@ -7,11 +7,13 @@ class AddFastForwardOptionToProject < ActiveRecord::Migration disable_ddl_transaction! - def add + def up add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false) end def down - remove_column(:projects, :merge_requests_ff_only_enabled) + if column_exists?(:projects, :merge_requests_ff_only_enabled) + remove_column(:projects, :merge_requests_ff_only_enabled) + end end end diff --git a/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb b/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb new file mode 100644 index 00000000000..ac266c3e22e --- /dev/null +++ b/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb @@ -0,0 +1,25 @@ +# rubocop:disable all +class MakeSureFastForwardOptionExists < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + disable_ddl_transaction! + + def up + # We had to fix the migration db/migrate/20150827121444_add_fast_forward_option_to_project.rb + # And this is why it's possible that someone has ran the migrations but does + # not have the merge_requests_ff_only_enabled column. This migration makes sure it will + # be added + unless column_exists?(:projects, :merge_requests_ff_only_enabled) + add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false) + end + end + + def down + if column_exists?(:projects, :merge_requests_ff_only_enabled) + remove_column(:projects, :merge_requests_ff_only_enabled) + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 3428807dd7c..fa1aad257db 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170928100231) do +ActiveRecord::Schema.define(version: 20171004121444) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index bff8a2d3e4d..63a5dd1445c 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -121,6 +121,15 @@ GET /projects/:id/merge_requests?labels=bug,reproduced GET /projects/:id/merge_requests?my_reaction_emoji=star ``` +`project_id` represents the ID of the project where the MR resides. +`project_id` will always equal `target_project_id`. + +In the case of a merge request from the same project, +`source_project_id`, `target_project_id` and `project_id` +will be the same. In the case of a merge request from a fork, +`target_project_id` and `project_id` will be the same and +`source_project_id` will be the fork project's ID. + Parameters: | Attribute | Type | Required | Description | diff --git a/doc/ci/enable_or_disable_ci.md b/doc/ci/enable_or_disable_ci.md index 796a025b951..b8f9988e3ef 100644 --- a/doc/ci/enable_or_disable_ci.md +++ b/doc/ci/enable_or_disable_ci.md @@ -1,51 +1,46 @@ -## Enable or disable GitLab CI +## Enable or disable GitLab CI/CD -_To effectively use GitLab CI, you need a valid [`.gitlab-ci.yml`](yaml/README.md) +To effectively use GitLab CI/CD, you need a valid [`.gitlab-ci.yml`](yaml/README.md) file present at the root directory of your project and a [runner](runners/README.md) properly set up. You can read our -[quick start guide](quick_start/README.md) to get you started._ +[quick start guide](quick_start/README.md) to get you started. -If you are using an external CI server like Jenkins or Drone CI, it is advised -to disable GitLab CI in order to not have any conflicts with the commits status +If you are using an external CI/CD server like Jenkins or Drone CI, it is advised +to disable GitLab CI/CD in order to not have any conflicts with the commits status API. --- -GitLab CI is exposed via the `/pipelines` and `/builds` pages of a project. -Disabling GitLab CI in a project does not delete any previous jobs. -In fact, the `/pipelines` and `/builds` pages can still be accessed, although +GitLab CI/CD is exposed via the `/pipelines` and `/jobs` pages of a project. +Disabling GitLab CI/CD in a project does not delete any previous jobs. +In fact, the `/pipelines` and `/jobs` pages can still be accessed, although it's hidden from the left sidebar menu. -GitLab CI is enabled by default on new installations and can be disabled either +GitLab CI/CD is enabled by default on new installations and can be disabled either individually under each project's settings, or site-wide by modifying the settings in `gitlab.yml` and `gitlab.rb` for source and Omnibus installations respectively. ### Per-project user setting -The setting to enable or disable GitLab CI can be found with the name **Pipelines** -under the **Sharing & Permissions** area of a project's settings along with -**Merge Requests**. Choose one of **Disabled**, **Only team members** and -**Everyone with access** and hit **Save changes** for the settings to take effect. +The setting to enable or disable GitLab CI/CD can be found under your project's +**Settings > General > Permissions**. Choose one of "Disabled", "Only team members" +or "Everyone with access" and hit **Save changes** for the settings to take effect. - + ---- - -### Site-wide administrator setting +### Site-wide admin setting -You can disable GitLab CI site-wide, by modifying the settings in `gitlab.yml` +You can disable GitLab CI/CD site-wide, by modifying the settings in `gitlab.yml` and `gitlab.rb` for source and Omnibus installations respectively. Two things to note: -1. Disabling GitLab CI, will affect only newly-created projects. Projects that +1. Disabling GitLab CI/CD, will affect only newly-created projects. Projects that had it enabled prior to this modification, will work as before. -1. Even if you disable GitLab CI, users will still be able to enable it in the +1. Even if you disable GitLab CI/CD, users will still be able to enable it in the project's settings. ---- - For installations from source, open `gitlab.yml` with your editor and set `builds` to `false`: diff --git a/doc/ci/environments.md b/doc/ci/environments.md index acd5682841a..c03e16b1b38 100644 --- a/doc/ci/environments.md +++ b/doc/ci/environments.md @@ -26,7 +26,7 @@ so every environment can have one or more deployments. GitLab keeps track of your deployments, so you always know what is currently being deployed on your servers. If you have a deployment service such as [Kubernetes][kubernetes-service] enabled for your project, you can use it to assist with your deployments, and -can even access a web terminal for your environment from within GitLab! +can even access a [web terminal](#web-terminals) for your environment from within GitLab! To better understand how environments and deployments work, let's consider an example. We assume that you have already created a project in GitLab and set up @@ -119,7 +119,7 @@ where you can find information of the last deployment status of an environment. Here's how the Environments page looks so far. - + There's a bunch of information there, specifically you can see: @@ -229,7 +229,7 @@ You can find it in the pipeline, job, environment, and deployment views. | Pipelines | Single pipeline | Environments | Deployments | jobs | | --------- | ----------------| ------------ | ----------- | -------| -|  |  |  |  |  | +|  |  |  |  |  | Clicking on the play button in either of these places will trigger the `deploy_prod` job, and the deployment will be recorded under a new @@ -402,7 +402,7 @@ places within GitLab. | In a merge request widget as a link | In the Environments view as a button | In the Deployments view as a button | | -------------------- | ------------ | ----------- | -|  |  |  | +|  |  |  | If a merge request is eventually merged to the default branch (in our case `master`) and that branch also deploys to an environment (in our case `staging` @@ -574,7 +574,7 @@ Once configured, GitLab will attempt to retrieve [supported performance metrics] environment which has had a successful deployment. If monitoring data was successfully retrieved, a Monitoring button will appear for each environment. - + Clicking on the Monitoring button will display a new page, showing up to the last 8 hours of performance data. It may take a minute or two for data to appear @@ -593,10 +593,11 @@ Web terminals were added in GitLab 8.15 and are only available to project masters and owners. If you deploy to your environments with the help of a deployment service (e.g., -the [Kubernetes service][kubernetes-service], GitLab can open +the [Kubernetes service][kubernetes-service]), GitLab can open a terminal session to your environment! This is a very powerful feature that allows you to debug issues without leaving the comfort of your web browser. To -enable it, just follow the instructions given in the service documentation. +enable it, just follow the instructions given in the service integration +documentation. Once enabled, your environments will gain a "terminal" button: diff --git a/doc/ci/img/builds_tab.png b/doc/ci/img/builds_tab.png Binary files differdeleted file mode 100644 index 2d7eec8a949..00000000000 --- a/doc/ci/img/builds_tab.png +++ /dev/null diff --git a/doc/ci/img/deployments_view.png b/doc/ci/img/deployments_view.png Binary files differindex 7ded0c97b72..436fed5f465 100644 --- a/doc/ci/img/deployments_view.png +++ b/doc/ci/img/deployments_view.png diff --git a/doc/ci/img/environments_available.png b/doc/ci/img/environments_available.png Binary files differnew file mode 100644 index 00000000000..2991a309655 --- /dev/null +++ b/doc/ci/img/environments_available.png diff --git a/doc/ci/img/environments_available_staging.png b/doc/ci/img/environments_available_staging.png Binary files differdeleted file mode 100644 index 5c031ad0d9d..00000000000 --- a/doc/ci/img/environments_available_staging.png +++ /dev/null diff --git a/doc/ci/img/environments_dynamic_groups.png b/doc/ci/img/environments_dynamic_groups.png Binary files differindex 0f42b368c5b..45124b3d8d8 100644 --- a/doc/ci/img/environments_dynamic_groups.png +++ b/doc/ci/img/environments_dynamic_groups.png diff --git a/doc/ci/img/environments_link_url.png b/doc/ci/img/environments_link_url.png Binary files differdeleted file mode 100644 index 44010f6aa6f..00000000000 --- a/doc/ci/img/environments_link_url.png +++ /dev/null diff --git a/doc/ci/img/environments_link_url_deployments.png b/doc/ci/img/environments_link_url_deployments.png Binary files differdeleted file mode 100644 index 4f90143527a..00000000000 --- a/doc/ci/img/environments_link_url_deployments.png +++ /dev/null diff --git a/doc/ci/img/environments_link_url_mr.png b/doc/ci/img/environments_link_url_mr.png Binary files differindex 64f134e0b0d..7ce46063062 100644 --- a/doc/ci/img/environments_link_url_mr.png +++ b/doc/ci/img/environments_link_url_mr.png diff --git a/doc/ci/img/environments_manual_action_builds.png b/doc/ci/img/environments_manual_action_builds.png Binary files differdeleted file mode 100644 index e7cf63a1031..00000000000 --- a/doc/ci/img/environments_manual_action_builds.png +++ /dev/null diff --git a/doc/ci/img/environments_manual_action_deployments.png b/doc/ci/img/environments_manual_action_deployments.png Binary files differindex 2b3f6f3edad..93beaa0de54 100644 --- a/doc/ci/img/environments_manual_action_deployments.png +++ b/doc/ci/img/environments_manual_action_deployments.png diff --git a/doc/ci/img/environments_manual_action_environments.png b/doc/ci/img/environments_manual_action_environments.png Binary files differindex e0c07604e7f..9490be63f14 100644 --- a/doc/ci/img/environments_manual_action_environments.png +++ b/doc/ci/img/environments_manual_action_environments.png diff --git a/doc/ci/img/environments_manual_action_jobs.png b/doc/ci/img/environments_manual_action_jobs.png Binary files differnew file mode 100644 index 00000000000..9ae223cf77f --- /dev/null +++ b/doc/ci/img/environments_manual_action_jobs.png diff --git a/doc/ci/img/environments_manual_action_pipelines.png b/doc/ci/img/environments_manual_action_pipelines.png Binary files differindex 82bbae88027..129e44f6fb0 100644 --- a/doc/ci/img/environments_manual_action_pipelines.png +++ b/doc/ci/img/environments_manual_action_pipelines.png diff --git a/doc/ci/img/environments_manual_action_single_pipeline.png b/doc/ci/img/environments_manual_action_single_pipeline.png Binary files differindex 36337cb1870..1eeb4379eb7 100644 --- a/doc/ci/img/environments_manual_action_single_pipeline.png +++ b/doc/ci/img/environments_manual_action_single_pipeline.png diff --git a/doc/ci/img/environments_mr_review_app.png b/doc/ci/img/environments_mr_review_app.png Binary files differindex 7bff84362a3..4bb643d708f 100644 --- a/doc/ci/img/environments_mr_review_app.png +++ b/doc/ci/img/environments_mr_review_app.png diff --git a/doc/ci/img/environments_terminal_button_on_index.png b/doc/ci/img/environments_terminal_button_on_index.png Binary files differindex 6f05b2aa343..061bb7c3c87 100644 --- a/doc/ci/img/environments_terminal_button_on_index.png +++ b/doc/ci/img/environments_terminal_button_on_index.png diff --git a/doc/ci/img/environments_terminal_button_on_show.png b/doc/ci/img/environments_terminal_button_on_show.png Binary files differindex 9469fab99ab..4d24304bc93 100644 --- a/doc/ci/img/environments_terminal_button_on_show.png +++ b/doc/ci/img/environments_terminal_button_on_show.png diff --git a/doc/ci/img/environments_view.png b/doc/ci/img/environments_view.png Binary files differdeleted file mode 100644 index 821352188ef..00000000000 --- a/doc/ci/img/environments_view.png +++ /dev/null diff --git a/doc/ci/img/permissions_settings.png b/doc/ci/img/permissions_settings.png Binary files differdeleted file mode 100644 index 1454c75fd24..00000000000 --- a/doc/ci/img/permissions_settings.png +++ /dev/null diff --git a/doc/ci/img/prometheus_environment_detail_with_metrics.png b/doc/ci/img/prometheus_environment_detail_with_metrics.png Binary files differdeleted file mode 100644 index 214b10624a9..00000000000 --- a/doc/ci/img/prometheus_environment_detail_with_metrics.png +++ /dev/null diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index ebcb92b5db1..17839cbaef1 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -149,14 +149,15 @@ script: ## Secret variables ->**Notes:** -- This feature requires GitLab Runner 0.4.0 or higher. -- Group-level secret variables added in GitLab 9.4. -- Be aware that secret variables are not masked, and their values can be shown - in the job logs if explicitly asked to do so. If your project is public or - internal, you can set the pipelines private from your project's Pipelines - settings. Follow the discussion in issue [#13784][ce-13784] for masking the - secret variables. +NOTE: **Note:** +Group-level secret variables were added in GitLab 9.4. + +CAUTION: **Important:** +Be aware that secret variables are not masked, and their values can be shown +in the job logs if explicitly asked to do so. If your project is public or +internal, you can set the pipelines private from your [project's Pipelines +settings](../../user/project/pipelines/settings.md#visibility-of-pipelines). +Follow the discussion in issue [#13784][ce-13784] for masking the secret variables. GitLab CI allows you to define per-project or per-group secret variables that are set in the pipeline environment. The secret variables are stored out of @@ -171,6 +172,8 @@ Likewise, group-level secret variables can be added by going to your group's **Settings > CI/CD**, then finding the section called **Secret variables**. Any variables of [subgroups] will be inherited recursively. + + Once you set them, they will be available for all subsequent pipelines. You can also [protect your variables](#protected-secret-variables). @@ -202,7 +205,7 @@ are set in the build environment. These variables are only defined for the project services that you are using to learn which variables they define. An example project service that defines deployment variables is -[Kubernetes Service](../../user/project/integrations/kubernetes.md). +[Kubernetes Service](../../user/project/integrations/kubernetes.md#deployment-variables). ## Debug tracing @@ -439,7 +442,7 @@ export CI_REGISTRY_USER="gitlab-ci-token" export CI_REGISTRY_PASSWORD="longalfanumstring" ``` -[ce-13784]: https://gitlab.com/gitlab-org/gitlab-ce/issues/13784 +[ce-13784]: https://gitlab.com/gitlab-org/gitlab-ce/issues/13784 "Simple protection of CI secret variables" [eep]: https://about.gitlab.com/gitlab-ee/ "Available only in GitLab Enterprise Edition Premium" [envs]: ../environments.md [protected branches]: ../../user/project/protected_branches.md diff --git a/doc/ci/variables/img/secret_variables.png b/doc/ci/variables/img/secret_variables.png Binary files differnew file mode 100644 index 00000000000..f70935069d9 --- /dev/null +++ b/doc/ci/variables/img/secret_variables.png diff --git a/doc/development/testing.md b/doc/development/testing.md index d856b003353..4d5b90de6fc 100644 --- a/doc/development/testing.md +++ b/doc/development/testing.md @@ -302,7 +302,7 @@ range of inputs, might look like this: ```ruby describe "#==" do - using Rspec::Parameterized::TableSyntax + using RSpec::Parameterized::TableSyntax let(:project1) { create(:project) } let(:project2) { create(:project) } diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md index 5c615daf464..2c4dfcff4a6 100644 --- a/doc/user/project/container_registry.md +++ b/doc/user/project/container_registry.md @@ -17,25 +17,25 @@ have its own space to store its Docker images. You can read more about Docker Registry at https://docs.docker.com/registry/introduction/. ---- - ## Enable the Container Registry for your project +NOTE: **Note:** +If you cannot find the Container Registry entry under your project's settings, +that means that it is not enabled in your GitLab instance. Ask your administrator +to enable it. + 1. First, ask your system administrator to enable GitLab Container Registry following the [administration documentation](../../administration/container_registry.md). If you are using GitLab.com, this is enabled by default so you can start using the Registry immediately. - -1. Go to your project's settings and enable the **Container Registry** feature - on your project. For new projects this might be enabled by default. For - existing projects (prior GitLab 8.8), you will have to explicitly enable it. - -  - +1. Go to your [project's General settings](settings/index.md#sharing-and-permissions) + and enable the **Container Registry** feature on your project. For new + projects this might be enabled by default. For existing projects + (prior GitLab 8.8), you will have to explicitly enable it. 1. Hit **Save changes** for the changes to take effect. You should now be able - to see the **Registry** link in the project menu. + to see the **Registry** link in the sidebar. -  + ## Build and push images diff --git a/doc/user/project/img/container_registry.png b/doc/user/project/img/container_registry.png Binary files differnew file mode 100644 index 00000000000..abbaf838538 --- /dev/null +++ b/doc/user/project/img/container_registry.png diff --git a/doc/user/project/img/container_registry_enable.png b/doc/user/project/img/container_registry_enable.png Binary files differdeleted file mode 100644 index d067a8be1ca..00000000000 --- a/doc/user/project/img/container_registry_enable.png +++ /dev/null diff --git a/doc/user/project/img/container_registry_tab.png b/doc/user/project/img/container_registry_tab.png Binary files differdeleted file mode 100644 index a85237271d9..00000000000 --- a/doc/user/project/img/container_registry_tab.png +++ /dev/null diff --git a/doc/user/project/img/issue_board.png b/doc/user/project/img/issue_board.png Binary files differindex cf7f519f783..5f6dc9e4e8b 100644 --- a/doc/user/project/img/issue_board.png +++ b/doc/user/project/img/issue_board.png diff --git a/doc/user/project/img/issue_board_move_issue_card_list.png b/doc/user/project/img/issue_board_move_issue_card_list.png Binary files differindex c6b17ada40e..3666dbb87ab 100644 --- a/doc/user/project/img/issue_board_move_issue_card_list.png +++ b/doc/user/project/img/issue_board_move_issue_card_list.png diff --git a/doc/user/project/img/labels_assign_label_in_new_issue.png b/doc/user/project/img/labels_assign_label_in_new_issue.png Binary files differdeleted file mode 100644 index badfbed0bbe..00000000000 --- a/doc/user/project/img/labels_assign_label_in_new_issue.png +++ /dev/null diff --git a/doc/user/project/img/labels_default.png b/doc/user/project/img/labels_default.png Binary files differindex 474953d565b..7934e3bfb5e 100644 --- a/doc/user/project/img/labels_default.png +++ b/doc/user/project/img/labels_default.png diff --git a/doc/user/project/img/labels_filter.png b/doc/user/project/img/labels_filter.png Binary files differindex 3aca77f0070..6a1ebfc2ecb 100644 --- a/doc/user/project/img/labels_filter.png +++ b/doc/user/project/img/labels_filter.png diff --git a/doc/user/project/img/labels_filter_by_priority.png b/doc/user/project/img/labels_filter_by_priority.png Binary files differindex 5609a1f6d7f..419e555e709 100644 --- a/doc/user/project/img/labels_filter_by_priority.png +++ b/doc/user/project/img/labels_filter_by_priority.png diff --git a/doc/user/project/img/labels_new_label.png b/doc/user/project/img/labels_new_label.png Binary files differindex b44b4bd296d..e26425d0188 100644 --- a/doc/user/project/img/labels_new_label.png +++ b/doc/user/project/img/labels_new_label.png diff --git a/doc/user/project/img/labels_prioritize.png b/doc/user/project/img/labels_prioritize.png Binary files differindex 3e888f36364..d602a3c90ec 100644 --- a/doc/user/project/img/labels_prioritize.png +++ b/doc/user/project/img/labels_prioritize.png diff --git a/doc/user/project/img/project_repository_settings.png b/doc/user/project/img/project_repository_settings.png Binary files differindex 1aa7efc36f1..aa4d4452c87 100644 --- a/doc/user/project/img/project_repository_settings.png +++ b/doc/user/project/img/project_repository_settings.png diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md index e2cc67726e0..96a5a23ee13 100644 --- a/doc/user/project/issue_board.md +++ b/doc/user/project/issue_board.md @@ -12,6 +12,8 @@ Other interesting links: - [GitLab Issue Board landing page on about.gitlab.com][landing] - [YouTube video introduction to Issue Boards][youtube] + + ## Overview The Issue Board builds on GitLab's existing @@ -89,10 +91,6 @@ two defaults: - **Backlog** (default): shows all open issues that does not belong to one of lists. Always appears on the very left. - **Closed** (default): shows all closed issues. Always appears on the very right. - - ---- - In short, here's a list of actions you can take in an Issue Board: - [Create a new list](#creating-a-new-list). diff --git a/doc/user/project/issues/img/button_close_issue.png b/doc/user/project/issues/img/button_close_issue.png Binary files differindex 8fb2e23f58a..05d257ce9bf 100644 --- a/doc/user/project/issues/img/button_close_issue.png +++ b/doc/user/project/issues/img/button_close_issue.png diff --git a/doc/user/project/issues/img/group_issues_list_view.png b/doc/user/project/issues/img/group_issues_list_view.png Binary files differindex 5d20e8cbc89..bba964076d0 100644 --- a/doc/user/project/issues/img/group_issues_list_view.png +++ b/doc/user/project/issues/img/group_issues_list_view.png diff --git a/doc/user/project/issues/img/issue_board.png b/doc/user/project/issues/img/issue_board.png Binary files differindex 1759b28a9ef..87b1016cc76 100644 --- a/doc/user/project/issues/img/issue_board.png +++ b/doc/user/project/issues/img/issue_board.png diff --git a/doc/user/project/issues/img/issue_template.png b/doc/user/project/issues/img/issue_template.png Binary files differindex c63229a4af2..0e4c8df897b 100644 --- a/doc/user/project/issues/img/issue_template.png +++ b/doc/user/project/issues/img/issue_template.png diff --git a/doc/user/project/issues/img/issues_main_view.png b/doc/user/project/issues/img/issues_main_view.png Binary files differindex 4faa42e40ee..a929916c682 100644 --- a/doc/user/project/issues/img/issues_main_view.png +++ b/doc/user/project/issues/img/issues_main_view.png diff --git a/doc/user/project/issues/img/issues_main_view_numbered.jpg b/doc/user/project/issues/img/issues_main_view_numbered.jpg Binary files differindex 4b5d7fba459..b4b68476d24 100644 --- a/doc/user/project/issues/img/issues_main_view_numbered.jpg +++ b/doc/user/project/issues/img/issues_main_view_numbered.jpg diff --git a/doc/user/project/issues/img/new_issue.png b/doc/user/project/issues/img/new_issue.png Binary files differindex e72ac49d6b9..07d65a93070 100644 --- a/doc/user/project/issues/img/new_issue.png +++ b/doc/user/project/issues/img/new_issue.png diff --git a/doc/user/project/issues/img/new_issue_from_issue_board.png b/doc/user/project/issues/img/new_issue_from_issue_board.png Binary files differindex 9c2b3ff50fa..da892eff0a6 100644 --- a/doc/user/project/issues/img/new_issue_from_issue_board.png +++ b/doc/user/project/issues/img/new_issue_from_issue_board.png diff --git a/doc/user/project/issues/img/new_issue_from_open_issue.png b/doc/user/project/issues/img/new_issue_from_open_issue.png Binary files differindex 2aed5372830..c6f3f0617ab 100644 --- a/doc/user/project/issues/img/new_issue_from_open_issue.png +++ b/doc/user/project/issues/img/new_issue_from_open_issue.png diff --git a/doc/user/project/issues/img/new_issue_from_projects_dashboard.png b/doc/user/project/issues/img/new_issue_from_projects_dashboard.png Binary files differindex cddf36b7457..4b9535f6b15 100644 --- a/doc/user/project/issues/img/new_issue_from_projects_dashboard.png +++ b/doc/user/project/issues/img/new_issue_from_projects_dashboard.png diff --git a/doc/user/project/issues/img/new_issue_from_tracker_list.png b/doc/user/project/issues/img/new_issue_from_tracker_list.png Binary files differindex 7e5413f0b7d..66793cb44fa 100644 --- a/doc/user/project/issues/img/new_issue_from_tracker_list.png +++ b/doc/user/project/issues/img/new_issue_from_tracker_list.png diff --git a/doc/user/project/issues/img/project_issues_list_view.png b/doc/user/project/issues/img/project_issues_list_view.png Binary files differindex 2fcc9e8d9da..584a81aab8a 100644 --- a/doc/user/project/issues/img/project_issues_list_view.png +++ b/doc/user/project/issues/img/project_issues_list_view.png diff --git a/doc/user/project/issues/img/sidebar_move_issue.png b/doc/user/project/issues/img/sidebar_move_issue.png Binary files differindex 111f7861364..1e688cec894 100644 --- a/doc/user/project/issues/img/sidebar_move_issue.png +++ b/doc/user/project/issues/img/sidebar_move_issue.png diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md index 8ec7adad172..21a2e1213ec 100644 --- a/doc/user/project/labels.md +++ b/doc/user/project/labels.md @@ -20,8 +20,6 @@ Head over a single project and navigate to **Issues > Labels**. The first time you visit this page, you'll notice that there are no labels created yet. - - Creating a new label from scratch is as easy as pressing the **New label** button. From there on you can choose the name, give it an optional description, a color and you are set. @@ -32,21 +30,23 @@ When you are ready press the **Create label** button to create the new label. --- -## Default Labels - -It's possible to populate the labels for your project from a set of predefined labels. - -### Generate GitLab's predefined label set +## Default labels - +The very first time you visit the labels area, it's gonna be empty. In that +case, it's possible to populate the labels for your project from a set of +predefined labels. Click the link to 'Generate a default set of labels' and GitLab will -generate a set of predefined labels for you. There are 8 default generated labels -in total and you can see them in the screenshot below. - - +generate them for you. There are 8 default generated labels in total: ---- +- bug +- confirmed +- critical +- discussion +- documentation +- enhancement +- suggestion +- support ## Labels Overview @@ -102,30 +102,25 @@ If you work on a large or popular project, try subscribing only to the labels that are relevant to you. You’ll notice it’ll be much easier to focus on what’s important. -## Create a new label right from the issue tracker - -> Introduced in GitLab 8.6. +## Create a new label when inside an issue -There are times when you are already in the issue tracker searching for a +There are times when you are already inside an issue searching to assign a label, only to realize it doesn't exist. Instead of going to the **Labels** page and being distracted from your original purpose, you can create new labels on the fly. -Select **Create new** from the labels dropdown list, provide a name, pick a -color and hit **Create**. +Expand the issue sidebar and select **Create new label** from the labels dropdown +list. Provide a name, pick a color and hit **Create**. The new label will be +ready to used right away! -  ## Assigning labels to issues and merge requests There are generally two ways to assign a label to an issue or merge request. -You can assign a label when you first create or edit an issue or merge request. - - - ---- +The first one is to assign a label when you first create or edit an issue or +merge request. The second way is by using the right sidebar when inside an issue or merge request. Expand it and hit **Edit** in the labels area. Start typing the name diff --git a/doc/user/project/merge_requests/cherry_pick_changes.md b/doc/user/project/merge_requests/cherry_pick_changes.md index 64b94d81024..22ef11e4049 100644 --- a/doc/user/project/merge_requests/cherry_pick_changes.md +++ b/doc/user/project/merge_requests/cherry_pick_changes.md @@ -2,24 +2,19 @@ > [Introduced][ce-3514] in GitLab 8.7. ---- - GitLab implements Git's powerful feature to [cherry-pick any commit][git-cherry-pick] -with introducing a **Cherry-pick** button in Merge Requests and commit details. +with introducing a **Cherry-pick** button in merge requests and commit details. -## Cherry-picking a Merge Request +## Cherry-picking a merge request -After the Merge Request has been merged, a **Cherry-pick** button will be available -to cherry-pick the changes introduced by that Merge Request: +After the merge request has been merged, a **Cherry-pick** button will be available +to cherry-pick the changes introduced by that merge request.  ---- - -You can cherry-pick the changes directly into the selected branch or you can opt to -create a new Merge Request with the cherry-pick changes: - - +After you click that button, a modal will appear where you can choose to +cherry-pick the changes directly into the selected branch or you can opt to +create a new merge request with the cherry-pick changes ## Cherry-picking a Commit @@ -27,15 +22,9 @@ You can cherry-pick a Commit from the Commit details page:  ---- - -Similar to cherry-picking a Merge Request, you can opt to cherry-pick the changes -directly into the target branch or create a new Merge Request to cherry-pick the -changes: - - - ---- +Similar to cherry-picking a merge request, you can opt to cherry-pick the changes +directly into the target branch or create a new merge request to cherry-pick the +changes. Please note that when cherry-picking merge commits, the mainline will always be the first parent. If you want to use a different mainline then you need to do that diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png b/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png Binary files differindex 5ab094ab367..7dc344f8cf6 100644 --- a/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png +++ b/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_commit_modal.png b/doc/user/project/merge_requests/img/cherry_pick_changes_commit_modal.png Binary files differdeleted file mode 100644 index 42dcb9203ec..00000000000 --- a/doc/user/project/merge_requests/img/cherry_pick_changes_commit_modal.png +++ /dev/null diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png b/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png Binary files differindex 71227747182..811b0998f85 100644 --- a/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png +++ b/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_mr_modal.png b/doc/user/project/merge_requests/img/cherry_pick_changes_mr_modal.png Binary files differdeleted file mode 100644 index 604eb22f51c..00000000000 --- a/doc/user/project/merge_requests/img/cherry_pick_changes_mr_modal.png +++ /dev/null diff --git a/doc/user/project/merge_requests/img/commit_compare.png b/doc/user/project/merge_requests/img/commit_compare.png Binary files differdeleted file mode 100644 index e612a39716e..00000000000 --- a/doc/user/project/merge_requests/img/commit_compare.png +++ /dev/null diff --git a/doc/user/project/merge_requests/img/merge_request.png b/doc/user/project/merge_requests/img/merge_request.png Binary files differnew file mode 100644 index 00000000000..f9ca6348953 --- /dev/null +++ b/doc/user/project/merge_requests/img/merge_request.png diff --git a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png Binary files differindex 33f5a4a7a02..d7f0535d3c5 100644 --- a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png +++ b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png diff --git a/doc/user/project/merge_requests/img/revert_changes_commit_modal.png b/doc/user/project/merge_requests/img/revert_changes_commit_modal.png Binary files differdeleted file mode 100644 index ef7b6dae553..00000000000 --- a/doc/user/project/merge_requests/img/revert_changes_commit_modal.png +++ /dev/null diff --git a/doc/user/project/merge_requests/img/revert_changes_mr_modal.png b/doc/user/project/merge_requests/img/revert_changes_mr_modal.png Binary files differdeleted file mode 100644 index f6540c9dd33..00000000000 --- a/doc/user/project/merge_requests/img/revert_changes_mr_modal.png +++ /dev/null diff --git a/doc/user/project/merge_requests/img/versions.png b/doc/user/project/merge_requests/img/versions.png Binary files differindex 33c58d2abff..3883fb4bc1c 100644 --- a/doc/user/project/merge_requests/img/versions.png +++ b/doc/user/project/merge_requests/img/versions.png diff --git a/doc/user/project/merge_requests/img/versions_compare.png b/doc/user/project/merge_requests/img/versions_compare.png Binary files differindex db978ea7b1d..f5bd85dc7c1 100644 --- a/doc/user/project/merge_requests/img/versions_compare.png +++ b/doc/user/project/merge_requests/img/versions_compare.png diff --git a/doc/user/project/merge_requests/img/versions_dropdown.png b/doc/user/project/merge_requests/img/versions_dropdown.png Binary files differindex 889a2d93e6c..cc70a5bf14b 100644 --- a/doc/user/project/merge_requests/img/versions_dropdown.png +++ b/doc/user/project/merge_requests/img/versions_dropdown.png diff --git a/doc/user/project/merge_requests/img/wip_blocked_accept_button.png b/doc/user/project/merge_requests/img/wip_blocked_accept_button.png Binary files differindex 047b0b4620f..0c492aca363 100644 --- a/doc/user/project/merge_requests/img/wip_blocked_accept_button.png +++ b/doc/user/project/merge_requests/img/wip_blocked_accept_button.png diff --git a/doc/user/project/merge_requests/img/wip_mark_as_wip.png b/doc/user/project/merge_requests/img/wip_mark_as_wip.png Binary files differindex 8bd206bc24a..e405879b28a 100644 --- a/doc/user/project/merge_requests/img/wip_mark_as_wip.png +++ b/doc/user/project/merge_requests/img/wip_mark_as_wip.png diff --git a/doc/user/project/merge_requests/img/wip_unmark_as_wip.png b/doc/user/project/merge_requests/img/wip_unmark_as_wip.png Binary files differindex c0bfa6a35a2..d7f8c419945 100644 --- a/doc/user/project/merge_requests/img/wip_unmark_as_wip.png +++ b/doc/user/project/merge_requests/img/wip_unmark_as_wip.png diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 8e081b4f0b8..6289fcf3c2b 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -3,6 +3,8 @@ Merge requests allow you to exchange changes you made to source code and collaborate with other people on the same project. + + ## Overview A Merge Request (**MR**) is the basis of GitLab as a code collaboration diff --git a/doc/user/project/merge_requests/revert_changes.md b/doc/user/project/merge_requests/revert_changes.md index 5ead9f4177f..8cf8a59dbfe 100644 --- a/doc/user/project/merge_requests/revert_changes.md +++ b/doc/user/project/merge_requests/revert_changes.md @@ -2,51 +2,39 @@ > [Introduced][ce-1990] in GitLab 8.5. ---- - GitLab implements Git's powerful feature to [revert any commit][git-revert] -with introducing a **Revert** button in Merge Requests and commit details. +with introducing a **Revert** button in merge requests and commit details. ## Reverting a Merge Request -_**Note:** The **Revert** button will only be available for Merge Requests -created since GitLab 8.5. However, you can still revert a Merge Request -by reverting the merge commit from the list of Commits page._ +NOTE: **Note:** +The **Revert** button will only be available for merge requests +created since GitLab 8.5. However, you can still revert a merge request +by reverting the merge commit from the list of Commits page. After the Merge Request has been merged, a **Revert** button will be available -to revert the changes introduced by that Merge Request: - - - ---- - -You can revert the changes directly into the selected branch or you can opt to -create a new Merge Request with the revert changes: +to revert the changes introduced by that merge request. - + ---- +After you click that button, a modal will appear where you can choose to +revert the changes directly into the selected branch or you can opt to +create a new merge request with the revert changes. -After the Merge Request has been reverted, the **Revert** button will not be +After the merge request has been reverted, the **Revert** button will not be available anymore. ## Reverting a Commit You can revert a Commit from the Commit details page: - - ---- - -Similar to reverting a Merge Request, you can opt to revert the changes -directly into the target branch or create a new Merge Request to revert the -changes: - - + ---- +Similar to reverting a merge request, you can opt to revert the changes +directly into the target branch or create a new merge request to revert the +changes. -After the Commit has been reverted, the **Revert** button will not be available +After the commit has been reverted, the **Revert** button will not be available anymore. Please note that when reverting merge commits, the mainline will always be the diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb index f88738b4c61..3490bbd968c 100644 --- a/features/steps/project/fork.rb +++ b/features/steps/project/fork.rb @@ -26,7 +26,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps end step 'I fork to my namespace' do - page.within '.fork-namespaces' do + page.within '.fork-thumbnail-container' do click_link current_user.name end end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index a76befe4b52..89b654253cb 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -53,14 +53,15 @@ module Gitlab # Rugged repo object attr_reader :rugged - attr_reader :storage, :gl_repository, :relative_path + attr_reader :storage, :gl_repository, :relative_path, :gitaly_resolver - # 'path' must be the path to a _bare_ git repository, e.g. - # /path/to/my-repo.git + # This initializer method is only used on the client side (gitlab-ce). + # Gitaly-ruby uses a different initializer. def initialize(storage, relative_path, gl_repository) @storage = storage @relative_path = relative_path @gl_repository = gl_repository + @gitaly_resolver = Gitlab::GitalyClient storage_path = Gitlab.config.repositories.storages[@storage]['path'] @path = File.join(storage_path, @relative_path) @@ -987,9 +988,9 @@ module Gitlab def with_repo_tmp_commit(start_repository, start_branch_name, sha) tmp_ref = fetch_ref( - start_repository.path, - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}", - "refs/tmp/#{SecureRandom.hex}/head" + start_repository, + source_ref: "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}", + target_ref: "refs/tmp/#{SecureRandom.hex}/head" ) yield commit(sha) @@ -1021,13 +1022,27 @@ module Gitlab end end - def write_ref(ref_path, sha) - rugged.references.create(ref_path, sha, force: true) + def write_ref(ref_path, ref) + raise ArgumentError, "invalid ref_path #{ref_path.inspect}" if ref_path.include?(' ') + raise ArgumentError, "invalid ref #{ref.inspect}" if ref.include?("\x00") + + command = [Gitlab.config.git.bin_path] + %w[update-ref --stdin -z] + input = "update #{ref_path}\x00#{ref}\x00\x00" + output, status = circuit_breaker.perform do + popen(command, path) { |stdin| stdin.write(input) } + end + + raise GitError, output unless status.zero? end - def fetch_ref(source_path, source_ref, target_ref) - args = %W(fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref}) - message, status = run_git(args) + def fetch_ref(source_repository, source_ref:, target_ref:) + message, status = GitalyClient.migrate(:fetch_ref) do |is_enabled| + if is_enabled + gitaly_fetch_ref(source_repository, source_ref: source_ref, target_ref: target_ref) + else + local_fetch_ref(source_repository.path, source_ref: source_ref, target_ref: target_ref) + end + end # Make sure ref was created, and raise Rugged::ReferenceError when not raise Rugged::ReferenceError, message if status != 0 @@ -1036,9 +1051,9 @@ module Gitlab end # Refactoring aid; allows us to copy code from app/models/repository.rb - def run_git(args) + def run_git(args, env: {}) circuit_breaker.perform do - popen([Gitlab.config.git.bin_path, *args], path) + popen([Gitlab.config.git.bin_path, *args], path, env) end end @@ -1495,9 +1510,33 @@ module Gitlab OperationService.new(user, self).add_branch(branch_name, target_object.oid) find_branch(branch_name) - rescue Rugged::ReferenceError + rescue Rugged::ReferenceError => ex raise InvalidRef, ex end + + def local_fetch_ref(source_path, source_ref:, target_ref:) + args = %W(fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref}) + run_git(args) + end + + def gitaly_fetch_ref(source_repository, source_ref:, target_ref:) + gitaly_ssh = File.absolute_path(File.join(Gitlab.config.gitaly.client_path, 'gitaly-ssh')) + gitaly_address = gitaly_resolver.address(source_repository.storage) + gitaly_token = gitaly_resolver.token(source_repository.storage) + + request = Gitaly::SSHUploadPackRequest.new(repository: source_repository.gitaly_repository) + env = { + 'GITALY_ADDRESS' => gitaly_address, + 'GITALY_PAYLOAD' => request.to_json, + 'GITALY_WD' => Dir.pwd, + 'GIT_SSH_COMMAND' => "#{gitaly_ssh} upload-pack" + } + env['GITALY_TOKEN'] = gitaly_token if gitaly_token.present? + + args = %W(fetch --no-tags -f ssh://gitaly/internal.git #{source_ref}:#{target_ref}) + + run_git(args, env: env) + end end end end diff --git a/lib/gitlab/git/rev_list.rb b/lib/gitlab/git/rev_list.rb index e0943d3a3eb..92a6a672534 100644 --- a/lib/gitlab/git/rev_list.rb +++ b/lib/gitlab/git/rev_list.rb @@ -31,7 +31,7 @@ module Gitlab output, status = popen(args, nil, Gitlab::Git::Env.all.stringify_keys) unless status.zero? - raise "Got a non-zero exit code while calling out `#{args.join(' ')}`." + raise "Got a non-zero exit code while calling out `#{args.join(' ')}`: #{output}" end output.split("\n") diff --git a/lib/gitlab/sql/union.rb b/lib/gitlab/sql/union.rb index 222021e8802..f30c771837a 100644 --- a/lib/gitlab/sql/union.rb +++ b/lib/gitlab/sql/union.rb @@ -12,8 +12,9 @@ module Gitlab # # Project.where("id IN (#{sql})") class Union - def initialize(relations) + def initialize(relations, remove_duplicates: true) @relations = relations + @remove_duplicates = remove_duplicates end def to_sql @@ -25,7 +26,11 @@ module Gitlab @relations.map { |rel| rel.reorder(nil).to_sql }.reject(&:blank?) end - fragments.join("\nUNION\n") + fragments.join("\n#{union_keyword}\n") + end + + def union_keyword + @remove_duplicates ? 'UNION' : 'UNION ALL' end end end diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake index 259a755d724..a42f02a84fd 100644 --- a/lib/tasks/gitlab/assets.rake +++ b/lib/tasks/gitlab/assets.rake @@ -3,8 +3,8 @@ namespace :gitlab do desc 'GitLab | Assets | Compile all frontend assets' task compile: [ 'yarn:check', - 'rake:assets:precompile', 'gettext:po_to_json', + 'rake:assets:precompile', 'webpack:compile', 'fix_urls' ] diff --git a/spec/factories/deployments.rb b/spec/factories/deployments.rb index e5abfd67d60..0dd1238d6e2 100644 --- a/spec/factories/deployments.rb +++ b/spec/factories/deployments.rb @@ -12,7 +12,7 @@ FactoryGirl.define do deployment.project ||= deployment.environment.project unless deployment.project.repository_exists? - allow(deployment.project.repository).to receive(:fetch_ref) + allow(deployment.project.repository).to receive(:create_ref) end end end diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb index ad06cee4e81..2f407b13c2f 100644 --- a/spec/features/projects/branches/download_buttons_spec.rb +++ b/spec/features/projects/branches/download_buttons_spec.rb @@ -29,7 +29,7 @@ feature 'Download buttons in branches page' do describe 'when checking branches' do context 'with artifacts' do before do - visit project_branches_path(project) + visit project_branches_path(project, search: 'binary-encoding') end scenario 'shows download artifacts button' do diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index ad4527a0b74..d1f5623554d 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -5,12 +5,6 @@ describe 'Branches' do let(:project) { create(:project, :public, :repository) } let(:repository) { project.repository } - def set_protected_branch_name(branch_name) - find(".js-protected-branch-select").click - find(".dropdown-input-field").set(branch_name) - click_on("Create wildcard #{branch_name}") - end - context 'logged in as developer' do before do sign_in(user) @@ -18,12 +12,10 @@ describe 'Branches' do end describe 'Initial branches page' do - it 'shows all the branches' do + it 'shows all the branches sorted by last updated by default' do visit project_branches_path(project) - repository.branches_sorted_by(:name).first(20).each do |branch| - expect(page).to have_content("#{branch.name}") - end + expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :updated_desc)) end it 'sorts the branches by name' do @@ -32,22 +24,7 @@ describe 'Branches' do click_button "Last updated" # Open sorting dropdown click_link "Name" - sorted = repository.branches_sorted_by(:name).first(20).map do |branch| - Regexp.escape(branch.name) - end - expect(page).to have_content(/#{sorted.join(".*")}/) - end - - it 'sorts the branches by last updated' do - visit project_branches_path(project) - - click_button "Last updated" # Open sorting dropdown - click_link "Last updated" - - sorted = repository.branches_sorted_by(:updated_desc).first(20).map do |branch| - Regexp.escape(branch.name) - end - expect(page).to have_content(/#{sorted.join(".*")}/) + expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :name)) end it 'sorts the branches by oldest updated' do @@ -56,10 +33,7 @@ describe 'Branches' do click_button "Last updated" # Open sorting dropdown click_link "Oldest updated" - sorted = repository.branches_sorted_by(:updated_asc).first(20).map do |branch| - Regexp.escape(branch.name) - end - expect(page).to have_content(/#{sorted.join(".*")}/) + expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :updated_asc)) end it 'avoids a N+1 query in branches index' do @@ -99,28 +73,6 @@ describe 'Branches' do expect(find('.all-branches')).to have_selector('li', count: 0) end end - - describe 'Delete protected branch' do - before do - project.add_user(user, :master) - visit project_protected_branches_path(project) - set_protected_branch_name('fix') - click_on "Protect" - - within(".protected-branches-list") { expect(page).to have_content('fix') } - expect(ProtectedBranch.count).to eq(1) - project.add_user(user, :developer) - end - - it 'does not allow devleoper to removes protected branch', js: true do - visit project_branches_path(project) - - fill_in 'branch-search', with: 'fix' - find('#branch-search').native.send_keys(:enter) - - expect(page).to have_css('.btn-remove.disabled') - end - end end context 'logged in as master' do @@ -136,37 +88,6 @@ describe 'Branches' do expect(page).to have_content("Protected branches can be managed in project settings") end end - - describe 'Delete protected branch' do - before do - visit project_protected_branches_path(project) - set_protected_branch_name('fix') - click_on "Protect" - - within(".protected-branches-list") { expect(page).to have_content('fix') } - expect(ProtectedBranch.count).to eq(1) - end - - it 'removes branch after modal confirmation', js: true do - visit project_branches_path(project) - - fill_in 'branch-search', with: 'fix' - find('#branch-search').native.send_keys(:enter) - - expect(page).to have_content('fix') - expect(find('.all-branches')).to have_selector('li', count: 1) - page.find('[data-target="#modal-delete-branch"]').trigger(:click) - - expect(page).to have_css('.js-delete-branch[disabled]') - fill_in 'delete_branch_input', with: 'fix' - click_link 'Delete protected branch' - - fill_in 'branch-search', with: 'fix' - find('#branch-search').native.send_keys(:enter) - - expect(page).to have_content('No branches to show') - end - end end context 'logged out' do @@ -180,4 +101,13 @@ describe 'Branches' do end end end + + def sorted_branches(repository, count:, sort_by:) + sorted_branches = + repository.branches_sorted_by(sort_by).first(count).map do |branch| + Regexp.escape(branch.name) + end + + Regexp.new(sorted_branches.join('.*')) + end end diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 3677bf38724..bf9885f73bd 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -1,93 +1,153 @@ require 'spec_helper' -feature 'Protected Branches', js: true do - let(:user) { create(:user, :admin) } +feature 'Protected Branches', :js do + let(:user) { create(:user) } + let(:admin) { create(:admin) } let(:project) { create(:project, :repository) } - before do - sign_in(user) - end + context 'logged in as developer' do + before do + project.add_developer(user) + sign_in(user) + end - def set_protected_branch_name(branch_name) - find(".js-protected-branch-select").trigger('click') - find(".dropdown-input-field").set(branch_name) - click_on("Create wildcard #{branch_name}") - end + describe 'Delete protected branch' do + before do + create(:protected_branch, project: project, name: 'fix') + expect(ProtectedBranch.count).to eq(1) + end + + it 'does not allow developer to removes protected branch' do + visit project_branches_path(project) + + fill_in 'branch-search', with: 'fix' + find('#branch-search').native.send_keys(:enter) - describe "explicit protected branches" do - it "allows creating explicit protected branches" do - visit project_protected_branches_path(project) - set_protected_branch_name('some-branch') - click_on "Protect" + expect(page).to have_css('.btn-remove.disabled') + end + end + end - within(".protected-branches-list") { expect(page).to have_content('some-branch') } - expect(ProtectedBranch.count).to eq(1) - expect(ProtectedBranch.last.name).to eq('some-branch') + context 'logged in as master' do + before do + project.add_master(user) + sign_in(user) end - it "displays the last commit on the matching branch if it exists" do - commit = create(:commit, project: project) - project.repository.add_branch(user, 'some-branch', commit.id) + describe 'Delete protected branch' do + before do + create(:protected_branch, project: project, name: 'fix') + expect(ProtectedBranch.count).to eq(1) + end - visit project_protected_branches_path(project) - set_protected_branch_name('some-branch') - click_on "Protect" + it 'removes branch after modal confirmation' do + visit project_branches_path(project) - within(".protected-branches-list") { expect(page).to have_content(commit.id[0..7]) } - end + fill_in 'branch-search', with: 'fix' + find('#branch-search').native.send_keys(:enter) - it "displays an error message if the named branch does not exist" do - visit project_protected_branches_path(project) - set_protected_branch_name('some-branch') - click_on "Protect" + expect(page).to have_content('fix') + expect(find('.all-branches')).to have_selector('li', count: 1) + page.find('[data-target="#modal-delete-branch"]').trigger(:click) - within(".protected-branches-list") { expect(page).to have_content('branch was removed') } + expect(page).to have_css('.js-delete-branch[disabled]') + fill_in 'delete_branch_input', with: 'fix' + click_link 'Delete protected branch' + + fill_in 'branch-search', with: 'fix' + find('#branch-search').native.send_keys(:enter) + + expect(page).to have_content('No branches to show') + end end end - describe "wildcard protected branches" do - it "allows creating protected branches with a wildcard" do - visit project_protected_branches_path(project) - set_protected_branch_name('*-stable') - click_on "Protect" - - within(".protected-branches-list") { expect(page).to have_content('*-stable') } - expect(ProtectedBranch.count).to eq(1) - expect(ProtectedBranch.last.name).to eq('*-stable') + context 'logged in as admin' do + before do + sign_in(admin) end - it "displays the number of matching branches" do - project.repository.add_branch(user, 'production-stable', 'master') - project.repository.add_branch(user, 'staging-stable', 'master') + describe "explicit protected branches" do + it "allows creating explicit protected branches" do + visit project_protected_branches_path(project) + set_protected_branch_name('some-branch') + click_on "Protect" - visit project_protected_branches_path(project) - set_protected_branch_name('*-stable') - click_on "Protect" + within(".protected-branches-list") { expect(page).to have_content('some-branch') } + expect(ProtectedBranch.count).to eq(1) + expect(ProtectedBranch.last.name).to eq('some-branch') + end - within(".protected-branches-list") { expect(page).to have_content("2 matching branches") } + it "displays the last commit on the matching branch if it exists" do + commit = create(:commit, project: project) + project.repository.add_branch(admin, 'some-branch', commit.id) + + visit project_protected_branches_path(project) + set_protected_branch_name('some-branch') + click_on "Protect" + + within(".protected-branches-list") { expect(page).to have_content(commit.id[0..7]) } + end + + it "displays an error message if the named branch does not exist" do + visit project_protected_branches_path(project) + set_protected_branch_name('some-branch') + click_on "Protect" + + within(".protected-branches-list") { expect(page).to have_content('branch was removed') } + end end - it "displays all the branches matching the wildcard" do - project.repository.add_branch(user, 'production-stable', 'master') - project.repository.add_branch(user, 'staging-stable', 'master') - project.repository.add_branch(user, 'development', 'master') + describe "wildcard protected branches" do + it "allows creating protected branches with a wildcard" do + visit project_protected_branches_path(project) + set_protected_branch_name('*-stable') + click_on "Protect" + + within(".protected-branches-list") { expect(page).to have_content('*-stable') } + expect(ProtectedBranch.count).to eq(1) + expect(ProtectedBranch.last.name).to eq('*-stable') + end - visit project_protected_branches_path(project) - set_protected_branch_name('*-stable') - click_on "Protect" + it "displays the number of matching branches" do + project.repository.add_branch(admin, 'production-stable', 'master') + project.repository.add_branch(admin, 'staging-stable', 'master') - visit project_protected_branches_path(project) - click_on "2 matching branches" + visit project_protected_branches_path(project) + set_protected_branch_name('*-stable') + click_on "Protect" - within(".protected-branches-list") do - expect(page).to have_content("production-stable") - expect(page).to have_content("staging-stable") - expect(page).not_to have_content("development") + within(".protected-branches-list") { expect(page).to have_content("2 matching branches") } end + + it "displays all the branches matching the wildcard" do + project.repository.add_branch(admin, 'production-stable', 'master') + project.repository.add_branch(admin, 'staging-stable', 'master') + project.repository.add_branch(admin, 'development', 'master') + + visit project_protected_branches_path(project) + set_protected_branch_name('*-stable') + click_on "Protect" + + visit project_protected_branches_path(project) + click_on "2 matching branches" + + within(".protected-branches-list") do + expect(page).to have_content("production-stable") + expect(page).to have_content("staging-stable") + expect(page).not_to have_content("development") + end + end + end + + describe "access control" do + include_examples "protected branches > access control > CE" end end - describe "access control" do - include_examples "protected branches > access control > CE" + def set_protected_branch_name(branch_name) + find(".js-protected-branch-select").trigger('click') + find(".dropdown-input-field").set(branch_name) + click_on("Create wildcard #{branch_name}") end end diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index 4bc2205e642..3fd16d76f51 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -41,6 +41,12 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont remove_repository(project) end + it 'merge_requests/merge_request_of_current_user.html.raw' do |example| + merge_request.update(author: admin) + + render_merge_request(example.description, merge_request) + end + it 'merge_requests/merge_request_with_task_list.html.raw' do |example| create(:ci_build, :pending, pipeline: pipeline) diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index 6ff42e2378d..3ab901da6b6 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -58,5 +58,44 @@ import IssuablesHelper from '~/helpers/issuables_helper'; expect(CloseReopenReportToggle.prototype.initDroplab).toHaveBeenCalled(); }); }); + + describe('hideCloseButton', () => { + describe('merge request of another user', () => { + beforeEach(() => { + loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + this.el = document.querySelector('.merge-request .issuable-actions'); + const merge = new MergeRequest(); + merge.hideCloseButton(); + }); + + it('hides the dropdown close item and selects the next item', () => { + const closeItem = this.el.querySelector('li.close-item'); + const smallCloseItem = this.el.querySelector('.js-close-item'); + const reportItem = this.el.querySelector('li.report-item'); + + expect(closeItem).toHaveClass('hidden'); + expect(smallCloseItem).toHaveClass('hidden'); + expect(reportItem).toHaveClass('droplab-item-selected'); + expect(reportItem).not.toHaveClass('hidden'); + }); + }); + + describe('merge request of current_user', () => { + beforeEach(() => { + loadFixtures('merge_requests/merge_request_of_current_user.html.raw'); + this.el = document.querySelector('.merge-request .issuable-actions'); + const merge = new MergeRequest(); + merge.hideCloseButton(); + }); + + it('hides the close button', () => { + const closeButton = this.el.querySelector('.btn-close'); + const smallCloseItem = this.el.querySelector('.js-close-item'); + + expect(closeButton).toHaveClass('hidden'); + expect(smallCloseItem).toHaveClass('hidden'); + }); + }); + }); }); }).call(window); diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index f405b2f2684..5f12125beb2 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1472,6 +1472,23 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + describe '#write_ref' do + context 'validations' do + using RSpec::Parameterized::TableSyntax + + where(:ref_path, :ref) do + 'foo bar' | '123' + 'foobar' | "12\x003" + end + + with_them do + it 'raises ArgumentError' do + expect { repository.write_ref(ref_path, ref) }.to raise_error(ArgumentError) + end + end + end + end + def create_remote_branch(repository, remote_name, branch_name, source_branch_name) source_branch = repository.branches.find { |branch| branch.name == source_branch_name } rugged = repository.rugged diff --git a/spec/lib/gitlab/sql/union_spec.rb b/spec/lib/gitlab/sql/union_spec.rb index baf8f6644bf..8026fba9f0a 100644 --- a/spec/lib/gitlab/sql/union_spec.rb +++ b/spec/lib/gitlab/sql/union_spec.rb @@ -22,5 +22,12 @@ describe Gitlab::SQL::Union do expect {User.where("users.id IN (#{union.to_sql})").to_a}.not_to raise_error expect(union.to_sql).to eq("#{to_sql(relation_1)}\nUNION\n#{to_sql(relation_2)}") end + + it 'uses UNION ALL when removing duplicates is disabled' do + union = described_class + .new([relation_1, relation_2], remove_duplicates: false) + + expect(union.to_sql).to include('UNION ALL') + end end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index bdcdad46390..7156c1b7aa8 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -636,18 +636,18 @@ describe Repository do describe '#fetch_ref' do describe 'when storage is broken', broken_storage: true do it 'should raise a storage error' do - path = broken_repository.path_to_repo - - expect_to_raise_storage_error { broken_repository.fetch_ref(path, '1', '2') } + expect_to_raise_storage_error do + broken_repository.fetch_ref(broken_repository, source_ref: '1', target_ref: '2') + end end end end describe '#create_ref' do - it 'redirects the call to fetch_ref' do + it 'redirects the call to write_ref' do ref, ref_path = '1', '2' - expect(repository).to receive(:fetch_ref).with(repository.path_to_repo, ref, ref_path) + expect(repository.raw_repository).to receive(:write_ref).with(ref_path, ref) repository.create_ref(ref, ref_path) end |