Commit 7cc25205410efc6b20b11d94ab2cbc1a322ff816

Authored by Jason Hollingsworth
1 parent b512fbc0

Add support for various archive formats.

Used mime-types gem instead of hardcoding content types.
Allow multiple extensions in archive route (.tar.gz, .tar.bz2).
Change content disposition from infile(?) to attachment for api.
Fixed api would return “archive” instead of {project}-{hash}.{ext}
app/controllers/projects/repositories_controller.rb
... ... @@ -16,7 +16,7 @@ class Projects::RepositoriesController < Projects::ApplicationController
16 16  
17 17 storage_path = Rails.root.join("tmp", "repositories")
18 18  
19   - file_path = @repository.archive_repo(params[:ref], storage_path)
  19 + file_path = @repository.archive_repo(params[:ref], storage_path, params[:format].downcase)
20 20  
21 21 if file_path
22 22 # Send file to user
... ...
config/routes.rb
... ... @@ -217,7 +217,7 @@ Gitlab::Application.routes.draw do
217 217 resource :repository, only: [:show] do
218 218 member do
219 219 get "stats"
220   - get "archive"
  220 + get "archive", constraints: { format: Gitlab::Regex.archive_formats_regex }
221 221 end
222 222 end
223 223  
... ...
lib/api/repositories.rb
  1 +require 'mime/types'
  2 +
1 3 module API
2 4 # Projects API
3 5 class Repositories < Grape::API
... ... @@ -206,18 +208,20 @@ module API
206 208 # sha (optional) - the commit sha to download defaults to the tip of the default branch
207 209 # Example Request:
208 210 # GET /projects/:id/repository/archive
209   - get ":id/repository/archive" do
  211 + get ":id/repository/archive", requirements: { format: Gitlab::Regex.archive_formats_regex } do
210 212 authorize! :download_code, user_project
211 213 repo = user_project.repository
212 214 ref = params[:sha]
  215 + format = params[:format]
213 216 storage_path = Rails.root.join("tmp", "repositories")
214 217  
215   - file_path = repo.archive_repo(ref, storage_path)
  218 + file_path = repo.archive_repo(ref, storage_path, format)
216 219 if file_path && File.exists?(file_path)
217 220 data = File.open(file_path, 'rb').read
218 221  
219   - header "Content-Disposition:", " infile; filename=\"#{File.basename(file_path)}\""
220   - content_type 'application/x-gzip'
  222 + header["Content-Disposition"] = "attachment; filename=\"#{File.basename(file_path)}\""
  223 +
  224 + content_type MIME::Types.type_for(file_path).first.content_type
221 225  
222 226 env['api.format'] = :binary
223 227  
... ...
lib/gitlab/regex.rb
... ... @@ -17,6 +17,11 @@ module Gitlab
17 17 def path_regex
18 18 default_regex
19 19 end
  20 +
  21 + def archive_formats_regex
  22 + #|zip|tar| tar.gz | tar.bz2 |
  23 + /(zip|tar|tar\.gz|tgz|gz|tar\.bz2|tbz|tbz2|tb2|bz2)/
  24 + end
20 25  
21 26 def git_reference_regex
22 27 # Valid git ref regex, see:
... ...
spec/requests/api/repositories_spec.rb
1 1 require 'spec_helper'
  2 +require 'mime/types'
2 3  
3 4 describe API::API do
4 5 include ApiHelpers
... ... @@ -232,11 +233,29 @@ describe API::API do
232 233 end
233 234 end
234 235  
235   - describe "GET /projects/:id/repository/archive/:sha" do
  236 + describe "GET /projects/:id/repository/archive(.:format)?:sha" do
236 237 it "should get the archive" do
237 238 get api("/projects/#{project.id}/repository/archive", user)
  239 + repo_name = project.repository.name.gsub("\.git", "")
238 240 response.status.should == 200
239   - response.content_type.should == 'application/x-gzip'
  241 + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.tar.gz\"/
  242 + response.content_type.should == MIME::Types.type_for('file.tar.gz').first.content_type
  243 + end
  244 +
  245 + it "should get the archive.zip" do
  246 + get api("/projects/#{project.id}/repository/archive.zip", user)
  247 + repo_name = project.repository.name.gsub("\.git", "")
  248 + response.status.should == 200
  249 + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.zip\"/
  250 + response.content_type.should == MIME::Types.type_for('file.zip').first.content_type
  251 + end
  252 +
  253 + it "should get the archive.tar.bz2" do
  254 + get api("/projects/#{project.id}/repository/archive.tar.bz2", user)
  255 + repo_name = project.repository.name.gsub("\.git", "")
  256 + response.status.should == 200
  257 + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.tar.bz2\"/
  258 + response.content_type.should == MIME::Types.type_for('file.tar.bz2').first.content_type
240 259 end
241 260  
242 261 it "should return 404 for invalid sha" do
... ...
spec/routing/project_routing_spec.rb
... ... @@ -130,6 +130,14 @@ describe Projects::RepositoriesController, &quot;routing&quot; do
130 130 get("/gitlab/gitlabhq/repository/archive").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq')
131 131 end
132 132  
  133 + it "to #archive format:zip" do
  134 + get("/gitlab/gitlabhq/repository/archive.zip").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'zip')
  135 + end
  136 +
  137 + it "to #archive format:tar.bz2" do
  138 + get("/gitlab/gitlabhq/repository/archive.tar.bz2").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'tar.bz2')
  139 + end
  140 +
133 141 it "to #show" do
134 142 get("/gitlab/gitlabhq/repository").should route_to('projects/repositories#show', project_id: 'gitlab/gitlabhq')
135 143 end
... ...