From 2845e8d9736b82c89ef33a3dd24caa4f9816b0e6 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Thu, 11 Apr 2019 15:03:02 +0100 Subject: [PATCH] Revert "Revert "Merge branch '24704-download-repository-path' into 'master'"" This reverts commit 171818df0a72097aa1a804c8213666b3f66b0966. --- .../stylesheets/framework/dropdowns.scss | 6 ++- .../projects/repositories_controller.rb | 2 +- app/helpers/projects_helper.rb | 4 ++ app/models/repository.rb | 5 ++- .../projects/buttons/_download.html.haml | 36 ++++++----------- .../buttons/_download_links.html.haml | 9 +++++ .../24704-download-repository-path.yml | 5 +++ .../repository/img/download_source_code.png | Bin 0 -> 61467 bytes doc/user/project/repository/index.md | 20 +++++++++ lib/gitlab/git/repository.rb | 7 ++-- lib/gitlab/workhorse.rb | 38 ++++++++++++++++-- locale/gitlab.pot | 16 +++----- .../branches/download_buttons_spec.rb | 2 +- .../projects/files/download_buttons_spec.rb | 2 +- .../projects/show/download_buttons_spec.rb | 3 +- .../projects/tags/download_buttons_spec.rb | 2 +- spec/lib/gitlab/git/repository_spec.rb | 11 ++++- spec/lib/gitlab/workhorse_spec.rb | 31 ++++++++------ 18 files changed, 136 insertions(+), 63 deletions(-) create mode 100644 app/views/projects/buttons/_download_links.html.haml create mode 100644 changelogs/unreleased/24704-download-repository-path.yml create mode 100644 doc/user/project/repository/img/download_source_code.png diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index b90db135b4a..efcd35a2e0e 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -287,7 +287,7 @@ list-style: none; padding: 0 1px; - a, + a:not(.btn), button, .menu-item { @include dropdown-link; @@ -351,6 +351,10 @@ // Expects up to 3 digits on the badge margin-right: 40px; } + + .dropdown-menu-content { + padding: $dropdown-item-padding-y $dropdown-item-padding-x; + } } .droplab-dropdown { diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb index 4eeaeb860ee..3b4215b766e 100644 --- a/app/controllers/projects/repositories_controller.rb +++ b/app/controllers/projects/repositories_controller.rb @@ -23,7 +23,7 @@ class Projects::RepositoriesController < Projects::ApplicationController append_sha = false if @filename == shortname end - send_git_archive @repository, ref: @ref, format: params[:format], append_sha: append_sha + send_git_archive @repository, ref: @ref, path: params[:path], format: params[:format], append_sha: append_sha rescue => ex logger.error("#{self.class.name}: #{ex}") git_not_found! diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 7da51da8473..2ac90eb8d9f 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -299,6 +299,10 @@ module ProjectsHelper }.to_json end + def directory? + @path.present? + end + def external_classification_label_help_message default_label = ::Gitlab::CurrentSettings.current_application_settings .external_authorization_service_default_label diff --git a/app/models/repository.rb b/app/models/repository.rb index 574ce12b309..51ab2247a03 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -299,13 +299,14 @@ class Repository end end - def archive_metadata(ref, storage_path, format = "tar.gz", append_sha:) + def archive_metadata(ref, storage_path, format = "tar.gz", append_sha:, path: nil) raw_repository.archive_metadata( ref, storage_path, project.path, format, - append_sha: append_sha + append_sha: append_sha, + path: path ) end diff --git a/app/views/projects/buttons/_download.html.haml b/app/views/projects/buttons/_download.html.haml index 4eb53faa6ff..acd63de2277 100644 --- a/app/views/projects/buttons/_download.html.haml +++ b/app/views/projects/buttons/_download.html.haml @@ -8,30 +8,20 @@ %span.sr-only= _('Select Archive Format') = sprite_icon("arrow-down") %ul.dropdown-menu.dropdown-menu-right{ role: 'menu' } - %li.dropdown-header - #{ _('Source code') } - %li - = link_to project_archive_path(project, id: tree_join(ref, archive_prefix), format: 'zip'), rel: 'nofollow', download: '' do - %span= _('Download zip') - %li - = link_to project_archive_path(project, id: tree_join(ref, archive_prefix), format: 'tar.gz'), rel: 'nofollow', download: '' do - %span= _('Download tar.gz') - %li - = link_to project_archive_path(project, id: tree_join(ref, archive_prefix), format: 'tar.bz2'), rel: 'nofollow', download: '' do - %span= _('Download tar.bz2') - %li - = link_to project_archive_path(project, id: tree_join(ref, archive_prefix), format: 'tar'), rel: 'nofollow', download: '' do - %span= _('Download tar') - + %li.dropdown-bold-header= _('Download source code') + %li.dropdown-menu-content + = render 'projects/buttons/download_links', project: project, ref: ref, archive_prefix: archive_prefix, path: nil + - if directory? + %li.separator + %li.dropdown-bold-header= _('Download this directory') + %li.dropdown-menu-content + = render 'projects/buttons/download_links', project: project, ref: ref, archive_prefix: archive_prefix, path: @path - if pipeline && pipeline.latest_builds_with_artifacts.any? - %li.dropdown-header Artifacts + %li.separator + %li.dropdown-bold-header= _('Download artifacts') - unless pipeline.latest? - - latest_pipeline = project.pipeline_for(ref) - %li - .unclickable= ci_status_for_statuseable(latest_pipeline) - %li.dropdown-header Previous Artifacts + %span.unclickable= ci_status_for_statuseable(project.pipeline_for(ref)) + %li.dropdown-header= _('Previous Artifacts') - pipeline.latest_builds_with_artifacts.each do |job| %li - = link_to latest_succeeded_project_artifacts_path(project, "#{ref}/download", job: job.name), rel: 'nofollow', download: '' do - %span - #{s_('DownloadArtifacts|Download')} '#{job.name}' + = link_to job.name, latest_succeeded_project_artifacts_path(project, "#{ref}/download", job: job.name), rel: 'nofollow', download: '' diff --git a/app/views/projects/buttons/_download_links.html.haml b/app/views/projects/buttons/_download_links.html.haml new file mode 100644 index 00000000000..47a1704f946 --- /dev/null +++ b/app/views/projects/buttons/_download_links.html.haml @@ -0,0 +1,9 @@ +%ul + %li.d-inline-block.m-0.p-0 + = link_to 'zip', project_archive_path(project, id: tree_join(ref, archive_prefix), path: path, format: 'zip'), rel: 'nofollow', download: '', class: 'btn btn-primary btn-xs' + %li.d-inline-block.m-0.p-0 + = link_to 'tar.gz', project_archive_path(project, id: tree_join(ref, archive_prefix), path: path, format: 'tar.gz'), rel: 'nofollow', download: '', class: 'btn btn-xs' + %li.d-inline-block.m-0.p-0 + = link_to 'tar.bz2', project_archive_path(project, id: tree_join(ref, archive_prefix), path: path, format: 'tar.bz2'), rel: 'nofollow', download: '', class: 'btn btn-xs' + %li.d-inline-block.m-0.p-0 + = link_to 'tar', project_archive_path(project, id: tree_join(ref, archive_prefix), path: path, format: 'tar'), rel: 'nofollow', download: '', class: 'btn btn-xs' diff --git a/changelogs/unreleased/24704-download-repository-path.yml b/changelogs/unreleased/24704-download-repository-path.yml new file mode 100644 index 00000000000..ff3082bec45 --- /dev/null +++ b/changelogs/unreleased/24704-download-repository-path.yml @@ -0,0 +1,5 @@ +--- +title: Download a folder from repository +merge_request: 26532 +author: kiameisomabes +type: added diff --git a/doc/user/project/repository/img/download_source_code.png b/doc/user/project/repository/img/download_source_code.png new file mode 100644 index 0000000000000000000000000000000000000000..17f2cb4b3e894d7e4908399d2a0d7977490a9184 GIT binary patch literal 61467 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 rtoLzJahkkUQE^i1; [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/24704) in GitLab 11.10 + + Only shows up when viewing a sub-directory. This allows users to download + the specific directory they're currently viewing. Also available in zip, tar, + tar.gz and tar.bz2. +- **Artifacts:** + This allows users to download the artifacts of the latest CI build. + [jupyter]: https://jupyter.org diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index be9e926728c..a22e3c4b9dd 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -231,12 +231,12 @@ module Gitlab end end - def archive_metadata(ref, storage_path, project_path, format = "tar.gz", append_sha:) + def archive_metadata(ref, storage_path, project_path, format = "tar.gz", append_sha:, path: nil) ref ||= root_ref commit = Gitlab::Git::Commit.find(self, ref) return {} if commit.nil? - prefix = archive_prefix(ref, commit.id, project_path, append_sha: append_sha) + prefix = archive_prefix(ref, commit.id, project_path, append_sha: append_sha, path: path) { 'ArchivePrefix' => prefix, @@ -248,13 +248,14 @@ module Gitlab # This is both the filename of the archive (missing the extension) and the # name of the top-level member of the archive under which all files go - def archive_prefix(ref, sha, project_path, append_sha:) + def archive_prefix(ref, sha, project_path, append_sha:, path:) append_sha = (ref != sha) if append_sha.nil? formatted_ref = ref.tr('/', '-') prefix_segments = [project_path, formatted_ref] prefix_segments << sha if append_sha + prefix_segments << path.tr('/', '-').gsub(%r{^/|/$}, '') if path prefix_segments.join('-') end diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 0c2acac3d1e..533757d2237 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -63,13 +63,26 @@ module Gitlab ] end - def send_git_archive(repository, ref:, format:, append_sha:) + def send_git_archive(repository, ref:, format:, append_sha:, path: nil) format ||= 'tar.gz' format = format.downcase - params = repository.archive_metadata(ref, Gitlab.config.gitlab.repository_downloads_path, format, append_sha: append_sha) - raise "Repository or ref not found" if params.empty? + metadata = repository.archive_metadata(ref, Gitlab.config.gitlab.repository_downloads_path, format, append_sha: append_sha, path: path) - params['GitalyServer'] = gitaly_server_hash(repository) + raise "Repository or ref not found" if metadata.empty? + + params = { + 'GitalyServer' => gitaly_server_hash(repository), + 'ArchivePath' => metadata['ArchivePath'], + 'GetArchiveRequest' => encode_binary( + Gitaly::GetArchiveRequest.new( + repository: repository.gitaly_repository, + commit_id: metadata['CommitId'], + prefix: metadata['ArchivePrefix'], + format: archive_format(format), + path: path.presence || "" + ).to_proto + ) + } # If present DisableCache must be a Boolean. Otherwise workhorse ignores it. params['DisableCache'] = true if git_archive_cache_disabled? @@ -220,6 +233,10 @@ module Gitlab Base64.urlsafe_encode64(JSON.dump(hash)) end + def encode_binary(binary) + Base64.urlsafe_encode64(binary) + end + def gitaly_server_hash(repository) { address: Gitlab::GitalyClient.address(repository.project.repository_storage), @@ -238,6 +255,19 @@ module Gitlab def git_archive_cache_disabled? ENV['WORKHORSE_ARCHIVE_CACHE_DISABLED'].present? || Feature.enabled?(:workhorse_archive_cache_disabled) end + + def archive_format(format) + case format + when "tar.bz2", "tbz", "tbz2", "tb2", "bz2" + Gitaly::GetArchiveRequest::Format::TAR_BZ2 + when "tar" + Gitaly::GetArchiveRequest::Format::TAR + when "zip" + Gitaly::GetArchiveRequest::Format::ZIP + else + Gitaly::GetArchiveRequest::Format::TAR_GZ + end + end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 435f2408a9e..8deca5a94e7 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3289,19 +3289,10 @@ msgstr "" msgid "Download export" msgstr "" -msgid "Download tar" +msgid "Download source code" msgstr "" -msgid "Download tar.bz2" -msgstr "" - -msgid "Download tar.gz" -msgstr "" - -msgid "Download zip" -msgstr "" - -msgid "DownloadArtifacts|Download" +msgid "Download this directory" msgstr "" msgid "DownloadCommit|Email Patches" @@ -6667,6 +6658,9 @@ msgstr "" msgid "Preview payload" msgstr "" +msgid "Previous Artifacts" +msgstr "" + msgid "Prioritize" msgstr "" diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb index c8dc72a34ec..3e75890725e 100644 --- a/spec/features/projects/branches/download_buttons_spec.rb +++ b/spec/features/projects/branches/download_buttons_spec.rb @@ -35,7 +35,7 @@ describe 'Download buttons in branches page' do it 'shows download artifacts button' do href = latest_succeeded_project_artifacts_path(project, 'binary-encoding/download', job: 'build') - expect(page).to have_link "Download '#{build.name}'", href: href + expect(page).to have_link build.name, href: href end end end diff --git a/spec/features/projects/files/download_buttons_spec.rb b/spec/features/projects/files/download_buttons_spec.rb index 03cb3530e2b..111972a6b00 100644 --- a/spec/features/projects/files/download_buttons_spec.rb +++ b/spec/features/projects/files/download_buttons_spec.rb @@ -30,7 +30,7 @@ describe 'Projects > Files > Download buttons in files tree' do it 'shows download artifacts button' do href = latest_succeeded_project_artifacts_path(project, "#{project.default_branch}/download", job: 'build') - expect(page).to have_link "Download '#{build.name}'", href: href + expect(page).to have_link build.name, href: href end end end diff --git a/spec/features/projects/show/download_buttons_spec.rb b/spec/features/projects/show/download_buttons_spec.rb index 3a2dcc5aa55..fee5f8001b0 100644 --- a/spec/features/projects/show/download_buttons_spec.rb +++ b/spec/features/projects/show/download_buttons_spec.rb @@ -35,11 +35,10 @@ describe 'Projects > Show > Download buttons' do it 'shows download artifacts button' do href = latest_succeeded_project_artifacts_path(project, "#{project.default_branch}/download", job: 'build') - expect(page).to have_link "Download '#{build.name}'", href: href + expect(page).to have_link build.name, href: href end it 'download links have download attribute' do - expect(page).to have_selector('a', text: 'Download') page.all('a', text: 'Download').each do |link| expect(link[:download]).to eq '' end diff --git a/spec/features/projects/tags/download_buttons_spec.rb b/spec/features/projects/tags/download_buttons_spec.rb index fbfd8cee7aa..4c8ec53836a 100644 --- a/spec/features/projects/tags/download_buttons_spec.rb +++ b/spec/features/projects/tags/download_buttons_spec.rb @@ -36,7 +36,7 @@ describe 'Download buttons in tags page' do it 'shows download artifacts button' do href = latest_succeeded_project_artifacts_path(project, "#{tag}/download", job: 'build') - expect(page).to have_link "Download '#{build.name}'", href: href + expect(page).to have_link build.name, href: href end end end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 088f8acf554..778950c95e4 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -152,13 +152,14 @@ describe Gitlab::Git::Repository, :seed_helper do let(:append_sha) { true } let(:ref) { 'master' } let(:format) { nil } + let(:path) { nil } let(:expected_extension) { 'tar.gz' } let(:expected_filename) { "#{expected_prefix}.#{expected_extension}" } let(:expected_path) { File.join(storage_path, cache_key, expected_filename) } let(:expected_prefix) { "gitlab-git-test-#{ref}-#{SeedRepo::LastCommit::ID}" } - subject(:metadata) { repository.archive_metadata(ref, storage_path, 'gitlab-git-test', format, append_sha: append_sha) } + subject(:metadata) { repository.archive_metadata(ref, storage_path, 'gitlab-git-test', format, append_sha: append_sha, path: path) } it 'sets CommitId to the commit SHA' do expect(metadata['CommitId']).to eq(SeedRepo::LastCommit::ID) @@ -176,6 +177,14 @@ describe Gitlab::Git::Repository, :seed_helper do expect(metadata['ArchivePath']).to eq(expected_path) end + context 'path is set' do + let(:path) { 'foo/bar' } + + it 'appends the path to the prefix' do + expect(metadata['ArchivePrefix']).to eq("#{expected_prefix}-foo-bar") + end + end + context 'append_sha varies archive path and filename' do where(:append_sha, :ref, :expected_prefix) do sha = SeedRepo::LastCommit::ID diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index d02d9be5c5c..f8ce399287a 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -16,20 +16,12 @@ describe Gitlab::Workhorse do let(:ref) { 'master' } let(:format) { 'zip' } let(:storage_path) { Gitlab.config.gitlab.repository_downloads_path } - let(:base_params) { repository.archive_metadata(ref, storage_path, format, append_sha: nil) } - let(:gitaly_params) do - base_params.merge( - 'GitalyServer' => { - 'address' => Gitlab::GitalyClient.address(project.repository_storage), - 'token' => Gitlab::GitalyClient.token(project.repository_storage) - }, - 'GitalyRepository' => repository.gitaly_repository.to_h.deep_stringify_keys - ) - end + let(:path) { 'some/path' } + let(:metadata) { repository.archive_metadata(ref, storage_path, format, append_sha: nil, path: path) } let(:cache_disabled) { false } subject do - described_class.send_git_archive(repository, ref: ref, format: format, append_sha: nil) + described_class.send_git_archive(repository, ref: ref, format: format, append_sha: nil, path: path) end before do @@ -41,7 +33,22 @@ describe Gitlab::Workhorse do expect(key).to eq('Gitlab-Workhorse-Send-Data') expect(command).to eq('git-archive') - expect(params).to include(gitaly_params) + expect(params).to eq({ + 'GitalyServer' => { + address: Gitlab::GitalyClient.address(project.repository_storage), + token: Gitlab::GitalyClient.token(project.repository_storage) + }, + 'ArchivePath' => metadata['ArchivePath'], + 'GetArchiveRequest' => Base64.urlsafe_encode64( + Gitaly::GetArchiveRequest.new( + repository: repository.gitaly_repository, + commit_id: metadata['CommitId'], + prefix: metadata['ArchivePrefix'], + format: Gitaly::GetArchiveRequest::Format::ZIP, + path: path + ).to_proto + ) + }.deep_stringify_keys) end context 'when archive caching is disabled' do