Commit 04665e93 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'issue_16834'

# Conflicts:
#	doc/api/v3_to_v4.md
parents e53fa960 a61bb7cd
---
title: Update API endpoints for raw files
merge_request:
author:
...@@ -15,7 +15,7 @@ Parameters: ...@@ -15,7 +15,7 @@ Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `path` (optional) - The path inside repository. Used to get contend of subdirectories - `path` (optional) - The path inside repository. Used to get contend of subdirectories
- `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch - `ref` (optional) - The name of a repository branch or tag or if not given the default branch
- `recursive` (optional) - Boolean value used to get a recursive tree (false by default) - `recursive` (optional) - Boolean value used to get a recursive tree (false by default)
```json ```json
...@@ -72,10 +72,11 @@ Parameters: ...@@ -72,10 +72,11 @@ Parameters:
] ]
``` ```
## Raw file content ## Get a blob from repository
Get the raw file contents for a file by commit SHA and path. This endpoint can Allows you to receive information about blob in repository like size and
be accessed without authentication if the repository is publicly accessible. content. Note that blob content is Base64 encoded. This endpoint can be accessed
without authentication if the repository is publicly accessible.
``` ```
GET /projects/:id/repository/blobs/:sha GET /projects/:id/repository/blobs/:sha
...@@ -85,7 +86,6 @@ Parameters: ...@@ -85,7 +86,6 @@ Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `sha` (required) - The commit or branch name - `sha` (required) - The commit or branch name
- `filepath` (required) - The path the file
## Raw blob content ## Raw blob content
...@@ -93,7 +93,7 @@ Get the raw file contents for a blob by blob SHA. This endpoint can be accessed ...@@ -93,7 +93,7 @@ Get the raw file contents for a blob by blob SHA. This endpoint can be accessed
without authentication if the repository is publicly accessible. without authentication if the repository is publicly accessible.
``` ```
GET /projects/:id/repository/raw_blobs/:sha GET /projects/:id/repository/blobs/:sha/raw
``` ```
Parameters: Parameters:
......
...@@ -11,11 +11,11 @@ content. Note that file content is Base64 encoded. This endpoint can be accessed ...@@ -11,11 +11,11 @@ content. Note that file content is Base64 encoded. This endpoint can be accessed
without authentication if the repository is publicly accessible. without authentication if the repository is publicly accessible.
``` ```
GET /projects/:id/repository/files GET /projects/:id/repository/files/:file_path
``` ```
```bash ```bash
curl --request GET --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files?file_path=app/models/key.rb&ref=master' curl --request GET --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master'
``` ```
Example response: Example response:
...@@ -36,17 +36,32 @@ Example response: ...@@ -36,17 +36,32 @@ Example response:
Parameters: Parameters:
- `file_path` (required) - Full path to new file. Ex. lib/class.rb - `file_path` (required) - Url encoded full path to new file. Ex. lib%2Fclass%2Erb
- `ref` (required) - The name of branch, tag or commit
## Get raw file from repository
```
GET /projects/:id/repository/files/:file_path/raw
```
```bash
curl --request GET --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb/raw?ref=master'
```
Parameters:
- `file_path` (required) - Url encoded full path to new file. Ex. lib%2Fclass%2Erb
- `ref` (required) - The name of branch, tag or commit - `ref` (required) - The name of branch, tag or commit
## Create new file in repository ## Create new file in repository
``` ```
POST /projects/:id/repository/files POST /projects/:id/repository/files/:file_path
``` ```
```bash ```bash
curl --request POST --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files?file_path=app/project.rb&branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&content=some%20content&commit_message=create%20a%20new%20file' curl --request POST --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/app%2Fprojectrb%2E?branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&content=some%20content&commit_message=create%20a%20new%20file'
``` ```
Example response: Example response:
...@@ -60,7 +75,7 @@ Example response: ...@@ -60,7 +75,7 @@ Example response:
Parameters: Parameters:
- `file_path` (required) - Full path to new file. Ex. lib/class.rb - `file_path` (required) - Url encoded full path to new file. Ex. lib%2Fclass%2Erb
- `branch` (required) - The name of branch - `branch` (required) - The name of branch
- `encoding` (optional) - Change encoding to 'base64'. Default is text. - `encoding` (optional) - Change encoding to 'base64'. Default is text.
- `author_email` (optional) - Specify the commit author's email address - `author_email` (optional) - Specify the commit author's email address
...@@ -71,11 +86,11 @@ Parameters: ...@@ -71,11 +86,11 @@ Parameters:
## Update existing file in repository ## Update existing file in repository
``` ```
PUT /projects/:id/repository/files PUT /projects/:id/repository/files/:file_path
``` ```
```bash ```bash
curl --request PUT --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files?file_path=app/project.rb&branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&content=some%20other%20content&commit_message=update%20file' curl --request PUT --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/app%2Fproject%2Erb?branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&content=some%20other%20content&commit_message=update%20file'
``` ```
Example response: Example response:
...@@ -89,7 +104,7 @@ Example response: ...@@ -89,7 +104,7 @@ Example response:
Parameters: Parameters:
- `file_path` (required) - Full path to file. Ex. lib/class.rb - `file_path` (required) - Url encoded full path to new file. Ex. lib%2Fclass%2Erb
- `branch` (required) - The name of branch - `branch` (required) - The name of branch
- `encoding` (optional) - Change encoding to 'base64'. Default is text. - `encoding` (optional) - Change encoding to 'base64'. Default is text.
- `author_email` (optional) - Specify the commit author's email address - `author_email` (optional) - Specify the commit author's email address
...@@ -109,11 +124,11 @@ Currently gitlab-shell has a boolean return code, preventing GitLab from specify ...@@ -109,11 +124,11 @@ Currently gitlab-shell has a boolean return code, preventing GitLab from specify
## Delete existing file in repository ## Delete existing file in repository
``` ```
DELETE /projects/:id/repository/files DELETE /projects/:id/repository/files/:file_path
``` ```
```bash ```bash
curl --request DELETE --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files?file_path=app/project.rb&branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&commit_message=delete%20file' curl --request DELETE --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/app%2Fproject%2Erb?branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&commit_message=delete%20file'
``` ```
Example response: Example response:
...@@ -127,7 +142,7 @@ Example response: ...@@ -127,7 +142,7 @@ Example response:
Parameters: Parameters:
- `file_path` (required) - Full path to file. Ex. lib/class.rb - `file_path` (required) - Url encoded full path to new file. Ex. lib%2Fclass%2Erb
- `branch` (required) - The name of branch - `branch` (required) - The name of branch
- `author_email` (optional) - Specify the commit author's email address - `author_email` (optional) - Specify the commit author's email address
- `author_name` (optional) - Specify the commit author's name - `author_name` (optional) - Specify the commit author's name
......
...@@ -75,4 +75,8 @@ Below are the changes made between V3 and V4. ...@@ -75,4 +75,8 @@ Below are the changes made between V3 and V4.
- API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530) - API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
- Change initial page from `0` to `1` on `GET projects/:id/repository/commits` (like on the rest of the API) [!9679] (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679) - Change initial page from `0` to `1` on `GET projects/:id/repository/commits` (like on the rest of the API) [!9679] (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
- Return correct `Link` header data for `GET projects/:id/repository/commits` [!9679] (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679) - Return correct `Link` header data for `GET projects/:id/repository/commits` [!9679] (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
- Update endpoints for repository files [!9637](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9637)
- Moved `/projects/:id/repository/files?file_path=:file_path` to `/projects/:id/repository/files/:file_path` (`:file_path` should be URL-encoded)
- `/projects/:id/repository/blobs/:sha` now returns JSON attributes for the blob identified by `:sha`, instead of finding the commit identified by `:sha` and returning the raw content of the blob in that commit identified by the required `?filepath=:filepath`
- Moved `/projects/:id/repository/commits/:sha/blob?file_path=:file_path` and `/projects/:id/repository/blobs/:sha?file_path=:file_path` to `/projects/:id/repository/files/:file_path/raw?ref=:sha`
- `/projects/:id/repository/tree` parameter `ref_name` has been renamed to `ref` for consistency
...@@ -14,6 +14,19 @@ module API ...@@ -14,6 +14,19 @@ module API
} }
end end
def assign_file_vars!
authorize! :download_code, user_project
@commit = user_project.commit(params[:ref])
not_found!('Commit') unless @commit
@repo = user_project.repository
@blob = @repo.blob_at(@commit.sha, params[:file_path])
not_found!('File') unless @blob
@blob.load_all_data!(@repo)
end
def commit_response(attrs) def commit_response(attrs)
{ {
file_path: attrs[:file_path], file_path: attrs[:file_path],
...@@ -22,7 +35,7 @@ module API ...@@ -22,7 +35,7 @@ module API
end end
params :simple_file_params do params :simple_file_params do
requires :file_path, type: String, desc: 'The path to new file. Ex. lib/class.rb' requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
requires :branch, type: String, desc: 'The name of branch' requires :branch, type: String, desc: 'The name of branch'
requires :commit_message, type: String, desc: 'Commit Message' requires :commit_message, type: String, desc: 'Commit Message'
optional :author_email, type: String, desc: 'The email of the author' optional :author_email, type: String, desc: 'The email of the author'
...@@ -40,34 +53,35 @@ module API ...@@ -40,34 +53,35 @@ module API
requires :id, type: String, desc: 'The project ID' requires :id, type: String, desc: 'The project ID'
end end
resource :projects do resource :projects do
desc 'Get a file from repository' desc 'Get raw file contents from the repository'
params do params do
requires :file_path, type: String, desc: 'The path to the file. Ex. lib/class.rb' requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
requires :ref, type: String, desc: 'The name of branch, tag, or commit' requires :ref, type: String, desc: 'The name of branch, tag commit'
end end
get ":id/repository/files" do get ":id/repository/files/:file_path/raw" do
authorize! :download_code, user_project assign_file_vars!
commit = user_project.commit(params[:ref])
not_found!('Commit') unless commit
repo = user_project.repository send_git_blob @repo, @blob
blob = repo.blob_at(commit.sha, params[:file_path]) end
not_found!('File') unless blob
blob.load_all_data!(repo) desc 'Get a file from the repository'
status(200) params do
requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
requires :ref, type: String, desc: 'The name of branch, tag or commit'
end
get ":id/repository/files/:file_path", requirements: { file_path: /.+/ } do
assign_file_vars!
{ {
file_name: blob.name, file_name: @blob.name,
file_path: blob.path, file_path: @blob.path,
size: blob.size, size: @blob.size,
encoding: "base64", encoding: "base64",
content: Base64.strict_encode64(blob.data), content: Base64.strict_encode64(@blob.data),
ref: params[:ref], ref: params[:ref],
blob_id: blob.id, blob_id: @blob.id,
commit_id: commit.id, commit_id: @commit.id,
last_commit_id: repo.last_commit_id_for_path(commit.sha, params[:file_path]) last_commit_id: @repo.last_commit_id_for_path(@commit.sha, params[:file_path])
} }
end end
...@@ -75,7 +89,7 @@ module API ...@@ -75,7 +89,7 @@ module API
params do params do
use :extended_file_params use :extended_file_params
end end
post ":id/repository/files" do post ":id/repository/files/:file_path", requirements: { file_path: /.+/ } do
authorize! :push_code, user_project authorize! :push_code, user_project
file_params = declared_params(include_missing: false) file_params = declared_params(include_missing: false)
...@@ -93,7 +107,7 @@ module API ...@@ -93,7 +107,7 @@ module API
params do params do
use :extended_file_params use :extended_file_params
end end
put ":id/repository/files" do put ":id/repository/files/:file_path", requirements: { file_path: /.+/ } do
authorize! :push_code, user_project authorize! :push_code, user_project
file_params = declared_params(include_missing: false) file_params = declared_params(include_missing: false)
...@@ -112,7 +126,7 @@ module API ...@@ -112,7 +126,7 @@ module API
params do params do
use :simple_file_params use :simple_file_params
end end
delete ":id/repository/files" do delete ":id/repository/files/:file_path", requirements: { file_path: /.+/ } do
authorize! :push_code, user_project authorize! :push_code, user_project
file_params = declared_params(include_missing: false) file_params = declared_params(include_missing: false)
......
...@@ -17,19 +17,34 @@ module API ...@@ -17,19 +17,34 @@ module API
end end
not_found! not_found!
end end
def assign_blob_vars!
authorize! :download_code, user_project
@repo = user_project.repository
begin
@blob = Gitlab::Git::Blob.raw(@repo, params[:sha])
@blob.load_all_data!(@repo)
rescue
not_found! 'Blob'
end
not_found! 'Blob' unless @blob
end
end end
desc 'Get a project repository tree' do desc 'Get a project repository tree' do
success Entities::RepoTreeObject success Entities::RepoTreeObject
end end
params do params do
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used' optional :ref, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
optional :path, type: String, desc: 'The path of the tree' optional :path, type: String, desc: 'The path of the tree'
optional :recursive, type: Boolean, default: false, desc: 'Used to get a recursive tree' optional :recursive, type: Boolean, default: false, desc: 'Used to get a recursive tree'
use :pagination use :pagination
end end
get ':id/repository/tree' do get ':id/repository/tree' do
ref = params[:ref_name] || user_project.try(:default_branch) || 'master' ref = params[:ref] || user_project.try(:default_branch) || 'master'
path = params[:path] || nil path = params[:path] || nil
commit = user_project.commit(ref) commit = user_project.commit(ref)
...@@ -40,39 +55,29 @@ module API ...@@ -40,39 +55,29 @@ module API
present paginate(entries), with: Entities::RepoTreeObject present paginate(entries), with: Entities::RepoTreeObject
end end
desc 'Get a raw file contents' desc 'Get raw blob contents from the repository'
params do params do
requires :sha, type: String, desc: 'The commit, branch name, or tag name' requires :sha, type: String, desc: 'The commit, branch name, or tag name'
requires :filepath, type: String, desc: 'The path to the file to display'
end end
get [":id/repository/blobs/:sha", ":id/repository/commits/:sha/blob"] do get ':id/repository/blobs/:sha/raw' do
repo = user_project.repository assign_blob_vars!
commit = repo.commit(params[:sha])
not_found! "Commit" unless commit
blob = Gitlab::Git::Blob.find(repo, commit.id, params[:filepath]) send_git_blob @repo, @blob
not_found! "File" unless blob
send_git_blob repo, blob
end end
desc 'Get a raw blob contents by blob sha' desc 'Get a blob from the repository'
params do params do
requires :sha, type: String, desc: 'The commit, branch name, or tag name' requires :sha, type: String, desc: 'The commit, branch name, or tag name'
end end
get ':id/repository/raw_blobs/:sha' do get ':id/repository/blobs/:sha' do
repo = user_project.repository assign_blob_vars!
begin
blob = Gitlab::Git::Blob.raw(repo, params[:sha])
rescue
not_found! 'Blob'
end
not_found! 'Blob' unless blob
send_git_blob repo, blob {
size: @blob.size,
encoding: "base64",
content: Base64.strict_encode64(@blob.data),
sha: @blob.id
}
end end
desc 'Get an archive of the repository' desc 'Get an archive of the repository'
......
...@@ -38,6 +38,60 @@ module API ...@@ -38,6 +38,60 @@ module API
present tree.sorted_entries, with: ::API::Entities::RepoTreeObject present tree.sorted_entries, with: ::API::Entities::RepoTreeObject
end end
desc 'Get a raw file contents'
params do
requires :sha, type: String, desc: 'The commit, branch name, or tag name'
requires :filepath, type: String, desc: 'The path to the file to display'
end
get [":id/repository/blobs/:sha", ":id/repository/commits/:sha/blob"] do
repo = user_project.repository
commit = repo.commit(params[:sha])
not_found! "Commit" unless commit
blob = Gitlab::Git::Blob.find(repo, commit.id, params[:filepath])
not_found! "File" unless blob
send_git_blob repo, blob
end
desc 'Get a raw blob contents by blob sha'
params do
requires :sha, type: String, desc: 'The commit, branch name, or tag name'
end
get ':id/repository/raw_blobs/:sha' do
repo = user_project.repository
begin
blob = Gitlab::Git::Blob.raw(repo, params[:sha])
rescue
not_found! 'Blob'
end
not_found! 'Blob' unless blob
send_git_blob repo, blob
end
desc 'Get an archive of the repository'
params do
optional :sha, type: String, desc: 'The commit sha of the archive to be downloaded'
optional :format, type: String, desc: 'The archive format'
end
get ':id/repository/archive', requirements: { format: Gitlab::Regex.archive_formats_regex } do
begin
send_git_archive user_project.repository, ref: params[:sha], format: params[:format]
rescue
not_found!('File')
end
end
desc 'Compare two branches, tags, or commits' do
success ::API::Entities::Compare
end
params do
requires :from, type: String, desc: 'The commit, branch name, or tag name to start comparison'
requires :to, type: String, desc: 'The commit, branch name, or tag name to stop comparison'
end
get ':id/repository/compare' do
compare = Gitlab::Git::Compare.new(user_project.repository.raw_repository, params[:from], params[:to])
present compare, with: ::API::Entities::Compare
end
desc 'Get repository contributors' do desc 'Get repository contributors' do
success ::API::Entities::Contributor success ::API::Entities::Contributor
end end
......
This diff is collapsed.
...@@ -30,7 +30,7 @@ describe API::Repositories, api: true do ...@@ -30,7 +30,7 @@ describe API::Repositories, api: true do
context 'when ref does not exist' do context 'when ref does not exist' do
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) { get api("#{route}?ref_name=foo", current_user) } let(:request) { get api("#{route}?ref=foo", current_user) }
let(:message) { '404 Tree Not Found' } let(:message) { '404 Tree Not Found' }
end end
end end
...@@ -66,7 +66,7 @@ describe API::Repositories, api: true do ...@@ -66,7 +66,7 @@ describe API::Repositories, api: true do
context 'when ref does not exist' do context 'when ref does not exist' do
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) { get api("#{route}?recursive=1&ref_name=foo", current_user) } let(:request) { get api("#{route}?recursive=1&ref=foo", current_user) }
let(:message) { '404 Tree Not Found' } let(:message) { '404 Tree Not Found' }
end end
end end
...@@ -100,82 +100,70 @@ describe API::Repositories, api: true do ...@@ -100,82 +100,70 @@ describe API::Repositories, api: true do
end end
end end
{ describe "GET /projects/:id/repository/blobs/:sha" do
'blobs/:sha' => 'blobs/master', let(:route) { "/projects/#{project.id}/repository/blobs/#{sample_blob.oid}" }
'commits/:sha/blob' => 'commits/master/blob'
}.each do |desc_path, example_path|
describe "GET /projects/:id/repository/#{desc_path}" do
let(:route) { "/projects/#{project.id}/repository/#{example_path}?filepath=README.md" }
shared_examples_for 'repository blob' do shared_examples_for 'repository blob' do
it 'returns the repository blob' do it 'returns blob attributes as json' do
get api(route, current_user) get api(route, current_user)
expect(response).to have_http_status(200)
end
context 'when sha does not exist' do
it_behaves_like '404 response' do
let(:request) { get api(route.sub('master', 'invalid_branch_name'), current_user) }
let(:message) { '404 Commit Not Found' }
end
end
context 'when filepath does not exist' do expect(response).to have_http_status(200)
it_behaves_like '404 response' do expect(json_response['size']).to eq(111)
let(:request) { get api(route.sub('README.md', 'README.invalid'), current_user) } expect(json_response['encoding']).to eq("base64")
let(:message) { '404 File Not Found' } expect(Base64.decode64(json_response['content']).lines.first).to eq("class Commit\n")
end expect(json_response['sha']).to eq(sample_blob.oid)
end end
context 'when no filepath is given' do context 'when sha does not exist' do
it_behaves_like '400 response' do it_behaves_like '404 response' do
let(:request) { get api(route.sub('?filepath=README.md', ''), current_user) } let(:request) { get api(route.sub(sample_blob.oid, '123456'), current_user) }
end let(:message) { '404 Blob Not Found' }
end end
end
context 'when repository is disabled' do context 'when repository is disabled' do
include_context 'disabled repository' include_context 'disabled repository'
it_behaves_like '403 response' do it_behaves_like '403 response' do
let(:request) { get api(route, current_user) } let(:request) { get api(route, current_user) }
end
end end
end end
end
context 'when unauthenticated', 'and project is public' do context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository blob' do it_behaves_like 'repository blob' do
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil } let(:current_user) { nil }
end
end end
end
context 'when unauthenticated', 'and project is private' do context 'when unauthenticated', 'and project is private' do
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) { get api(route) } let(:request) { get api(route) }
let(:message) { '404 Project Not Found' } let(:message) { '404 Project Not Found' }
end
end end
end
context 'when authenticated', 'as a developer' do context 'when authenticated', 'as a developer' do
it_behaves_like 'repository blob' do it_behaves_like 'repository blob' do
let(:current_user) { user } let(:current_user) { user }
end
end end
end
context 'when authenticated', 'as a guest' do context 'when authenticated', 'as a guest' do
it_behaves_like '403 response' do it_behaves_like '403 response' do
let(:request) { get api(route, guest) } let(:request) { get api(route, guest) }
end
end end
end end
end end
describe "GET /projects/:id/repository/raw_blobs/:sha" do describe "GET /projects/:id/repository/blobs/:sha/raw" do
let(:route) { "/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}" } let(:route) { "/projects/#{project.id}/repository/blobs/#{sample_blob.oid}/raw" }
shared_examples_for 'repository raw blob' do shared_examples_for 'repository raw blob' do
it 'returns the repository raw blob' do it 'returns the repository raw blob' do
expect(Gitlab::Workhorse).to receive(:send_git_blob)
get api(route, current_user) get api(route, current_user)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
......
...@@ -3,6 +3,8 @@ require 'mime/types' ...@@ -3,6 +3,8 @@ require 'mime/types'
describe API::V3::Repositories, api: true do describe API::V3::Repositories, api: true do
include ApiHelpers include ApiHelpers
include RepoHelpers
include WorkhorseHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } } let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } }
...@@ -96,6 +98,226 @@ describe API::V3::Repositories, api: true do ...@@ -96,6 +98,226 @@ describe API::V3::Repositories, api: true do
end end
end end
{
'blobs/:sha' => 'blobs/master',
'commits/:sha/blob' => 'commits/master/blob'
}.each do |desc_path, example_path|
describe "GET /projects/:id/repository/#{desc_path}" do
let(:route) { "/projects/#{project.id}/repository/#{example_path}?filepath=README.md" }
shared_examples_for 'repository blob' do
it 'returns the repository blob' do
get v3_api(route, current_user)
expect(response).to have_http_status(200)
end
context 'when sha does not exist' do
it_behaves_like '404 response' do
let(:request) { get v3_api(route.sub('master', 'invalid_branch_name'), current_user) }
let(:message) { '404 Commit Not Found' }
end
end
context 'when filepath does not exist' do
it_behaves_like '404 response' do
let(:request) { get v3_api(route.sub('README.md', 'README.invalid'), current_user) }
let(:message) { '404 File Not Found' }
end
end
context 'when no filepath is given' do
it_behaves_like '400 response' do
let(:request) { get v3_api(route.sub('?filepath=README.md', ''), current_user) }
end
end
context 'when repository is disabled' do
include_context 'disabled repository'
it_behaves_like '403 response' do
let(:request) { get v3_api(route, current_user) }
end
end
end
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository blob' do
let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
context 'when unauthenticated', 'and project is private' do
it_behaves_like '404 response' do
let(:request) { get v3_api(route) }
let(:message) { '404 Project Not Found' }
end
end
context 'when authenticated', 'as a developer' do
it_behaves_like 'repository blob' do
let(:current_user) { user }
end
end
context 'when authenticated', 'as a guest' do
it_behaves_like '403 response' do
let(:request) { get v3_api(route, guest) }
end
end
end
end
describe "GET /projects/:id/repository/raw_blobs/:sha" do
let(:route) { "/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}" }
shared_examples_for 'repository raw blob' do
it 'returns the repository raw blob' do
get v3_api(route, current_user)
expect(response).to have_http_status(200)
end
context 'when sha does not exist' do
it_behaves_like '404 response' do
let(:request) { get v3_api(route.sub(sample_blob.oid, '123456'), current_user) }
let(:message) { '404 Blob Not Found' }
end
end
context 'when repository is disabled' do
include_context 'disabled repository'
it_behaves_like '403 response' do
let(:request) { get v3_api(route, current_user) }
end
end
end
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository raw blob' do
let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
context 'when unauthenticated', 'and project is private' do
it_behaves_like '404 response' do
let(:request) { get v3_api(route) }
let(:message) { '404 Project Not Found' }
end
end
context 'when authenticated', 'as a developer' do
it_behaves_like 'repository raw blob' do
let(:current_user) { user }
end
end
context 'when authenticated', 'as a guest' do
it_behaves_like '403 response' do
let(:request) { get v3_api(route, guest) }
end
end
end
describe "GET /projects/:id/repository/archive(.:format)?:sha" do
let(:route) { "/projects/#{project.id}/repository/archive" }
shared_examples_for 'repository archive' do
it 'returns the repository archive' do
get v3_api(route, current_user)
expect(response).to have_http_status(200)
repo_name = project.repository.name.gsub("\.git", "")
type, params = workhorse_send_data
expect(type).to eq('git-archive')
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/)
end
it 'returns the repository archive archive.zip' do
get v3_api("/projects/#{project.id}/repository/archive.zip", user)
expect(response).to have_http_status(200)
repo_name = project.repository.name.gsub("\.git", "")
type, params = workhorse_send_data
expect(type).to eq('git-archive')
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/)
end
it 'returns the repository archive archive.tar.bz2' do
get v3_api("/projects/#{project.id}/repository/archive.tar.bz2", user)
expect(response).to have_http_status(200)
repo_name = project.repository.name.gsub("\.git", "")
type, params = workhorse_send_data
expect(type).to eq('git-archive')
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/)
end
context 'when sha does not exist' do
it_behaves_like '404 response' do
let(:request) { get v3_api("#{route}?sha=xxx", current_user) }
let(:message) { '404 File Not Found' }
end
end
end
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository archive' do
let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
context 'when unauthenticated', 'and project is private' do
it_behaves_like '404 response' do
let(:request) { get v3_api(route) }
let(:message) { '404 Project Not Found' }
end
end
context 'when authenticated', 'as a developer' do
it_behaves_like 'repository archive' do
let(:current_user) { user }
end
end
context 'when authenticated', 'as a guest' do
it_behaves_like '403 response' do
let(:request) { get v3_api(route, guest) }
end
end
end
describe 'GET /projects/:id/repository/compare' do
let(:route) { "/projects/#{project.id}/repository/compare" }
shared_examples_for 'repository compare' do
it "compares branches" do
get v3_api(route, current_user), from: 'master', to: 'feature'
expect(response).to have_http_status(200)
expect(json_response['commits']).to be_present
expect(json_response['diffs']).to be_present
end
it "compares tags" do
get v3_api(route, current_user), from: 'v1.0.0', to: 'v1.1.0'
expect(response).to have_http_status(200)
expect(json_response['commits']).to be_present
expect(json_response['diffs']).to be_present
end
it "compares commits" do
get v3_api(route, current_user), from: sample_commit.id, to: sample_commit.parent_id
expect(response).to have_http_status(200)
expect(json_response['commits']).to be_empty
expect(json_response['diffs']).to be_empty
expect(json_response['compare_same_ref']).to be_falsey
end
it "compares commits in reverse order" do
get v3_api(route, current_user), from: sample_commit.parent_id, to: sample_commit.id
expect(response).to have_http_status(200)
expect(json_response['commits']).to be_present
expect(json_response['diffs']).to be_present
end
it "compares same refs" do
get v3_api(route, current_user), from: 'master', to: 'master'
expect(response).to have_http_status(200)
expect(json_response['commits']).to be_empty
expect(json_response['diffs']).to be_empty
expect(json_response['compare_same_ref']).to be_truthy
end
end
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository compare' do
let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
context 'when unauthenticated', 'and project is private' do
it_behaves_like '404 response' do
let(:request) { get v3_api(route) }
let(:message) { '404 Project Not Found' }
end
end
context 'when authenticated', 'as a developer' do
it_behaves_like 'repository compare' do
let(:current_user) { user }
end
end
context 'when authenticated', 'as a guest' do
it_behaves_like '403 response' do
let(:request) { get v3_api(route, guest) }
end
end
end
describe 'GET /projects/:id/repository/contributors' do describe 'GET /projects/:id/repository/contributors' do
let(:route) { "/projects/#{project.id}/repository/contributors" } let(:route) { "/projects/#{project.id}/repository/contributors" }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment