diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-10 18:08:17 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-10 18:08:17 +0000 |
commit | 219eead23f9feb5da9ec378c451d773aea2dfe61 (patch) | |
tree | eec14421a05ca8eb79f3cc782abe99532bb6070c | |
parent | 7c38405be9e79099f399aa429503ea7b463bbf5a (diff) | |
download | gitlab-ce-219eead23f9feb5da9ec378c451d773aea2dfe61.tar.gz |
Add latest changes from gitlab-org/gitlab@master
35 files changed, 359 insertions, 62 deletions
diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 7ee4f639633..dd94d0b494d 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -305,7 +305,6 @@ linters: - 'app/views/shared/_milestone_expired.html.haml' - 'app/views/shared/_no_password.html.haml' - 'app/views/shared/_no_ssh.html.haml' - - 'app/views/shared/_outdated_browser.html.haml' - 'app/views/shared/_ping_consent.html.haml' - 'app/views/shared/_project_limit.html.haml' - 'app/views/shared/boards/components/_board.html.haml' diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue index 43fa97e4095..6c4f59eb49f 100644 --- a/app/assets/javascripts/error_tracking/components/error_details.vue +++ b/app/assets/javascripts/error_tracking/components/error_details.vue @@ -25,6 +25,8 @@ import { severityLevel, severityLevelVariant, errorStatus } from './constants'; import query from '../queries/details.query.graphql'; +const SENTRY_TIMEOUT = 10000; + export default { components: { GlButton, @@ -87,6 +89,8 @@ export default { if (res.data.project?.sentryErrors?.detailedError) { this.$apollo.queries.error.stopPolling(); this.setStatus(this.error.status); + } else { + this.onNoApolloResult(); } }, }, @@ -94,6 +98,8 @@ export default { data() { return { error: null, + errorLoading: true, + errorPollTimeout: 0, issueCreationInProgress: false, isAlertVisible: false, closedIssueId: null, @@ -158,8 +164,19 @@ export default { return this.errorStatus !== errorStatus.RESOLVED ? __('Resolve') : __('Unresolve'); }, }, + watch: { + error(val) { + if (val) { + this.errorLoading = false; + } + }, + }, mounted() { this.startPollingStacktrace(this.issueStackTracePath); + this.errorPollTimeout = Date.now() + SENTRY_TIMEOUT; + this.$apollo.queries.error.setOptions({ + fetchPolicy: 'cache-and-network', + }); }, methods: { ...mapActions('details', [ @@ -191,6 +208,13 @@ export default { } }); }, + onNoApolloResult() { + if (Date.now() > this.errorPollTimeout) { + this.$apollo.queries.error.stopPolling(); + this.errorLoading = false; + createFlash(__('Could not connect to Sentry. Refresh the page to try again.'), 'warning'); + } + }, formatDate(date) { return `${this.timeFormatted(date)} (${dateFormat(date, 'UTC:yyyy-mm-dd h:MM:ssTT Z')})`; }, @@ -200,7 +224,7 @@ export default { <template> <div> - <div v-if="$apollo.queries.error.loading" class="py-3"> + <div v-if="errorLoading" class="py-3"> <gl-loading-icon :size="3" /> </div> <div v-else-if="error" class="error-details"> diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb index c9c487cec26..6b8436d766c 100644 --- a/app/controllers/import/gitlab_projects_controller.rb +++ b/app/controllers/import/gitlab_projects_controller.rb @@ -1,9 +1,14 @@ # frozen_string_literal: true class Import::GitlabProjectsController < Import::BaseController + include WorkhorseRequest + before_action :whitelist_query_limiting, only: [:create] before_action :verify_gitlab_project_import_enabled + skip_before_action :verify_authenticity_token, only: [:authorize] + before_action :verify_workhorse_api!, only: [:authorize] + def new @namespace = Namespace.find(project_params[:namespace_id]) return render_404 unless current_user.can?(:create_projects, @namespace) @@ -28,10 +33,29 @@ class Import::GitlabProjectsController < Import::BaseController end end + def authorize + set_workhorse_internal_api_content_type + + authorized = ImportExportUploader.workhorse_authorize( + has_length: false, + maximum_size: Gitlab::CurrentSettings.max_attachment_size.megabytes.to_i) + + render json: authorized + rescue SocketError + render json: _("Error uploading file"), status: :internal_server_error + end + private def file_is_valid? - return false unless project_params[:file] && project_params[:file].respond_to?(:read) + # TODO: remove the condition and the private method after the WH version including + # https://gitlab.com/gitlab-org/gitlab-workhorse/-/merge_requests/470 + # is released and GITLAB_WORKHORSE_VERSION is updated accordingly. + if with_workhorse_upload_acceleration? + return false unless project_params[:file].is_a?(::UploadedFile) + else + return false unless project_params[:file] && project_params[:file].respond_to?(:read) + end filename = project_params[:file].original_filename @@ -51,4 +75,8 @@ class Import::GitlabProjectsController < Import::BaseController def whitelist_query_limiting Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42437') end + + def with_workhorse_upload_acceleration? + request.headers[Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER].present? + end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8833b36c42d..83ecc7753b6 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -227,7 +227,7 @@ module ApplicationHelper end def outdated_browser? - browser.ie? && browser.version.to_i < 10 + browser.ie? end def path_to_key(key, admin = false) diff --git a/app/models/concerns/bulk_insert_safe.rb b/app/models/concerns/bulk_insert_safe.rb index 0d022418b1a..d8587ea78ec 100644 --- a/app/models/concerns/bulk_insert_safe.rb +++ b/app/models/concerns/bulk_insert_safe.rb @@ -111,8 +111,8 @@ module BulkInsertSafe end def _bulk_insert_reject_primary_key!(attributes, primary_key) - if attributes.delete(primary_key) - raise PrimaryKeySetError, "Primary key set: #{primary_key}:#{attributes[primary_key]}\n" \ + if existing_pk = attributes.delete(primary_key) + raise PrimaryKeySetError, "Primary key set: #{primary_key}:#{existing_pk}\n" \ "Bulk-inserts are only supported for rows that don't already have PK set" end end diff --git a/app/models/concerns/bulk_insertable_associations.rb b/app/models/concerns/bulk_insertable_associations.rb index 35bdabbcefd..5ee2e8356bd 100644 --- a/app/models/concerns/bulk_insertable_associations.rb +++ b/app/models/concerns/bulk_insertable_associations.rb @@ -93,11 +93,14 @@ module BulkInsertableAssociations end def _bulk_insert_configure_foreign_key(reflection, items) - primary_key = self[reflection.active_record_primary_key] - raise "Classes including `BulkInsertableAssociations` must define a `primary_key`" unless primary_key + primary_key_column = reflection.active_record_primary_key + raise "Classes including `BulkInsertableAssociations` must define a `primary_key`" unless primary_key_column + + primary_key_value = self[primary_key_column] + raise "No value found for primary key `#{primary_key_column}`" unless primary_key_value items.each do |item| - item[reflection.foreign_key] = primary_key + item[reflection.foreign_key] = primary_key_value if reflection.type item[reflection.type] = self.class.polymorphic_name diff --git a/app/services/notification_recipients/build_service.rb b/app/services/notification_recipients/build_service.rb index 67f9849aece..df807f11e1b 100644 --- a/app/services/notification_recipients/build_service.rb +++ b/app/services/notification_recipients/build_service.rb @@ -14,23 +14,23 @@ module NotificationRecipients end def self.build_recipients(*args) - Builder::Default.new(*args).notification_recipients + ::NotificationRecipients::Builder::Default.new(*args).notification_recipients end def self.build_new_note_recipients(*args) - Builder::NewNote.new(*args).notification_recipients + ::NotificationRecipients::Builder::NewNote.new(*args).notification_recipients end def self.build_merge_request_unmergeable_recipients(*args) - Builder::MergeRequestUnmergeable.new(*args).notification_recipients + ::NotificationRecipients::Builder::MergeRequestUnmergeable.new(*args).notification_recipients end def self.build_project_maintainers_recipients(*args) - Builder::ProjectMaintainers.new(*args).notification_recipients + ::NotificationRecipients::Builder::ProjectMaintainers.new(*args).notification_recipients end def self.build_new_release_recipients(*args) - Builder::NewRelease.new(*args).notification_recipients + ::NotificationRecipients::Builder::NewRelease.new(*args).notification_recipients end end end diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 2b2ffd6abeb..06e3bca99a1 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -2,9 +2,9 @@ - if defined?(nav) && nav = render "layouts/nav/sidebar/#{nav}" .content-wrapper{ class: "#{@content_wrapper_class}" } - = render 'shared/outdated_browser' .mobile-overlay .alert-wrapper + = render 'shared/outdated_browser' = render_if_exists "layouts/header/ee_license_banner" = render "layouts/broadcast" = render "layouts/header/read_only_banner" diff --git a/app/views/layouts/fullscreen.html.haml b/app/views/layouts/fullscreen.html.haml index 8d0775f6f27..63bb9f8fff5 100644 --- a/app/views/layouts/fullscreen.html.haml +++ b/app/views/layouts/fullscreen.html.haml @@ -5,9 +5,9 @@ = render 'peek/bar' = header_message = render partial: "layouts/header/default", locals: { project: @project, group: @group } - = render 'shared/outdated_browser' .mobile-overlay .alert-wrapper + = render 'shared/outdated_browser' = render "layouts/broadcast" = yield :flash_message = render "layouts/flash" diff --git a/app/views/shared/_outdated_browser.html.haml b/app/views/shared/_outdated_browser.html.haml index 8ddb1b2bc99..30255e18f04 100644 --- a/app/views/shared/_outdated_browser.html.haml +++ b/app/views/shared/_outdated_browser.html.haml @@ -1,8 +1,15 @@ - if outdated_browser? - .flash-container - .flash-alert.text-center - GitLab may not work properly because you are using an outdated web browser. + .gl-alert.gl-alert-danger.outdated-browser{ :role => "alert" } + = sprite_icon('error', size: 16, css_class: "gl-alert-icon gl-alert-icon-no-title gl-icon") + .gl-alert-body + - if browser.ie? && browser.version.to_i == 11 + - feedback_link_url = 'https://gitlab.com/gitlab-org/gitlab/issues/197987' + - feedback_link_start = '<a href="%{url}" class="gl-link" target="_blank" rel="noopener noreferrer">'.html_safe % { url: feedback_link_url } + = s_('OutdatedBrowser|From May 2020 GitLab no longer supports Internet Explorer 11.') + %br + = s_('OutdatedBrowser|You can provide feedback %{feedback_link_start}on this issue%{feedback_link_end} or via your usual support channels.').html_safe % { feedback_link_start: feedback_link_start, feedback_link_end: '</a>'.html_safe } + - else + = s_('OutdatedBrowser|GitLab may not work properly, because you are using an outdated web browser.') %br - Please install a - = link_to 'supported web browser', help_page_path('install/requirements', anchor: 'supported-web-browsers') - for a better experience. + - browser_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('install/requirements', anchor: 'supported-web-browsers') } + = s_('OutdatedBrowser|Please install a %{browser_link_start}supported web browser%{browser_link_end} for a better experience.').html_safe % { browser_link_start: browser_link_start, browser_link_end: '</a>'.html_safe } diff --git a/changelogs/unreleased/118503.yml b/changelogs/unreleased/118503.yml new file mode 100644 index 00000000000..3aa2e0399a8 --- /dev/null +++ b/changelogs/unreleased/118503.yml @@ -0,0 +1,5 @@ +--- +title: Fix infinite spinner on error detail page +merge_request: 26188 +author: +type: fixed diff --git a/changelogs/unreleased/197480-remove-package-file_type.yml b/changelogs/unreleased/197480-remove-package-file_type.yml new file mode 100644 index 00000000000..c315a0289f5 --- /dev/null +++ b/changelogs/unreleased/197480-remove-package-file_type.yml @@ -0,0 +1,5 @@ +--- +title: Remove unused file_type column from packages_package_files +merge_request: 26527 +author: +type: changed diff --git a/changelogs/unreleased/208674-use-wh-acceleration-for-ui-project-import.yml b/changelogs/unreleased/208674-use-wh-acceleration-for-ui-project-import.yml new file mode 100644 index 00000000000..118e7efa2fb --- /dev/null +++ b/changelogs/unreleased/208674-use-wh-acceleration-for-ui-project-import.yml @@ -0,0 +1,5 @@ +--- +title: Use Workhorse acceleration for Project Import file upload via UI +merge_request: 26278 +author: +type: performance diff --git a/changelogs/unreleased/208830-conan-package-reference-fix.yml b/changelogs/unreleased/208830-conan-package-reference-fix.yml new file mode 100644 index 00000000000..9318b5d71f1 --- /dev/null +++ b/changelogs/unreleased/208830-conan-package-reference-fix.yml @@ -0,0 +1,5 @@ +--- +title: Fix package file finder for conan packages with a conan_package_reference filter +merge_request: 26240 +author: +type: fixed diff --git a/changelogs/unreleased/25995-default-relative-links-to-blobs.yml b/changelogs/unreleased/25995-default-relative-links-to-blobs.yml new file mode 100644 index 00000000000..dea0ac22ee3 --- /dev/null +++ b/changelogs/unreleased/25995-default-relative-links-to-blobs.yml @@ -0,0 +1,5 @@ +--- +title: Default to generating blob links for missing paths +merge_request: 26817 +author: +type: fixed diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 330e5109ed4..ce9df6b6024 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -1226,6 +1226,8 @@ test: gitaly: client_path: tmp/tests/gitaly token: secret + workhorse: + secret_file: tmp/tests/gitlab_workhorse_secret backup: path: tmp/tests/backups pseudonymizer: diff --git a/config/routes/import.rb b/config/routes/import.rb index 9fe2688de1e..57a1fab48e9 100644 --- a/config/routes/import.rb +++ b/config/routes/import.rb @@ -60,6 +60,7 @@ namespace :import do resource :gitlab_project, only: [:create, :new] do post :create + post :authorize end resource :manifest, only: [:create, :new], controller: :manifest do diff --git a/db/post_migrate/20200304211738_remove_file_type_from_packages_package_files.rb b/db/post_migrate/20200304211738_remove_file_type_from_packages_package_files.rb new file mode 100644 index 00000000000..98bce8845ab --- /dev/null +++ b/db/post_migrate/20200304211738_remove_file_type_from_packages_package_files.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class RemoveFileTypeFromPackagesPackageFiles < ActiveRecord::Migration[6.0] + DOWNTIME = false + + def change + remove_column :packages_package_files, :file_type, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 40cf50354db..2f1bcddb38f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -3029,7 +3029,6 @@ ActiveRecord::Schema.define(version: 2020_03_06_170531) do t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.bigint "size" - t.integer "file_type" t.integer "file_store" t.binary "file_md5" t.binary "file_sha1" diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 052a5d2782a..cfab6352e46 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -236,18 +236,21 @@ For reference, GitLab.com's [auto-scaling shared runner](../user/gitlab_com/inde ## Supported web browsers +CAUTION: **Caution:** With GitLab 13.0 (May 2020) we are removing official support for Internet Explorer 11. +With the release of GitLab 13.4 (September 2020) we will remove all code that supports Internet Explorer 11. +You can provide feedback [on this issue](https://gitlab.com/gitlab-org/gitlab/issues/197987) or via your usual support channels. + GitLab supports the following web browsers: - Firefox - Chrome/Chromium - Safari - Microsoft Edge -- Internet Explorer 11 +- Internet Explorer 11 (until May 2020) For the listed web browsers, GitLab supports: - The current and previous major versions of browsers except Internet Explorer. -- Only version 11 of Internet Explorer. - The current minor version of a supported major version. NOTE: **Note:** We do not support running GitLab with JavaScript disabled in the browser and have no plans of supporting that diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md index 8998a2430f3..f087280f693 100644 --- a/doc/user/admin_area/settings/usage_statistics.md +++ b/doc/user/admin_area/settings/usage_statistics.md @@ -74,6 +74,8 @@ You can view the exact JSON payload in the administration panel. To view the pay You can see how [the usage ping data maps to different stages of the product](https://gitlab.com/gitlab-data/analytics/blob/master/transform/snowflake-dbt/data/version_usage_stats_to_stage_mappings.csv). +Usage ping is important to GitLab as we use it to calculate our [Action Monthly Active Users (AMAU)](https://about.gitlab.com/handbook/product/metrics/#action-monthly-active-users-amau) which helps us measure the success of our features. + ### Request flow example The following example shows a basic request/response flow between the self-managed GitLab instance, GitLab Version Application, diff --git a/lib/banzai/filter/repository_link_filter.rb b/lib/banzai/filter/repository_link_filter.rb index e15201b05cb..24900217560 100644 --- a/lib/banzai/filter/repository_link_filter.rb +++ b/lib/banzai/filter/repository_link_filter.rb @@ -131,7 +131,7 @@ module Banzai path = cleaned_file_path(uri) nested_path = relative_file_path(uri) - file_exists?(nested_path) ? nested_path : path + path_exists?(nested_path) ? nested_path : path end def cleaned_file_path(uri) @@ -190,12 +190,12 @@ module Banzai parts.push(path).join('/') end - def file_exists?(path) - path.present? && uri_type(path).present? + def path_exists?(path) + path.present? && @uri_types[path] != :unknown end def uri_type(path) - @uri_types[path] == :unknown ? "" : @uri_types[path] + @uri_types[path] == :unknown ? :blob : @uri_types[path] end def current_commit diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b0960e66ea7..2eaf892d8c1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5609,6 +5609,9 @@ msgstr "" msgid "Could not connect to FogBugz, check your URL" msgstr "" +msgid "Could not connect to Sentry. Refresh the page to try again." +msgstr "" + msgid "Could not connect to Web IDE file mirror service." msgstr "" @@ -13697,6 +13700,18 @@ msgstr "" msgid "Outbound requests" msgstr "" +msgid "OutdatedBrowser|From May 2020 GitLab no longer supports Internet Explorer 11." +msgstr "" + +msgid "OutdatedBrowser|GitLab may not work properly, because you are using an outdated web browser." +msgstr "" + +msgid "OutdatedBrowser|Please install a %{browser_link_start}supported web browser%{browser_link_end} for a better experience." +msgstr "" + +msgid "OutdatedBrowser|You can provide feedback %{feedback_link_start}on this issue%{feedback_link_end} or via your usual support channels." +msgstr "" + msgid "Overview" msgstr "" diff --git a/spec/controllers/import/gitlab_projects_controller_spec.rb b/spec/controllers/import/gitlab_projects_controller_spec.rb index a9aaefda0f6..0b74e2bbcbf 100644 --- a/spec/controllers/import/gitlab_projects_controller_spec.rb +++ b/spec/controllers/import/gitlab_projects_controller_spec.rb @@ -39,4 +39,62 @@ describe Import::GitlabProjectsController do it_behaves_like 'project import rate limiter' end + + describe 'POST authorize' do + let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') } + + before do + request.headers['GitLab-Workhorse'] = '1.0' + request.headers[Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER] = workhorse_token + end + + it 'authorizes importing project with workhorse header' do + post :authorize, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) + end + + it 'rejects requests that bypassed gitlab-workhorse or have invalid header' do + request.headers[Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER] = 'INVALID_HEADER' + + expect { post :authorize, format: :json }.to raise_error(JWT::DecodeError) + end + + context 'when using remote storage' do + context 'when direct upload is enabled' do + before do + stub_uploads_object_storage(ImportExportUploader, enabled: true, direct_upload: true) + end + + it 'responds with status 200, location of file remote store and object details' do + post :authorize, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) + expect(json_response).not_to have_key('TempPath') + expect(json_response['RemoteObject']).to have_key('ID') + expect(json_response['RemoteObject']).to have_key('GetURL') + expect(json_response['RemoteObject']).to have_key('StoreURL') + expect(json_response['RemoteObject']).to have_key('DeleteURL') + expect(json_response['RemoteObject']).to have_key('MultipartUpload') + end + end + + context 'when direct upload is disabled' do + before do + stub_uploads_object_storage(ImportExportUploader, enabled: true, direct_upload: false) + end + + it 'handles as a local file' do + post :authorize, format: :json + + expect(response).to have_gitlab_http_status(:ok) + expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) + expect(json_response['TempPath']).to eq(ImportExportUploader.workhorse_local_upload_path) + expect(json_response['RemoteObject']).to be_nil + end + end + end + end end diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb index b0a2a734877..efcaa8247df 100644 --- a/spec/features/issues/user_creates_issue_spec.rb +++ b/spec/features/issues/user_creates_issue_spec.rb @@ -156,7 +156,7 @@ describe "User creates issue" do expect(page.find_field("issue_description").value).not_to match /\n\n$/ end - it "cancels a file upload correctly" do + it "cancels a file upload correctly", :capybara_ignore_server_errors do slow_requests do dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false) diff --git a/spec/features/projects/tags/user_edits_tags_spec.rb b/spec/features/projects/tags/user_edits_tags_spec.rb index b1cb7685f63..6388875a619 100644 --- a/spec/features/projects/tags/user_edits_tags_spec.rb +++ b/spec/features/projects/tags/user_edits_tags_spec.rb @@ -68,7 +68,7 @@ describe 'Project > Tags', :js do end end - it 'shows "Attaching a file" message on uploading 1 file', :js do + it 'shows "Attaching a file" message on uploading 1 file', :js, :capybara_ignore_server_errors do slow_requests do dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false) diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb index 30b5cf267ae..570ecad41fa 100644 --- a/spec/features/uploads/user_uploads_file_to_note_spec.rb +++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb @@ -22,7 +22,7 @@ describe 'User uploads file to note' do end end - context 'uploading is in progress' do + context 'uploading is in progress', :capybara_ignore_server_errors do it 'cancels uploading on clicking to "Cancel" button', :js do slow_requests do dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false) diff --git a/spec/frontend/diffs/components/commit_item_spec.js b/spec/frontend/diffs/components/commit_item_spec.js index ecc28c78fb7..61bab77964e 100644 --- a/spec/frontend/diffs/components/commit_item_spec.js +++ b/spec/frontend/diffs/components/commit_item_spec.js @@ -59,7 +59,9 @@ describe('diffs/components/commit_item', () => { expect(titleElement.text()).toBe(commit.title_html); }); - it('renders commit description', () => { + // https://gitlab.com/gitlab-org/gitlab/-/issues/209776 + // eslint-disable-next-line jest/no-disabled-tests + it.skip('renders commit description', () => { const descElement = getDescElement(); const descExpandElement = getDescExpandElement(); diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js index 2baec5f37fb..72b0466a1f0 100644 --- a/spec/frontend/error_tracking/components/error_details_spec.js +++ b/spec/frontend/error_tracking/components/error_details_spec.js @@ -1,6 +1,7 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; import { __ } from '~/locale'; +import createFlash from '~/flash'; import { GlButton, GlLoadingIcon, @@ -18,6 +19,8 @@ import { errorStatus, } from '~/error_tracking/components/constants'; +jest.mock('~/flash'); + const localVue = createLocalVue(); localVue.use(Vuex); @@ -49,18 +52,6 @@ describe('ErrorDetails', () => { csrfToken: 'fakeToken', }, }); - wrapper.setData({ - error: { - id: 'gid://gitlab/Gitlab::ErrorTracking::DetailedError/129381', - sentryId: 129381, - title: 'Issue title', - externalUrl: 'http://sentry.gitlab.net/gitlab', - firstSeen: '2017-05-26T13:32:48Z', - lastSeen: '2018-05-26T13:32:48Z', - count: 12, - userCount: 2, - }, - }); } beforeEach(() => { @@ -78,6 +69,7 @@ describe('ErrorDetails', () => { const state = { stacktraceData: {}, loadingStacktrace: true, + errorStatus: '', }; store = new Vuex.Store({ @@ -99,6 +91,7 @@ describe('ErrorDetails', () => { error: { loading: true, stopPolling: jest.fn(), + setOptions: jest.fn(), }, }, }, @@ -123,10 +116,61 @@ describe('ErrorDetails', () => { }); }); + describe('sentry response timeout', () => { + const initTime = 300000; + const endTime = initTime + 10000; + + beforeEach(() => { + mocks.$apollo.queries.error.loading = false; + jest.spyOn(Date, 'now').mockReturnValue(initTime); + mountComponent(); + }); + + it('when before timeout, still shows loading', () => { + Date.now.mockReturnValue(endTime - 1); + + wrapper.vm.onNoApolloResult(); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); + expect(createFlash).not.toHaveBeenCalled(); + expect(mocks.$apollo.queries.error.stopPolling).not.toHaveBeenCalled(); + }); + }); + + it('when timeout is hit and no apollo result, stops loading and shows flash', () => { + Date.now.mockReturnValue(endTime + 1); + + wrapper.vm.onNoApolloResult(); + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); + expect(wrapper.find(GlLink).exists()).toBe(false); + expect(createFlash).toHaveBeenCalledWith( + 'Could not connect to Sentry. Refresh the page to try again.', + 'warning', + ); + expect(mocks.$apollo.queries.error.stopPolling).toHaveBeenCalled(); + }); + }); + }); + describe('Error details', () => { beforeEach(() => { mocks.$apollo.queries.error.loading = false; mountComponent(); + wrapper.setData({ + error: { + id: 'gid://gitlab/Gitlab::ErrorTracking::DetailedError/129381', + sentryId: 129381, + title: 'Issue title', + externalUrl: 'http://sentry.gitlab.net/gitlab', + firstSeen: '2017-05-26T13:32:48Z', + lastSeen: '2018-05-26T13:32:48Z', + count: 12, + userCount: 2, + }, + }); }); it('should show Sentry error details without stacktrace', () => { @@ -232,10 +276,6 @@ describe('ErrorDetails', () => { }); describe('When a user clicks the create issue button', () => { - beforeEach(() => { - mountComponent(); - }); - it('should send sentry_issue_identifier', () => { const sentryErrorIdInput = findInput( 'issue[sentry_issue_attributes][sentry_issue_identifier]', @@ -275,7 +315,8 @@ describe('ErrorDetails', () => { describe('when error is unresolved', () => { beforeEach(() => { store.state.details.errorStatus = errorStatus.UNRESOLVED; - mountComponent(); + + return wrapper.vm.$nextTick(); }); it('displays Ignore and Resolve buttons', () => { @@ -301,7 +342,8 @@ describe('ErrorDetails', () => { describe('when error is ignored', () => { beforeEach(() => { store.state.details.errorStatus = errorStatus.IGNORED; - mountComponent(); + + return wrapper.vm.$nextTick(); }); it('displays Undo Ignore and Resolve buttons', () => { @@ -327,7 +369,8 @@ describe('ErrorDetails', () => { describe('when error is resolved', () => { beforeEach(() => { store.state.details.errorStatus = errorStatus.RESOLVED; - mountComponent(); + + return wrapper.vm.$nextTick(); }); it('displays Ignore and Unresolve buttons', () => { diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 96c8b557625..33347f20de8 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -114,7 +114,7 @@ describe MarkupHelper do let(:requested_path) { nil } it 'returns the link to the image path as a relative path' do - expanded_path = "/#{project.full_path}/master/./#{image_file}" + expanded_path = "/#{project.full_path}/-/blob/master/./#{image_file}" expect(subject.css('a')[0].attr('href')).to eq(expanded_path) end diff --git a/spec/lib/banzai/filter/repository_link_filter_spec.rb b/spec/lib/banzai/filter/repository_link_filter_spec.rb index f093a5b0a79..460c76acd78 100644 --- a/spec/lib/banzai/filter/repository_link_filter_spec.rb +++ b/spec/lib/banzai/filter/repository_link_filter_spec.rb @@ -145,7 +145,7 @@ describe Banzai::Filter::RepositoryLinkFilter do it 'ignores ref if commit is passed' do doc = filter(link('non/existent.file'), commit: project.commit('empty-branch') ) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/#{ref}/non/existent.file" # non-existent files have no leading blob/raw/tree + .to eq "/#{project_path}/-/blob/#{ref}/non/existent.file" end shared_examples :valid_repository do @@ -201,6 +201,12 @@ describe Banzai::Filter::RepositoryLinkFilter do .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md" end + it 'rebuilds relative URL for a missing file in the repo' do + doc = filter(link('missing-file')) + expect(doc.at_css('a')['href']) + .to eq "/#{project_path}/-/blob/#{ref}/missing-file" + end + it 'rebuilds relative URL for a file in the repo with leading ./' do doc = filter(link('./doc/api/README.md')) expect(doc.at_css('a')['href']) diff --git a/spec/models/concerns/bulk_insertable_associations_spec.rb b/spec/models/concerns/bulk_insertable_associations_spec.rb index 9e584417697..6359b2c57ef 100644 --- a/spec/models/concerns/bulk_insertable_associations_spec.rb +++ b/spec/models/concerns/bulk_insertable_associations_spec.rb @@ -57,16 +57,12 @@ describe BulkInsertableAssociations do end end - before do - ActiveRecord::Base.connection.execute('TRUNCATE bulk_foos RESTART IDENTITY') - end - context 'saving bulk insertable associations' do let(:parent) { BulkParent.new(name: 'parent') } context 'when items already have IDs' do it 'stores nothing and raises an error' do - build_items(parent: parent) { |n, item| item.id = 100 + n } + build_items(parent: parent) { |n, item| item.id = n } expect { save_with_bulk_inserts(parent) }.to raise_error(BulkInsertSafe::PrimaryKeySetError) expect(BulkFoo.count).to eq(0) @@ -79,7 +75,7 @@ describe BulkInsertableAssociations do expect(BulkFoo).to receive(:bulk_insert!).once.and_call_original expect { save_with_bulk_inserts(parent) }.to change { BulkFoo.count }.from(0).to(items.size) - expect(parent.bulk_foos.pluck(:id)).to contain_exactly(*(1..10)) + expect(parent.bulk_foos.pluck(:id)).to all(be_a Integer) end end diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index af179e81b08..ca4a81773aa 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -23,6 +23,18 @@ JS_CONSOLE_FILTER = Regexp.union([ CAPYBARA_WINDOW_SIZE = [1366, 768].freeze +# Run Workhorse on the given host and port, proxying to Puma on a UNIX socket, +# for a closer-to-production experience +Capybara.register_server :puma_via_workhorse do |app, port, host, **options| + file = Tempfile.new + socket_path = file.path + file.close! # We just want the filename + + TestEnv.with_workhorse(TestEnv.workhorse_dir, host, port, socket_path) do + Capybara.servers[:puma].call(app, nil, socket_path, **options) + end +end + Capybara.register_driver :chrome do |app| capabilities = Selenium::WebDriver::Remote::Capabilities.chrome( # This enables access to logs with `page.driver.manage.get_log(:browser)` @@ -60,7 +72,7 @@ Capybara.register_driver :chrome do |app| ) end -Capybara.server = :puma +Capybara.server = :puma_via_workhorse Capybara.javascript_driver = :chrome Capybara.default_max_wait_time = timeout Capybara.ignore_hidden_elements = true @@ -101,6 +113,18 @@ RSpec.configure do |config| end end + # The :capybara_ignore_server_errors metadata means unhandled exceptions raised + # by the application under test will not necessarily fail the server. This is + # useful when testing conditions that are expected to raise a 500 error in + # production; it should not be used on the happy path. + config.around(:each, :capybara_ignore_server_errors) do |example| + Capybara.raise_server_errors = false + + example.run + ensure + Capybara.raise_server_errors = true + end + config.after(:example, :js) do |example| # when a test fails, display any messages in the browser's console # but fail don't add the message if the failure is a pending test that got diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index bd945fe6409..0320f966c37 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -104,6 +104,9 @@ module TestEnv setup_gitaly + # Feature specs are run through Workhorse + setup_workhorse + # Create repository for FactoryBot.create(:project) setup_factory_repo @@ -218,6 +221,52 @@ module TestEnv ENV.fetch('GITALY_REPO_URL', nil) end + def setup_workhorse + install_workhorse_args = [workhorse_dir, workhorse_url].compact.join(',') + + component_timed_setup( + 'GitLab Workhorse', + install_dir: workhorse_dir, + version: Gitlab::Workhorse.version, + task: "gitlab:workhorse:install[#{install_workhorse_args}]" + ) + end + + def workhorse_dir + @workhorse_path ||= File.join('tmp', 'tests', 'gitlab-workhorse') + end + + def with_workhorse(workhorse_dir, host, port, upstream, &blk) + host = "[#{host}]" if host.include?(':') + listen_addr = [host, port].join(':') + + workhorse_pid = spawn( + File.join(workhorse_dir, 'gitlab-workhorse'), + '-authSocket', upstream, + '-documentRoot', Rails.root.join('public').to_s, + '-listenAddr', listen_addr, + '-secretPath', Gitlab::Workhorse.secret_path.to_s, + # TODO: Needed for workhorse + redis features. + # https://gitlab.com/gitlab-org/gitlab/-/issues/209245 + # + # '-config', '', + '-logFile', 'log/workhorse-test.log', + '-logFormat', 'structured', + '-developmentMode' # to serve assets and rich error messages + ) + + begin + yield + ensure + Process.kill('TERM', workhorse_pid) + Process.wait(workhorse_pid) + end + end + + def workhorse_url + ENV.fetch('GITLAB_WORKHORSE_URL', nil) + end + def setup_factory_repo setup_repo(factory_repo_path, factory_repo_path_bare, factory_repo_name, BRANCH_SHA) @@ -347,6 +396,8 @@ module TestEnv gitlab-test_bare gitlab-test-fork gitlab-test-fork_bare + gitlab-workhorse + gitlab_workhorse_secret ] end diff --git a/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb b/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb index 867290fb2d6..d30e8241da0 100644 --- a/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb +++ b/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb @@ -20,7 +20,7 @@ RSpec.shared_examples 'wiki file attachments' do end end - context 'uploading is in progress' do + context 'uploading is in progress', :capybara_ignore_server_errors do it 'cancels uploading on clicking to "Cancel" button' do slow_requests do attach_with_dropzone |