diff options
35 files changed, 360 insertions, 81 deletions
diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js index 3b2bb6f082f..d80b7f5bd42 100644 --- a/app/assets/javascripts/build.js +++ b/app/assets/javascripts/build.js @@ -20,6 +20,7 @@ window.Build = (function () { this.$document = $(document); this.logBytes = 0; this.scrollOffsetPadding = 30; + this.hasBeenScrolled = false; this.updateDropdown = this.updateDropdown.bind(this); this.getBuildTrace = this.getBuildTrace.bind(this); @@ -62,6 +63,15 @@ window.Build = (function () { .off('click') .on('click', this.scrollToBottom.bind(this)); + const scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100); + + this.$scrollContainer + .off('scroll') + .on('scroll', () => { + this.hasBeenScrolled = true; + scrollThrottled(); + }); + $(window) .off('resize.build') .on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100)); @@ -70,25 +80,16 @@ window.Build = (function () { // eslint-disable-next-line this.getBuildTrace() - .then(() => this.makeTraceScrollable()) - .then(() => this.scrollToBottom()); + .then(() => this.toggleScroll()) + .then(() => { + if (!this.hasBeenScrolled) { + this.scrollToBottom(); + } + }); this.verifyTopPosition(); } - Build.prototype.makeTraceScrollable = function () { - this.$scrollContainer.niceScroll({ - cursorcolor: '#fff', - cursoropacitymin: 1, - cursorwidth: '7px', - railpadding: { top: 5, bottom: 5, right: 5 }, - }); - - this.$scrollContainer.on('scroll', _.throttle(this.toggleScroll.bind(this), 100)); - - this.toggleScroll(); - }; - Build.prototype.canScroll = function () { return (this.$scrollContainer.prop('scrollHeight') - this.scrollOffsetPadding) > this.$scrollContainer.height(); }; @@ -104,12 +105,11 @@ window.Build = (function () { * */ Build.prototype.toggleScroll = function () { - const bottomScroll = this.$scrollContainer.scrollTop() + - this.scrollOffsetPadding + - this.$scrollContainer.height(); + const currentPosition = this.$scrollContainer.scrollTop(); + const bottomScroll = currentPosition + this.$scrollContainer.innerHeight(); if (this.canScroll()) { - if (this.$scrollContainer.scrollTop() === 0) { + if (currentPosition === 0) { this.toggleDisableButton(this.$scrollTopBtn, true); this.toggleDisableButton(this.$scrollBottomBtn, false); } else if (bottomScroll === this.$scrollContainer.prop('scrollHeight')) { @@ -123,12 +123,14 @@ window.Build = (function () { }; Build.prototype.scrollToTop = function () { - this.$scrollContainer.getNiceScroll(0).doScrollTop(0); + this.hasBeenScrolled = true; + this.$scrollContainer.scrollTop(0); this.toggleScroll(); }; Build.prototype.scrollToBottom = function () { - this.$scrollContainer.getNiceScroll(0).doScrollTo(this.$scrollContainer.prop('scrollHeight')); + this.hasBeenScrolled = true; + this.$scrollContainer.scrollTop(this.$scrollContainer.prop('scrollHeight')); this.toggleScroll(); }; @@ -216,7 +218,11 @@ window.Build = (function () { Build.timeout = setTimeout(() => { //eslint-disable-next-line this.getBuildTrace() - .then(() => this.scrollToBottom()); + .then(() => { + if (!this.hasBeenScrolled) { + this.scrollToBottom(); + } + }); }, 4000); } else { this.$buildRefreshAnimation.remove(); @@ -253,7 +259,7 @@ window.Build = (function () { this.verifyTopPosition(); - if (this.$scrollContainer.getNiceScroll(0)) { + if (this.canScroll()) { this.toggleScroll(); } }; diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js index cb054a2a197..bc3e741f524 100644 --- a/app/assets/javascripts/commons/polyfills.js +++ b/app/assets/javascripts/commons/polyfills.js @@ -1,5 +1,6 @@ // ECMAScript polyfills import 'core-js/fn/array/find'; +import 'core-js/fn/array/find-index'; import 'core-js/fn/array/from'; import 'core-js/fn/array/includes'; import 'core-js/fn/object/assign'; diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index e35558ad8e8..d931a78e112 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -71,7 +71,9 @@ height: 35px; display: flex; justify-content: flex-end; - border-bottom: 1px outset $white-light; + background: $gray-light; + border: 1px solid $gray-normal; + color: $gl-text-color; .truncated-info { margin: 0 auto; @@ -82,7 +84,7 @@ } .raw-link { - color: inherit; + color: $gl-text-color; margin-left: 5px; text-decoration: underline; } @@ -93,17 +95,25 @@ display: flex; align-self: center; font-size: 15px; + margin-bottom: 4px; svg { height: 15px; display: block; - fill: $white-light; + fill: $gl-text-color; } - a, + .controllers-buttons, .btn-scroll { - margin: 0 8px; - color: $white-light; + color: $gl-text-color; + height: 15px; + vertical-align: middle; + padding: 0; + width: 12px; + } + + .controllers-buttons { + margin: 1px 10px; } .btn-scroll.animate { @@ -137,9 +147,9 @@ top: 35px; left: 10px; bottom: 0; - overflow-y: hidden; - padding-bottom: 20px; - padding-right: 20px; + overflow-y: scroll; + overflow-x: hidden; + padding: 10px 20px 20px 5px; } .environment-information { diff --git a/app/controllers/concerns/milestone_actions.rb b/app/controllers/concerns/milestone_actions.rb index 3e2a0fe4f8b..b2536a1c949 100644 --- a/app/controllers/concerns/milestone_actions.rb +++ b/app/controllers/concerns/milestone_actions.rb @@ -46,8 +46,10 @@ module MilestoneActions def milestone_redirect_path if @project namespace_project_milestone_path(@project.namespace, @project, @milestone) - else + elsif @group group_milestone_path(@group, @milestone.safe_title, title: @milestone.title) + else + dashboard_milestone_path(@milestone.safe_title, title: @milestone.title) end end end diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb index df528d10f6e..751dbbd8e96 100644 --- a/app/controllers/dashboard/milestones_controller.rb +++ b/app/controllers/dashboard/milestones_controller.rb @@ -1,6 +1,8 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController + include MilestoneActions + before_action :projects - before_action :milestone, only: [:show] + before_action :milestone, only: [:show, :merge_requests, :participants, :labels] def index respond_to do |format| diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb index c585d26df77..11db164b3fa 100644 --- a/app/controllers/jwt_controller.rb +++ b/app/controllers/jwt_controller.rb @@ -39,7 +39,7 @@ class JwtController < ApplicationController errors: [ { code: 'UNAUTHORIZED', message: "HTTP Basic: Access denied\n" \ - "You have 2FA enabled, please use a personal access token for Git over HTTP.\n" \ + "You must use a personal access token with 'api' scope for Git over HTTP.\n" \ "You can generate one at #{profile_personal_access_tokens_url}" } ] }, status: 401 diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb index 7f3205a8001..928f17e6a8e 100644 --- a/app/controllers/projects/git_http_client_controller.rb +++ b/app/controllers/projects/git_http_client_controller.rb @@ -104,7 +104,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController def render_missing_personal_token render plain: "HTTP Basic: Access denied\n" \ - "You have 2FA enabled, please use a personal access token for Git over HTTP.\n" \ + "You must use a personal access token with 'api' scope for Git over HTTP.\n" \ "You can generate one at #{profile_personal_access_tokens_url}", status: 401 end diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb index c515774140c..a230db22fa2 100644 --- a/app/helpers/milestones_helper.rb +++ b/app/helpers/milestones_helper.rb @@ -121,6 +121,8 @@ module MilestonesHelper merge_requests_namespace_project_milestone_path(@project.namespace, @project, milestone, format: :json) elsif @group merge_requests_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json) + else + merge_requests_dashboard_milestone_path(milestone, title: milestone.title, format: :json) end end @@ -129,6 +131,8 @@ module MilestonesHelper participants_namespace_project_milestone_path(@project.namespace, @project, milestone, format: :json) elsif @group participants_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json) + else + participants_dashboard_milestone_path(milestone, title: milestone.title, format: :json) end end @@ -137,6 +141,8 @@ module MilestonesHelper labels_namespace_project_milestone_path(@project.namespace, @project, milestone, format: :json) elsif @group labels_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json) + else + labels_dashboard_milestone_path(milestone, title: milestone.title, format: :json) end end end diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb index 0db9e31031c..8bf35953d29 100644 --- a/app/presenters/merge_request_presenter.rb +++ b/app/presenters/merge_request_presenter.rb @@ -110,12 +110,24 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated end def closing_issues_links - markdown issues_sentence(project, closing_issues), pipeline: :gfm, author: author, project: project + markdown( + issues_sentence(project, closing_issues), + pipeline: :gfm, + author: author, + project: project, + issuable_state_filter_enabled: true + ) end def mentioned_issues_links mentioned_issues = issues_mentioned_but_not_closing(current_user) - markdown issues_sentence(project, mentioned_issues), pipeline: :gfm, author: author, project: project + markdown( + issues_sentence(project, mentioned_issues), + pipeline: :gfm, + author: author, + project: project, + issuable_state_filter_enabled: true + ) end def assign_to_closing_issues_link diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index b20e3a22133..31d0e589c26 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -4,7 +4,7 @@ Community Edition - if user_signed_in? %span= Gitlab::VERSION - %small= Gitlab::REVISION + %small= link_to Gitlab::REVISION, Gitlab::COM_URL + namespace_project_commits_path('gitlab-org', 'gitlab-ce', Gitlab::REVISION) = version_status_badge %p.slead GitLab is open source software to collaborate on code. diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index 0d10dfcef70..987068dc18e 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -66,29 +66,24 @@ .controllers - if @build.has_trace? = link_to raw_namespace_project_job_path(@project.namespace, @project, @build), - title: 'Open raw trace', + title: 'Show complete raw', data: { placement: 'top', container: 'body' }, - class: 'js-raw-link-controller has-tooltip' do - = icon('download') + class: 'js-raw-link-controller has-tooltip controllers-buttons' do + = icon('file-text-o') - if can?(current_user, :update_build, @project) && @build.erasable? = link_to erase_namespace_project_job_path(@project.namespace, @project, @build), method: :post, data: { confirm: 'Are you sure you want to erase this build?', placement: 'top', container: 'body' }, - title: 'Erase Build', - class: 'has-tooltip js-erase-link' do + title: 'Erase job log', + class: 'has-tooltip js-erase-link controllers-buttons' do = icon('trash') - - %button.js-scroll-up.btn-scroll.btn-transparent.btn-blank.has-tooltip{ type: 'button', - disabled: true, - title: 'Scroll Up', - data: { placement: 'top', container: 'body'} } - = custom_icon('scroll_up') - %button.js-scroll-down.btn-scroll.btn-transparent.btn-blank.has-tooltip{ type: 'button', - disabled: true, - title: 'Scroll Down', - data: { placement: 'top', container: 'body'} } - = custom_icon('scroll_down') + .has-tooltip.controllers-buttons{ title: 'Scroll to top', data: { placement: 'top', container: 'body'} } + %button.js-scroll-up.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true } + = custom_icon('scroll_up') + .has-tooltip.controllers-buttons{ title: 'Scroll to bottom', data: { placement: 'top', container: 'body'} } + %button.js-scroll-down.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true } + = custom_icon('scroll_down') .bash.sticky.js-scroll-container %code.js-build-output .build-loader-animation.js-build-refresh diff --git a/changelogs/unreleased/33381-display-issue-state-in-mr-widget-issue-links.yml b/changelogs/unreleased/33381-display-issue-state-in-mr-widget-issue-links.yml new file mode 100644 index 00000000000..4a7b02fec94 --- /dev/null +++ b/changelogs/unreleased/33381-display-issue-state-in-mr-widget-issue-links.yml @@ -0,0 +1,4 @@ +--- +title: Display issue state in issue links section of merge request widget +merge_request: 12021 +author: diff --git a/changelogs/unreleased/dashboard-milestone-tabs-loading-async.yml b/changelogs/unreleased/dashboard-milestone-tabs-loading-async.yml new file mode 100644 index 00000000000..357a623e0e8 --- /dev/null +++ b/changelogs/unreleased/dashboard-milestone-tabs-loading-async.yml @@ -0,0 +1,4 @@ +--- +title: Fixed dashboard milestone tabs not loading +merge_request: +author: diff --git a/changelogs/unreleased/pat-msg-on-auth-failure.yml b/changelogs/unreleased/pat-msg-on-auth-failure.yml new file mode 100644 index 00000000000..c1b1528bb7a --- /dev/null +++ b/changelogs/unreleased/pat-msg-on-auth-failure.yml @@ -0,0 +1,4 @@ +--- +title: Instruct user to use personal access token for Git over HTTP +merge_request: 11986 +author: Robin Bobbitt diff --git a/changelogs/unreleased/tc-link-to-commit-on-help-page.yml b/changelogs/unreleased/tc-link-to-commit-on-help-page.yml new file mode 100644 index 00000000000..3d11ba43d1f --- /dev/null +++ b/changelogs/unreleased/tc-link-to-commit-on-help-page.yml @@ -0,0 +1,4 @@ +--- +title: Make the revision on the `/help` page clickable +merge_request: 12016 +author: diff --git a/config/locales/de.yml b/config/locales/de.yml index 533663a2704..38c3711c6c7 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -62,6 +62,43 @@ de: - :month - :year datetime: + # used in a custom scope that has been created to fix https://gitlab.com/gitlab-org/gitlab-ce/issues/32747 + time_ago_in_words: + half_a_minute: vor einer halben Minute + less_than_x_seconds: + one: vor weniger als einer Sekunde + other: "vor weniger als %{count} Sekunden" + x_seconds: + one: vor einer Sekunde + other: "vor %{count} Sekunden" + less_than_x_minutes: + one: vor weniger als einer Minute + other: vor weniger als %{count} Minuten + x_minutes: + one: vor einer Minute + other: "vor %{count} Minuten" + about_x_hours: + one: vor etwa einer Stunde + other: "vor etwa %{count} Stunden" + x_days: + one: vor einem Tag + other: "vor %{count} Tagen" + about_x_months: + one: vor etwa einem Monat + other: "vor etwa %{count} Monaten" + x_months: + one: vor einem Monat + other: "vor %{count} Monaten" + about_x_years: + one: vor etwa einem Jahr + other: "vor etwa %{count} Jahren" + over_x_years: + one: vor mehr als einem Jahr + other: "vor mehr als %{count} Jahren" + almost_x_years: + one: vor fast einem Jahr + other: "vor fast %{count} Jahren" + # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() distance_in_words: about_x_hours: one: etwa eine Stunde diff --git a/config/locales/es.yml b/config/locales/es.yml index 0f9dc39535d..d71c6eb5047 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -61,6 +61,7 @@ es: - :month - :year datetime: + # used in a custom scope that has been created to fix https://gitlab.com/gitlab-org/gitlab-ce/issues/32747 time_ago_in_words: half_a_minute: "hace medio minuto" less_than_x_seconds: @@ -96,6 +97,7 @@ es: almost_x_years: one: "hace casi 1 año" other: "hace casi %{count} años" + # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() distance_in_words: about_x_hours: one: alrededor de 1 hora diff --git a/config/routes/dashboard.rb b/config/routes/dashboard.rb index 8e380a0b0ac..d2437285cdf 100644 --- a/config/routes/dashboard.rb +++ b/config/routes/dashboard.rb @@ -4,7 +4,13 @@ resource :dashboard, controller: 'dashboard', only: [] do get :activity scope module: :dashboard do - resources :milestones, only: [:index, :show] + resources :milestones, only: [:index, :show] do + member do + get :merge_requests + get :participants + get :labels + end + end resources :labels, only: [:index] resources :groups, only: [:index] diff --git a/doc/api/projects.md b/doc/api/projects.md index bf21aa0e179..716486022b0 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -2,10 +2,10 @@ ### Project visibility level -Project in GitLab has be either private, internal or public. -You can determine it by `visibility` field in project. +Project in GitLab can be either private, internal or public. +This is determined by the `visibility` field in the project. -Constants for project visibility levels are next: +Values for the project visibility level are: * `private`: Project access must be granted explicitly for each user. @@ -18,7 +18,7 @@ Constants for project visibility levels are next: ## List projects -Get a list of visible projects for authenticated user. When being accessed without authentication, all public projects are returned. +Get a list of visible projects for authenticated user. When accessed without authentication, only public projects are returned. ``` GET /projects diff --git a/doc/integration/google.md b/doc/integration/google.md index 1e7ad90c5a8..d5b523e6dc0 100644 --- a/doc/integration/google.md +++ b/doc/integration/google.md @@ -72,6 +72,21 @@ To enable the Google OAuth2 OmniAuth provider you must register your application 1. Change 'YOUR_APP_SECRET' to the client secret from the Google Developer page from step 10. +1. Make sure that you configure GitLab to use an FQDN as Google will not accept raw IP addresses. + + For Omnibus packages: + + ```ruby + external_url 'https://gitlab.example.com' + ``` + + For installations from source: + + ```yaml + gitlab: + host: https://gitlab.example.com + ``` + 1. Save the configuration file. 1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you diff --git a/doc/university/glossary/README.md b/doc/university/glossary/README.md index 591d1524061..9544de41b9a 100644 --- a/doc/university/glossary/README.md +++ b/doc/university/glossary/README.md @@ -1,4 +1,3 @@ - ## What is the Glossary This contains a simplified list and definitions of some of the terms that you will encounter in your day to day activities when working with GitLab. @@ -10,7 +9,7 @@ User authentication by combination of 2 different steps during login. This allow ### Access Levels -Process of selective restriction to create, view, modify or delete a resource based on a set of assigned permissions. See [GitLab's Permission Guidelines](../../permissions/permissions.md +Process of selective restriction to create, view, modify or delete a resource based on a set of assigned permissions. See [GitLab's Permission Guidelines](../../user/permissions.md) ### Active Directory (AD) diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md index 10c281448a3..75ea911b9bc 100644 --- a/doc/user/project/container_registry.md +++ b/doc/user/project/container_registry.md @@ -39,6 +39,14 @@ You can read more about Docker Registry at https://docs.docker.com/registry/intr ## Build and push images +>**Notes:** +- Moving or renaming existing container registry repositories is not supported +once you have pushed images because the images are signed, and the +signature includes the repository name. +- To move or rename a repository with a container registry you will have to +delete all existing images. + + If you visit the **Registry** link under your project's menu, you can see the explicit instructions to login to the Container Registry using your GitLab credentials. diff --git a/doc/workflow/groups.md b/doc/workflow/groups.md index 1cb3c940f00..1645e7e8d65 100644 --- a/doc/workflow/groups.md +++ b/doc/workflow/groups.md @@ -23,9 +23,10 @@ You can use the 'New project' button to add a project to the new group. ## Transferring an existing project into a group -You can transfer an existing project into a group you own from the project settings page. The option to transfer a project is only available if you are the Owner of the project. +You can transfer an existing project into a group you have at least Master access in from the project settings page. +The option to transfer a project is only available if you are the Owner of the project. First scroll down to the 'Dangerous settings' and click 'Show them to me'. -Now you can pick any of the groups you manage as the new namespace for the group. +Now you can pick any of the groups you have at least Master access in as the new namespace for the group.  diff --git a/features/steps/project/source/markdown_render.rb b/features/steps/project/source/markdown_render.rb index 0fee158d590..cf31e61437e 100644 --- a/features/steps/project/source/markdown_render.rb +++ b/features/steps/project/source/markdown_render.rb @@ -90,6 +90,8 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps click_link "api" end + wait_for_requests + page.within '.tree-table' do click_link "README.md" end diff --git a/lib/gitlab.rb b/lib/gitlab.rb index c3064163e07..11f7c8b9510 100644 --- a/lib/gitlab.rb +++ b/lib/gitlab.rb @@ -1,9 +1,11 @@ require_dependency 'gitlab/git' module Gitlab + COM_URL = 'https://gitlab.com'.freeze + def self.com? # Check `staging?` as well to keep parity with gitlab.com - Gitlab.config.gitlab.url == 'https://gitlab.com' || staging? + Gitlab.config.gitlab.url == COM_URL || staging? end def self.staging? diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index da07ba2f2a3..3933c3b04dd 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -37,7 +37,11 @@ module Gitlab rate_limit!(ip, success: result.success?, login: login) Gitlab::Auth::UniqueIpsLimiter.limit_user!(result.actor) - result + return result if result.success? || current_application_settings.signin_enabled? || Gitlab::LDAP::Config.enabled? + + # If sign-in is disabled and LDAP is not configured, recommend a + # personal access token on failed auth attempts + raise Gitlab::Auth::MissingPersonalTokenError end def find_with_user_password(login, password) diff --git a/scripts/trigger-build b/scripts/trigger-build index e4603533872..dcda70d7ed8 100755 --- a/scripts/trigger-build +++ b/scripts/trigger-build @@ -9,7 +9,7 @@ params = { "token" => ENV["BUILD_TRIGGER_TOKEN"], "variables[GITLAB_VERSION]" => ENV["CI_COMMIT_SHA"], "variables[ALTERNATIVE_SOURCES]" => true, - "variables[ee]" => ENV["EE_PACKAGE"] + "variables[ee]" => ENV["EE_PACKAGE"] || "false" } Dir.glob("*_VERSION").each do |version_file| @@ -19,4 +19,9 @@ end res = Net::HTTP.post_form(uri, params) pipeline_id = JSON.parse(res.body)['id'] -puts "Triggered pipeline can be found at https://gitlab.com/gitlab-org/omnibus-gitlab/pipelines/#{pipeline_id}" +unless pipeline_id.nil? + puts "Triggered pipeline can be found at https://gitlab.com/gitlab-org/omnibus-gitlab/pipelines/#{pipeline_id}" +else + puts "Trigger failed. The response from trigger is: " + puts res.body +end diff --git a/spec/controllers/dashboard/milestones_controller_spec.rb b/spec/controllers/dashboard/milestones_controller_spec.rb new file mode 100644 index 00000000000..424f39fd3b8 --- /dev/null +++ b/spec/controllers/dashboard/milestones_controller_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe Dashboard::MilestonesController do + let(:project) { create(:empty_project) } + let(:user) { create(:user) } + let(:project_milestone) { create(:milestone, project: project) } + let(:milestone) do + DashboardMilestone.build( + [project], + project_milestone.title + ) + end + let(:issue) { create(:issue, project: project, milestone: project_milestone) } + let!(:label) { create(:label, project: project, title: 'Issue Label', issues: [issue]) } + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: project_milestone) } + let(:milestone_path) { dashboard_milestone_path(milestone.safe_title, title: milestone.title) } + + before do + sign_in(user) + project.team << [user, :master] + end + + it_behaves_like 'milestone tabs' + + describe "#show" do + render_views + + def view_milestone + get :show, id: milestone.safe_title, title: milestone.title + end + + it 'shows milestone page' do + view_milestone + + expect(response).to have_http_status(200) + end + end +end diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb new file mode 100644 index 00000000000..0c7b992c500 --- /dev/null +++ b/spec/features/dashboard/milestone_tabs_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe 'Dashboard milestone tabs', :js, :feature do + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + let!(:label) { create(:label, project: project) } + let(:project_milestone) { create(:milestone, project: project) } + let(:milestone) do + DashboardMilestone.build( + [project], + project_milestone.title + ) + end + let!(:merge_request) { create(:labeled_merge_request, source_project: project, target_project: project, milestone: project_milestone, labels: [label]) } + + before do + project.add_master(user) + login_as(user) + + visit dashboard_milestone_path(milestone.safe_title, title: milestone.title) + end + + it 'loads merge requests async' do + click_link 'Merge Requests' + + expect(page).to have_selector('.merge_requests-sortable-list') + end + + it 'loads participants async' do + click_link 'Participants' + + expect(page).to have_selector('#tab-participants .bordered-list') + end + + it 'loads labels async' do + click_link 'Labels' + + expect(page).to have_selector('#tab-labels .bordered-list') + end +end diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index d6006eab0c9..d09da951869 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -204,6 +204,12 @@ describe Gitlab::Auth, lib: true do expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login) expect(gl_auth.find_for_git_client(login, 'bar', project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new) end + + it 'throws an error suggesting user create a PAT when internal auth is disabled' do + allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } + + expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, ip: 'ip') }.to raise_error(Gitlab::Auth::MissingPersonalTokenError) + end end describe 'find_with_user_password' do diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index 44720fc4448..f5a14b1d04d 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -132,6 +132,11 @@ describe MergeRequestPresenter do it 'does not present related issues links' do is_expected.not_to match("#{project.full_path}/issues/#{issue_b.iid}") end + + it 'appends status when closing issue is already closed' do + issue_a.close + is_expected.to match('(closed)') + end end describe '#mentioned_issues_links' do @@ -147,6 +152,11 @@ describe MergeRequestPresenter do it 'does not present closing issues links' do is_expected.not_to match("#{project.full_path}/issues/#{issue_a.iid}") end + + it 'appends status when mentioned issue is already closed' do + issue_b.close + is_expected.to match('(closed)') + end end describe '#assign_to_closing_issues_link' do diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index c09be0ce1b9..6a83024d0d5 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -418,17 +418,17 @@ describe 'Git HTTP requests', lib: true do end context 'when username and password are provided' do - it 'rejects pulls with 2FA error message' do + it 'rejects pulls with personal access token error message' do download(path, user: user.username, password: user.password) do |response| expect(response).to have_http_status(:unauthorized) - expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP') + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') end end - it 'rejects the push attempt' do + it 'rejects the push attempt with personal access token error message' do upload(path, user: user.username, password: user.password) do |response| expect(response).to have_http_status(:unauthorized) - expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP') + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') end end end @@ -441,6 +441,41 @@ describe 'Git HTTP requests', lib: true do end end + context 'when internal auth is disabled' do + before do + allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } + end + + it 'rejects pulls with personal access token error message' do + download(path, user: 'foo', password: 'bar') do |response| + expect(response).to have_http_status(:unauthorized) + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end + + it 'rejects pushes with personal access token error message' do + upload(path, user: 'foo', password: 'bar') do |response| + expect(response).to have_http_status(:unauthorized) + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end + + context 'when LDAP is configured' do + before do + allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true) + allow_any_instance_of(Gitlab::LDAP::Authentication). + to receive(:login).and_return(nil) + end + + it 'does not display the personal access token error message' do + upload(path, user: 'foo', password: 'bar') do |response| + expect(response).to have_http_status(:unauthorized) + expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end + end + end + context "when blank password attempts follow a valid login" do def attempt_login(include_password) password = include_password ? user.password : "" diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb index e056353fa6f..54d7cf5f10d 100644 --- a/spec/requests/jwt_controller_spec.rb +++ b/spec/requests/jwt_controller_spec.rb @@ -70,7 +70,7 @@ describe JwtController do context 'without personal token' do it 'rejects the authorization attempt' do expect(response).to have_http_status(401) - expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP') + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') end end @@ -88,9 +88,24 @@ describe JwtController do context 'using invalid login' do let(:headers) { { authorization: credentials('invalid', 'password') } } - subject! { get '/jwt/auth', parameters, headers } + context 'when internal auth is enabled' do + it 'rejects the authorization attempt' do + get '/jwt/auth', parameters, headers + + expect(response).to have_http_status(401) + expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end - it { expect(response).to have_http_status(401) } + context 'when internal auth is disabled' do + it 'rejects the authorization attempt with personal access token message' do + allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } + get '/jwt/auth', parameters, headers + + expect(response).to have_http_status(401) + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end end end diff --git a/spec/support/milestone_tabs_examples.rb b/spec/support/milestone_tabs_examples.rb index 4ad8b0a16e1..7cfc1e06975 100644 --- a/spec/support/milestone_tabs_examples.rb +++ b/spec/support/milestone_tabs_examples.rb @@ -1,10 +1,14 @@ shared_examples 'milestone tabs' do def go(path, extra_params = {}) - params = if milestone.is_a?(GlobalMilestone) - { group_id: group.to_param, id: milestone.safe_title, title: milestone.title } - else - { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid } - end + params = + case milestone + when DashboardMilestone + { id: milestone.safe_title, title: milestone.title } + when GroupMilestone + { group_id: group.to_param, id: milestone.safe_title, title: milestone.title } + else + { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid } + end get path, params.merge(extra_params) end diff --git a/spec/views/help/index.html.haml_spec.rb b/spec/views/help/index.html.haml_spec.rb index 6b07fcfc987..1f8261cc46b 100644 --- a/spec/views/help/index.html.haml_spec.rb +++ b/spec/views/help/index.html.haml_spec.rb @@ -21,7 +21,7 @@ describe 'help/index' do render expect(rendered).to match '8.0.2' - expect(rendered).to match 'abcdefg' + expect(rendered).to have_link('abcdefg', 'https://gitlab.com/gitlab-org/gitlab-ce/commits/abcdefg') end end |
