From d653f217614f1a4b6a7348c81801ca41a232d33e Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 9 Jul 2018 10:13:23 +0000 Subject: Update Git version to 2.18.0 --- doc/install/installation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 259d8f73a22..22e0f00e2df 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -92,9 +92,9 @@ Is the system packaged Git too old? Remove it and compile from source. # Download and compile from source cd /tmp - curl --remote-name --progress https://www.kernel.org/pub/software/scm/git/git-2.16.3.tar.gz - echo 'dda229e9c73f4fbb7d4324e0d993e11311673df03f73b194c554c2e9451e17cd git-2.16.3.tar.gz' | shasum -a256 -c - && tar -xzf git-2.16.3.tar.gz - cd git-2.16.3/ + curl --remote-name --progress https://www.kernel.org/pub/software/scm/git/git-2.18.0.tar.gz + echo '94faf2c0b02a7920b0b46f4961d8e9cad08e81418614102898a55f980fa3e7e4 git-2.18.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.18.0.tar.gz + cd git-2.18.0/ ./configure make prefix=/usr/local all -- cgit v1.2.1 From 4c7b120acf503e087d935fce2fe5af3f77d00d1e Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 10 Jul 2018 11:40:39 +0200 Subject: add upload manager and spec --- lib/gitlab/import_export/uploads_manager.rb | 62 ++++++++++++++++++++++ .../gitlab/import_export/uploads_manager_spec.rb | 40 ++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 lib/gitlab/import_export/uploads_manager.rb create mode 100644 spec/lib/gitlab/import_export/uploads_manager_spec.rb diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb new file mode 100644 index 00000000000..b229ab12291 --- /dev/null +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -0,0 +1,62 @@ +module Gitlab + module ImportExport + class UploadsManager + include Gitlab::ImportExport::CommandLineUtil + + 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 copy + copy_files(@from, uploads_export_path) if File.directory?(@from) + + copy_from_object_storage + end + + private + + def copy_from_object_storage + return unless Gitlab::ImportExport.object_storage? + return if uploads.empty? + + mkdir_p(uploads_export_path) + + uploads.each do |upload_model| + next unless upload_model.file + next if upload_model.upload.local? # Already copied + + download_and_copy(upload_model) + 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 uploads + @uploads ||= begin + if @relative_export_path == 'avatar' + [@project.avatar].compact + else + (@project.uploads - [@project.avatar&.upload]).map(&:build_uploader) + end + end + end + + def download_and_copy(upload) + upload_path = File.join(uploads_export_path, upload.filename) + + File.open(upload_path, 'w') do |file| + IO.copy_stream(URI.parse(upload.file.url).open, file) + end + end + end + end +end diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb new file mode 100644 index 00000000000..dcb065fef24 --- /dev/null +++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb @@ -0,0 +1,40 @@ +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) } + + 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 '#copy' do + context 'when the project has uploads locally stored' do + let(:upload) { create(:upload) } + + before do + project.uploads << upload + end + + it 'does not cause errors' do + manager.copy + + expect(shared.errors).to be_empty + end + + it 'copies the file in the correct location when there is an upload' do + manager.copy + + expect(File).to exist("#{shared.export_path}/uploads/#{File.basename(upload.path)}") + end + end + end +end -- cgit v1.2.1 From 874a4ff16ab883f3b22f8e11474522af120bfa86 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 10 Jul 2018 15:29:31 +0200 Subject: add more object storage specs --- lib/gitlab/import_export/uploads_manager.rb | 6 +++--- .../gitlab/import_export/uploads_manager_spec.rb | 25 ++++++++++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb index b229ab12291..2992c81b731 100644 --- a/lib/gitlab/import_export/uploads_manager.rb +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -22,8 +22,6 @@ module Gitlab return unless Gitlab::ImportExport.object_storage? return if uploads.empty? - mkdir_p(uploads_export_path) - uploads.each do |upload_model| next unless upload_model.file next if upload_model.upload.local? # Already copied @@ -51,7 +49,9 @@ module Gitlab end def download_and_copy(upload) - upload_path = File.join(uploads_export_path, upload.filename) + mkdir_p(File.join(uploads_export_path, upload.secret)) + + upload_path = File.join(uploads_export_path, upload.secret, upload.filename) File.open(upload_path, 'w') do |file| IO.copy_stream(URI.parse(upload.file.url).open, file) diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb index dcb065fef24..33c90c3a785 100644 --- a/spec/lib/gitlab/import_export/uploads_manager_spec.rb +++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb @@ -4,6 +4,7 @@ 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) } @@ -18,7 +19,7 @@ describe Gitlab::ImportExport::UploadsManager do describe '#copy' do context 'when the project has uploads locally stored' do - let(:upload) { create(:upload) } + let(:upload) { create(:upload, :issuable_upload, :with_file, model: project) } before do project.uploads << upload @@ -33,7 +34,27 @@ describe Gitlab::ImportExport::UploadsManager do it 'copies the file in the correct location when there is an upload' do manager.copy - expect(File).to exist("#{shared.export_path}/uploads/#{File.basename(upload.path)}") + 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 'downloads the file to include in an archive' 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.copy + + expect(File.read(exported_file_path)).to eq('File content') end end end -- cgit v1.2.1 From 81d8ddf8cad78097cfba503553f879eb76c2485f Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 10 Jul 2018 15:59:00 +0200 Subject: Add a 10 ms bucket for SQL timings This allows us to calculate quantiles of SQL timings more accurately, instead of a lot of timings being assigned to the 50 ms bucket. --- changelogs/unreleased/tweak-sql-buckets.yml | 5 +++++ lib/gitlab/metrics/subscribers/active_record.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/tweak-sql-buckets.yml diff --git a/changelogs/unreleased/tweak-sql-buckets.yml b/changelogs/unreleased/tweak-sql-buckets.yml new file mode 100644 index 00000000000..00a0f733ee1 --- /dev/null +++ b/changelogs/unreleased/tweak-sql-buckets.yml @@ -0,0 +1,5 @@ +--- +title: Add a 10 ms bucket for SQL timings +merge_request: +author: +type: changed diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb index 38f119cf06d..c205f348023 100644 --- a/lib/gitlab/metrics/subscribers/active_record.rb +++ b/lib/gitlab/metrics/subscribers/active_record.rb @@ -20,7 +20,7 @@ module Gitlab define_histogram :gitlab_sql_duration_seconds do docstring 'SQL time' base_labels Transaction::BASE_LABELS - buckets [0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0] + buckets [0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0] end def current_transaction -- cgit v1.2.1 From 2c1e66d4d2124ec3d6101a6c5586867139f6fd20 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 10 Jul 2018 16:23:45 +0200 Subject: Fix avatar saver and spec --- lib/gitlab/import_export/avatar_saver.rb | 11 ++++++----- spec/lib/gitlab/import_export/avatar_saver_spec.rb | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/import_export/avatar_saver.rb b/lib/gitlab/import_export/avatar_saver.rb index 998c21e2586..848c05f116b 100644 --- a/lib/gitlab/import_export/avatar_saver.rb +++ b/lib/gitlab/import_export/avatar_saver.rb @@ -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 + ).copy 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 diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb index 2223f163177..792596bfaa5 100644 --- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb @@ -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 @@ -18,6 +19,8 @@ describe Gitlab::ImportExport::AvatarSaver do it 'saves a project avatar' do described_class.new(project: project_with_avatar, shared: shared).save + puts "#{shared.export_path}/avatar/dk.png" + expect(File).to exist("#{shared.export_path}/avatar/dk.png") end -- cgit v1.2.1 From a27d4d9e524ee0b7eb5f5518fc6f8af00e1e6dfe Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 10 Jul 2018 16:33:40 +0200 Subject: update uploads saver --- lib/gitlab/import_export/uploads_manager.rb | 14 ++++++++++++-- lib/gitlab/import_export/uploads_saver.rb | 15 ++++----------- spec/factories/uploads.rb | 7 +++++++ spec/lib/gitlab/import_export/uploads_saver_spec.rb | 4 ++-- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb index 2992c81b731..63935fc6822 100644 --- a/lib/gitlab/import_export/uploads_manager.rb +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -13,7 +13,16 @@ module Gitlab def copy 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 private @@ -49,9 +58,10 @@ module Gitlab end def download_and_copy(upload) - mkdir_p(File.join(uploads_export_path, upload.secret)) + secret = upload.try(:secret) || '' + upload_path = File.join(uploads_export_path, secret, upload.filename) - upload_path = File.join(uploads_export_path, upload.secret, upload.filename) + mkdir_p(File.join(uploads_export_path, secret)) File.open(upload_path, 'w') do |file| IO.copy_stream(URI.parse(upload.file.url).open, file) diff --git a/lib/gitlab/import_export/uploads_saver.rb b/lib/gitlab/import_export/uploads_saver.rb index 2f08dda55fd..9cdd015d82a 100644 --- a/lib/gitlab/import_export/uploads_saver.rb +++ b/lib/gitlab/import_export/uploads_saver.rb @@ -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, + ).copy 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 diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb index b45f6f30e40..a81b2169b89 100644 --- a/spec/factories/uploads.rb +++ b/spec/factories/uploads.rb @@ -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 diff --git a/spec/lib/gitlab/import_export/uploads_saver_spec.rb b/spec/lib/gitlab/import_export/uploads_saver_spec.rb index 095687fa89d..24993460e51 100644 --- a/spec/lib/gitlab/import_export/uploads_saver_spec.rb +++ b/spec/lib/gitlab/import_export/uploads_saver_spec.rb @@ -30,7 +30,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 +52,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 -- cgit v1.2.1 From 7c9f21683ce2eea8f1f901d81b32ad775d7f9ba6 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 11 Jul 2018 10:24:59 +0200 Subject: add restore method --- lib/gitlab/import_export/avatar_saver.rb | 2 +- lib/gitlab/import_export/uploads_manager.rb | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/import_export/avatar_saver.rb b/lib/gitlab/import_export/avatar_saver.rb index 848c05f116b..31ef0490cb3 100644 --- a/lib/gitlab/import_export/avatar_saver.rb +++ b/lib/gitlab/import_export/avatar_saver.rb @@ -16,7 +16,7 @@ module Gitlab shared: @shared, relative_export_path: 'avatar', from: avatar_path - ).copy + ).save rescue => e @shared.error(e) false diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb index 63935fc6822..d47b1f2e8f7 100644 --- a/lib/gitlab/import_export/uploads_manager.rb +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -10,8 +10,8 @@ module Gitlab @from = from || default_uploads_path end - def copy - copy_files(@from, uploads_export_path) if File.directory?(@from) + def save + copy_files(@from, default_uploads_path) if File.directory?(@from) if File.file?(@from) && @relative_export_path == 'avatar' copy_files(@from, File.join(uploads_export_path, @project.avatar.filename)) @@ -25,6 +25,21 @@ module Gitlab false end + def restore + Dir["#{uploads_export_path}/**/*"].each do |upload| + next if File.directory?(upload) + + upload_path = File.join(uploads_export_path, upload) + + UploadService.new(@project, File.open(upload_path, 'r'), FileUploader).execute + end + + true + rescue => e + @shared.error(e) + false + end + private def copy_from_object_storage -- cgit v1.2.1 From 3a114c2d119a9d0a7a8a9c85a6c7ec405f3a0f12 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 11 Jul 2018 11:36:59 +0200 Subject: fix specs --- lib/gitlab/import_export/uploads_manager.rb | 6 ++--- lib/gitlab/import_export/uploads_restorer.rb | 13 +++++++--- lib/gitlab/import_export/uploads_saver.rb | 4 +-- .../gitlab/import_export/uploads_manager_spec.rb | 29 +++++++++++++++++++--- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb index d47b1f2e8f7..c968deb6b19 100644 --- a/lib/gitlab/import_export/uploads_manager.rb +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -11,7 +11,7 @@ module Gitlab end def save - copy_files(@from, default_uploads_path) if File.directory?(@from) + 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)) @@ -29,9 +29,7 @@ module Gitlab Dir["#{uploads_export_path}/**/*"].each do |upload| next if File.directory?(upload) - upload_path = File.join(uploads_export_path, upload) - - UploadService.new(@project, File.open(upload_path, 'r'), FileUploader).execute + UploadService.new(@project, File.open(upload, 'r'), FileUploader).execute end true diff --git a/lib/gitlab/import_export/uploads_restorer.rb b/lib/gitlab/import_export/uploads_restorer.rb index df19354b76e..b7e07fc1226 100644 --- a/lib/gitlab/import_export/uploads_restorer.rb +++ b/lib/gitlab/import_export/uploads_restorer.rb @@ -2,9 +2,16 @@ module Gitlab module ImportExport class UploadsRestorer < UploadsSaver def restore - return true unless File.directory?(uploads_export_path) - - copy_files(uploads_export_path, uploads_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) + else + true + end rescue => e @shared.error(e) false diff --git a/lib/gitlab/import_export/uploads_saver.rb b/lib/gitlab/import_export/uploads_saver.rb index 9cdd015d82a..b3f17af5661 100644 --- a/lib/gitlab/import_export/uploads_saver.rb +++ b/lib/gitlab/import_export/uploads_saver.rb @@ -11,8 +11,8 @@ module Gitlab def save Gitlab::ImportExport::UploadsManager.new( project: @project, - shared: @shared, - ).copy + shared: @shared + ).save rescue => e @shared.error(e) false diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb index 33c90c3a785..ffb8d140f32 100644 --- a/spec/lib/gitlab/import_export/uploads_manager_spec.rb +++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb @@ -17,7 +17,7 @@ describe Gitlab::ImportExport::UploadsManager do FileUtils.rm_rf(shared.export_path) end - describe '#copy' do + describe '#save' do context 'when the project has uploads locally stored' do let(:upload) { create(:upload, :issuable_upload, :with_file, model: project) } @@ -26,13 +26,15 @@ describe Gitlab::ImportExport::UploadsManager do end it 'does not cause errors' do - manager.copy + manager.save expect(shared.errors).to be_empty end it 'copies the file in the correct location when there is an upload' do - manager.copy + manager.save + + puts exported_file_path expect(File).to exist(exported_file_path) end @@ -52,10 +54,29 @@ describe Gitlab::ImportExport::UploadsManager do expect(fake_uri).to receive(:open).and_return(StringIO.new('File content')) expect(URI).to receive(:parse).and_return(fake_uri) - manager.copy + 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/random')) + FileUtils.touch(File.join(shared.export_path, 'uploads/random', "dummy.txt")) + end + + it 'downloads the file to include in an archive' 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 -- cgit v1.2.1 From 414939c97ce8a14e78d88db06f7378e98bea42a3 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 11 Jul 2018 12:02:01 +0200 Subject: fix uploads restorer --- lib/gitlab/import_export/uploads_restorer.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/gitlab/import_export/uploads_restorer.rb b/lib/gitlab/import_export/uploads_restorer.rb index b7e07fc1226..15714c52c1a 100644 --- a/lib/gitlab/import_export/uploads_restorer.rb +++ b/lib/gitlab/import_export/uploads_restorer.rb @@ -16,6 +16,10 @@ module Gitlab @shared.error(e) false end + + def uploads_path + FileUploader.absolute_base_dir(@project) + end end end end -- cgit v1.2.1 From 3c31de752027abfb247efc5c588496d329e5b47b Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 11 Jul 2018 14:52:48 +0200 Subject: refactor uploads manager --- app/services/upload_service.rb | 6 +++--- lib/gitlab/import_export/uploads_manager.rb | 11 ++++++++--- spec/lib/gitlab/import_export/uploads_manager_spec.rb | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/services/upload_service.rb b/app/services/upload_service.rb index d5a9b344905..8e20512cd61 100644 --- a/app/services/upload_service.rb +++ b/app/services/upload_service.rb @@ -1,12 +1,12 @@ 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 diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb index c968deb6b19..b1ea7f19068 100644 --- a/lib/gitlab/import_export/uploads_manager.rb +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -29,10 +29,15 @@ module Gitlab Dir["#{uploads_export_path}/**/*"].each do |upload| next if File.directory?(upload) - UploadService.new(@project, File.open(upload, 'r'), FileUploader).execute - end + secret, identifier = upload.split('/').last(2) - true + uploader_context = { + secret: secret, + identifier: identifier + } + + UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute + end rescue => e @shared.error(e) false diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb index ffb8d140f32..922f6f6376c 100644 --- a/spec/lib/gitlab/import_export/uploads_manager_spec.rb +++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb @@ -48,7 +48,7 @@ describe Gitlab::ImportExport::UploadsManager do stub_uploads_object_storage(FileUploader) end - it 'downloads the file to include in an archive' do + it 'saves the file' do fake_uri = double expect(fake_uri).to receive(:open).and_return(StringIO.new('File content')) @@ -70,7 +70,7 @@ describe Gitlab::ImportExport::UploadsManager do FileUtils.touch(File.join(shared.export_path, 'uploads/random', "dummy.txt")) end - it 'downloads the file to include in an archive' do + it 'restores the file' do manager.restore expect(project.uploads.size).to eq(1) -- cgit v1.2.1 From fa2e3162f8955eaa7259c17c080a083b5d9e8ba9 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 11 Jul 2018 15:02:59 +0200 Subject: added changelog, small refactor --- ...xports-fail-when-uploads-have-been-migrated-to-object-storage.yml | 5 +++++ lib/gitlab/import_export/uploads_manager.rb | 3 +-- spec/lib/gitlab/import_export/avatar_saver_spec.rb | 2 -- spec/lib/gitlab/import_export/uploads_manager_spec.rb | 2 -- 4 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/48745-project-exports-fail-when-uploads-have-been-migrated-to-object-storage.yml diff --git a/changelogs/unreleased/48745-project-exports-fail-when-uploads-have-been-migrated-to-object-storage.yml b/changelogs/unreleased/48745-project-exports-fail-when-uploads-have-been-migrated-to-object-storage.yml new file mode 100644 index 00000000000..7552e0d3878 --- /dev/null +++ b/changelogs/unreleased/48745-project-exports-fail-when-uploads-have-been-migrated-to-object-storage.yml @@ -0,0 +1,5 @@ +--- +title: Add uploader support to Import/Export uploads +merge_request: 20484 +author: +type: added diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb index b1ea7f19068..6af8620ccd0 100644 --- a/lib/gitlab/import_export/uploads_manager.rb +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -47,11 +47,10 @@ module Gitlab def copy_from_object_storage return unless Gitlab::ImportExport.object_storage? - return if uploads.empty? uploads.each do |upload_model| next unless upload_model.file - next if upload_model.upload.local? # Already copied + next if upload_model.upload.local? # Already copied, using the old method download_and_copy(upload_model) end diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb index 792596bfaa5..90e6d653d34 100644 --- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb @@ -19,8 +19,6 @@ describe Gitlab::ImportExport::AvatarSaver do it 'saves a project avatar' do described_class.new(project: project_with_avatar, shared: shared).save - puts "#{shared.export_path}/avatar/dk.png" - expect(File).to exist("#{shared.export_path}/avatar/dk.png") end diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb index 922f6f6376c..0c9c4574469 100644 --- a/spec/lib/gitlab/import_export/uploads_manager_spec.rb +++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb @@ -34,8 +34,6 @@ describe Gitlab::ImportExport::UploadsManager do it 'copies the file in the correct location when there is an upload' do manager.save - puts exported_file_path - expect(File).to exist(exported_file_path) end end -- cgit v1.2.1 From 3d1a23162ae14e0b5ccf7b42c6bac13adfda1e4e Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 11 Jul 2018 16:03:02 +0300 Subject: Update issue closing pattern --- changelogs/unreleased/update-issue-closing-pattern.yml | 5 +++++ config/initializers/1_settings.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/update-issue-closing-pattern.yml diff --git a/changelogs/unreleased/update-issue-closing-pattern.yml b/changelogs/unreleased/update-issue-closing-pattern.yml new file mode 100644 index 00000000000..95488adf449 --- /dev/null +++ b/changelogs/unreleased/update-issue-closing-pattern.yml @@ -0,0 +1,5 @@ +--- +title: Update issue closing pattern +merge_request: 20554 +author: George Tsiolis +type: changed diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 693a2934a1b..4b9cc59ec45 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -135,7 +135,7 @@ Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled']. Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? Settings.gitlab['restricted_visibility_levels'] = Settings.__send__(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? -Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?: *,? +and +| *, *)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil? +Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?: *,? +and +| *,? *)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil? Settings.gitlab['default_projects_features'] ||= {} Settings.gitlab['webhook_timeout'] ||= 10 Settings.gitlab['max_attachment_size'] ||= 10 -- cgit v1.2.1 From 69f9c9116141f291e90374ffa5959a8881c950e1 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 11 Jul 2018 16:28:53 +0300 Subject: Add tests for non-comma-separated issue numbers in single line message --- spec/lib/gitlab/closing_issue_extractor_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index 8d4862932b2..e6cb402aef3 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -379,6 +379,20 @@ describe Gitlab::ClosingIssueExtractor do .to match_array([issue, other_issue, third_issue]) end + it 'allows non-comma-separated issue numbers in single line message' do + message = "Closes #{reference} #{reference2} #{reference3}" + + expect(subject.closed_by_message(message)) + .to match_array([issue, other_issue, third_issue]) + end + + it 'allows mixed comma-separated and non-comma-separated issue numbers in single line message' do + message = "Closes #{reference}, #{reference2} and #{reference3}" + + expect(subject.closed_by_message(message)) + .to match_array([issue, other_issue, third_issue]) + end + it 'fetches issues in multi-line message' do message = "Awesome commit (closes #{reference})\nAlso fixes #{reference2}" -- cgit v1.2.1 From e2b7880b9d959f71e4127b8d6eb993e27460b5d3 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 11 Jul 2018 15:58:42 +0200 Subject: fix spec --- lib/gitlab/import_export/uploads_manager.rb | 22 ++++++++++++++-------- lib/gitlab/import_export/uploads_restorer.rb | 2 ++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb index 6af8620ccd0..070a0cefe85 100644 --- a/lib/gitlab/import_export/uploads_manager.rb +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -29,15 +29,10 @@ module Gitlab Dir["#{uploads_export_path}/**/*"].each do |upload| next if File.directory?(upload) - secret, identifier = upload.split('/').last(2) - - uploader_context = { - secret: secret, - identifier: identifier - } - - UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute + add_upload(upload) end + + true rescue => e @shared.error(e) false @@ -45,6 +40,17 @@ module Gitlab private + def add_upload(upload) + secret, identifier = upload.split('/').last(2) + + uploader_context = { + secret: secret, + identifier: identifier + } + + UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute + end + def copy_from_object_storage return unless Gitlab::ImportExport.object_storage? diff --git a/lib/gitlab/import_export/uploads_restorer.rb b/lib/gitlab/import_export/uploads_restorer.rb index 15714c52c1a..69c1f289797 100644 --- a/lib/gitlab/import_export/uploads_restorer.rb +++ b/lib/gitlab/import_export/uploads_restorer.rb @@ -9,6 +9,8 @@ module Gitlab ).restore elsif File.directory?(uploads_export_path) copy_files(uploads_export_path, uploads_path) + + true else true end -- cgit v1.2.1 From 0ddedab5d59c259d454eee01bdc22832048bd7d4 Mon Sep 17 00:00:00 2001 From: Lukas Eipert Date: Mon, 9 Jul 2018 23:31:33 +0200 Subject: improve log output of jasmine `toEqual` with nested objects/arrays --- package.json | 1 + spec/javascripts/test_bundle.js | 11 ++++++++++- yarn.lock | 8 +++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 26b87c70e98..d494b06e97e 100644 --- a/package.json +++ b/package.json @@ -123,6 +123,7 @@ "ignore": "^3.3.7", "istanbul": "^0.4.5", "jasmine-core": "^2.9.0", + "jasmine-diff": "^0.1.3", "jasmine-jquery": "^2.1.1", "karma": "^2.0.2", "karma-chrome-launcher": "^2.2.0", diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js index 0eff98bcc9d..f77040bb5c6 100644 --- a/spec/javascripts/test_bundle.js +++ b/spec/javascripts/test_bundle.js @@ -6,6 +6,7 @@ import '~/commons'; import Vue from 'vue'; import VueResource from 'vue-resource'; import Translate from '~/vue_shared/translate'; +import jasmineDiff from 'jasmine-diff'; import { getDefaultAdapter } from '~/lib/utils/axios_utils'; import { FIXTURES_PATH, TEST_HOST } from './test_constants'; @@ -35,7 +36,15 @@ Vue.use(Translate); jasmine.getFixtures().fixturesPath = FIXTURES_PATH; jasmine.getJSONFixtures().fixturesPath = FIXTURES_PATH; -beforeAll(() => jasmine.addMatchers(customMatchers)); +beforeAll(() => { + jasmine.addMatchers( + jasmineDiff(jasmine, { + colors: true, + inline: true, + }), + ); + jasmine.addMatchers(customMatchers); +}); // globalize common libraries window.$ = $; diff --git a/yarn.lock b/yarn.lock index d844ae4f8e9..d478ed84f1b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2522,7 +2522,7 @@ di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" -diff@^3.4.0: +diff@^3.2.0, diff@^3.4.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -4554,6 +4554,12 @@ jasmine-core@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.9.0.tgz#bfbb56defcd30789adec5a3fbba8504233289c72" +jasmine-diff@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/jasmine-diff/-/jasmine-diff-0.1.3.tgz#93ccc2dcc41028c5ddd4606558074839f2deeaa8" + dependencies: + diff "^3.2.0" + jasmine-jquery@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/jasmine-jquery/-/jasmine-jquery-2.1.1.tgz#d4095e646944a26763235769ab018d9f30f0d47b" -- cgit v1.2.1 From 8ea2027f43e5a60de2e969866d3e461617959cb8 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 12 Jul 2018 08:46:24 +0200 Subject: fix uploads restorer missing path --- lib/gitlab/import_export/uploads_restorer.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/gitlab/import_export/uploads_restorer.rb b/lib/gitlab/import_export/uploads_restorer.rb index 69c1f289797..df24333cd74 100644 --- a/lib/gitlab/import_export/uploads_restorer.rb +++ b/lib/gitlab/import_export/uploads_restorer.rb @@ -22,6 +22,10 @@ module Gitlab 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 -- cgit v1.2.1 From 4223a6fe4583d7b8cbb1a25f627ec453404c56dd Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 12 Jul 2018 11:08:19 +0200 Subject: refactor uploads manager to grab uploads in batches --- lib/gitlab/import_export/uploads_manager.rb | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb index 070a0cefe85..3e756bdaa79 100644 --- a/lib/gitlab/import_export/uploads_manager.rb +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -3,6 +3,8 @@ module Gitlab class UploadsManager include Gitlab::ImportExport::CommandLineUtil + UPLOADS_BATCH_SIZE = 100 + def initialize(project:, shared:, relative_export_path: 'uploads', from: nil) @project = project @shared = shared @@ -54,7 +56,7 @@ module Gitlab def copy_from_object_storage return unless Gitlab::ImportExport.object_storage? - uploads.each do |upload_model| + uploads do |upload_model| next unless upload_model.file next if upload_model.upload.local? # Already copied, using the old method @@ -71,15 +73,23 @@ module Gitlab end def uploads - @uploads ||= begin - if @relative_export_path == 'avatar' - [@project.avatar].compact - else - (@project.uploads - [@project.avatar&.upload]).map(&:build_uploader) + avatar_path = @project.avatar&.upload&.path + + if @relative_export_path == 'avatar' + yield(@project.avatar) + else + project_uploads(avatar_path).find_each(batch_size: UPLOADS_BATCH_SIZE) do |upload| + yield(upload.build_uploader) end end end + def project_uploads(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) -- cgit v1.2.1 From 3a77664d1a550cfbedc92068926e4adae9c82b87 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 10 Jul 2018 10:35:16 +0100 Subject: Allow merge requests from forks to be opened in Web IDE Closes #47460 --- app/assets/javascripts/ide/ide_router.js | 3 +++ .../javascripts/ide/stores/actions/merge_request.js | 14 ++++++++------ .../components/mr_widget_header.vue | 6 +++++- .../vue_merge_request_widget/stores/mr_widget_store.js | 10 +++++++--- app/serializers/merge_request_widget_entity.rb | 6 ++++++ .../api/schemas/entities/merge_request_widget.json | 2 ++ spec/javascripts/vue_mr_widget/mock_data.js | 2 ++ spec/serializers/merge_request_widget_entity_spec.rb | 15 +++++++++++++++ 8 files changed, 48 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js index cc8dbb942d8..44c35e9a5a5 100644 --- a/app/assets/javascripts/ide/ide_router.js +++ b/app/assets/javascripts/ide/ide_router.js @@ -101,6 +101,7 @@ router.beforeEach((to, from, next) => { store .dispatch('getMergeRequestData', { projectId: fullProjectId, + targetProjectId: to.query.target_project, mergeRequestId: to.params.mrid, }) .then(mr => { @@ -119,12 +120,14 @@ router.beforeEach((to, from, next) => { .then(() => store.dispatch('getMergeRequestVersions', { projectId: fullProjectId, + targetProjectId: to.query.target_project, mergeRequestId: to.params.mrid, }), ) .then(() => store.dispatch('getMergeRequestChanges', { projectId: fullProjectId, + targetProjectId: to.query.target_project, mergeRequestId: to.params.mrid, }), ) diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js index 6bdf9dc3028..1887b77b00b 100644 --- a/app/assets/javascripts/ide/stores/actions/merge_request.js +++ b/app/assets/javascripts/ide/stores/actions/merge_request.js @@ -4,12 +4,14 @@ import * as types from '../mutation_types'; export const getMergeRequestData = ( { commit, dispatch, state }, - { projectId, mergeRequestId, force = false } = {}, + { projectId, mergeRequestId, targetProjectId = null, force = false } = {}, ) => new Promise((resolve, reject) => { if (!state.projects[projectId].mergeRequests[mergeRequestId] || force) { service - .getProjectMergeRequestData(projectId, mergeRequestId, { render_html: true }) + .getProjectMergeRequestData(targetProjectId || projectId, mergeRequestId, { + render_html: true, + }) .then(({ data }) => { commit(types.SET_MERGE_REQUEST, { projectPath: projectId, @@ -38,12 +40,12 @@ export const getMergeRequestData = ( export const getMergeRequestChanges = ( { commit, dispatch, state }, - { projectId, mergeRequestId, force = false } = {}, + { projectId, mergeRequestId, targetProjectId = null, force = false } = {}, ) => new Promise((resolve, reject) => { if (!state.projects[projectId].mergeRequests[mergeRequestId].changes.length || force) { service - .getProjectMergeRequestChanges(projectId, mergeRequestId) + .getProjectMergeRequestChanges(targetProjectId || projectId, mergeRequestId) .then(({ data }) => { commit(types.SET_MERGE_REQUEST_CHANGES, { projectPath: projectId, @@ -71,12 +73,12 @@ export const getMergeRequestChanges = ( export const getMergeRequestVersions = ( { commit, dispatch, state }, - { projectId, mergeRequestId, force = false } = {}, + { projectId, mergeRequestId, targetProjectId = null, force = false } = {}, ) => new Promise((resolve, reject) => { if (!state.projects[projectId].mergeRequests[mergeRequestId].versions.length || force) { service - .getProjectMergeRequestVersions(projectId, mergeRequestId) + .getProjectMergeRequestVersions(targetProjectId || projectId, mergeRequestId) .then(res => res.data) .then(data => { commit(types.SET_MERGE_REQUEST_VERSIONS, { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue index c18b74743e4..a3b1e7d1340 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue @@ -43,7 +43,11 @@ export default { return this.isBranchTitleLong(this.mr.targetBranch); }, webIdePath() { - return webIDEUrl(this.mr.statusPath.replace('.json', '')); + return webIDEUrl( + `/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}?target_project=${ + this.mr.targetProjectFullPath + }`, + ); }, }, methods: { diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index c881cd496d1..e84c436905d 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -16,10 +16,11 @@ export default class MergeRequestStore { const pipelineStatus = data.pipeline ? data.pipeline.details.status : null; this.squash = data.squash; - this.squashBeforeMergeHelpPath = this.squashBeforeMergeHelpPath || - data.squash_before_merge_help_path; + this.squashBeforeMergeHelpPath = + this.squashBeforeMergeHelpPath || data.squash_before_merge_help_path; this.enableSquashBeforeMerge = this.enableSquashBeforeMerge || true; + this.iid = data.iid; this.title = data.title; this.targetBranch = data.target_branch; this.sourceBranch = data.source_branch; @@ -85,6 +86,8 @@ export default class MergeRequestStore { this.isMergeAllowed = data.mergeable || false; this.mergeOngoing = data.merge_ongoing; this.allowCollaboration = data.allow_collaboration; + this.targetProjectFullPath = data.target_project_full_path; + this.sourceProjectFullPath = data.source_project_full_path; // Cherry-pick and Revert actions related this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false; @@ -97,7 +100,8 @@ export default class MergeRequestStore { this.hasCI = data.has_ci; this.ciStatus = data.ci_status; this.isPipelineFailed = this.ciStatus === 'failed' || this.ciStatus === 'canceled'; - this.isPipelinePassing = this.ciStatus === 'success' || this.ciStatus === 'success_with_warnings'; + this.isPipelinePassing = + this.ciStatus === 'success' || this.ciStatus === 'success_with_warnings'; this.isPipelineSkipped = this.ciStatus === 'skipped'; this.pipelineDetailedStatus = pipelineStatus; this.isPipelineActive = data.pipeline ? data.pipeline.active : false; diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb index 5d72ebdd7fd..a78bd77cf7c 100644 --- a/app/serializers/merge_request_widget_entity.rb +++ b/app/serializers/merge_request_widget_entity.rb @@ -10,9 +10,15 @@ class MergeRequestWidgetEntity < IssuableEntity expose :merge_when_pipeline_succeeds expose :source_branch expose :source_project_id + expose :source_project_full_path do |merge_request| + merge_request.source_project&.full_path + end expose :squash expose :target_branch expose :target_project_id + expose :target_project_full_path do |merge_request| + merge_request.project&.full_path + end expose :allow_collaboration expose :should_be_rebased?, as: :should_be_rebased diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json index 38ce92a5dc7..3b741d51598 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_widget.json +++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json @@ -29,8 +29,10 @@ "merge_when_pipeline_succeeds": { "type": "boolean" }, "source_branch": { "type": "string" }, "source_project_id": { "type": "integer" }, + "source_project_full_path": { "type": ["string", "null"]}, "target_branch": { "type": "string" }, "target_project_id": { "type": "integer" }, + "target_project_full_path": { "type": ["string", "null"]}, "allow_collaboration": { "type": "boolean"}, "metrics": { "oneOf": [ diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js index 9d2a15ff009..c0b5a7d4455 100644 --- a/spec/javascripts/vue_mr_widget/mock_data.js +++ b/spec/javascripts/vue_mr_widget/mock_data.js @@ -29,8 +29,10 @@ export default { source_branch: 'daaaa', source_branch_link: 'daaaa', source_project_id: 19, + source_project_full_path: '/group1/project1', target_branch: 'master', target_project_id: 19, + target_project_full_path: '/group2/project2', metrics: { merged_by: { name: 'Administrator', diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb index d2072198d83..0ba2539a717 100644 --- a/spec/serializers/merge_request_widget_entity_spec.rb +++ b/spec/serializers/merge_request_widget_entity_spec.rb @@ -11,6 +11,21 @@ describe MergeRequestWidgetEntity do described_class.new(resource, request: request).as_json end + describe 'source_project_full_path' do + it 'includes the full path of the source project' do + expect(subject[:source_project_full_path]).to be_present + end + + context 'when the source project is missing' do + it 'returns `nil` for the source project' do + resource.allow_broken = true + resource.update!(source_project: nil) + + expect(subject[:source_project_full_path]).to be_nil + end + end + end + describe 'pipeline' do let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.source_branch, sha: resource.source_branch_sha, head_pipeline_of: resource) } -- cgit v1.2.1 From b7ffc097fbb61972e150a6d48cbe9e5194aed11b Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 11 Jul 2018 17:26:00 +0200 Subject: Allow collaboration with forks through the API These APIs are used by the web IDE. They need to be on par with git & web access, allowing edits from maintainers to forks with merge requests that allow access. --- lib/api/commits.rb | 16 ++++++- spec/requests/api/commits_spec.rb | 54 +++++++++++++++++++++- .../merge_requests_allowing_collaboration.rb | 15 ++++++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 spec/support/shared_contexts/merge_requests_allowing_collaboration.rb diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 964780cba6a..92329465b2c 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -6,6 +6,18 @@ module API before { authorize! :download_code, user_project } + helpers do + def user_access + @user_access ||= Gitlab::UserAccess.new(current_user, project: user_project) + end + + def authorize_push_to_branch!(branch) + unless user_access.can_push_to_branch?(branch) + forbidden!("You are not allowed to push into this branch") + end + end + end + params do requires :id, type: String, desc: 'The ID of a project' end @@ -67,7 +79,7 @@ module API optional :author_name, type: String, desc: 'Author name for commit' end post ':id/repository/commits' do - authorize! :push_code, user_project + authorize_push_to_branch!(params[:branch]) attrs = declared_params attrs[:branch_name] = attrs.delete(:branch) @@ -142,7 +154,7 @@ module API requires :branch, type: String, desc: 'The name of the branch' end post ':id/repository/commits/:sha/cherry_pick', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do - authorize! :push_code, user_project + authorize_push_to_branch!(params[:branch]) commit = user_project.commit(params[:sha]) not_found!('Commit') unless commit diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 113703fac38..246947e58a8 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -514,6 +514,38 @@ describe API::Commits do expect(response).to have_gitlab_http_status(400) end end + + context 'when committing into a fork as a maintainer' do + include_context 'merge request allowing collaboration' + + let(:project_id) { forked_project.id } + + def push_params(branch_name) + { + branch: branch_name, + commit_message: 'Hello world', + actions: [ + { + action: 'create', + file_path: 'foo/bar/baz.txt', + content: 'puts 8' + } + ] + } + end + + it 'allows pushing to the source branch of the merge request' do + post api(url, user), push_params('feature') + + expect(response).to have_gitlab_http_status(:created) + end + + it 'denies pushing to another branch' do + post api(url, user), push_params('other-branch') + + expect(response).to have_gitlab_http_status(:forbidden) + end + end end describe 'GET /projects/:id/repository/commits/:sha/refs' do @@ -1065,11 +1097,29 @@ describe API::Commits do it 'returns 400 if you are not allowed to push to the target branch' do post api(route, current_user), branch: 'feature' - expect(response).to have_gitlab_http_status(400) - expect(json_response['message']).to eq('You are not allowed to push into this branch') + expect(response).to have_gitlab_http_status(:forbidden) + expect(json_response['message']).to match(/You are not allowed to push into this branch/) end end end + + context 'when cherry picking to a fork as a maintainer' do + include_context 'merge request allowing collaboration' + + let(:project_id) { forked_project.id } + + it 'allows access from a maintainer that to the source branch' do + post api(route, user), branch: 'feature' + + expect(response).to have_gitlab_http_status(:created) + end + + it 'denies cherry picking to another branch' do + post api(route, user), branch: 'master' + + expect(response).to have_gitlab_http_status(:forbidden) + end + end end describe 'POST /projects/:id/repository/commits/:sha/comments' do diff --git a/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb new file mode 100644 index 00000000000..05424d08b9d --- /dev/null +++ b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb @@ -0,0 +1,15 @@ +shared_context 'merge request allowing collaboration' do + include ProjectForksHelper + + let(:canonical) { create(:project, :public, :repository) } + let(:forked_project) { fork_project(canonical, nil, repository: true) } + + before do + canonical.add_maintainer(user) + create(:merge_request, + target_project: canonical, + source_project: forked_project, + source_branch: 'feature', + allow_collaboration: true) + end +end -- cgit v1.2.1 From e270366d844d27ba55b96fb589b8505502c76a08 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 12 Jul 2018 12:22:11 +0200 Subject: Rename environments stop action method This makes it more explicit that an environment is not a stop action, but instead is merely contains a stop action. --- app/models/environment.rb | 2 +- app/policies/environment_policy.rb | 5 +++-- app/serializers/environment_entity.rb | 2 +- app/services/ci/stop_environments_service.rb | 2 +- app/views/projects/environments/show.html.haml | 2 +- spec/javascripts/environments/environment_item_spec.js | 2 +- spec/javascripts/environments/mock_data.js | 12 ++++++------ spec/models/environment_spec.rb | 17 +++++++++++++---- 8 files changed, 27 insertions(+), 17 deletions(-) diff --git a/app/models/environment.rb b/app/models/environment.rb index 8d523dae324..4856d313318 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -117,7 +117,7 @@ class Environment < ActiveRecord::Base external_url.gsub(%r{\A.*?://}, '') end - def stop_action? + def stop_action_available? available? && stop_action.present? end diff --git a/app/policies/environment_policy.rb b/app/policies/environment_policy.rb index 978dc3a7c81..2d07311db72 100644 --- a/app/policies/environment_policy.rb +++ b/app/policies/environment_policy.rb @@ -2,11 +2,12 @@ class EnvironmentPolicy < BasePolicy delegate { @subject.project } condition(:stop_with_deployment_allowed) do - @subject.stop_action? && can?(:create_deployment) && can?(:update_build, @subject.stop_action) + @subject.stop_action_available? && + can?(:create_deployment) && can?(:update_build, @subject.stop_action) end condition(:stop_with_update_allowed) do - !@subject.stop_action? && can?(:update_environment, @subject) + !@subject.stop_action_available? && can?(:update_environment, @subject) end rule { stop_with_deployment_allowed | stop_with_update_allowed }.enable :stop_environment diff --git a/app/serializers/environment_entity.rb b/app/serializers/environment_entity.rb index 0fc3f92b151..83558fc6659 100644 --- a/app/serializers/environment_entity.rb +++ b/app/serializers/environment_entity.rb @@ -7,7 +7,7 @@ class EnvironmentEntity < Grape::Entity expose :external_url expose :environment_type expose :last_deployment, using: DeploymentEntity - expose :stop_action?, as: :has_stop_action + expose :stop_action_available?, as: :has_stop_action expose :metrics_path, if: -> (environment, _) { environment.has_metrics? } do |environment| metrics_project_environment_path(environment.project, environment) diff --git a/app/services/ci/stop_environments_service.rb b/app/services/ci/stop_environments_service.rb index 43c9a065fcf..439746e82bd 100644 --- a/app/services/ci/stop_environments_service.rb +++ b/app/services/ci/stop_environments_service.rb @@ -8,7 +8,7 @@ module Ci return unless @ref.present? environments.each do |environment| - next unless environment.stop_action? + next unless environment.stop_action_available? next unless can?(current_user, :stop_environment, environment) environment.stop_with_action!(current_user) diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml index a33bc9d4ce6..c7890b37381 100644 --- a/app/views/projects/environments/show.html.haml +++ b/app/views/projects/environments/show.html.haml @@ -16,7 +16,7 @@ ? .modal-body %p= s_('Environments|Are you sure you want to stop this environment?') - - unless @environment.stop_action? + - unless @environment.stop_action_available? .warning_message %p= s_('Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file.').html_safe % { emphasis_start: ''.html_safe, emphasis_end: ''.html_safe, diff --git a/spec/javascripts/environments/environment_item_spec.js b/spec/javascripts/environments/environment_item_spec.js index 7a34126eef7..0b933dda431 100644 --- a/spec/javascripts/environments/environment_item_spec.js +++ b/spec/javascripts/environments/environment_item_spec.js @@ -104,7 +104,7 @@ describe('Environment item', () => { }, ], }, - 'stop_action?': true, + has_stop_action: true, environment_path: 'root/ci-folders/environments/31', created_at: '2016-11-07T11:11:16.525Z', updated_at: '2016-11-10T15:55:58.778Z', diff --git a/spec/javascripts/environments/mock_data.js b/spec/javascripts/environments/mock_data.js index 8a1e26935d9..7bb57f938b8 100644 --- a/spec/javascripts/environments/mock_data.js +++ b/spec/javascripts/environments/mock_data.js @@ -7,7 +7,7 @@ export const environmentsList = [ external_url: null, environment_type: null, last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/7', stop_path: '/root/review-app/environments/7/stop', created_at: '2017-01-31T10:53:46.894Z', @@ -22,7 +22,7 @@ export const environmentsList = [ external_url: null, environment_type: 'build', last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/12', stop_path: '/root/review-app/environments/12/stop', created_at: '2017-02-01T19:42:18.400Z', @@ -41,7 +41,7 @@ export const serverData = [ external_url: null, environment_type: null, last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/7', stop_path: '/root/review-app/environments/7/stop', created_at: '2017-01-31T10:53:46.894Z', @@ -58,7 +58,7 @@ export const serverData = [ external_url: null, environment_type: 'build', last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/12', stop_path: '/root/review-app/environments/12/stop', created_at: '2017-02-01T19:42:18.400Z', @@ -77,7 +77,7 @@ export const environment = { external_url: null, environment_type: null, last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/7', stop_path: '/root/review-app/environments/7/stop', created_at: '2017-01-31T10:53:46.894Z', @@ -95,7 +95,7 @@ export const folder = { external_url: null, environment_type: 'build', last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/12', stop_path: '/root/review-app/environments/12/stop', created_at: '2017-02-01T19:42:18.400Z', diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 4bded9efe91..c65e0b81451 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -170,8 +170,8 @@ describe Environment do end end - describe '#stop_action?' do - subject { environment.stop_action? } + describe '#stop_action_available?' do + subject { environment.stop_action_available? } context 'when no other actions' do it { is_expected.to be_falsey } @@ -179,8 +179,17 @@ describe Environment do context 'when matching action is defined' do let(:build) { create(:ci_build) } - let!(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } - let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') } + + let!(:deployment) do + create(:deployment, environment: environment, + deployable: build, + on_stop: 'close_app') + end + + let!(:close_action) do + create(:ci_build, :manual, pipeline: build.pipeline, + name: 'close_app') + end context 'when environment is available' do before do -- cgit v1.2.1 From af00a1591412655202a634fbca999b80b97a676e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 12 Jul 2018 12:31:33 +0200 Subject: Remove unused `stop_action?` method from deployment class --- app/models/deployment.rb | 4 ---- spec/models/deployment_spec.rb | 18 ------------------ 2 files changed, 22 deletions(-) diff --git a/app/models/deployment.rb b/app/models/deployment.rb index ac86e9e8de0..687246b47b2 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -92,10 +92,6 @@ class Deployment < ActiveRecord::Base @stop_action ||= manual_actions.find_by(name: on_stop) end - def stop_action? - stop_action.present? - end - def formatted_deployment_time created_at.to_time.in_time_zone.to_s(:medium) end diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index e01906f4b6c..b335e0fbeb3 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -157,22 +157,4 @@ describe Deployment do end end end - - describe '#stop_action?' do - subject { deployment.stop_action? } - - context 'when no other actions' do - let(:deployment) { build(:deployment) } - - it { is_expected.to be_falsey } - end - - context 'when matching action is defined' do - let(:build) { create(:ci_build) } - let(:deployment) { FactoryBot.build(:deployment, deployable: build, on_stop: 'close_app') } - let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') } - - it { is_expected.to be_truthy } - end - end end -- cgit v1.2.1 From c2d297d97a62ddbde0ffcab3a69662684d60f8aa Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 12 Jul 2018 12:53:57 +0200 Subject: update saver spec to use the old uploads code --- spec/lib/gitlab/import_export/uploads_saver_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/lib/gitlab/import_export/uploads_saver_spec.rb b/spec/lib/gitlab/import_export/uploads_saver_spec.rb index 24993460e51..c716edd9397 100644 --- a/spec/lib/gitlab/import_export/uploads_saver_spec.rb +++ b/spec/lib/gitlab/import_export/uploads_saver_spec.rb @@ -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 -- cgit v1.2.1 From 246ac064229be24c9f28a3781bc6182cffc221b6 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 12 Jul 2018 16:05:06 +0100 Subject: fixed karma specs --- .../vue_mr_widget/components/mr_widget_header_spec.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js index 61b7bd2c226..e73f74c5bc1 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js @@ -119,6 +119,7 @@ describe('MRWidgetHeader', () => { beforeEach(() => { vm = mountComponent(Component, { mr: { + iid: 1, divergedCommitsCount: 12, sourceBranch: 'mr-widget-refactor', sourceBranchLink: 'mr-widget-refactor', @@ -130,6 +131,8 @@ describe('MRWidgetHeader', () => { emailPatchesPath: '/mr/email-patches', plainDiffPath: '/mr/plainDiffPath', statusPath: 'abc', + sourceProjectFullPath: 'root/gitlab-ce', + targetProjectFullPath: 'gitlab-org/gitlab-ce', }, }); }); @@ -146,7 +149,9 @@ describe('MRWidgetHeader', () => { const button = vm.$el.querySelector('.js-web-ide'); expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.getAttribute('href')).toEqual('/-/ide/projectabc'); + expect(button.getAttribute('href')).toEqual( + '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=gitlab-org/gitlab-ce', + ); }); it('renders web ide button with relative URL', () => { @@ -155,7 +160,9 @@ describe('MRWidgetHeader', () => { const button = vm.$el.querySelector('.js-web-ide'); expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.getAttribute('href')).toEqual('/-/ide/projectabc'); + expect(button.getAttribute('href')).toEqual( + '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=gitlab-org/gitlab-ce', + ); }); it('renders download dropdown with links', () => { -- cgit v1.2.1 From 926ba6e5fab25a1f4aaff18ca6d2a846e502d038 Mon Sep 17 00:00:00 2001 From: Tao Wang Date: Tue, 12 Jun 2018 19:47:43 +1000 Subject: i18n: externalize strings from 'app/views/doorkeeper' Signed-off-by: Tao Wang --- .../doorkeeper/applications/_delete_form.html.haml | 6 +- app/views/doorkeeper/applications/_form.html.haml | 8 +- app/views/doorkeeper/applications/edit.html.haml | 4 +- app/views/doorkeeper/applications/index.html.haml | 35 ++++--- app/views/doorkeeper/applications/new.html.haml | 4 +- app/views/doorkeeper/applications/show.html.haml | 14 +-- .../doorkeeper/authorizations/error.html.haml | 2 +- app/views/doorkeeper/authorizations/new.html.haml | 28 ++---- app/views/doorkeeper/authorizations/show.html.haml | 2 +- .../authorized_applications/_delete_form.html.haml | 2 +- .../authorized_applications/index.html.haml | 6 +- locale/gitlab.pot | 111 +++++++++++++++++++++ qa/qa/page/main/oauth.rb | 2 +- 13 files changed, 163 insertions(+), 61 deletions(-) diff --git a/app/views/doorkeeper/applications/_delete_form.html.haml b/app/views/doorkeeper/applications/_delete_form.html.haml index 84b4ce5b606..ac5cac50699 100644 --- a/app/views/doorkeeper/applications/_delete_form.html.haml +++ b/app/views/doorkeeper/applications/_delete_form.html.haml @@ -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 diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml index be0935b8313..1ddd0df54cd 100644 --- a/app/views/doorkeeper/applications/_form.html.haml +++ b/app/views/doorkeeper/applications/_form.html.haml @@ -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 %{native_redirect_uri} 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" diff --git a/app/views/doorkeeper/applications/edit.html.haml b/app/views/doorkeeper/applications/edit.html.haml index 49f90298a50..aad4200f240 100644 --- a/app/views/doorkeeper/applications/edit.html.haml +++ b/app/views/doorkeeper/applications/edit.html.haml @@ -1,4 +1,4 @@ -- 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 diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml index cdf3ff81bd9..ab3a1b100ce 100644 --- a/app/views/doorkeeper/applications/index.html.haml +++ b/app/views/doorkeeper/applications/index.html.haml @@ -1,4 +1,4 @@ -- 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") diff --git a/app/views/doorkeeper/applications/new.html.haml b/app/views/doorkeeper/applications/new.html.haml index d3692d1f759..a66fab20d7c 100644 --- a/app/views/doorkeeper/applications/new.html.haml +++ b/app/views/doorkeeper/applications/new.html.haml @@ -1,6 +1,6 @@ -- page_title "New Application" +- page_title _("New Application") -%h3.page-title New Application +%h3.page-title= _("New Application") %hr diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml index 89ad626f73f..bb76ac6d5f6 100644 --- a/app/views/doorkeeper/applications/show.html.haml +++ b/app/views/doorkeeper/applications/show.html.haml @@ -1,27 +1,27 @@ -- 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' diff --git a/app/views/doorkeeper/authorizations/error.html.haml b/app/views/doorkeeper/authorizations/error.html.haml index 6117b00149f..32b4ccb0fe6 100644 --- a/app/views/doorkeeper/authorizations/error.html.haml +++ b/app/views/doorkeeper/authorizations/error.html.haml @@ -1,3 +1,3 @@ -%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] diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml index 28cdc7607e0..ca62a59d909 100644 --- a/app/views/doorkeeper/authorizations/new.html.haml +++ b/app/views/doorkeeper/authorizations/new.html.haml @@ -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 %{client_name} 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" diff --git a/app/views/doorkeeper/authorizations/show.html.haml b/app/views/doorkeeper/authorizations/show.html.haml index 44e868e6782..e4bfd69e7f8 100644 --- a/app/views/doorkeeper/authorizations/show.html.haml +++ b/app/views/doorkeeper/authorizations/show.html.haml @@ -1,3 +1,3 @@ -%h3.page-title Authorization code: +%h3.page-title= _("Authorization code:") %main{ :role => "main" } %code#authorization_code= params[:code] diff --git a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml index 11c1e67878e..08f2442f025 100644 --- a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml +++ b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml @@ -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' diff --git a/app/views/doorkeeper/authorized_applications/index.html.haml b/app/views/doorkeeper/authorized_applications/index.html.haml index 30c9d02b72e..8e73298b250 100644 --- a/app/views/doorkeeper/authorized_applications/index.html.haml +++ b/app/views/doorkeeper/authorized_applications/index.html.haml @@ -1,12 +1,12 @@ %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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ab488218288..1e7e9aa7405 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -280,6 +280,9 @@ msgstr "" msgid "Add Readme" msgstr "" +msgid "Add new application" +msgstr "" + msgid "Add new directory" msgstr "" @@ -379,9 +382,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 repo 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 "" @@ -475,12 +484,24 @@ msgstr "" msgid "An error occurred. Please try again." msgstr "" +msgid "Anonymous" +msgstr "" + msgid "Any" msgstr "" msgid "Appearance" msgstr "" +msgid "Application" +msgstr "" + +msgid "Application Id" +msgstr "" + +msgid "Application: %{name}" +msgstr "" + msgid "Applications" msgstr "" @@ -562,6 +583,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 "" @@ -921,6 +960,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 "" @@ -1104,6 +1149,9 @@ msgstr "" msgid "Click to expand text" msgstr "" +msgid "Clients" +msgstr "" + msgid "Clone repository" msgstr "" @@ -1768,6 +1816,9 @@ msgstr "" msgid "Created" msgstr "" +msgid "Created At" +msgstr "" + msgid "Created by me" msgstr "" @@ -1846,6 +1897,9 @@ msgstr "" msgid "Delete list" msgstr "" +msgid "Deny" +msgstr "" + msgid "Deploy" msgid_plural "Deploys" msgstr[0] "" @@ -1983,6 +2037,9 @@ msgstr "" msgid "Description:" msgstr "" +msgid "Destroy" +msgstr "" + msgid "Details" msgstr "" @@ -2076,6 +2133,9 @@ msgstr "" msgid "Edit Snippet" msgstr "" +msgid "Edit application" +msgstr "" + msgid "Edit files in the editor and commit changes here" msgstr "" @@ -2940,6 +3000,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 "" @@ -3141,6 +3207,9 @@ msgstr "" msgid "New" msgstr "" +msgid "New Application" +msgstr "" + msgid "New Group" msgstr "" @@ -3620,6 +3689,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 "" @@ -4060,6 +4132,9 @@ msgstr "" msgid "Reviewing (merge request !%{mergeRequestId})" msgstr "" +msgid "Revoke" +msgstr "" + msgid "Runner token" msgstr "" @@ -4084,6 +4159,9 @@ msgstr "" msgid "Save" msgstr "" +msgid "Save application" +msgstr "" + msgid "Save changes" msgstr "" @@ -4105,6 +4183,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "" +msgid "Scope" +msgstr "" + msgid "Scroll to bottom" msgstr "" @@ -4144,6 +4225,9 @@ msgstr "" msgid "Seconds to wait for a storage access attempt" msgstr "" +msgid "Secret:" +msgstr "" + msgid "Select" msgstr "" @@ -4730,6 +4814,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 diff is collapsed." msgstr "" @@ -5126,9 +5216,15 @@ msgstr "" msgid "Usage statistics" msgstr "" +msgid "Use %{native_redirect_uri} for local tests" +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 "" @@ -5369,6 +5465,9 @@ msgstr "" msgid "Yes, add it" msgstr "" +msgid "You are an admin, which means granting access to %{client_name} 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 "" @@ -5420,6 +5519,12 @@ msgstr "" msgid "You do not have any assigned merge requests" msgstr "" +msgid "You don't have any applications" +msgstr "" + +msgid "You don't have any authorized applications" +msgstr "" + msgid "You have no permissions" msgstr "" @@ -5486,6 +5591,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 "" diff --git a/qa/qa/page/main/oauth.rb b/qa/qa/page/main/oauth.rb index 6f548148363..618f114e058 100644 --- a/qa/qa/page/main/oauth.rb +++ b/qa/qa/page/main/oauth.rb @@ -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? -- cgit v1.2.1 From 9265e7692033c8a38ade4e31281613e3fb299611 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Fri, 13 Jul 2018 05:08:45 +0200 Subject: Use the correct exceptions to look for invalid YAML in Changelogs --- danger/changelog/Dangerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/danger/changelog/Dangerfile b/danger/changelog/Dangerfile index 2424e650d07..0374de24520 100644 --- a/danger/changelog/Dangerfile +++ b/danger/changelog/Dangerfile @@ -38,12 +38,14 @@ def check_changelog(path) if yaml["merge_request"].nil? message "Consider setting `merge_request` to #{gitlab.mr_json["iid"]} in #{gitlab.html_link(path)}. #{SEE_DOC}" - elsif yaml["merge_request"] != gitlab.mr_json["iid"] && !ce_port_changelog?(changelog_path) + elsif yaml["merge_request"] != gitlab.mr_json["iid"] && !ce_port_changelog?(path) fail "Merge request ID was not set to #{gitlab.mr_json["iid"]}! #{SEE_DOC}" end -rescue StandardError +rescue Psych::SyntaxError, Psych::DisallowedClass, Psych::BadAlias # YAML could not be parsed, fail the build. fail "#{gitlab.html_link(path)} isn't valid YAML! #{SEE_DOC}" +rescue StandardError => e + warn "There was a problem trying to check the Changelog. Exception: #{e.name} - #{e.message}" end def presented_no_changelog_labels -- cgit v1.2.1 From 9b9cbb4a1a046d4aa04af94373216fa8fdba79db Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 13 Jul 2018 09:13:36 +0100 Subject: fixed test to correctly text relative URLs doesnt add query param if source & target projects match --- .../components/mr_widget_header.vue | 11 ++++--- .../components/mr_widget_header_spec.js | 34 +++++++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue index a3b1e7d1340..a4c2289c590 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue @@ -1,7 +1,7 @@