diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb index 20e2a9311ee..f686db70bd4 100644 --- a/app/controllers/projects/repositories_controller.rb +++ b/app/controllers/projects/repositories_controller.rb @@ -16,7 +16,7 @@ class Projects::RepositoriesController < Projects::ApplicationController storage_path = Rails.root.join("tmp", "repositories") - file_path = @repository.archive_repo(params[:ref], storage_path) + file_path = @repository.archive_repo(params[:ref], storage_path, params[:format].downcase) if file_path # Send file to user diff --git a/config/routes.rb b/config/routes.rb index 8322d6a9d4e..734421ede1d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -217,7 +217,7 @@ Gitlab::Application.routes.draw do resource :repository, only: [:show] do member do get "stats" - get "archive" + get "archive", constraints: { format: Gitlab::Regex.archive_formats_regex } end end diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index 6a9dc9a39f1..0a32135ff10 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -1,3 +1,5 @@ +require 'mime/types' + module API # Projects API class Repositories < Grape::API @@ -206,18 +208,20 @@ module API # sha (optional) - the commit sha to download defaults to the tip of the default branch # Example Request: # GET /projects/:id/repository/archive - get ":id/repository/archive" do + get ":id/repository/archive", requirements: { format: Gitlab::Regex.archive_formats_regex } do authorize! :download_code, user_project repo = user_project.repository ref = params[:sha] + format = params[:format] storage_path = Rails.root.join("tmp", "repositories") - file_path = repo.archive_repo(ref, storage_path) + file_path = repo.archive_repo(ref, storage_path, format) if file_path && File.exists?(file_path) data = File.open(file_path, 'rb').read - header "Content-Disposition:", " infile; filename=\"#{File.basename(file_path)}\"" - content_type 'application/x-gzip' + header["Content-Disposition"] = "attachment; filename=\"#{File.basename(file_path)}\"" + + content_type MIME::Types.type_for(file_path).first.content_type env['api.format'] = :binary diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index 93e013ab1b3..943dc9dc7ea 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -17,6 +17,11 @@ module Gitlab def path_regex default_regex end + + def archive_formats_regex + #|zip|tar| tar.gz | tar.bz2 | + /(zip|tar|tar\.gz|tgz|gz|tar\.bz2|tbz|tbz2|tb2|bz2)/ + end def git_reference_regex # Valid git ref regex, see: diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index e078efcc50a..f73ac4372b2 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'mime/types' describe API::API do include ApiHelpers @@ -232,11 +233,29 @@ describe API::API do end end - describe "GET /projects/:id/repository/archive/:sha" do + describe "GET /projects/:id/repository/archive(.:format)?:sha" do it "should get the archive" do get api("/projects/#{project.id}/repository/archive", user) + repo_name = project.repository.name.gsub("\.git", "") response.status.should == 200 - response.content_type.should == 'application/x-gzip' + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.tar.gz\"/ + response.content_type.should == MIME::Types.type_for('file.tar.gz').first.content_type + end + + it "should get the archive.zip" do + get api("/projects/#{project.id}/repository/archive.zip", user) + repo_name = project.repository.name.gsub("\.git", "") + response.status.should == 200 + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.zip\"/ + response.content_type.should == MIME::Types.type_for('file.zip').first.content_type + end + + it "should get the archive.tar.bz2" do + get api("/projects/#{project.id}/repository/archive.tar.bz2", user) + repo_name = project.repository.name.gsub("\.git", "") + response.status.should == 200 + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.tar.bz2\"/ + response.content_type.should == MIME::Types.type_for('file.tar.bz2').first.content_type end it "should return 404 for invalid sha" do diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 5597f08d186..97f7392e50a 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -130,6 +130,14 @@ describe Projects::RepositoriesController, "routing" do get("/gitlab/gitlabhq/repository/archive").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq') end + it "to #archive format:zip" do + get("/gitlab/gitlabhq/repository/archive.zip").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'zip') + end + + it "to #archive format:tar.bz2" do + get("/gitlab/gitlabhq/repository/archive.tar.bz2").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'tar.bz2') + end + it "to #show" do get("/gitlab/gitlabhq/repository").should route_to('projects/repositories#show', project_id: 'gitlab/gitlabhq') end