Commit cd486031 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-07-16

# Conflicts:
#	app/serializers/environment_entity.rb
#	locale/gitlab.pot
#	spec/javascripts/environments/mock_data.js

[ci skip]
parents 2190828c 05af3768
...@@ -10,8 +10,11 @@ class EnvironmentEntity < Grape::Entity ...@@ -10,8 +10,11 @@ class EnvironmentEntity < Grape::Entity
expose :environment_type expose :environment_type
expose :last_deployment, using: DeploymentEntity expose :last_deployment, using: DeploymentEntity
expose :stop_action_available?, as: :has_stop_action expose :stop_action_available?, as: :has_stop_action
<<<<<<< HEAD
expose :rollout_status, if: -> (*) { can_read_deploy_board? }, using: RolloutStatusEntity expose :rollout_status, if: -> (*) { can_read_deploy_board? }, using: RolloutStatusEntity
=======
>>>>>>> upstream/master
expose :metrics_path, if: -> (*) { environment.has_metrics? } do |environment| expose :metrics_path, if: -> (*) { environment.has_metrics? } do |environment|
metrics_project_environment_path(environment.project, environment) metrics_project_environment_path(environment.project, environment)
......
class UploadService class UploadService
def initialize(model, file, uploader_class = FileUploader) def initialize(model, file, uploader_class = FileUploader, **uploader_context)
@model, @file, @uploader_class = model, file, uploader_class @model, @file, @uploader_class, @uploader_context = model, file, uploader_class, uploader_context
end end
def execute def execute
return nil unless @file && @file.size <= max_attachment_size 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.store!(@file)
uploader.to_h uploader.to_h
......
...@@ -15,7 +15,7 @@ class FileUploader < GitlabUploader ...@@ -15,7 +15,7 @@ class FileUploader < GitlabUploader
prepend ObjectStorage::Extension::RecordsUploads prepend ObjectStorage::Extension::RecordsUploads
MARKDOWN_PATTERN = %r{\!?\[.*?\]\(/uploads/(?<secret>[0-9a-f]{32})/(?<file>.*?)\)} 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 after :remove, :prune_store_dir
...@@ -67,6 +67,10 @@ class FileUploader < GitlabUploader ...@@ -67,6 +67,10 @@ class FileUploader < GitlabUploader
SecureRandom.hex SecureRandom.hex
end end
def self.extract_dynamic_path(path)
DYNAMIC_PATH_PATTERN.match(path)
end
def upload_paths(identifier) def upload_paths(identifier)
[ [
File.join(secret, identifier), File.join(secret, identifier),
...@@ -143,7 +147,7 @@ class FileUploader < GitlabUploader ...@@ -143,7 +147,7 @@ class FileUploader < GitlabUploader
return if apply_context!(value.uploader_context) return if apply_context!(value.uploader_context)
# fallback to the regex based extraction # 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] @secret = matches[:secret]
@identifier = matches[:identifier] @identifier = matches[:identifier]
end end
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
= form_tag oauth_application_path(application) do = form_tag oauth_application_path(application) do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/ %input{ :name => "_method", :type => "hidden", :value => "delete" }/
- if defined? small - 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 %span.sr-only
Destroy = _('Destroy')
= icon('trash') = icon('trash')
- else - 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 @@ ...@@ -10,16 +10,14 @@
= f.text_area :redirect_uri, class: 'form-control', required: true = f.text_area :redirect_uri, class: 'form-control', required: true
%span.form-text.text-muted %span.form-text.text-muted
Use one line per URI = _('Use one line per URI')
- if Doorkeeper.configuration.native_redirect_uri - if Doorkeeper.configuration.native_redirect_uri
%span.form-text.text-muted %span.form-text.text-muted
Use = _('Use <code>%{native_redirect_uri}</code> for local tests').html_safe % { native_redirect_uri: Doorkeeper.configuration.native_redirect_uri }
%code= Doorkeeper.configuration.native_redirect_uri
for local tests
.form-group .form-group
= f.label :scopes, class: 'label-light' = f.label :scopes, class: 'label-light'
= render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes = render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes
.prepend-top-default .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 - @content_class = "limit-container-width" unless fluid_layout
%h3.page-title Edit application %h3.page-title= _('Edit application')
= render 'form', application: @application = render 'form', application: @application
- page_title "Applications" - page_title _("Applications")
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
.row.prepend-top-default .row.prepend-top-default
...@@ -7,28 +7,27 @@ ...@@ -7,28 +7,27 @@
= page_title = page_title
%p %p
- if user_oauth_applications? - if user_oauth_applications?
Manage applications that can use GitLab as an OAuth provider, = _("Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account.")
and applications that you've authorized to use your account.
- else - else
Manage applications that you've authorized to use your account. = _("Manage applications that you've authorized to use your account.")
.col-lg-8 .col-lg-8
- if user_oauth_applications? - if user_oauth_applications?
%h5.prepend-top-0 %h5.prepend-top-0
Add new application = _('Add new application')
= render 'form', application: @application = render 'form', application: @application
%hr %hr
- if user_oauth_applications? - if user_oauth_applications?
.oauth-applications .oauth-applications
%h5 %h5
Your applications (#{@applications.size}) = _("Your applications (%{size})") % { size: @applications.size }
- if @applications.any? - if @applications.any?
.table-responsive .table-responsive
%table.table %table.table
%thead %thead
%tr %tr
%th Name %th= _('Name')
%th Callback URL %th= _('Callback URL')
%th Clients %th= _('Clients')
%th.last-heading %th.last-heading
%tbody %tbody
- @applications.each do |application| - @applications.each do |application|
...@@ -41,25 +40,25 @@ ...@@ -41,25 +40,25 @@
%td %td
= link_to edit_oauth_application_path(application), class: "btn btn-transparent append-right-5" do = link_to edit_oauth_application_path(application), class: "btn btn-transparent append-right-5" do
%span.sr-only %span.sr-only
Edit = _('Edit')
= icon('pencil') = icon('pencil')
= render 'delete_form', application: application, small: true = render 'delete_form', application: application, small: true
- else - else
.settings-message.text-center .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 .oauth-authorized-applications.prepend-top-20.append-bottom-default
- if user_oauth_applications? - if user_oauth_applications?
%h5 %h5
Authorized applications (#{@authorized_tokens.size}) = _("Authorized applications (%{size})") % { size: @authorized_tokens.size }
- if @authorized_tokens.any? - if @authorized_tokens.any?
.table-responsive .table-responsive
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Name %th= _('Name')
%th Authorized At %th= _('Authorized At')
%th Scope %th= _('Scope')
%th %th
%tbody %tbody
- @authorized_apps.each do |app| - @authorized_apps.each do |app|
...@@ -72,12 +71,12 @@ ...@@ -72,12 +71,12 @@
- @authorized_anonymous_tokens.each do |token| - @authorized_anonymous_tokens.each do |token|
%tr %tr
%td %td
Anonymous = _('Anonymous')
.form-text.text-muted .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.created_at
%td= token.scopes %td= token.scopes
%td= render 'doorkeeper/authorized_applications/delete_form', token: token %td= render 'doorkeeper/authorized_applications/delete_form', token: token
- else - else
.settings-message.text-center .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 %hr
......
- add_to_breadcrumbs "Applications", oauth_applications_path - add_to_breadcrumbs _("Applications"), oauth_applications_path
- breadcrumb_title @application.name - breadcrumb_title @application.name
- page_title @application.name, "Applications" - page_title @application.name, _("Applications")
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
%h3.page-title %h3.page-title
Application: #{@application.name} = _("Application: %{name}") % { name: @application.name }
.table-holder.oauth-application-show .table-holder.oauth-application-show
%table.table %table.table
%tr %tr
%td %td
Application Id = _('Application Id')
%td %td
%code#application_id= @application.uid %code#application_id= @application.uid
%tr %tr
%td %td
Secret: = _('Secret:')
%td %td
%code#secret= @application.secret %code#secret= @application.secret
%tr %tr
%td %td
Callback url = _('Callback url')
%td %td
- @application.redirect_uri.split.each do |uri| - @application.redirect_uri.split.each do |uri|
%div %div
...@@ -30,5 +30,5 @@ ...@@ -30,5 +30,5 @@
= render "shared/tokens/scopes_list", token: @application = render "shared/tokens/scopes_list", token: @application
.form-actions .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' = 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" } %main{ :role => "main" }
%pre= @pre_auth.error_response.body[:error_description] %pre= @pre_auth.error_response.body[:error_description]
...@@ -3,34 +3,28 @@ ...@@ -3,34 +3,28 @@
.modal-content .modal-content
.modal-header .modal-header
%h3.page-title %h3.page-title
Authorize - link_to_client = link_to(@pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer')
= link_to @pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer' = _("Authorize %{link_to_client} to use your account?")
to use your account?
.modal-body .modal-body
- if current_user.admin? - if current_user.admin?
.text-warning .text-warning
%p %p
= icon("exclamation-triangle fw") = icon("exclamation-triangle fw")
You are an admin, which means granting access to = _('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 }
%strong= @pre_auth.client.name
will allow them to interact with GitLab as an admin as well. Proceed with caution.
%p %p
An application called - link_to_client = link_to(@pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer')
= 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 }
is requesting access to your GitLab account.
- auth_app_owner = @pre_auth.client.application.owner - auth_app_owner = @pre_auth.client.application.owner
- if auth_app_owner - if auth_app_owner
This application was created by - link_to_owner = link_to(auth_app_owner.name, user_path(auth_app_owner))
= succeed "." do = _("This application was created by %{link_to_owner}.").html_safe % { link_to_owner: link_to_owner }
= link_to auth_app_owner.name, user_path(auth_app_owner)
Please note that this application is not provided by GitLab and you should verify its authenticity before = _("Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access.")
allowing access.
- if @pre_auth.scopes - if @pre_auth.scopes
%p %p
This application will be able to: = _("This application will be able to:")
%ul %ul
- @pre_auth.scopes.each do |scope| - @pre_auth.scopes.each do |scope|
%li %li
...@@ -44,7 +38,7 @@ ...@@ -44,7 +38,7 @@
= hidden_field_tag :response_type, @pre_auth.response_type = hidden_field_tag :response_type, @pre_auth.response_type
= hidden_field_tag :scope, @pre_auth.scope = hidden_field_tag :scope, @pre_auth.scope
= hidden_field_tag :nonce, @pre_auth.nonce = 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 = form_tag oauth_authorization_path, method: :post, class: 'inline' do
= hidden_field_tag :client_id, @pre_auth.client.uid = hidden_field_tag :client_id, @pre_auth.client.uid
= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
...@@ -52,4 +46,4 @@ ...@@ -52,4 +46,4 @@
= hidden_field_tag :response_type, @pre_auth.response_type = hidden_field_tag :response_type, @pre_auth.response_type
= hidden_field_tag :scope, @pre_auth.scope = hidden_field_tag :scope, @pre_auth.scope
= hidden_field_tag :nonce, @pre_auth.nonce = 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" } %main{ :role => "main" }
%code#authorization_code= params[:code] %code#authorization_code= params[:code]
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
= form_tag path do = form_tag path do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/ %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 %header
%h1 Your authorized applications %h1= _("Your authorized applications")
%main{ :role => "main" } %main{ :role => "main" }
.table-holder .table-holder
%table.table.table-striped %table.table.table-striped
%thead %thead
%tr %tr
%th Application %th= _('Application')
%th Created At %th= _('Created At')
%th %th
%th %th
%tbody %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 ...@@ -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! 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 ### 1. Revert the code to the previous version
......
...@@ -11,7 +11,12 @@ module Gitlab ...@@ -11,7 +11,12 @@ module Gitlab
def save def save
return true unless @project.avatar.exists? 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 rescue => e
@shared.error(e) @shared.error(e)
false false
...@@ -19,10 +24,6 @@ module Gitlab ...@@ -19,10 +24,6 @@ module Gitlab
private private
def avatar_export_path
File.join(@shared.export_path, 'avatar', @project.avatar_identifier)
end
def avatar_path def avatar_path
@project.avatar.path @project.avatar.path
end 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 ...@@ -2,13 +2,30 @@ module Gitlab
module ImportExport module ImportExport
class UploadsRestorer < UploadsSaver class UploadsRestorer < UploadsSaver
def restore 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 rescue => e
@shared.error(e) @shared.error(e)
false false
end 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 end
end end
...@@ -9,21 +9,14 @@ module Gitlab ...@@ -9,21 +9,14 @@ module Gitlab
end end
def save def save
return true unless File.directory?(uploads_path) Gitlab::ImportExport::UploadsManager.new(
project: @project,
copy_files(uploads_path, uploads_export_path) shared: @shared
).save
rescue => e rescue => e
@shared.error(e) @shared.error(e)
false false
end end
def uploads_path
FileUploader.absolute_base_dir(@project)
end
def uploads_export_path
File.join(@shared.export_path, 'uploads')
end
end end
end end
end end
...@@ -335,7 +335,11 @@ msgstr "" ...@@ -335,7 +335,11 @@ msgstr ""
msgid "Add Readme" msgid "Add Readme"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Add additional text to appear in all email communications. %{character_limit} character limit" msgid "Add additional text to appear in all email communications. %{character_limit} character limit"
=======
msgid "Add new application"
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "Add new directory" msgid "Add new directory"
...@@ -449,9 +453,15 @@ msgstr "" ...@@ -449,9 +453,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." 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 "" msgstr ""
msgid "An application called %{link_to_client} is requesting access to your GitLab account."
msgstr ""
msgid "An error accured whilst committing your changes." msgid "An error accured whilst committing your changes."
msgstr "" msgstr ""
msgid "An error has occurred"
msgstr ""
msgid "An error occured creating the new branch." msgid "An error occured creating the new branch."
msgstr "" msgstr ""
...@@ -569,6 +579,9 @@ msgstr "" ...@@ -569,6 +579,9 @@ msgstr ""
msgid "An error occurred. Please try again." msgid "An error occurred. Please try again."
msgstr "" msgstr ""
msgid "Anonymous"
msgstr ""
msgid "Any" msgid "Any"
msgstr "" msgstr ""
...@@ -578,6 +591,15 @@ msgstr "" ...@@ -578,6 +591,15 @@ msgstr ""
msgid "Appearance" msgid "Appearance"
msgstr "" msgstr ""
msgid "Application"
msgstr ""
msgid "Application Id"
msgstr ""
msgid "Application: %{name}"
msgstr ""
msgid "Applications" msgid "Applications"
msgstr "" msgstr ""
...@@ -677,6 +699,24 @@ msgstr "" ...@@ -677,6 +699,24 @@ msgstr ""
msgid "Author" msgid "Author"
msgstr "" 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}" msgid "Authors: %{authors}"
msgstr "" msgstr ""
...@@ -1126,6 +1166,12 @@ msgstr "" ...@@ -1126,6 +1166,12 @@ msgstr ""
msgid "CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages." msgid "CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages."
msgstr "" msgstr ""
msgid "Callback URL"
msgstr ""
msgid "Callback url"
msgstr ""
msgid "Can't find HEAD commit for this branch" msgid "Can't find HEAD commit for this branch"
msgstr "" msgstr ""
...@@ -1336,6 +1382,7 @@ msgstr "" ...@@ -1336,6 +1382,7 @@ msgstr ""
msgid "Click to expand text" msgid "Click to expand text"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Client authentication certificate" msgid "Client authentication certificate"
msgstr "" msgstr ""
...@@ -1343,6 +1390,9 @@ msgid "Client authentication key" ...@@ -1343,6 +1390,9 @@ msgid "Client authentication key"
msgstr "" msgstr ""
msgid "Client authentication key password" msgid "Client authentication key password"
=======
msgid "Clients"
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "Clone repository" msgid "Clone repository"
...@@ -2060,6 +2110,9 @@ msgstr "" ...@@ -2060,6 +2110,9 @@ msgstr ""
msgid "Created" msgid "Created"
msgstr "" msgstr ""
msgid "Created At"
msgstr ""
msgid "Created by me" msgid "Created by me"
msgstr "" msgstr ""
...@@ -2150,6 +2203,9 @@ msgstr "" ...@@ -2150,6 +2203,9 @@ msgstr ""
msgid "Delete list" msgid "Delete list"
msgstr "" msgstr ""
msgid "Deny"
msgstr ""
msgid "Deploy" msgid "Deploy"
msgid_plural "Deploys" msgid_plural "Deploys"
msgstr[0] "" msgstr[0] ""
...@@ -2293,6 +2349,9 @@ msgstr "" ...@@ -2293,6 +2349,9 @@ msgstr ""
msgid "Description:" msgid "Description:"
msgstr "" msgstr ""
msgid "Destroy"
msgstr ""
msgid "Details" msgid "Details"
msgstr "" msgstr ""
...@@ -2398,6 +2457,9 @@ msgstr "" ...@@ -2398,6 +2457,9 @@ msgstr ""
msgid "Edit Snippet" msgid "Edit Snippet"
msgstr "" msgstr ""
msgid "Edit application"
msgstr ""
msgid "Edit files in the editor and commit changes here" msgid "Edit files in the editor and commit changes here"
msgstr "" msgstr ""
...@@ -3636,6 +3698,12 @@ msgstr "" ...@@ -3636,6 +3698,12 @@ msgstr ""
msgid "Manage all notifications" msgid "Manage all notifications"
msgstr "" 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" msgid "Manage group labels"
msgstr "" msgstr ""
...@@ -3930,6 +3998,9 @@ msgstr "" ...@@ -3930,6 +3998,9 @@ msgstr ""
msgid "New" msgid "New"
msgstr "" msgstr ""
msgid "New Application"
msgstr ""
msgid "New Group" msgid "New Group"
msgstr "" msgstr ""
...@@ -4460,6 +4531,9 @@ msgstr "" ...@@ -4460,6 +4531,9 @@ msgstr ""
msgid "Please accept the Terms of Service before continuing." msgid "Please accept the Terms of Service before continuing."
msgstr "" 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" msgid "Please select at least one filter to see results"
msgstr "" msgstr ""
...@@ -5008,10 +5082,14 @@ msgstr "" ...@@ -5008,10 +5082,14 @@ msgstr ""
msgid "Reviewing (merge request !%{mergeRequestId})" msgid "Reviewing (merge request !%{mergeRequestId})"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Roadmap" msgid "Roadmap"
msgstr "" msgstr ""
msgid "Run CI/CD pipelines for external repositories" msgid "Run CI/CD pipelines for external repositories"
=======
msgid "Revoke"
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "Runner token" msgid "Runner token"
...@@ -5053,6 +5131,9 @@ msgstr "" ...@@ -5053,6 +5131,9 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "" msgstr ""
msgid "Save application"
msgstr ""
msgid "Save changes" msgid "Save changes"
msgstr "" msgstr ""
...@@ -5074,7 +5155,11 @@ msgstr "" ...@@ -5074,7 +5155,11 @@ msgstr ""
msgid "Scheduling Pipelines" msgid "Scheduling Pipelines"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Scoped issue boards" msgid "Scoped issue boards"
=======
msgid "Scope"
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "Scroll to bottom" msgid "Scroll to bottom"
...@@ -5116,6 +5201,7 @@ msgstr "" ...@@ -5116,6 +5201,7 @@ msgstr ""
msgid "Seconds to wait for a storage access attempt" msgid "Seconds to wait for a storage access attempt"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Security Dashboard" msgid "Security Dashboard"
msgstr "" msgstr ""
...@@ -5126,6 +5212,9 @@ msgid "SecurityDashboard|Monitor vulnerabilities in your code" ...@@ -5126,6 +5212,9 @@ msgid "SecurityDashboard|Monitor vulnerabilities in your code"
msgstr "" msgstr ""
msgid "SecurityDashboard|Pipeline %{pipelineLink} triggered" msgid "SecurityDashboard|Pipeline %{pipelineLink} triggered"
=======
msgid "Secret:"
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "Select" msgid "Select"
...@@ -5813,7 +5902,14 @@ msgstr "" ...@@ -5813,7 +5902,14 @@ msgstr ""
msgid "This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area." msgid "This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area."
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "This board\\'s scope is reduced" msgid "This board\\'s scope is reduced"
=======
msgid "This application was created by %{link_to_owner}."
msgstr ""
msgid "This application will be able to:"
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "This diff is collapsed." msgid "This diff is collapsed."
...@@ -6278,12 +6374,19 @@ msgstr "" ...@@ -6278,12 +6374,19 @@ msgstr ""
msgid "Usage statistics" msgid "Usage statistics"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
=======
msgid "Use <code>%{native_redirect_uri}</code> for local tests"
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "Use group milestones to manage issues from multiple projects in the same milestone." msgid "Use group milestones to manage issues from multiple projects in the same milestone."
msgstr "" msgstr ""
msgid "Use one line per URI"
msgstr ""
msgid "Use the following registration token during setup:" msgid "Use the following registration token during setup:"
msgstr "" msgstr ""
...@@ -6554,6 +6657,9 @@ msgstr "" ...@@ -6554,6 +6657,9 @@ msgstr ""
msgid "Yes, add it" msgid "Yes, add it"
msgstr "" 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?" msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "" msgstr ""
...@@ -6611,7 +6717,14 @@ msgstr "" ...@@ -6611,7 +6717,14 @@ msgstr ""
msgid "You do not have any assigned merge requests" msgid "You do not have any assigned merge requests"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "You do not have the correct permissions to override the settings from the LDAP group sync." msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
=======
msgid "You don't have any applications"
msgstr ""
msgid "You don't have any authorized applications"
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "You have no permissions" msgid "You have no permissions"
...@@ -6686,6 +6799,12 @@ msgstr "" ...@@ -6686,6 +6799,12 @@ msgstr ""
msgid "Your Todos" msgid "Your Todos"
msgstr "" 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." msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "" msgstr ""
......
...@@ -3,7 +3,7 @@ module QA ...@@ -3,7 +3,7 @@ module QA
module Main module Main
class OAuth < Page::Base class OAuth < Page::Base
view 'app/views/doorkeeper/authorizations/new.html.haml' do view 'app/views/doorkeeper/authorizations/new.html.haml' do
element :authorization_button, 'submit_tag "Authorize"' element :authorization_button, 'submit_tag _("Authorize")'
end end
def needs_authorization? def needs_authorization?
......
...@@ -28,6 +28,13 @@ FactoryBot.define do ...@@ -28,6 +28,13 @@ FactoryBot.define do
secret SecureRandom.hex secret SecureRandom.hex
end 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 trait :object_storage do
store ObjectStorage::Store::REMOTE store ObjectStorage::Store::REMOTE
end end
......
...@@ -64,6 +64,7 @@ export const serverData = [ ...@@ -64,6 +64,7 @@ export const serverData = [
environment_type: 'build', environment_type: 'build',
last_deployment: null, last_deployment: null,
has_stop_action: false, has_stop_action: false,
<<<<<<< HEAD
environment_path: '/root/review-app/environments/12', environment_path: '/root/review-app/environments/12',
stop_path: '/root/review-app/environments/12/stop', stop_path: '/root/review-app/environments/12/stop',
created_at: '2017-02-01T19:42:18.400Z', created_at: '2017-02-01T19:42:18.400Z',
...@@ -81,6 +82,8 @@ export const serverData = [ ...@@ -81,6 +82,8 @@ export const serverData = [
environment_type: 'build', environment_type: 'build',
last_deployment: null, last_deployment: null,
has_stop_action: false, has_stop_action: false,
=======
>>>>>>> upstream/master
environment_path: '/root/review-app/environments/12', environment_path: '/root/review-app/environments/12',
stop_path: '/root/review-app/environments/12/stop', stop_path: '/root/review-app/environments/12/stop',
created_at: '2017-02-01T19:42:18.400Z', created_at: '2017-02-01T19:42:18.400Z',
......
...@@ -9,6 +9,7 @@ describe Gitlab::ImportExport::AvatarSaver do ...@@ -9,6 +9,7 @@ describe Gitlab::ImportExport::AvatarSaver do
before do before do
FileUtils.mkdir_p("#{shared.export_path}/avatar/") FileUtils.mkdir_p("#{shared.export_path}/avatar/")
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
stub_feature_flags(import_export_object_storage: false)
end end
after do 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 ...@@ -7,6 +7,7 @@ describe Gitlab::ImportExport::UploadsSaver do
let(:shared) { project.import_export_shared } let(:shared) { project.import_export_shared }
before do before do
stub_feature_flags(import_export_object_storage: false)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
end end
...@@ -30,7 +31,7 @@ describe Gitlab::ImportExport::UploadsSaver do ...@@ -30,7 +31,7 @@ describe Gitlab::ImportExport::UploadsSaver do
it 'copies the uploads to the export path' do it 'copies the uploads to the export path' do
saver.save 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') expect(uploads).to include('banana_sample.gif')
end end
...@@ -52,7 +53,7 @@ describe Gitlab::ImportExport::UploadsSaver do ...@@ -52,7 +53,7 @@ describe Gitlab::ImportExport::UploadsSaver do
it 'copies the uploads to the export path' do it 'copies the uploads to the export path' do
saver.save 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') expect(uploads).to include('banana_sample.gif')
end end
......
...@@ -124,6 +124,15 @@ describe FileUploader do ...@@ -124,6 +124,15 @@ describe FileUploader do
end end
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 describe '#secret' do
it 'generates a secret if none is provided' do it 'generates a secret if none is provided' do
expect(described_class).to receive(:generate_secret).and_return('secret') 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