Commit c975e29e authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge branch 'ce-to-ee-2018-07-16' into 'master'

CE upstream - 2018-07-16 12:22 UTC

See merge request gitlab-org/gitlab-ee!6522
parents 2190828c 4eb46f10
......@@ -10,7 +10,6 @@ class EnvironmentEntity < Grape::Entity
expose :environment_type
expose :last_deployment, using: DeploymentEntity
expose :stop_action_available?, as: :has_stop_action
expose :rollout_status, if: -> (*) { can_read_deploy_board? }, using: RolloutStatusEntity
expose :metrics_path, if: -> (*) { environment.has_metrics? } do |environment|
......
class UploadService
def initialize(model, file, uploader_class = FileUploader)
@model, @file, @uploader_class = model, file, uploader_class
def initialize(model, file, uploader_class = FileUploader, **uploader_context)
@model, @file, @uploader_class, @uploader_context = model, file, uploader_class, uploader_context
end
def execute
return nil unless @file && @file.size <= max_attachment_size
uploader = @uploader_class.new(@model)
uploader = @uploader_class.new(@model, nil, @uploader_context)
uploader.store!(@file)
uploader.to_h
......
......@@ -15,7 +15,7 @@ class FileUploader < GitlabUploader
prepend ObjectStorage::Extension::RecordsUploads
MARKDOWN_PATTERN = %r{\!?\[.*?\]\(/uploads/(?<secret>[0-9a-f]{32})/(?<file>.*?)\)}
DYNAMIC_PATH_PATTERN = %r{(?<secret>\h{32})/(?<identifier>.*)}
DYNAMIC_PATH_PATTERN = %r{.*(?<secret>\h{32})/(?<identifier>.*)}
after :remove, :prune_store_dir
......@@ -67,6 +67,10 @@ class FileUploader < GitlabUploader
SecureRandom.hex
end
def self.extract_dynamic_path(path)
DYNAMIC_PATH_PATTERN.match(path)
end
def upload_paths(identifier)
[
File.join(secret, identifier),
......@@ -143,7 +147,7 @@ class FileUploader < GitlabUploader
return if apply_context!(value.uploader_context)
# fallback to the regex based extraction
if matches = DYNAMIC_PATH_PATTERN.match(value.path)
if matches = self.class.extract_dynamic_path(value.path)
@secret = matches[:secret]
@identifier = matches[:identifier]
end
......
......@@ -2,9 +2,9 @@
= form_tag oauth_application_path(application) do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/
- if defined? small
= button_tag type: "submit", class: "btn btn-transparent", data: { confirm: "Are you sure?" } do
= button_tag type: "submit", class: "btn btn-transparent", data: { confirm: _("Are you sure?") } do
%span.sr-only
Destroy
= _('Destroy')
= icon('trash')
- else
= submit_tag 'Destroy', data: { confirm: "Are you sure?" }, class: submit_btn_css
= submit_tag _('Destroy'), data: { confirm: _("Are you sure?") }, class: submit_btn_css
......@@ -10,16 +10,14 @@
= f.text_area :redirect_uri, class: 'form-control', required: true
%span.form-text.text-muted
Use one line per URI
= _('Use one line per URI')
- if Doorkeeper.configuration.native_redirect_uri
%span.form-text.text-muted
Use
%code= Doorkeeper.configuration.native_redirect_uri
for local tests
= _('Use <code>%{native_redirect_uri}</code> for local tests').html_safe % { native_redirect_uri: Doorkeeper.configuration.native_redirect_uri }
.form-group
= f.label :scopes, class: 'label-light'
= render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes
.prepend-top-default
= f.submit 'Save application', class: "btn btn-create"
= f.submit _('Save application'), class: "btn btn-create"
- page_title "Edit", @application.name, "Applications"
- page_title _("Edit"), @application.name, _("Applications")
- @content_class = "limit-container-width" unless fluid_layout
%h3.page-title Edit application
%h3.page-title= _('Edit application')
= render 'form', application: @application
- page_title "Applications"
- page_title _("Applications")
- @content_class = "limit-container-width" unless fluid_layout
.row.prepend-top-default
......@@ -7,28 +7,27 @@
= page_title
%p
- if user_oauth_applications?
Manage applications that can use GitLab as an OAuth provider,
and applications that you've authorized to use your account.
= _("Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account.")
- else
Manage applications that you've authorized to use your account.
= _("Manage applications that you've authorized to use your account.")
.col-lg-8
- if user_oauth_applications?
%h5.prepend-top-0
Add new application
= _('Add new application')
= render 'form', application: @application
%hr
- if user_oauth_applications?
.oauth-applications
%h5
Your applications (#{@applications.size})
= _("Your applications (%{size})") % { size: @applications.size }
- if @applications.any?
.table-responsive
%table.table
%thead
%tr
%th Name
%th Callback URL
%th Clients
%th= _('Name')
%th= _('Callback URL')
%th= _('Clients')
%th.last-heading
%tbody
- @applications.each do |application|
......@@ -41,25 +40,25 @@
%td
= link_to edit_oauth_application_path(application), class: "btn btn-transparent append-right-5" do
%span.sr-only
Edit
= _('Edit')
= icon('pencil')
= render 'delete_form', application: application, small: true
- else
.settings-message.text-center
You don't have any applications
= _("You don't have any applications")
.oauth-authorized-applications.prepend-top-20.append-bottom-default
- if user_oauth_applications?
%h5
Authorized applications (#{@authorized_tokens.size})
= _("Authorized applications (%{size})") % { size: @authorized_tokens.size }
- if @authorized_tokens.any?
.table-responsive
%table.table.table-striped
%thead
%tr
%th Name
%th Authorized At
%th Scope
%th= _('Name')
%th= _('Authorized At')
%th= _('Scope')
%th
%tbody
- @authorized_apps.each do |app|
......@@ -72,12 +71,12 @@
- @authorized_anonymous_tokens.each do |token|
%tr
%td
Anonymous
= _('Anonymous')
.form-text.text-muted
%em Authorization was granted by entering your username and password in the application.
%em= _("Authorization was granted by entering your username and password in the application.")
%td= token.created_at
%td= token.scopes
%td= render 'doorkeeper/authorized_applications/delete_form', token: token
- else
.settings-message.text-center
You don't have any authorized applications
= _("You don't have any authorized applications")
- page_title "New Application"
- page_title _("New Application")
%h3.page-title New Application
%h3.page-title= _("New Application")
%hr
......
- add_to_breadcrumbs "Applications", oauth_applications_path
- add_to_breadcrumbs _("Applications"), oauth_applications_path
- breadcrumb_title @application.name
- page_title @application.name, "Applications"
- page_title @application.name, _("Applications")
- @content_class = "limit-container-width" unless fluid_layout
%h3.page-title
Application: #{@application.name}
= _("Application: %{name}") % { name: @application.name }
.table-holder.oauth-application-show
%table.table
%tr
%td
Application Id
= _('Application Id')
%td
%code#application_id= @application.uid
%tr
%td
Secret:
= _('Secret:')
%td
%code#secret= @application.secret
%tr
%td
Callback url
= _('Callback url')
%td
- @application.redirect_uri.split.each do |uri|
%div
......@@ -30,5 +30,5 @@
= render "shared/tokens/scopes_list", token: @application
.form-actions
= link_to 'Edit', edit_oauth_application_path(@application), class: 'btn btn-primary wide float-left'
= link_to _('Edit'), edit_oauth_application_path(@application), class: 'btn btn-primary wide float-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
%h3.page-title An error has occurred
%h3.page-title= _("An error has occurred")
%main{ :role => "main" }
%pre= @pre_auth.error_response.body[:error_description]
......@@ -3,34 +3,28 @@
.modal-content
.modal-header
%h3.page-title
Authorize
= link_to @pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer'
to use your account?
- link_to_client = link_to(@pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer')
= _("Authorize %{link_to_client} to use your account?")
.modal-body
- if current_user.admin?
.text-warning
%p
= icon("exclamation-triangle fw")
You are an admin, which means granting access to
%strong= @pre_auth.client.name
will allow them to interact with GitLab as an admin as well. Proceed with caution.
= _('You are an admin, which means granting access to <strong>%{client_name}</strong> will allow them to interact with GitLab as an admin as well. Proceed with caution.').html_safe % { client_name: @pre_auth.client.name }
%p
An application called
= link_to @pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer'
is requesting access to your GitLab account.
- link_to_client = link_to(@pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer')
= _("An application called %{link_to_client} is requesting access to your GitLab account.").html_safe % { link_to_client: link_to_client }
- auth_app_owner = @pre_auth.client.application.owner
- if auth_app_owner
This application was created by
= succeed "." do
= link_to auth_app_owner.name, user_path(auth_app_owner)
- link_to_owner = link_to(auth_app_owner.name, user_path(auth_app_owner))
= _("This application was created by %{link_to_owner}.").html_safe % { link_to_owner: link_to_owner }
Please note that this application is not provided by GitLab and you should verify its authenticity before
allowing access.
= _("Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access.")
- if @pre_auth.scopes
%p
This application will be able to:
= _("This application will be able to:")
%ul
- @pre_auth.scopes.each do |scope|
%li
......@@ -44,7 +38,7 @@
= hidden_field_tag :response_type, @pre_auth.response_type
= hidden_field_tag :scope, @pre_auth.scope
= hidden_field_tag :nonce, @pre_auth.nonce
= submit_tag "Deny", class: "btn btn-danger"
= submit_tag _("Deny"), class: "btn btn-danger"
= form_tag oauth_authorization_path, method: :post, class: 'inline' do
= hidden_field_tag :client_id, @pre_auth.client.uid
= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
......@@ -52,4 +46,4 @@
= hidden_field_tag :response_type, @pre_auth.response_type
= hidden_field_tag :scope, @pre_auth.scope
= hidden_field_tag :nonce, @pre_auth.nonce
= submit_tag "Authorize", class: "btn btn-success prepend-left-10"
= submit_tag _("Authorize"), class: "btn btn-success prepend-left-10"
%h3.page-title Authorization code:
%h3.page-title= _("Authorization code:")
%main{ :role => "main" }
%code#authorization_code= params[:code]
......@@ -6,4 +6,4 @@
= form_tag path do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/
= submit_tag 'Revoke', onclick: "return confirm('Are you sure?')", class: 'btn btn-remove btn-sm'
= submit_tag _('Revoke'), onclick: "return confirm('#{_('Are you sure?')}')", class: 'btn btn-remove btn-sm'
%header
%h1 Your authorized applications
%h1= _("Your authorized applications")
%main{ :role => "main" }
.table-holder
%table.table.table-striped
%thead
%tr
%th Application
%th Created At
%th= _('Application')
%th= _('Created At')
%th
%th
%tbody
......
---
title: Add uploader support to Import/Export uploads
merge_request: 20484
author:
type: added
......@@ -340,7 +340,7 @@ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
If all items are green, then congratulations, the upgrade is complete!
## Things went south? Revert to previous version (10.5)
## Things went south? Revert to previous version (10.6)
### 1. Revert the code to the previous version
......
......@@ -11,7 +11,12 @@ module Gitlab
def save
return true unless @project.avatar.exists?
copy_files(avatar_path, avatar_export_path)
Gitlab::ImportExport::UploadsManager.new(
project: @project,
shared: @shared,
relative_export_path: 'avatar',
from: avatar_path
).save
rescue => e
@shared.error(e)
false
......@@ -19,10 +24,6 @@ module Gitlab
private
def avatar_export_path
File.join(@shared.export_path, 'avatar', @project.avatar_identifier)
end
def avatar_path
@project.avatar.path
end
......
module Gitlab
module ImportExport
class UploadsManager
include Gitlab::ImportExport::CommandLineUtil
UPLOADS_BATCH_SIZE = 100
def initialize(project:, shared:, relative_export_path: 'uploads', from: nil)
@project = project
@shared = shared
@relative_export_path = relative_export_path
@from = from || default_uploads_path
end
def save
copy_files(@from, uploads_export_path) if File.directory?(@from)
if File.file?(@from) && @relative_export_path == 'avatar'
copy_files(@from, File.join(uploads_export_path, @project.avatar.filename))
end
copy_from_object_storage
true
rescue => e
@shared.error(e)
false
end
def restore
Dir["#{uploads_export_path}/**/*"].each do |upload|
next if File.directory?(upload)
add_upload(upload)
end
true
rescue => e
@shared.error(e)
false
end
private
def add_upload(upload)
uploader_context = FileUploader.extract_dynamic_path(upload).named_captures.symbolize_keys
UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute
end
def copy_from_object_storage
return unless Gitlab::ImportExport.object_storage?
each_uploader do |uploader|
next unless uploader.file
next if uploader.upload.local? # Already copied, using the old method
download_and_copy(uploader)
end
end
def default_uploads_path
FileUploader.absolute_base_dir(@project)
end
def uploads_export_path
@uploads_export_path ||= File.join(@shared.export_path, @relative_export_path)
end
def each_uploader
avatar_path = @project.avatar&.upload&.path
if @relative_export_path == 'avatar'
yield(@project.avatar)
else
project_uploads_except_avatar(avatar_path).find_each(batch_size: UPLOADS_BATCH_SIZE) do |upload|
yield(upload.build_uploader)
end
end
end
def project_uploads_except_avatar(avatar_path)
return @project.uploads unless avatar_path
@project.uploads.where("path != ?", avatar_path)
end
def download_and_copy(upload)
secret = upload.try(:secret) || ''
upload_path = File.join(uploads_export_path, secret, upload.filename)
mkdir_p(File.join(uploads_export_path, secret))
File.open(upload_path, 'w') do |file|
# Download (stream) file from the uploader's location
IO.copy_stream(URI.parse(upload.file.url).open, file)
end
end
end
end
end
......@@ -2,13 +2,30 @@ module Gitlab
module ImportExport
class UploadsRestorer < UploadsSaver
def restore
return true unless File.directory?(uploads_export_path)
if Gitlab::ImportExport.object_storage?
Gitlab::ImportExport::UploadsManager.new(
project: @project,
shared: @shared
).restore
elsif File.directory?(uploads_export_path)
copy_files(uploads_export_path, uploads_path)
copy_files(uploads_export_path, uploads_path)
true
else
true # Proceed without uploads
end
rescue => e
@shared.error(e)
false
end
def uploads_path
FileUploader.absolute_base_dir(@project)
end
def uploads_export_path
@uploads_export_path ||= File.join(@shared.export_path, 'uploads')
end
end
end
end
......@@ -9,21 +9,14 @@ module Gitlab
end
def save
return true unless File.directory?(uploads_path)
copy_files(uploads_path, uploads_export_path)
Gitlab::ImportExport::UploadsManager.new(
project: @project,
shared: @shared
).save
rescue => e
@shared.error(e)
false
end
def uploads_path
FileUploader.absolute_base_dir(@project)
end
def uploads_export_path
File.join(@shared.export_path, 'uploads')
end
end
end
end
......@@ -8,6 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-07-16 12:42+0000\n"
"PO-Revision-Date: 2018-07-16 12:42+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
......@@ -338,6 +340,9 @@ msgstr ""
msgid "Add additional text to appear in all email communications. %{character_limit} character limit"
msgstr ""
msgid "Add new application"
msgstr ""
msgid "Add new directory"
msgstr ""
......@@ -449,9 +454,15 @@ msgstr ""
msgid "Alternatively, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import."
msgstr ""
msgid "An application called %{link_to_client} is requesting access to your GitLab account."
msgstr ""
msgid "An error accured whilst committing your changes."
msgstr ""
msgid "An error has occurred"
msgstr ""
msgid "An error occured creating the new branch."
msgstr ""
......@@ -569,6 +580,9 @@ msgstr ""
msgid "An error occurred. Please try again."
msgstr ""
msgid "Anonymous"
msgstr ""
msgid "Any"
msgstr ""
......@@ -578,6 +592,15 @@ msgstr ""
msgid "Appearance"
msgstr ""
msgid "Application"
msgstr ""
msgid "Application Id"
msgstr ""
msgid "Application: %{name}"
msgstr ""
msgid "Applications"
msgstr ""
......@@ -677,6 +700,24 @@ msgstr ""
msgid "Author"
msgstr ""
msgid "Authorization code:"
msgstr ""
msgid "Authorization was granted by entering your username and password in the application."
msgstr ""
msgid "Authorize"
msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
msgid "Authorized At"
msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
msgid "Authors: %{authors}"
msgstr ""
......@@ -1126,6 +1167,12 @@ msgstr ""
msgid "CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages."
msgstr ""
msgid "Callback URL"
msgstr ""
msgid "Callback url"
msgstr ""
msgid "Can't find HEAD commit for this branch"
msgstr ""
......@@ -1345,6 +1392,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
msgid "Clients"
msgstr ""
msgid "Clone repository"
msgstr ""
......@@ -2060,6 +2110,9 @@ msgstr ""
msgid "Created"
msgstr ""
msgid "Created At"
msgstr ""
msgid "Created by me"
msgstr ""
......@@ -2150,6 +2203,9 @@ msgstr ""
msgid "Delete list"
msgstr ""
msgid "Deny"
msgstr ""
msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] ""
......@@ -2293,6 +2349,9 @@ msgstr ""
msgid "Description:"
msgstr ""
msgid "Destroy"
msgstr ""
msgid "Details"
msgstr ""
......@@ -2398,6 +2457,9 @@ msgstr ""
msgid "Edit Snippet"
msgstr ""
msgid "Edit application"
msgstr ""
msgid "Edit files in the editor and commit changes here"
msgstr ""
......@@ -3636,6 +3698,12 @@ msgstr ""
msgid "Manage all notifications"
msgstr ""
msgid "Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account."
msgstr ""
msgid "Manage applications that you've authorized to use your account."
msgstr ""
msgid "Manage group labels"
msgstr ""
......@@ -3930,6 +3998,9 @@ msgstr ""
msgid "New"
msgstr ""
msgid "New Application"
msgstr ""
msgid "New Group"
msgstr ""
......@@ -4460,6 +4531,9 @@ msgstr ""
msgid "Please accept the Terms of Service before continuing."
msgstr ""
msgid "Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access."
msgstr ""
msgid "Please select at least one filter to see results"
msgstr ""
......@@ -5008,6 +5082,9 @@ msgstr ""
msgid "Reviewing (merge request !%{mergeRequestId})"
msgstr ""
msgid "Revoke"
msgstr ""
msgid "Roadmap"
msgstr ""
......@@ -5053,6 +5130,9 @@ msgstr ""
msgid "Save"
msgstr ""
msgid "Save application"
msgstr ""
msgid "Save changes"
msgstr ""
......@@ -5074,6 +5154,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr ""
msgid "Scope"
msgstr ""
msgid "Scoped issue boards"
msgstr ""
......@@ -5116,6 +5199,9 @@ msgstr ""
msgid "Seconds to wait for a storage access attempt"
msgstr ""
msgid "Secret:"
msgstr ""
msgid "Security Dashboard"
msgstr ""
......@@ -5813,6 +5899,12 @@ msgstr ""
msgid "This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area."
msgstr ""
msgid "This application was created by %{link_to_owner}."
msgstr ""
msgid "This application will be able to:"
msgstr ""
msgid "This board\\'s scope is reduced"
msgstr ""
......@@ -6278,12 +6370,18 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
msgid "Use <code>%{native_redirect_uri}</code> for local tests"
msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
msgid "Use group milestones to manage issues from multiple projects in the same milestone."
msgstr ""
msgid "Use one line per URI"
msgstr ""
msgid "Use the following registration token during setup:"
msgstr ""
......@@ -6554,6 +6652,9 @@ msgstr ""
msgid "Yes, add it"
msgstr ""
msgid "You are an admin, which means granting access to <strong>%{client_name}</strong> will allow them to interact with GitLab as an admin as well. Proceed with caution."
msgstr ""
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr ""
......@@ -6614,6 +6715,12 @@ msgstr ""
msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
msgstr ""
msgid "You don't have any applications"
msgstr ""
msgid "You don't have any authorized applications"
msgstr ""
msgid "You have no permissions"
msgstr ""
......@@ -6686,6 +6793,12 @@ msgstr ""
msgid "Your Todos"
msgstr ""
msgid "Your applications (%{size})"
msgstr ""
msgid "Your authorized applications"
msgstr ""
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
......
......@@ -3,7 +3,7 @@ module QA
module Main
class OAuth < Page::Base
view 'app/views/doorkeeper/authorizations/new.html.haml' do
element :authorization_button, 'submit_tag "Authorize"'
element :authorization_button, 'submit_tag _("Authorize")'
end
def needs_authorization?
......
......@@ -28,6 +28,13 @@ FactoryBot.define do
secret SecureRandom.hex
end
trait :with_file do
after(:create) do |upload|
FileUtils.mkdir_p(File.dirname(upload.absolute_path))
FileUtils.touch(upload.absolute_path)
end
end
trait :object_storage do
store ObjectStorage::Store::REMOTE
end
......
......@@ -9,6 +9,7 @@ describe Gitlab::ImportExport::AvatarSaver do
before do
FileUtils.mkdir_p("#{shared.export_path}/avatar/")
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
stub_feature_flags(import_export_object_storage: false)
end
after do
......
require 'spec_helper'
describe Gitlab::ImportExport::UploadsManager do
let(:shared) { project.import_export_shared }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:project) { create(:project) }
let(:exported_file_path) { "#{shared.export_path}/uploads/#{upload.secret}/#{File.basename(upload.path)}" }
subject(:manager) { described_class.new(project: project, shared: shared) }
before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
FileUtils.mkdir_p(shared.export_path)
end
after do
FileUtils.rm_rf(shared.export_path)
end
describe '#save' do
context 'when the project has uploads locally stored' do
let(:upload) { create(:upload, :issuable_upload, :with_file, model: project) }
before do
project.uploads << upload
end
it 'does not cause errors' do
manager.save
expect(shared.errors).to be_empty
end
it 'copies the file in the correct location when there is an upload' do
manager.save
expect(File).to exist(exported_file_path)
end
end
context 'using object storage' do
let!(:upload) { create(:upload, :issuable_upload, :object_storage, model: project) }
before do
stub_feature_flags(import_export_object_storage: true)
stub_uploads_object_storage(FileUploader)
end
it 'saves the file' do
fake_uri = double
expect(fake_uri).to receive(:open).and_return(StringIO.new('File content'))
expect(URI).to receive(:parse).and_return(fake_uri)
manager.save
expect(File.read(exported_file_path)).to eq('File content')
end
end
describe '#restore' do
context 'using object storage' do
before do
stub_feature_flags(import_export_object_storage: true)
stub_uploads_object_storage(FileUploader)
FileUtils.mkdir_p(File.join(shared.export_path, 'uploads/72a497a02fe3ee09edae2ed06d390038'))
FileUtils.touch(File.join(shared.export_path, 'uploads/72a497a02fe3ee09edae2ed06d390038', "dummy.txt"))
end
it 'restores the file' do
manager.restore
expect(project.uploads.size).to eq(1)
expect(project.uploads.first.build_uploader.filename).to eq('dummy.txt')
end
end
end
end
end
......@@ -7,6 +7,7 @@ describe Gitlab::ImportExport::UploadsSaver do
let(:shared) { project.import_export_shared }
before do
stub_feature_flags(import_export_object_storage: false)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
end
......@@ -30,7 +31,7 @@ describe Gitlab::ImportExport::UploadsSaver do
it 'copies the uploads to the export path' do
saver.save
uploads = Dir.glob(File.join(saver.uploads_export_path, '**/*')).map { |file| File.basename(file) }
uploads = Dir.glob(File.join(shared.export_path, 'uploads/**/*')).map { |file| File.basename(file) }
expect(uploads).to include('banana_sample.gif')
end
......@@ -52,7 +53,7 @@ describe Gitlab::ImportExport::UploadsSaver do
it 'copies the uploads to the export path' do
saver.save
uploads = Dir.glob(File.join(saver.uploads_export_path, '**/*')).map { |file| File.basename(file) }
uploads = Dir.glob(File.join(shared.export_path, 'uploads/**/*')).map { |file| File.basename(file) }
expect(uploads).to include('banana_sample.gif')
end
......
......@@ -124,6 +124,15 @@ describe FileUploader do
end
end
describe '.extract_dynamic_path' do
it 'works with hashed storage' do
path = 'export/4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a/test/uploads/72a497a02fe3ee09edae2ed06d390038/dummy.txt'
expect(described_class.extract_dynamic_path(path)[:identifier]).to eq('dummy.txt')
expect(described_class.extract_dynamic_path(path)[:secret]).to eq('72a497a02fe3ee09edae2ed06d390038')
end
end
describe '#secret' do
it 'generates a secret if none is provided' do
expect(described_class).to receive(:generate_secret).and_return('secret')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment