diff options
80 files changed, 543 insertions, 165 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ba0c5074839..9a0102c65fd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -415,6 +415,7 @@ setup-test-env: script: - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' - scripts/gitaly-test-build # Do not use 'bundle exec' here + - BUNDLE_GEMFILE=Gemfile.rails5 bundle install $BUNDLE_INSTALL_FLAGS artifacts: expire_in: 7d paths: @@ -590,6 +591,12 @@ downtime_check: - /(^docs[\/-].*|.*-docs$)/ - /(^qa[\/-].*|.*-qa$)/ +rails5_gemfile_lock_check: + <<: *dedicated-no-docs-no-db-pull-cache-job + <<: *except-docs-and-qa + script: + - scripts/rails5-gemfile-lock-check + ee_compat_check: <<: *rake-exec except: diff --git a/Gemfile.lock b/Gemfile.lock index 4fc5af40ce6..883e580b86b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -296,7 +296,7 @@ GEM flowdock (~> 0.7) gitlab-grit (>= 2.4.1) multi_json - gitlab-gollum-lib (4.2.7.2) + gitlab-gollum-lib (4.2.7.4) gemojione (~> 3.2) github-markup (~> 1.6) gollum-grit_adapter (~> 1.0) @@ -304,7 +304,7 @@ GEM rouge (~> 3.1) sanitize (~> 2.1) stringex (~> 2.6) - gitlab-gollum-rugged_adapter (0.4.4) + gitlab-gollum-rugged_adapter (0.4.4.1) mime-types (>= 1.15) rugged (~> 0.25) gitlab-grit (2.8.2) diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock index efb4dfd263a..952e27df29d 100644 --- a/Gemfile.rails5.lock +++ b/Gemfile.rails5.lock @@ -315,7 +315,7 @@ GEM diff-lcs (~> 1.1) mime-types (>= 1.16) posix-spawn (~> 0.3) - gitlab-markup (1.6.3) + gitlab-markup (1.6.4) gitlab-styles (2.3.2) rubocop (~> 0.51) rubocop-gitlab-security (~> 0.1.0) @@ -751,36 +751,36 @@ GEM chunky_png rqrcode-rails3 (0.1.7) rqrcode (>= 0.4.2) - rspec (3.6.0) - rspec-core (~> 3.6.0) - rspec-expectations (~> 3.6.0) - rspec-mocks (~> 3.6.0) - rspec-core (3.6.0) - rspec-support (~> 3.6.0) - rspec-expectations (3.6.0) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.1) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-mocks (3.6.0) + rspec-support (~> 3.7.0) + rspec-mocks (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) + rspec-support (~> 3.7.0) rspec-parameterized (0.4.0) binding_of_caller parser proc_to_ast rspec (>= 2.13, < 4) unparser - rspec-rails (3.6.0) + rspec-rails (3.7.2) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 3.6.0) - rspec-expectations (~> 3.6.0) - rspec-mocks (~> 3.6.0) - rspec-support (~> 3.6.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-support (~> 3.7.0) rspec-retry (0.4.5) rspec-core rspec-set (0.1.3) - rspec-support (3.6.0) + rspec-support (3.7.1) rspec_profiling (0.0.5) activerecord pg @@ -1054,7 +1054,7 @@ DEPENDENCIES gitlab-flowdock-git-hook (~> 1.0.1) gitlab-gollum-lib (~> 4.2) gitlab-gollum-rugged_adapter (~> 0.4.4) - gitlab-markup (~> 1.6.2) + gitlab-markup (~> 1.6.4) gitlab-styles (~> 2.3) gitlab_omniauth-ldap (~> 2.0.4) gon (~> 6.2) @@ -1152,7 +1152,7 @@ DEPENDENCIES rouge (~> 3.1) rqrcode-rails3 (~> 0.1.7) rspec-parameterized - rspec-rails (~> 3.6.0) + rspec-rails (~> 3.7.0) rspec-retry (~> 0.4.5) rspec-set (~> 0.1.3) rspec_profiling (~> 0.0.5) diff --git a/PROCESS.md b/PROCESS.md index 7438df8014b..958bc7b9edc 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -185,11 +185,7 @@ next patch release. If a merge request is to be picked into more than one release it will need one `Pick into X.Y` label per release where the merge request should be back-ported -to. - -For example, if the current patch release is `10.1.1` and a regression fix needs -to be backported down to the `9.5` release, you will need to assign it the -`10.1` milestone and the following labels: +to. For example: - `Pick into 10.1` - `Pick into 10.0` diff --git a/app/assets/images/favicon-blue.ico b/app/assets/images/favicon-blue.ico Binary files differdeleted file mode 100644 index 156fcf07588..00000000000 --- a/app/assets/images/favicon-blue.ico +++ /dev/null diff --git a/app/assets/javascripts/lib/utils/http_status.js b/app/assets/javascripts/lib/utils/http_status.js index bb151929431..229d53b18b0 100644 --- a/app/assets/javascripts/lib/utils/http_status.js +++ b/app/assets/javascripts/lib/utils/http_status.js @@ -8,4 +8,5 @@ export default { OK: 200, MULTIPLE_CHOICES: 300, BAD_REQUEST: 400, + NOT_FOUND: 404, }; diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss index e3c63ae5e1a..88d6bae349a 100644 --- a/app/assets/stylesheets/bootstrap_migration.scss +++ b/app/assets/stylesheets/bootstrap_migration.scss @@ -89,6 +89,10 @@ a { color: $gl-link-color; } +hr { + overflow: hidden; +} + .form-group.row .col-form-label { // Bootstrap 4 aligns labels to the left // for horizontal forms @@ -209,6 +213,10 @@ table { border-bottom: 1px solid $well-inner-border; } } + + .badge.badge-gray { + background-color: $well-expand-item; + } } .card { @@ -258,9 +266,17 @@ pre code { .alert-danger { background-color: $red-500; border-color: $red-500; +} + +.alert-warning, +.alert-danger, +.flash-notice { + border-radius: 0; color: $white-light; - h4 { + h4, + a, + .alert-link { color: $white-light; } } @@ -268,3 +284,11 @@ pre code { input[type=color].form-control { height: $input-height; } + +.toggle-sidebar-button { + .collapse-text, + .icon-angle-double-left, + .icon-angle-double-right { + color: $gl-text-color-secondary; + } +} diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 996e5c1512d..e5197e27b82 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -305,14 +305,6 @@ img.emoji { margin-bottom: 10px; } -.btn-sign-in { - text-shadow: none; - - @include media-breakpoint-up(sm) { - margin-top: 8px; - } -} - .side-filters { fieldset { margin-bottom: 15px; diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index c76ea532912..03520f42997 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -170,7 +170,7 @@ label { } .form-control::-webkit-input-placeholder { - color: $gl-text-color-secondary; + color: $placeholder-text-color; } .input-group { diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 6fbc624dee4..1d5bdaa8961 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -447,12 +447,16 @@ .btn-sign-in { background-color: $indigo-100; color: $indigo-900; - margin-top: 3px; font-weight: $gl-font-weight-bold; + line-height: 18px; &:hover { background-color: $white-light; } + + @include media-breakpoint-down(xs) { + margin-top: $gl-padding-4; + } } .navbar-nav { diff --git a/app/assets/stylesheets/framework/pagination.scss b/app/assets/stylesheets/framework/pagination.scss index 50a1b1c446d..61d02511ff4 100644 --- a/app/assets/stylesheets/framework/pagination.scss +++ b/app/assets/stylesheets/framework/pagination.scss @@ -4,3 +4,11 @@ text-decoration: none; } } + +.page-item { + &.active { + .page-link { + z-index: 3; + } + } +} diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss index 75c11590547..dfb145debe7 100644 --- a/app/assets/stylesheets/framework/timeline.scss +++ b/app/assets/stylesheets/framework/timeline.scss @@ -4,7 +4,7 @@ padding: 0; &::before { - @include notes-media('max', map-get($grid-breakpoints, xs)) { + @include notes-media('max', map-get($grid-breakpoints, sm)) { background: none; } } @@ -34,7 +34,7 @@ .timeline-entry-inner { position: relative; - @include notes-media('max', map-get($grid-breakpoints, xs)) { + @include notes-media('max', map-get($grid-breakpoints, sm)) { .timeline-icon { display: none; } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 497261f938f..d1179df96a9 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -99,7 +99,7 @@ $theme-gray-200: #dfdfdf; $theme-gray-300: #cccccc; $theme-gray-400: #bababa; $theme-gray-500: #a7a7a7; -$theme-gray-600: #949494; +$theme-gray-600: #919191; $theme-gray-700: #707070; $theme-gray-800: #4f4f4f; $theme-gray-900: #2e2e2e; @@ -191,7 +191,7 @@ $gl-font-weight-normal: 400; $gl-font-weight-bold: 600; $gl-text-color: #2e2e2e; $gl-text-color-secondary: #707070; -$gl-text-color-tertiary: #949494; +$gl-text-color-tertiary: #919191; $gl-text-color-quaternary: #d6d6d6; $gl-text-color-inverted: rgba(255, 255, 255, 1); $gl-text-color-secondary-inverted: rgba(255, 255, 255, 0.85); @@ -435,6 +435,22 @@ $badge-bg: rgba(0, 0, 0, 0.07); $badge-color: $gl-text-color-secondary; /* +* Pagination +*/ +$pagination-padding-y: 6px; +$pagination-padding-x: 16px; +$pagination-line-height: 20px; +$pagination-border-color: $border-color; +$pagination-active-bg: $blue-600; +$pagination-active-border-color: $blue-600; +$pagination-hover-bg: $blue-50; +$pagination-hover-border-color: $border-color; +$pagination-hover-color: $gl-text-color; +$pagination-disabled-color: #cdcdcd; +$pagination-disabled-bg: $gray-light; +$pagination-disabled-border-color: $border-color; + +/* * Status icons */ $status-icon-size: 22px; diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 3c7edb0d4bb..6e7fc50c63d 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -1129,7 +1129,7 @@ .ide-context-header { .avatar { - flex: 0 0 40px; + flex: 0 0 38px; } .ide-merge-requests-dropdown.dropdown-menu { diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss index 5f15795a8e3..765c926751a 100644 --- a/app/assets/stylesheets/pages/search.scss +++ b/app/assets/stylesheets/pages/search.scss @@ -29,7 +29,7 @@ input[type="checkbox"]:hover { } .search { - margin: 4px 8px 0; + margin: 0 8px; form { @extend .form-control; diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 2d675726939..41446946a5e 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -611,6 +611,7 @@ module Ci variables .concat(pipeline.persisted_variables) .append(key: 'CI_JOB_ID', value: id.to_s) + .append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self)) .append(key: 'CI_JOB_TOKEN', value: token, public: false) .append(key: 'CI_BUILD_ID', value: id.to_s) .append(key: 'CI_BUILD_TOKEN', value: token, public: false) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 0878356e87a..f430f18ca9a 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -549,7 +549,10 @@ module Ci def persisted_variables Gitlab::Ci::Variables::Collection.new.tap do |variables| - variables.append(key: 'CI_PIPELINE_ID', value: id.to_s) if persisted? + break variables unless persisted? + + variables.append(key: 'CI_PIPELINE_ID', value: id.to_s) + variables.append(key: 'CI_PIPELINE_URL', value: Gitlab::Routing.url_helpers.project_pipeline_url(project, self)) end end diff --git a/app/models/project.rb b/app/models/project.rb index 9ca733ecd98..f0d8c40bfea 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1616,6 +1616,7 @@ class Project < ActiveRecord::Base def after_import repository.after_import + wiki.repository.after_import import_finish remove_import_jid update_project_counter_caches @@ -2139,10 +2140,14 @@ class Project < ActiveRecord::Base check_access = -> do next false if empty_repo? - merge_request = source_of_merge_requests.opened - .where(allow_collaboration: true) - .find_by(source_branch: branch_name) - merge_request&.can_be_merged_by?(user) + merge_requests = source_of_merge_requests.opened + .where(allow_collaboration: true) + + if branch_name + merge_requests.find_by(source_branch: branch_name)&.can_be_merged_by?(user) + else + merge_requests.any? { |merge_request| merge_request.can_be_merged_by?(user) } + end end if RequestStore.active? diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb index 5aa1bc7227c..23b3dcf84c0 100644 --- a/app/uploaders/object_storage.rb +++ b/app/uploaders/object_storage.rb @@ -22,10 +22,10 @@ module ObjectStorage module RecordsUploads extend ActiveSupport::Concern - def prepended(base) + prepended do |base| raise "#{base} must include ObjectStorage::Concern to use extensions." unless base < Concern - base.include(RecordsUploads::Concern) + base.include(::RecordsUploads::Concern) end def retrieve_from_store!(identifier) diff --git a/app/views/ci/variables/_variable_row.html.haml b/app/views/ci/variables/_variable_row.html.haml index 571eb28f195..6ee55836dd2 100644 --- a/app/views/ci/variables/_variable_row.html.haml +++ b/app/views/ci/variables/_variable_row.html.haml @@ -43,5 +43,6 @@ %span.toggle-icon = sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked') = sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked') + = render_if_exists 'ci/variables/environment_scope', form_field: form_field, variable: variable %button.js-row-remove-button.ci-variable-row-remove-button{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') } = icon('minus-circle') diff --git a/app/views/import/gitlab_projects/new.html.haml b/app/views/import/gitlab_projects/new.html.haml index 2d059e78490..f311ac98ac6 100644 --- a/app/views/import/gitlab_projects/new.html.haml +++ b/app/views/import/gitlab_projects/new.html.haml @@ -37,6 +37,6 @@ .form-group = file_field_tag :file, class: '' .row - .form-actions + .form-actions.col-sm-12 = submit_tag 'Import project', class: 'btn btn-create' = link_to 'Cancel', new_project_path, class: 'btn btn-cancel' diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 1bca837a311..5cec443e969 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -61,7 +61,7 @@ - if header_link?(:sign_in) %li.nav-item %div - = link_to "Sign in / Register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'nav-link btn btn-sign-in' + = link_to "Sign in / Register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in' %button.navbar-toggler.d-block.d-sm-none{ type: 'button' } %span.sr-only Toggle navigation diff --git a/app/views/projects/commit/_change.html.haml b/app/views/projects/commit/_change.html.haml index 30605927fd1..3d97e93c9e9 100644 --- a/app/views/projects/commit/_change.html.haml +++ b/app/views/projects/commit/_change.html.haml @@ -20,18 +20,18 @@ %span{ "aria-hidden": true } × .modal-body - if description - %p.append-bottom-20= description + %p= description = form_tag [type.underscore, @project.namespace.becomes(Namespace), @project, commit], method: :post, remote: false, class: "js-#{type}-form js-requires-input" do - .form-group.row.branch - = label_tag 'start_branch', branch_label, class: 'col-form-label col-sm-2' - .col-sm-10 - = hidden_field_tag :start_branch, @project.default_branch, id: 'start_branch' - = dropdown_tag(@project.default_branch, options: { title: s_("BranchSwitcherTitle|Switch branch"), filter: true, placeholder: s_("BranchSwitcherPlaceholder|Search branches"), toggle_class: 'js-project-refs-dropdown dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "start_branch", selected: @project.default_branch, start_branch: @project.default_branch, refs_url: project_branches_path(@project), submit_form_on_click: false } }) + .form-group.branch + = label_tag 'start_branch', branch_label, class: 'label-light' - - if can?(current_user, :push_code, @project) - = render 'shared/new_merge_request_checkbox' - - else - = hidden_field_tag 'create_merge_request', 1, id: nil + = hidden_field_tag :start_branch, @project.default_branch, id: 'start_branch' + = dropdown_tag(@project.default_branch, options: { title: s_("BranchSwitcherTitle|Switch branch"), filter: true, placeholder: s_("BranchSwitcherPlaceholder|Search branches"), toggle_class: 'js-project-refs-dropdown dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "start_branch", selected: @project.default_branch, start_branch: @project.default_branch, refs_url: project_branches_path(@project), submit_form_on_click: false } }) + + - if can?(current_user, :push_code, @project) + = render 'shared/new_merge_request_checkbox' + - else + = hidden_field_tag 'create_merge_request', 1, id: nil .form-actions = submit_tag label, class: 'btn btn-create' = link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal" diff --git a/app/views/projects/commit/branches.html.haml b/app/views/projects/commit/branches.html.haml index a91e31afc2b..0b8e5105bc0 100644 --- a/app/views/projects/commit/branches.html.haml +++ b/app/views/projects/commit/branches.html.haml @@ -6,7 +6,7 @@ - if @branches.any? || @tags.any? || @tags_limit_exceeded %span - = link_to "#", class: "js-details-expand label label-gray ref-name" do + = link_to "#", class: "js-details-expand badge badge-gray ref-name" do = sprite_icon('ellipsis_h', size: 12, css_class: 'vertical-align-middle') %span.js-details-content.hide = commit_branches_links(@project, @branches) diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml index b4787032966..d6f758608a0 100644 --- a/app/views/projects/releases/edit.html.haml +++ b/app/views/projects/releases/edit.html.haml @@ -13,7 +13,7 @@ = form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name), html: { class: 'common-note-form release-form js-quick-submit' }) do |f| = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do - = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here..." + = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here…" = render 'shared/notes/hints' .error-alert .prepend-top-default diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index b596748ca5f..da822ac5675 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -36,7 +36,7 @@ = label_tag :release_description, s_('TagsPage|Release notes'), class: 'col-form-label col-sm-2' .col-sm-10 = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do - = render 'projects/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here...'), current_text: @release_description + = render 'projects/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description = render 'shared/notes/hints' .form-text.text-muted = s_('TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page.') diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index bcceb69954a..26fe1de31fe 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -25,7 +25,7 @@ .col-sm-12= f.label :content, class: 'control-label-full-width' .col-sm-12 = render layout: 'projects/md_preview', locals: { url: project_wiki_preview_markdown_path(@project, @page.slug) } do - = render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: s_("WikiPage|Write your content or drag files here...") + = render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: s_("WikiPage|Write your content or drag files here…") = render 'shared/notes/hints' .clearfix diff --git a/app/views/shared/_new_merge_request_checkbox.html.haml b/app/views/shared/_new_merge_request_checkbox.html.haml index 165109b6b70..24c0dfe247f 100644 --- a/app/views/shared/_new_merge_request_checkbox.html.haml +++ b/app/views/shared/_new_merge_request_checkbox.html.haml @@ -1,4 +1,4 @@ -.form-check +.form-check.prepend-top-8 - nonce = SecureRandom.hex = check_box_tag 'create_merge_request', 1, true, class: 'js-create-merge-request form-check-input', id: "create_merge_request-#{nonce}" = label_tag "create_merge_request-#{nonce}", class: 'form-check-label' do diff --git a/app/views/shared/form_elements/_description.html.haml b/app/views/shared/form_elements/_description.html.haml index e5dfa7dbf71..25df2fe5cd6 100644 --- a/app/views/shared/form_elements/_description.html.haml +++ b/app/views/shared/form_elements/_description.html.haml @@ -16,7 +16,7 @@ = render layout: 'projects/md_preview', locals: { url: preview_url, referenced_users: true } do = render 'projects/zen', f: form, attr: :description, classes: 'note-textarea qa-issuable-form-description', - placeholder: "Write a comment or drag your files here...", + placeholder: "Write a comment or drag your files here…", supports_quick_actions: supports_quick_actions = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions .clearfix diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 9e50e888b35..0ca35ea1298 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -43,7 +43,7 @@ .selectbox.hide-collapsed = f.hidden_field 'milestone_id', value: issuable.milestone_id, id: nil - = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable.to_ability_name}[milestone_id]", project_id: @project.id, issuable_id: issuable.id, milestones: project_milestones_path(@project, :json), ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), use_id: true, default_no: true, selected: (issuable.milestone.name if issuable.milestone), null_default: true }}) + = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable.to_ability_name}[milestone_id]", project_id: @project.id, issuable_id: issuable.id, milestones: project_milestones_path(@project, :json), ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), use_id: true, default_no: true, selected: (issuable.milestone.name if issuable.milestone), null_default: true, display: 'static' }}) - if issuable.has_attribute?(:time_estimate) #issuable-time-tracker.block // Fallback while content is loading @@ -77,7 +77,7 @@ .selectbox.hide-collapsed = f.hidden_field :due_date, value: issuable.due_date.try(:strftime, 'yy-mm-dd') .dropdown - %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable.to_ability_name}[due_date]", ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable) } } + %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable.to_ability_name}[due_date]", ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), display: 'static' } } %span.dropdown-toggle-text = _('Due date') = icon('chevron-down', 'aria-hidden': 'true') @@ -109,7 +109,7 @@ - selected_labels.each do |label| = hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil .dropdown - %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:full_path), project_path: @project.try(:path), issue_update: issuable_json_path(issuable), labels: (labels_filter_path(false) if @project) } } + %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:full_path), project_path: @project.try(:path), issue_update: issuable_json_path(issuable), labels: (labels_filter_path(false) if @project), display: 'static' } } %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) } = multi_label_name(selected_labels, "Labels") = icon('chevron-down', 'aria-hidden': 'true') diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml index e1cde527ad7..ed3ef6155db 100644 --- a/app/views/shared/issuable/_sidebar_assignees.html.haml +++ b/app/views/shared/issuable/_sidebar_assignees.html.haml @@ -37,7 +37,7 @@ - issuable.assignees.each do |assignee| = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username } - - options = { toggle_class: 'js-user-search js-author-search', title: _('Assign to'), filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: _('Search users'), data: { first_user: current_user&.username, current_user: true, project_id: @project&.id, author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true } } + - options = { toggle_class: 'js-user-search js-author-search', title: _('Assign to'), filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: _('Search users'), data: { first_user: current_user&.username, current_user: true, project_id: @project&.id, author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true, display: 'static' } } - title = _('Select assignee') - if issuable.is_a?(Issue) diff --git a/app/views/shared/issuable/form/_contribution.html.haml b/app/views/shared/issuable/form/_contribution.html.haml index 519b5fae846..bc9a1edc39c 100644 --- a/app/views/shared/issuable/form/_contribution.html.haml +++ b/app/views/shared/issuable/form/_contribution.html.haml @@ -7,11 +7,11 @@ %hr -.form-group - .col-form-label +.form-group.row + %label.col-form-label.col-sm-2 = _('Contribution') .col-sm-10 - .form-check + .form-check.prepend-top-5 = form.check_box :allow_collaboration, disabled: !issuable.can_allow_collaboration?(current_user), class: 'form-check-input' = form.label :allow_collaboration, class: 'form-check-label' do = _('Allow commits from members who can merge to the target branch.') diff --git a/app/views/shared/notes/_edit_form.html.haml b/app/views/shared/notes/_edit_form.html.haml index 8923e5602a4..71a5b94e958 100644 --- a/app/views/shared/notes/_edit_form.html.haml +++ b/app/views/shared/notes/_edit_form.html.haml @@ -3,7 +3,7 @@ = hidden_field_tag :target_id, '', class: 'js-form-target-id' = hidden_field_tag :target_type, '', class: 'js-form-target-type' = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(project), referenced_users: true } do - = render 'projects/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: "Write a comment or drag your files here..." + = render 'projects/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: "Write a comment or drag your files here…" = render 'shared/notes/hints' .note-form-actions.clearfix diff --git a/app/views/shared/notes/_form.html.haml b/app/views/shared/notes/_form.html.haml index 71c0d740bc8..c360f1ffe2a 100644 --- a/app/views/shared/notes/_form.html.haml +++ b/app/views/shared/notes/_form.html.haml @@ -29,7 +29,7 @@ = render 'projects/zen', f: f, attr: :note, classes: 'note-textarea js-note-text', - placeholder: "Write a comment or drag your files here...", + placeholder: "Write a comment or drag your files here…", supports_quick_actions: supports_quick_actions, supports_autocomplete: supports_autocomplete = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions diff --git a/changelogs/unreleased/47604-avatars-and-system-icons-for-mobile.yml b/changelogs/unreleased/47604-avatars-and-system-icons-for-mobile.yml new file mode 100644 index 00000000000..ff66385375f --- /dev/null +++ b/changelogs/unreleased/47604-avatars-and-system-icons-for-mobile.yml @@ -0,0 +1,5 @@ +--- +title: Make avatars/icons hidden on mobile +merge_request: 19585 +author: Takuya Noguchi +type: fixed diff --git a/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml b/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml new file mode 100644 index 00000000000..69d49f3e3e0 --- /dev/null +++ b/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml @@ -0,0 +1,5 @@ +--- +title: Add CI job to check Gemfile.rails5.lock +merge_request: 19605 +author: "@blackst0ne" +type: other diff --git a/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml b/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml new file mode 100644 index 00000000000..54154ad2449 --- /dev/null +++ b/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml @@ -0,0 +1,6 @@ +--- +title: Fix bug where maintainer would not be allowed to push to forks with merge requests + that have `Allow maintainer edits` enabled. +merge_request: 18968 +author: +type: fixed diff --git a/changelogs/unreleased/da-port-cte-to-ce.yml b/changelogs/unreleased/da-port-cte-to-ce.yml new file mode 100644 index 00000000000..6fa759fcf7d --- /dev/null +++ b/changelogs/unreleased/da-port-cte-to-ce.yml @@ -0,0 +1,5 @@ +--- +title: Add Gitlab::SQL:CTE for easily building CTE statements +merge_request: +author: +type: added diff --git a/changelogs/unreleased/expose-ci-url.yml b/changelogs/unreleased/expose-ci-url.yml new file mode 100644 index 00000000000..b6ad7d18e0d --- /dev/null +++ b/changelogs/unreleased/expose-ci-url.yml @@ -0,0 +1,5 @@ +--- +title: Add CI_PIPELINE_URL and CI_JOB_URL +merge_request: 19618 +author: +type: added diff --git a/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml b/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml new file mode 100644 index 00000000000..3b4d429707f --- /dev/null +++ b/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml @@ -0,0 +1,5 @@ +--- +title: Fixed bug that allowed to remove other wiki pages if the title had wildcard characters +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/gitaly-opt-out-branch-tag.yml b/changelogs/unreleased/gitaly-opt-out-branch-tag.yml new file mode 100644 index 00000000000..750fc863eed --- /dev/null +++ b/changelogs/unreleased/gitaly-opt-out-branch-tag.yml @@ -0,0 +1,5 @@ +--- +title: Move Gitaly branch/tag/ref RPC's to opt-out +merge_request: 19644 +author: +type: other diff --git a/changelogs/unreleased/sh-expire-content-cache-after-import.yml b/changelogs/unreleased/sh-expire-content-cache-after-import.yml new file mode 100644 index 00000000000..8876a487b86 --- /dev/null +++ b/changelogs/unreleased/sh-expire-content-cache-after-import.yml @@ -0,0 +1,5 @@ +--- +title: Expire Wiki content cache after importing a repository +merge_request: +author: +type: fixed diff --git a/config/routes/wiki.rb b/config/routes/wiki.rb index c2da84ff6f2..cd3828b743c 100644 --- a/config/routes/wiki.rb +++ b/config/routes/wiki.rb @@ -6,7 +6,7 @@ scope(controller: :wikis) do post '/', to: 'wikis#create' end - scope(path: 'wikis/*id', as: :wiki, format: false) do + scope(path: 'wikis/*id', as: :wiki, format: false, defaults: { format: :html }) do get :edit get :history post :preview_markdown diff --git a/doc/administration/integration/koding.md b/doc/administration/integration/koding.md index 67f9f01efb8..6c1ec3028cc 100644 --- a/doc/administration/integration/koding.md +++ b/doc/administration/integration/koding.md @@ -100,14 +100,14 @@ As it's pointed out before, you will need public access to this machine that you've installed Koding and GitLab on. Better to use a domain but a static IP is also fine. -For IP based installation you can use [xip.io](https://xip.io) service which is +For IP based installation you can use [nip.io](https://nip.io) service which is free and provides DNS resolution to IP based requests like following; - - 127.0.0.1.xip.io -> resolves to 127.0.0.1 - - foo.bar.baz.127.0.0.1.xip.io -> resolves to 127.0.0.1 + - 127.0.0.1.nip.io -> resolves to 127.0.0.1 + - foo.bar.baz.127.0.0.1.nip.io -> resolves to 127.0.0.1 - and so on... -As Koding needs subdomains for team names; `foo.127.0.0.1.xip.io` requests for +As Koding needs subdomains for team names; `foo.127.0.0.1.nip.io` requests for a running koding instance on `127.0.0.1` server will be handled as `foo` team requests. @@ -127,8 +127,8 @@ your Koding installation. Team called `gitlab` has integration on Koding out of the box, so if you didn't change anything your team on Koding should be `gitlab`. -So, if your Koding is running on `http://1.2.3.4.xip.io:8090` your URL needs -to be `http://gitlab.1.2.3.4.xip.io:8090`. You need to provide the same host +So, if your Koding is running on `http://1.2.3.4.nip.io:8090` your URL needs +to be `http://gitlab.1.2.3.4.nip.io:8090`. You need to provide the same host with your Koding installation here. @@ -192,7 +192,7 @@ cd koding docker-compose run \ --service-ports backend \ /opt/koding/scripts/bootstrap-container build \ - --host=**YOUR_IP**.xip.io \ + --host=**YOUR_IP**.nip.io \ --gitlabHost=**GITLAB_IP** \ --gitlabPort=**GITLAB_PORT** \ --gitlabToken=**SECRET_TOKEN** \ @@ -224,7 +224,7 @@ cd koding docker-compose run \ --service-ports backend \ /opt/koding/scripts/bootstrap-container build \ - --host=**YOUR_IP**.xip.io \ + --host=**YOUR_IP**.nip.io \ ``` #### Enable Single Sign On @@ -233,7 +233,7 @@ Once you restarted your Koding and logged in with your username and password you need to activate oauth authentication for your user. To do that - Navigate to Dashboard on Koding from; - `http://gitlab.**YOUR_IP**.xip.io:8090/Home/my-account` + `http://gitlab.**YOUR_IP**.nip.io:8090/Home/my-account` - Scroll down to Integrations section - Click on toggle to turn On integration in GitLab integration section diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index 1b24bcdbf6f..a3da6515a19 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -64,6 +64,7 @@ future GitLab releases.** | **CI_JOB_NAME** | 9.0 | 0.5 | The name of the job as defined in `.gitlab-ci.yml` | | **CI_JOB_STAGE** | 9.0 | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` | | **CI_JOB_TOKEN** | 9.0 | 1.2 | Token used for authenticating with the GitLab Container Registry | +| **CI_JOB_URL** | 11.0 | 0.5 | Job details URL | | **CI_REPOSITORY_URL** | 9.0 | all | The URL to clone the Git repository | | **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab | | **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used | @@ -81,6 +82,7 @@ future GitLab releases.** | **CI_PROJECT_NAMESPACE** | 8.10 | 0.5 | The project namespace (username or groupname) that is currently being built | | **CI_PROJECT_PATH** | 8.10 | 0.5 | The namespace with project name | | **CI_PROJECT_PATH_SLUG** | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. | +| **CI_PIPELINE_URL** | 11.0 | 0.5 | Pipeline details URL | | **CI_PROJECT_URL** | 8.10 | 0.5 | The HTTP address to access project | | **CI_PROJECT_VISIBILITY** | 10.3 | all | The project visibility (internal, private, public) | | **CI_REGISTRY** | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry | diff --git a/doc/development/README.md b/doc/development/README.md index 92d9829192e..5d6fed5bc72 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -32,7 +32,7 @@ description: 'Learn how to contribute to GitLab.' - [GitLab utilities](utilities.md) - [API styleguide](api_styleguide.md) Use this styleguide if you are contributing to the API. -- [GrapQL API styleguide](api_graphql_styleguide.md) Use this +- [GraphQL API styleguide](api_graphql_styleguide.md) Use this styleguide if you are contribution to the [GraphQL API](../api/graphql/index.md) - [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers - [Working with Gitaly](gitaly.md) diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md index 0edcb23c7c5..4ba9958e2c6 100644 --- a/doc/development/i18n/externalization.md +++ b/doc/development/i18n/externalization.md @@ -233,7 +233,7 @@ This makes use of [`Intl.DateTimeFormat`]. Please never split a sentence as that would assume the sentence grammar and structure is the same in all languages. -For instance, the following +For instance, the following: ```js {{ s__("mrWidget|Set by") }} @@ -247,6 +247,27 @@ should be externalized as follows: {{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: author.name }) }} ``` +#### Avoid splitting sentences when adding links + +This also applies when using links in between translated sentences, otherwise these texts are not translatable in certain languages. + +Instead of: + +```haml +- zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer') += s_('ClusterIntegration|Learn more about %{zones_link}').html_safe % { zones_link: zones_link } +``` + +Set the link starting and ending HTML fragments as variables like so: + +```haml +- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones' +- zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url } += s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe } +``` + +The reasoning behind this is that in some languages words change depending on context. For example in Japanese は is added to the subject of a sentence and を to the object. This is impossible to translate correctly if we extract individual words from the sentence. + When in doubt, try to follow the best practices described in this [Mozilla Developer documentation][mdn]. diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md index c9766040234..4666511d747 100644 --- a/doc/gitlab-basics/command-line-commands.md +++ b/doc/gitlab-basics/command-line-commands.md @@ -7,17 +7,19 @@ In Git, when you copy a project you say you "clone" it. To work on a git project When you are on your Dashboard, click on the project that you'd like to clone. To work in the project, you can copy a link to the Git repository through a SSH or a HTTPS protocol. SSH is easier to use after it's been -[setup](create-your-ssh-keys.md). While you are at the **Project** tab, select -HTTPS or SSH from the dropdown menu and copy the link using the 'Copy to clipboard' +[set up](create-your-ssh-keys.md). While you are at the **Project** tab, select +HTTPS or SSH from the dropdown menu and copy the link using the _Copy URL to clipboard_ button (you'll have to paste it on your shell in the next step). ![Copy the HTTPS or SSH](img/project_clone_url.png) ## On the command line +This section has examples of some basic shell commands that you might find useful. For more information, search the web for _bash commands_. + ### Clone your project -Go to your computer's shell and type the following command: +Go to your computer's shell and type the following command with your SSH or HTTPS URL: ``` git clone PASTE HTTPS OR SSH HERE @@ -25,33 +27,45 @@ git clone PASTE HTTPS OR SSH HERE A clone of the project will be created in your computer. ->**Note:** If you clone your project via an URL that contains special characters, make sure that they are URL-encoded. +>**Note:** If you clone your project via a URL that contains special characters, make sure that characters are URL-encoded. -### Go into a project, directory or file to work in it +### Go into a project directory to work in it ``` -cd NAME-OF-PROJECT-OR-FILE +cd NAME-OF-PROJECT ``` -### Go back one directory or file +### Go back one directory ``` -cd ../ +cd .. ``` -### View what’s in the directory that you are in +### List what’s in the current directory ``` ls ``` -### Create a directory +### List what’s in the current directory that starts with `a` + +``` +ls a* +``` + +### List what’s in the current directory that ends with `.md` + +``` +ls *.md +``` + +### Create a new directory ``` mkdir NAME-OF-YOUR-DIRECTORY ``` -### Create a README.md or file in directory +### Create a README.md file in the current directory ``` touch README.md @@ -62,6 +76,12 @@ nano README.md #### Press: enter ``` +### Show the contents of the README.md file + +``` +cat README.md +``` + ### Remove a file ``` @@ -74,12 +94,18 @@ rm NAME-OF-FILE rm -r NAME-OF-DIRECTORY ``` -### View history in the command line +### View command history ``` history ``` +### Execute command 123 from history + +``` +!123 +``` + ### Carry out commands for which the account you are using lacks authority You will be asked for an administrator’s password. @@ -88,8 +114,14 @@ You will be asked for an administrator’s password. sudo ``` -### Tell where you are +### Show which directory I am in ``` pwd ``` + +### Clear the shell window + +``` +clear +``` diff --git a/doc/install/kubernetes/gitlab_omnibus.md b/doc/install/kubernetes/gitlab_omnibus.md index e1d1969651e..852a58a9afc 100644 --- a/doc/install/kubernetes/gitlab_omnibus.md +++ b/doc/install/kubernetes/gitlab_omnibus.md @@ -120,7 +120,7 @@ gitlabConfigStorageSize: 1Gi Ingress routing and SSL are automatically configured within this Chart. An NGINX ingress is provisioned and configured, and will route traffic to any service. SSL certificates are automatically created and configured by [kube-lego](https://github.com/kubernetes/charts/tree/master/stable/kube-lego). > **Note:** -Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [xip.io](http://xip.io) and [nip.io](http://nip.io) are unlikely to work. +Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [nip.io](http://nip.io) and [nip.io](http://nip.io) are unlikely to work. ## Installing GitLab using the Helm Chart > **Note:** diff --git a/doc/install/openshift_and_gitlab/index.md b/doc/install/openshift_and_gitlab/index.md index 1ced1fb513d..60e1e2b5f8a 100644 --- a/doc/install/openshift_and_gitlab/index.md +++ b/doc/install/openshift_and_gitlab/index.md @@ -307,10 +307,10 @@ hostname** and use greater values for the volume sizes. If you don't provide a password for PostgreSQL, it will be created automatically. >**Note:** -The `gitlab.apps.10.2.2.2.xip.io` hostname that is used by default will +The `gitlab.apps.10.2.2.2.nip.io` hostname that is used by default will resolve to the host with IP `10.2.2.2` which is the IP our VM uses. It is a trick to have distinct FQDNs pointing to services that are on our local network. -Read more on how this works in <http://xip.io>. +Read more on how this works in <http://nip.io>. Now that we configured this, let's see how to manage and scale GitLab. @@ -347,7 +347,7 @@ Navigate back to the **Overview** and hopefully all pods will be up and running. ![GitLab running](img/gitlab-running.png) Congratulations! You can now navigate to your new shinny GitLab instance by -visiting <http://gitlab.apps.10.2.2.2.xip.io> where you will be asked to +visiting <http://gitlab.apps.10.2.2.2.nip.io> where you will be asked to change the root user password. Login using `root` as username and providing the password you just set, and start using GitLab! @@ -521,4 +521,4 @@ PaaS and managing your applications with the ease of containers. [autoscaling]: https://docs.openshift.org/latest/dev_guide/pod_autoscaling.html "Documentation - Autoscale" [basic-cli]: https://docs.openshift.org/latest/cli_reference/basic_cli_operations.html "Documentation - Basic CLI operations" [openshift-docs]: https://docs.openshift.org "OpenShift documentation" -[scc]: https://docs.openshift.org/latest/admin_guide/manage_scc.html "Documentation - Managing Security Context Constraints"
\ No newline at end of file +[scc]: https://docs.openshift.org/latest/admin_guide/manage_scc.html "Documentation - Managing Security Context Constraints" diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index fe6a88b1df7..103836e59d0 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -135,9 +135,9 @@ and `1.2.3.4` is the IP address of your load balancer; generally NGINX ([see requirements](#requirements)). How to set up the DNS record is beyond the scope of this document; you should check with your DNS provider. -Alternatively you can use free public services like [xip.io](http://xip.io) or +Alternatively you can use free public services like [nip.io](http://nip.io) or [nip.io](http://nip.io) which provide automatic wildcard DNS without any -configuration. Just set the Auto DevOps base domain to `1.2.3.4.xip.io` or +configuration. Just set the Auto DevOps base domain to `1.2.3.4.nip.io` or `1.2.3.4.nip.io`. Once set up, all requests will hit the load balancer, which in turn will route diff --git a/doc/user/profile/img/profil-preferences-navigation-theme.png b/doc/user/profile/img/profil-preferences-navigation-theme.png Binary files differnew file mode 100644 index 00000000000..7adaec33b60 --- /dev/null +++ b/doc/user/profile/img/profil-preferences-navigation-theme.png diff --git a/doc/user/profile/img/profile-preferences-syntax-themes.png b/doc/user/profile/img/profile-preferences-syntax-themes.png Binary files differnew file mode 100644 index 00000000000..719df9410fc --- /dev/null +++ b/doc/user/profile/img/profile-preferences-syntax-themes.png diff --git a/doc/user/profile/img/profile_settings_dropdown.png b/doc/user/profile/img/profile_settings_dropdown.png Binary files differindex a2c620642e2..99b06a1bf58 100644 --- a/doc/user/profile/img/profile_settings_dropdown.png +++ b/doc/user/profile/img/profile_settings_dropdown.png diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md index 930e506802a..e028861a419 100644 --- a/doc/user/profile/preferences.md +++ b/doc/user/profile/preferences.md @@ -7,6 +7,34 @@ To navigate to your profile's preferences, click your avatar icon in the top right corner and select **Settings**. From there on, choose the **Preferences** tab. +![Profile preferences settings](img/profile_settings_dropdown.png) + +## Navigation theme + +>**Note:** +Navigation themes have been re-introduced with [GitLab 10.0](https://about.gitlab.com/2017/09/22/gitlab-10-0-released/). + +The GitLab navigation theme setting allows you to personalize your GitLab experience. +You can choose from several color themes that add unique colors to the top navigation +and left side navigation. +Using individual color themes might help you differentiate between your different +GitLab instances. + +The default palette is Indigo. You can choose between 10 different themes: + +- Indigo +- Light Indigo +- Blue +- Light Blue +- Green +- Light Green +- Red +- Light Red +- Dark +- Light + +![Profile preferences syntax highlighting themes](img/profile-preferences-syntax-themes.png) + ## Syntax highlighting theme >**Note:** @@ -16,7 +44,7 @@ list of supported languages visit the rouge website. Changing this setting allows you to customize the color theme when viewing any syntax highlighted code on GitLab. -The default one is **White**, and you can choose among 5 different colors: +The default syntax theme is White, and you can choose among 5 different colors: - White - Dark @@ -24,6 +52,8 @@ The default one is **White**, and you can choose among 5 different colors: - Solarized dark - Monokai +![Profile preferences navigation themes](img/profil-preferences-navigation-theme.png) + ## Behavior The following settings allow you to customize the behavior of GitLab's layout @@ -52,16 +82,16 @@ You have 8 options here that you can use for your default dashboard view: - Assigned Issues - Assigned Merge Requests -### Project home page content +### Project overview content -The project home page content setting allows you to choose what content you want to +The project overview content setting allows you to choose what content you want to see on a project’s home page. You can choose between 3 options: -- Show the files and the readme (default) -- Show the readme -- Show the project’s activity +- Files and Readme (default) +- Readme +- Activity [rouge]: http://rouge.jneen.net/ "Rouge website" [todos]: ../../workflow/todos.md diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index 1e909e9f5f7..48bb2e543c1 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -41,20 +41,20 @@ new Kubernetes cluster that will be hosted on GKE to your project: 1. Navigate to your project's **Operations > Kubernetes** page. 1. Click on **Add Kubernetes cluster**. -1. Click on **Create with GKE**. +1. Click on **Create with Google Kubernetes Engine**. 1. Connect your Google account if you haven't done already by clicking the **Sign in with Google** button. 1. Fill in the requested values: - - **Cluster name** (required) - The name you wish to give the cluster. - - **GCP project ID** (required) - The ID of the project you created in your GCP + - **Kubernetes cluster name** - The name you wish to give the cluster. + - **Environment scope** - The [associated environment](#setting-the-environment-scope) to this cluster. + - **Google Cloud Platform project** - The project you created in your GCP console that will host the Kubernetes cluster. This must **not** be confused - with the project name. Learn more about [Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects). + with the project ID. Learn more about [Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects). - **Zone** - The [zone](https://cloud.google.com/compute/docs/regions-zones/) under which the cluster will be created. - **Number of nodes** - The number of nodes you wish the cluster to have. - **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types) of the Virtual Machine instance that the cluster will be based on. - - **Environment scope** - The [associated environment](#setting-the-environment-scope) to this cluster. 1. Finally, click the **Create Kubernetes cluster** button. After a few moments, your cluster should be created. If something goes wrong, diff --git a/doc/user/project/import/img/import_projects_from_repo_url.png b/doc/user/project/import/img/import_projects_from_repo_url.png Binary files differindex ec867da1087..c453c7e558a 100644 --- a/doc/user/project/import/img/import_projects_from_repo_url.png +++ b/doc/user/project/import/img/import_projects_from_repo_url.png diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 63e1102f686..e883964a090 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -120,7 +120,7 @@ module Gitlab # Default branch in the repository def root_ref - @root_ref ||= gitaly_migrate(:root_ref) do |is_enabled| + @root_ref ||= gitaly_migrate(:root_ref, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_ref_client.default_branch_name else @@ -152,7 +152,7 @@ module Gitlab # Returns an Array of branch names # sorted by name ASC def branch_names - gitaly_migrate(:branch_names) do |is_enabled| + gitaly_migrate(:branch_names, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_ref_client.branch_names else @@ -163,7 +163,7 @@ module Gitlab # Returns an Array of Branches def branches - gitaly_migrate(:branches) do |is_enabled| + gitaly_migrate(:branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_ref_client.branches else @@ -200,7 +200,7 @@ module Gitlab end def local_branches(sort_by: nil) - gitaly_migrate(:local_branches) do |is_enabled| + gitaly_migrate(:local_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_ref_client.local_branches(sort_by: sort_by) else @@ -270,7 +270,7 @@ module Gitlab # Returns an Array of tag names def tag_names - gitaly_migrate(:tag_names) do |is_enabled| + gitaly_migrate(:tag_names, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_ref_client.tag_names else @@ -283,7 +283,7 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/390 def tags - gitaly_migrate(:tags) do |is_enabled| + gitaly_migrate(:tags, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled tags_from_gitaly else @@ -310,7 +310,7 @@ module Gitlab # # name - The name of the tag as a String. def tag_exists?(name) - gitaly_migrate(:ref_exists_tags) do |is_enabled| + gitaly_migrate(:ref_exists_tags, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_ref_exists?("refs/tags/#{name}") else @@ -323,7 +323,7 @@ module Gitlab # # name - The name of the branch as a String. def branch_exists?(name) - gitaly_migrate(:ref_exists_branches) do |is_enabled| + gitaly_migrate(:ref_exists_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_ref_exists?("refs/heads/#{name}") else diff --git a/lib/gitlab/github_import/sequential_importer.rb b/lib/gitlab/github_import/sequential_importer.rb index 3cad919b4eb..6a181caf65d 100644 --- a/lib/gitlab/github_import/sequential_importer.rb +++ b/lib/gitlab/github_import/sequential_importer.rb @@ -42,8 +42,6 @@ module Gitlab klass.new(project, client, parallel: false).execute end - project.repository.after_import - true end end diff --git a/lib/gitlab/sql/cte.rb b/lib/gitlab/sql/cte.rb new file mode 100644 index 00000000000..f357829ba3f --- /dev/null +++ b/lib/gitlab/sql/cte.rb @@ -0,0 +1,50 @@ +module Gitlab + module SQL + # Class for easily building CTE statements. + # + # Example: + # + # cte = CTE.new(:my_cte_name) + # ns = Arel::Table.new(:namespaces) + # + # cte << Namespace. + # where(ns[:parent_id].eq(some_namespace_id)) + # + # Namespace + # with(cte.to_arel). + # from(cte.alias_to(ns)) + class CTE + attr_reader :table, :query + + # name - The name of the CTE as a String or Symbol. + def initialize(name, query) + @table = Arel::Table.new(name) + @query = query + end + + # Returns the Arel relation for this CTE. + def to_arel + sql = Arel::Nodes::SqlLiteral.new("(#{query.to_sql})") + + Arel::Nodes::As.new(table, sql) + end + + # Returns an "AS" statement that aliases the CTE name as the given table + # name. This allows one to trick ActiveRecord into thinking it's selecting + # from an actual table, when in reality it's selecting from a CTE. + # + # alias_table - The Arel table to use as the alias. + def alias_to(alias_table) + Arel::Nodes::As.new(table, alias_table) + end + + # Applies the CTE to the given relation, returning a new one that will + # query from it. + def apply_to(relation) + relation.except(:where) + .with(to_arel) + .from(alias_to(relation.model.arel_table)) + end + end + end +end diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake index aafbe52e5f8..fc59b3f937d 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/import.rake @@ -9,7 +9,10 @@ class GithubImport def initialize(token, gitlab_username, project_path, extras) @options = { token: token } @project_path = project_path - @current_user = User.find_by_username(gitlab_username) + @current_user = User.find_by(username: gitlab_username) + + raise "GitLab user #{gitlab_username} not found. Please specify a valid username." unless @current_user + @github_repo = extras.empty? ? nil : extras.first end @@ -50,7 +53,7 @@ class GithubImport end if import_success - @project.import_finish + @project.after_import puts "Import finished. Timings: #{timings}".color(:green) else puts "Import was not successful. Errors were as follows:" diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 058a02833b1..5aa6e5c05e6 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-08 18:19+0200\n" -"PO-Revision-Date: 2018-06-08 18:19+0200\n" +"POT-Creation-Date: 2018-06-11 09:18+0200\n" +"PO-Revision-Date: 2018-06-11 09:18+0200\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: \n" @@ -4109,7 +4109,7 @@ msgstr "" msgid "TagsPage|Use git tag command to add a new one:" msgstr "" -msgid "TagsPage|Write your release notes or drag files here..." +msgid "TagsPage|Write your release notes or drag files here…" msgstr "" msgid "TagsPage|protected" @@ -4806,7 +4806,7 @@ msgstr "" msgid "WikiPage|Page slug" msgstr "" -msgid "WikiPage|Write your content or drag files here..." +msgid "WikiPage|Write your content or drag files here…" msgstr "" msgid "Wiki|Create Page" diff --git a/qa/qa/factory/repository/push.rb b/qa/qa/factory/repository/push.rb index 7bb808652da..7c0d580c5ca 100644 --- a/qa/qa/factory/repository/push.rb +++ b/qa/qa/factory/repository/push.rb @@ -1,3 +1,5 @@ +require 'pathname' + module QA module Factory module Repository diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index fe432edfa2a..81d00d45753 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -46,6 +46,18 @@ module QA def sandbox_name ENV['GITLAB_SANDBOX_NAME'] end + + def gcloud_account_key + ENV.fetch("GCLOUD_ACCOUNT_KEY") + end + + def gcloud_account_email + ENV.fetch("GCLOUD_ACCOUNT_EMAIL") + end + + def gcloud_zone + ENV.fetch('GCLOUD_ZONE') + end end end end diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb index 604bc522983..7627c8c7ad9 100644 --- a/qa/qa/service/kubernetes_cluster.rb +++ b/qa/qa/service/kubernetes_cluster.rb @@ -20,9 +20,11 @@ module QA gcloud container clusters create #{cluster_name} --enable-legacy-authorization - --zone us-central1-a + --zone #{Runtime::Env.gcloud_zone} && gcloud container clusters - get-credentials #{cluster_name} + get-credentials + --zone #{Runtime::Env.gcloud_zone} + #{cluster_name} CMD @api_url = `kubectl config view --minify -o jsonpath='{.clusters[].cluster.server}'` @@ -32,7 +34,12 @@ module QA end def remove! - shell("gcloud container clusters delete #{cluster_name} --quiet --async") + shell <<~CMD.tr("\n", ' ') + gcloud container clusters delete + --zone #{Runtime::Env.gcloud_zone} + #{cluster_name} + --quiet --async + CMD end private @@ -54,9 +61,9 @@ module QA def attempt_login_with_env_vars puts "No gcloud account. Attempting to login from env vars GCLOUD_ACCOUNT_EMAIL and GCLOUD_ACCOUNT_KEY." gcloud_account_key = Tempfile.new('gcloud-account-key') - gcloud_account_key.write(ENV.fetch("GCLOUD_ACCOUNT_KEY")) + gcloud_account_key.write(Runtime::Env.gcloud_account_key) gcloud_account_key.close - gcloud_account_email = ENV.fetch("GCLOUD_ACCOUNT_EMAIL") + gcloud_account_email = Runtime::Env.gcloud_account_email shell("gcloud auth activate-service-account #{gcloud_account_email} --key-file #{gcloud_account_key.path}") ensure gcloud_account_key && gcloud_account_key.unlink diff --git a/qa/qa/specs/features/project/auto_devops_spec.rb b/qa/qa/specs/features/project/auto_devops_spec.rb index f3f59d33457..202a847d1a5 100644 --- a/qa/qa/specs/features/project/auto_devops_spec.rb +++ b/qa/qa/specs/features/project/auto_devops_spec.rb @@ -1,3 +1,5 @@ +require 'pathname' + module QA feature 'Auto Devops', :kubernetes do after do diff --git a/scripts/rails5-gemfile-lock-check b/scripts/rails5-gemfile-lock-check new file mode 100755 index 00000000000..da6f1b7145e --- /dev/null +++ b/scripts/rails5-gemfile-lock-check @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +echo -e "=> Checking if Gemfile.rails5.lock is up-to-date...\\n" + +cp Gemfile.rails5.lock Gemfile.rails5.lock.orig +BUNDLE_GEMFILE=Gemfile.rails5 bundle install "$BUNDLE_INSTALL_FLAGS" +diff -u Gemfile.rails5.lock.orig Gemfile.rails5.lock >/dev/null 2>&1 + +if [ $? == 1 ] +then + diff -u Gemfile.rails5.lock.orig Gemfile.rails5.lock + + echo -e "\\n✖ ERROR: Gemfile.rails5.lock is not up-to-date! + Please run 'BUNDLE_GEMFILE=Gemfile.rails5 bundle install'\\n" >&2 + exit 1 +fi + +echo "✔ Gemfile.rails5.lock is up-to-date" +exit 0 diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js index 224debbeff6..a7d1e4331eb 100644 --- a/spec/javascripts/notes/components/comment_form_spec.js +++ b/spec/javascripts/notes/components/comment_form_spec.js @@ -84,7 +84,7 @@ describe('issue_comment_form component', () => { it('should render textarea with placeholder', () => { expect( vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), - ).toEqual('Write a comment or drag your files here...'); + ).toEqual('Write a comment or drag your files here…'); }); it('should make textarea disabled while requesting', (done) => { diff --git a/spec/javascripts/notes/components/note_app_spec.js b/spec/javascripts/notes/components/note_app_spec.js index 0e792eee5e9..d494c63ff11 100644 --- a/spec/javascripts/notes/components/note_app_spec.js +++ b/spec/javascripts/notes/components/note_app_spec.js @@ -106,7 +106,7 @@ describe('note_app', () => { expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM'); expect( vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), - ).toEqual('Write a comment or drag your files here...'); + ).toEqual('Write a comment or drag your files here…'); }); it('should render form comment button as disabled', () => { @@ -129,7 +129,7 @@ describe('note_app', () => { expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM'); expect( vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), - ).toEqual('Write a comment or drag your files here...'); + ).toEqual('Write a comment or drag your files here…'); }); }); diff --git a/spec/javascripts/notes/components/note_form_spec.js b/spec/javascripts/notes/components/note_form_spec.js index f841a408d09..413d4f69434 100644 --- a/spec/javascripts/notes/components/note_form_spec.js +++ b/spec/javascripts/notes/components/note_form_spec.js @@ -49,7 +49,7 @@ describe('issue_note_form component', () => { it('should render text area with placeholder', () => { expect( vm.$el.querySelector('textarea').getAttribute('placeholder'), - ).toEqual('Write a comment or drag your files here...'); + ).toEqual('Write a comment or drag your files here…'); }); it('should link to markdown docs', () => { diff --git a/spec/lib/gitlab/git/wiki_spec.rb b/spec/lib/gitlab/git/wiki_spec.rb index 722d697c28e..35b06b14620 100644 --- a/spec/lib/gitlab/git/wiki_spec.rb +++ b/spec/lib/gitlab/git/wiki_spec.rb @@ -25,6 +25,22 @@ describe Gitlab::Git::Wiki do end end + describe '#delete_page', :skip_gitaly_mock do + after do + destroy_page('page1') + end + + it 'only removes the page with the same path' do + create_page('page1', 'content') + create_page('*', 'content') + + subject.delete_page('*', commit_details('whatever')) + + expect(subject.pages.count).to eq 1 + expect(subject.pages.first.title).to eq 'page1' + end + end + def create_page(name, content) subject.write_page(name, :markdown, content, commit_details(name)) end diff --git a/spec/lib/gitlab/github_import/sequential_importer_spec.rb b/spec/lib/gitlab/github_import/sequential_importer_spec.rb index 6089b0b751f..05d3243f806 100644 --- a/spec/lib/gitlab/github_import/sequential_importer_spec.rb +++ b/spec/lib/gitlab/github_import/sequential_importer_spec.rb @@ -30,7 +30,6 @@ describe Gitlab::GithubImport::SequentialImporter do expect(instance).to receive(:execute) end - expect(repository).to receive(:after_import) expect(importer.execute).to eq(true) end end diff --git a/spec/lib/gitlab/sql/cte_spec.rb b/spec/lib/gitlab/sql/cte_spec.rb new file mode 100644 index 00000000000..d6763c7b2e1 --- /dev/null +++ b/spec/lib/gitlab/sql/cte_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Gitlab::SQL::CTE, :postgresql do + describe '#to_arel' do + it 'generates an Arel relation for the CTE body' do + relation = User.where(id: 1) + cte = described_class.new(:cte_name, relation) + sql = cte.to_arel.to_sql + name = ActiveRecord::Base.connection.quote_table_name(:cte_name) + + sql1 = ActiveRecord::Base.connection.unprepared_statement do + relation.except(:order).to_sql + end + + expect(sql).to eq("#{name} AS (#{sql1})") + end + end + + describe '#alias_to' do + it 'returns an alias for the CTE' do + cte = described_class.new(:cte_name, nil) + table = Arel::Table.new(:kittens) + + source_name = ActiveRecord::Base.connection.quote_table_name(:cte_name) + alias_name = ActiveRecord::Base.connection.quote_table_name(:kittens) + + expect(cte.alias_to(table).to_sql).to eq("#{source_name} AS #{alias_name}") + end + end + + describe '#apply_to' do + it 'applies a CTE to an ActiveRecord::Relation' do + user = create(:user) + cte = described_class.new(:cte_name, User.where(id: user.id)) + + relation = cte.apply_to(User.all) + + expect(relation.to_sql).to match(/WITH .+cte_name/) + expect(relation.to_a).to eq(User.where(id: user.id).to_a) + end + end +end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 0a0d7d3fea9..51b9b518117 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1548,7 +1548,9 @@ describe Ci::Build do let(:predefined_variables) do [ { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true }, + { key: 'CI_PIPELINE_URL', value: project.web_url + "/pipelines/#{pipeline.id}", public: true }, { key: 'CI_JOB_ID', value: build.id.to_s, public: true }, + { key: 'CI_JOB_URL', value: project.web_url + "/-/jobs/#{build.id}", public: true }, { key: 'CI_JOB_TOKEN', value: build.token, public: false }, { key: 'CI_BUILD_ID', value: build.id.to_s, public: true }, { key: 'CI_BUILD_TOKEN', value: build.token, public: false }, @@ -2171,6 +2173,7 @@ describe Ci::Build do it 'does not return prohibited variables' do keys = %w[CI_JOB_ID + CI_JOB_URL CI_JOB_TOKEN CI_BUILD_ID CI_BUILD_TOKEN diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 2bae98dcbb8..a41657b53b7 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -194,7 +194,7 @@ describe Ci::Pipeline, :mailer do it 'does contains persisted variables' do keys = subject.map { |variable| variable[:key] } - expect(keys).to eq %w[CI_PIPELINE_ID] + expect(keys).to eq %w[CI_PIPELINE_ID CI_PIPELINE_URL] end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index b9a9c4ebf42..585cf7aab44 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1733,7 +1733,11 @@ describe Project do .with(project.repository_storage, project.disk_path, project.import_url) .and_return(true) - expect_any_instance_of(Repository).to receive(:after_import) + # Works around https://github.com/rspec/rspec-mocks/issues/910 + allow(described_class).to receive(:find).with(project.id).and_return(project) + expect(project.repository).to receive(:after_import) + .and_call_original + expect(project.wiki.repository).to receive(:after_import) .and_call_original end @@ -3398,10 +3402,11 @@ describe Project do end describe '#after_import' do - let(:project) { build(:project) } + let(:project) { create(:project) } it 'runs the correct hooks' do expect(project.repository).to receive(:after_import) + expect(project.wiki.repository).to receive(:after_import) expect(project).to receive(:import_finish) expect(project).to receive(:update_project_counter_caches) expect(project).to receive(:remove_import_jid) @@ -3658,6 +3663,11 @@ describe Project do .to be_truthy end + it 'allows access when there are merge requests open but no branch name is given' do + expect(project.branch_allows_collaboration?(user, nil)) + .to be_truthy + end + it 'does not allow guest users access' do guest = create(:user) target_project.add_guest(guest) diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 2514dab1714..92fcfb65269 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -1,6 +1,7 @@ require "spec_helper" describe 'Git HTTP requests' do + include ProjectForksHelper include TermsHelper include GitHttpHelpers include WorkhorseHelpers @@ -305,6 +306,22 @@ describe 'Git HTTP requests' do expect(response.body).to eq(change_access_error(:push_code)) end end + + context 'when merge requests are open that allow maintainer access' do + let(:canonical_project) { create(:project, :public, :repository) } + let(:project) { fork_project(canonical_project, nil, repository: true) } + + before do + canonical_project.add_master(user) + create(:merge_request, + source_project: project, + target_project: canonical_project, + source_branch: 'fixes', + allow_collaboration: true) + end + + it_behaves_like 'pushes are allowed' + end end end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index e1b4e618092..56d93095a85 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -36,33 +36,36 @@ describe 'project routing' do shared_examples 'RESTful project resources' do let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] } let(:controller_path) { controller } + let(:id) { { id: '1' } } + let(:format) { {} } # response format, e.g. { format: :html } + let(:params) { { namespace_id: 'gitlab', project_id: 'gitlabhq' } } it 'to #index' do - expect(get("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#index", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:index) + expect(get("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#index", params) if actions.include?(:index) end it 'to #create' do - expect(post("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#create", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:create) + expect(post("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#create", params) if actions.include?(:create) end it 'to #new' do - expect(get("/gitlab/gitlabhq/#{controller_path}/new")).to route_to("projects/#{controller}#new", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:new) + expect(get("/gitlab/gitlabhq/#{controller_path}/new")).to route_to("projects/#{controller}#new", params) if actions.include?(:new) end it 'to #edit' do - expect(get("/gitlab/gitlabhq/#{controller_path}/1/edit")).to route_to("projects/#{controller}#edit", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:edit) + expect(get("/gitlab/gitlabhq/#{controller_path}/1/edit")).to route_to("projects/#{controller}#edit", params.merge(**id, **format)) if actions.include?(:edit) end it 'to #show' do - expect(get("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#show", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:show) + expect(get("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#show", params.merge(**id, **format)) if actions.include?(:show) end it 'to #update' do - expect(put("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#update", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:update) + expect(put("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#update", params.merge(id)) if actions.include?(:update) end it 'to #destroy' do - expect(delete("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#destroy", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:destroy) + expect(delete("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#destroy", params.merge(**id, **format)) if actions.include?(:destroy) end end @@ -150,12 +153,13 @@ describe 'project routing' do end it 'to #history' do - expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') + expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: :html) end it_behaves_like 'RESTful project resources' do let(:actions) { [:create, :edit, :show, :destroy] } let(:controller) { 'wikis' } + let(:format) { { format: :html } } end end diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb index 4b3c1736ea0..ae4786389c7 100644 --- a/spec/workers/repository_fork_worker_spec.rb +++ b/spec/workers/repository_fork_worker_spec.rb @@ -55,10 +55,15 @@ describe RepositoryForkWorker do it 'flushes various caches' do expect_fork_repository.and_return(true) - expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) + # Works around https://github.com/rspec/rspec-mocks/issues/910 + expect(Project).to receive(:find).with(fork_project.id).and_return(fork_project) + expect(fork_project.repository).to receive(:expire_emptiness_caches) .and_call_original - - expect_any_instance_of(Repository).to receive(:expire_exists_cache) + expect(fork_project.repository).to receive(:expire_exists_cache) + .and_call_original + expect(fork_project.wiki.repository).to receive(:expire_emptiness_caches) + .and_call_original + expect(fork_project.wiki.repository).to receive(:expire_exists_cache) .and_call_original perform! diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb index 84d1b38ef19..f0884ad0aff 100644 --- a/spec/workers/repository_import_worker_spec.rb +++ b/spec/workers/repository_import_worker_spec.rb @@ -22,8 +22,11 @@ describe RepositoryImportWorker do expect_any_instance_of(Projects::ImportService).to receive(:execute) .and_return({ status: :ok }) - expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) - expect_any_instance_of(Project).to receive(:import_finish) + # Works around https://github.com/rspec/rspec-mocks/issues/910 + expect(Project).to receive(:find).with(project.id).and_return(project) + expect(project.repository).to receive(:expire_emptiness_caches) + expect(project.wiki.repository).to receive(:expire_emptiness_caches) + expect(project).to receive(:import_finish) subject.perform(project.id) end @@ -34,9 +37,11 @@ describe RepositoryImportWorker do expect_any_instance_of(Projects::ImportService).to receive(:execute) .and_return({ status: :ok }) - expect_any_instance_of(Project).to receive(:after_import).and_call_original - expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) - expect_any_instance_of(Project).to receive(:import_finish) + # Works around https://github.com/rspec/rspec-mocks/issues/910 + expect(Project).to receive(:find).with(project.id).and_return(project) + expect(project.repository).to receive(:expire_emptiness_caches) + expect(project.wiki.repository).to receive(:expire_emptiness_caches) + expect(project).to receive(:import_finish) subject.perform(project.id) end |