Commit e27ebba5 authored by Sean McGivern's avatar Sean McGivern

Merge branch '4269-public-repositories-and-files-api-ee' into 'master'

[EE] Allow unauthenticated access to Repositories & Repository Files API GET endpoints

See merge request !985
parents 1333a40a f0b933ec
--- ---
title: Allow public access to some Project API endpoints title: Allow unauthenticated access to some Project API GET endpoints
merge_request: 7843 merge_request: 7843
author: author:
---
title: Allow unauthenticated access to Repositories Files API GET endpoints
merge_request:
author:
---
title: Allow unauthenticated access to Repositories API GET endpoints
merge_request: 8148
author:
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
## List repository tree ## List repository tree
Get a list of repository files and directories in a project. Get a list of repository files and directories in a project. This endpoint can
be accessed without authentication if the repository is publicly accessible.
``` ```
GET /projects/:id/repository/tree GET /projects/:id/repository/tree
...@@ -71,7 +72,8 @@ Parameters: ...@@ -71,7 +72,8 @@ Parameters:
## Raw file content ## Raw file content
Get the raw file contents for a file by commit SHA and path. Get the raw file contents for a file by commit SHA and path. 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 +87,8 @@ Parameters: ...@@ -85,7 +87,8 @@ Parameters:
## Raw blob content ## Raw blob content
Get the raw file contents for a blob by blob SHA. Get the raw file contents for a blob by blob SHA. This endpoint can be accessed
without authentication if the repository is publicly accessible.
``` ```
GET /projects/:id/repository/raw_blobs/:sha GET /projects/:id/repository/raw_blobs/:sha
...@@ -98,7 +101,8 @@ Parameters: ...@@ -98,7 +101,8 @@ Parameters:
## Get file archive ## Get file archive
Get an archive of the repository Get an archive of the repository. This endpoint can be accessed without
authentication if the repository is publicly accessible.
``` ```
GET /projects/:id/repository/archive GET /projects/:id/repository/archive
...@@ -111,6 +115,9 @@ Parameters: ...@@ -111,6 +115,9 @@ Parameters:
## Compare branches, tags or commits ## Compare branches, tags or commits
This endpoint can be accessed without authentication if the repository is
publicly accessible.
``` ```
GET /projects/:id/repository/compare GET /projects/:id/repository/compare
``` ```
...@@ -163,7 +170,8 @@ Response: ...@@ -163,7 +170,8 @@ Response:
## Contributors ## Contributors
Get repository contributors list Get repository contributors list. This endpoint can be accessed without
authentication if the repository is publicly accessible.
``` ```
GET /projects/:id/repository/contributors GET /projects/:id/repository/contributors
......
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
## Get file from repository ## Get file from repository
Allows you to receive information about file in repository like name, size, content. Note that file content is Base64 encoded. Allows you to receive information about file in repository like name, size,
content. Note that file content is Base64 encoded. This endpoint can be accessed
without authentication if the repository is publicly accessible.
``` ```
GET /projects/:id/repository/files GET /projects/:id/repository/files
......
module API module API
# Projects API # Projects API
class Files < Grape::API class Files < Grape::API
before { authenticate! }
helpers do helpers do
def commit_params(attrs) def commit_params(attrs)
{ {
......
...@@ -2,7 +2,6 @@ require 'mime/types' ...@@ -2,7 +2,6 @@ require 'mime/types'
module API module API
class Repositories < Grape::API class Repositories < Grape::API
before { authenticate! }
before { authorize! :download_code, user_project } before { authorize! :download_code, user_project }
params do params do
...@@ -79,8 +78,6 @@ module API ...@@ -79,8 +78,6 @@ module API
optional :format, type: String, desc: 'The archive format' optional :format, type: String, desc: 'The archive format'
end end
get ':id/repository/archive', requirements: { format: Gitlab::Regex.archive_formats_regex } do get ':id/repository/archive', requirements: { format: Gitlab::Regex.archive_formats_regex } do
authorize! :download_code, user_project
begin begin
send_git_archive user_project.repository, ref: params[:sha], format: params[:format] send_git_archive user_project.repository, ref: params[:sha], format: params[:format]
rescue rescue
...@@ -96,7 +93,6 @@ module API ...@@ -96,7 +93,6 @@ module API
requires :to, type: String, desc: 'The commit, branch name, or tag name to stop comparison' requires :to, type: String, desc: 'The commit, branch name, or tag name to stop comparison'
end end
get ':id/repository/compare' do get ':id/repository/compare' do
authorize! :download_code, user_project
compare = Gitlab::Git::Compare.new(user_project.repository.raw_repository, params[:from], params[:to]) compare = Gitlab::Git::Compare.new(user_project.repository.raw_repository, params[:from], params[:to])
present compare, with: Entities::Compare present compare, with: Entities::Compare
end end
...@@ -105,8 +101,6 @@ module API ...@@ -105,8 +101,6 @@ module API
success Entities::Contributor success Entities::Contributor
end end
get ':id/repository/contributors' do get ':id/repository/contributors' do
authorize! :download_code, user_project
begin begin
present user_project.repository.contributors, present user_project.repository.contributors,
with: Entities::Contributor with: Entities::Contributor
......
...@@ -4,7 +4,14 @@ describe API::Files, api: true do ...@@ -4,7 +4,14 @@ describe API::Files, api: true do
include ApiHelpers include ApiHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace ) } let!(:project) { create(:project, namespace: user.namespace ) }
let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } }
let(:file_path) { 'files/ruby/popen.rb' } let(:file_path) { 'files/ruby/popen.rb' }
let(:params) do
{
file_path: file_path,
ref: 'master'
}
end
let(:author_email) { FFaker::Internet.email } let(:author_email) { FFaker::Internet.email }
# I have to remove periods from the end of the name # I have to remove periods from the end of the name
...@@ -24,36 +31,72 @@ describe API::Files, api: true do ...@@ -24,36 +31,72 @@ describe API::Files, api: true do
before { project.team << [user, :developer] } before { project.team << [user, :developer] }
describe "GET /projects/:id/repository/files" do describe "GET /projects/:id/repository/files" do
it "returns file info" do let(:route) { "/projects/#{project.id}/repository/files" }
params = {
file_path: file_path,
ref: 'master',
}
get api("/projects/#{project.id}/repository/files", user), params shared_examples_for 'repository files' do
it "returns file info" do
get api(route, current_user), params
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response['file_path']).to eq(file_path) expect(json_response['file_path']).to eq(file_path)
expect(json_response['file_name']).to eq('popen.rb') expect(json_response['file_name']).to eq('popen.rb')
expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n") expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n")
end end
it "returns a 400 bad request if no params given" do context 'when no params are given' do
get api("/projects/#{project.id}/repository/files", user) it_behaves_like '400 response' do
let(:request) { get api(route, current_user) }
end
end
expect(response).to have_http_status(400) context 'when file_path does not exist' do
let(:params) do
{
file_path: 'app/models/application.rb',
ref: 'master',
}
end
it_behaves_like '404 response' do
let(:request) { get api(route, current_user), params }
let(:message) { '404 File Not Found' }
end
end
context 'when repository is disabled' do
include_context 'disabled repository'
it_behaves_like '403 response' do
let(:request) { get api(route, current_user), params }
end
end
end end
it "returns a 404 if such file does not exist" do context 'when unauthenticated', 'and project is public' do
params = { it_behaves_like 'repository files' do
file_path: 'app/models/application.rb', let(:project) { create(:project, :public) }
ref: 'master', let(:current_user) { nil }
} end
end
get api("/projects/#{project.id}/repository/files", user), params context 'when unauthenticated', 'and project is private' do
it_behaves_like '404 response' do
let(:request) { get api(route), params }
let(:message) { '404 Project Not Found' }
end
end
context 'when authenticated', 'as a developer' do
it_behaves_like 'repository files' do
let(:current_user) { user }
end
end
expect(response).to have_http_status(404) context 'when authenticated', 'as a guest' do
it_behaves_like '403 response' do
let(:request) { get api(route, guest), params }
end
end end
end end
......
...@@ -7,204 +7,415 @@ describe API::Repositories, api: true do ...@@ -7,204 +7,415 @@ describe API::Repositories, api: true do
include WorkhorseHelpers include WorkhorseHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } }
let!(:project) { create(:project, creator_id: user.id) } let!(:project) { create(:project, creator_id: user.id) }
let!(:master) { create(:project_member, :master, user: user, project: project) } let!(:master) { create(:project_member, :master, user: user, project: project) }
let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
describe "GET /projects/:id/repository/tree" do describe "GET /projects/:id/repository/tree" do
context "authorized user" do let(:route) { "/projects/#{project.id}/repository/tree" }
before { project.team << [user2, :reporter] }
it "returns project commits" do shared_examples_for 'repository tree' do
get api("/projects/#{project.id}/repository/tree", user) it 'returns the repository tree' do
get api(route, current_user)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
first_commit = json_response.first
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.first['name']).to eq('bar') expect(first_commit['name']).to eq('bar')
expect(json_response.first['type']).to eq('tree') expect(first_commit['type']).to eq('tree')
expect(json_response.first['mode']).to eq('040000') expect(first_commit['mode']).to eq('040000')
end
context 'when ref does not exist' do
it_behaves_like '404 response' do
let(:request) { get api("#{route}?ref_name=foo", current_user) }
let(:message) { '404 Tree Not Found' }
end
end end
it 'returns a 404 for unknown ref' do context 'when repository is disabled' do
get api("/projects/#{project.id}/repository/tree?ref_name=foo", user) include_context 'disabled repository'
expect(response).to have_http_status(404)
expect(json_response).to be_an Object it_behaves_like '403 response' do
json_response['message'] == '404 Tree Not Found' let(:request) { get api(route, current_user) }
end
end
context 'with recursive=1' do
it 'returns recursive project paths tree' do
get api("#{route}?recursive=1", current_user)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response[4]['name']).to eq('html')
expect(json_response[4]['path']).to eq('files/html')
expect(json_response[4]['type']).to eq('tree')
expect(json_response[4]['mode']).to eq('040000')
end
context 'when repository is disabled' do
include_context 'disabled repository'
it_behaves_like '403 response' do
let(:request) { get api(route, current_user) }
end
end
context 'when ref does not exist' do
it_behaves_like '404 response' do
let(:request) { get api("#{route}?recursive=1&ref_name=foo", current_user) }
let(:message) { '404 Tree Not Found' }
end
end
end end
end end
context "unauthorized user" do context 'when unauthenticated', 'and project is public' do
it "does not return project commits" do it_behaves_like 'repository tree' do
get api("/projects/#{project.id}/repository/tree") let(:project) { create(:project, :public) }
expect(response).to have_http_status(401) let(:current_user) { nil }
end end
end end
end
describe 'GET /projects/:id/repository/tree?recursive=1' do context 'when unauthenticated', 'and project is private' do
context 'authorized user' do it_behaves_like '404 response' do
before { project.team << [user2, :reporter] } let(:request) { get api(route) }
let(:message) { '404 Project Not Found' }
end
end
context 'when authenticated', 'as a developer' do
it_behaves_like 'repository tree' do
let(:current_user) { user }
end
end
it 'should return recursive project paths tree' do context 'when authenticated', 'as a guest' do
get api("/projects/#{project.id}/repository/tree?recursive=1", user) it_behaves_like '403 response' do
let(:request) { get api(route, guest) }
end
end
end
expect(response.status).to eq(200) {
'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 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
it_behaves_like '404 response' do
let(:request) { get 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 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 api(route, current_user) }
end
end
end
expect(json_response).to be_an Array context 'when unauthenticated', 'and project is public' do
expect(json_response[4]['name']).to eq('html') it_behaves_like 'repository blob' do
expect(json_response[4]['path']).to eq('files/html') let(:project) { create(:project, :public) }
expect(json_response[4]['type']).to eq('tree') let(:current_user) { nil }
expect(json_response[4]['mode']).to eq('040000') end
end end
it 'returns a 404 for unknown ref' do context 'when unauthenticated', 'and project is private' do
get api("/projects/#{project.id}/repository/tree?ref_name=foo&recursive=1", user) it_behaves_like '404 response' do
expect(response).to have_http_status(404) let(:request) { get api(route) }
let(:message) { '404 Project Not Found' }
end
end
expect(json_response).to be_an Object context 'when authenticated', 'as a developer' do
json_response['message'] == '404 Tree Not Found' it_behaves_like 'repository blob' do
let(:current_user) { user }
end
end end
end
context "unauthorized user" do context 'when authenticated', 'as a guest' do
it "does not return project commits" do it_behaves_like '403 response' do
get api("/projects/#{project.id}/repository/tree?recursive=1") let(:request) { get api(route, guest) }
expect(response).to have_http_status(401) end
end end
end end
end end
describe "GET /projects/:id/repository/blobs/:sha" do describe "GET /projects/:id/repository/raw_blobs/:sha" do
it "gets the raw file contents" do let(:route) { "/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}" }
get api("/projects/#{project.id}/repository/blobs/master?filepath=README.md", user)
expect(response).to have_http_status(200) shared_examples_for 'repository raw blob' do
it 'returns the repository raw blob' do
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(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 api(route, current_user) }
end
end
end end
it "returns 404 for invalid branch_name" do context 'when unauthenticated', 'and project is public' do
get api("/projects/#{project.id}/repository/blobs/invalid_branch_name?filepath=README.md", user) it_behaves_like 'repository raw blob' do
expect(response).to have_http_status(404) let(:project) { create(:project, :public) }
let(:current_user) { nil }
end
end end
it "returns 404 for invalid file" do context 'when unauthenticated', 'and project is private' do
get api("/projects/#{project.id}/repository/blobs/master?filepath=README.invalid", user) it_behaves_like '404 response' do
expect(response).to have_http_status(404) let(:request) { get api(route) }
let(:message) { '404 Project Not Found' }
end
end end
it "returns a 400 error if filepath is missing" do context 'when authenticated', 'as a developer' do
get api("/projects/#{project.id}/repository/blobs/master", user) it_behaves_like 'repository raw blob' do
expect(response).to have_http_status(400) let(:current_user) { user }
end
end end
end
describe "GET /projects/:id/repository/commits/:sha/blob" do context 'when authenticated', 'as a guest' do
it "gets the raw file contents" do it_behaves_like '403 response' do
get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", user) let(:request) { get api(route, guest) }
expect(response).to have_http_status(200) end
end end
end end
describe "GET /projects/:id/repository/raw_blobs/:sha" do describe "GET /projects/:id/repository/archive(.:format)?:sha" do
it "gets the raw file contents" do let(:route) { "/projects/#{project.id}/repository/archive" }
get api("/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}", user)
expect(response).to have_http_status(200) shared_examples_for 'repository archive' do
end it 'returns the repository archive' do
get api(route, current_user)
expect(response).to have_http_status(200)
it 'returns a 404 for unknown blob' do repo_name = project.repository.name.gsub("\.git", "")
get api("/projects/#{project.id}/repository/raw_blobs/123456", user) type, params = workhorse_send_data
expect(response).to have_http_status(404)
expect(json_response).to be_an Object expect(type).to eq('git-archive')
json_response['message'] == '404 Blob Not Found' expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/)
end
it 'returns the repository archive archive.zip' do
get 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 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 api("#{route}?sha=xxx", current_user) }
let(:message) { '404 File Not Found' }
end
end
end end
end
describe "GET /projects/:id/repository/archive(.:format)?:sha" do context 'when unauthenticated', 'and project is public' do
it "gets the archive" do it_behaves_like 'repository archive' do
get api("/projects/#{project.id}/repository/archive", user) let(:project) { create(:project, :public) }
repo_name = project.repository.name.gsub("\.git", "") let(:current_user) { nil }
expect(response).to have_http_status(200) end
type, params = workhorse_send_data
expect(type).to eq('git-archive')
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/)
end end
it "gets the archive.zip" do context 'when unauthenticated', 'and project is private' do
get api("/projects/#{project.id}/repository/archive.zip", user) it_behaves_like '404 response' do
repo_name = project.repository.name.gsub("\.git", "") let(:request) { get api(route) }
expect(response).to have_http_status(200) let(:message) { '404 Project Not Found' }
type, params = workhorse_send_data end
expect(type).to eq('git-archive')
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/)
end end
it "gets the archive.tar.bz2" do context 'when authenticated', 'as a developer' do
get api("/projects/#{project.id}/repository/archive.tar.bz2", user) it_behaves_like 'repository archive' do
repo_name = project.repository.name.gsub("\.git", "") let(:current_user) { user }
expect(response).to have_http_status(200) end
type, params = workhorse_send_data
expect(type).to eq('git-archive')
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/)
end end
it "returns 404 for invalid sha" do context 'when authenticated', 'as a guest' do
get api("/projects/#{project.id}/repository/archive/?sha=xxx", user) it_behaves_like '403 response' do
expect(response).to have_http_status(404) let(:request) { get api(route, guest) }
end
end end
end end
describe 'GET /projects/:id/repository/compare' do describe 'GET /projects/:id/repository/compare' do
it "compares branches" do let(:route) { "/projects/#{project.id}/repository/compare" }
get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'feature'
expect(response).to have_http_status(200) shared_examples_for 'repository compare' do
expect(json_response['commits']).to be_present it "compares branches" do
expect(json_response['diffs']).to be_present get 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 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 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 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 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 end
it "compares tags" do context 'when unauthenticated', 'and project is public' do
get api("/projects/#{project.id}/repository/compare", user), from: 'v1.0.0', to: 'v1.1.0' it_behaves_like 'repository compare' do
expect(response).to have_http_status(200) let(:project) { create(:project, :public) }
expect(json_response['commits']).to be_present let(:current_user) { nil }
expect(json_response['diffs']).to be_present end
end end
it "compares commits" do context 'when unauthenticated', 'and project is private' do
get api("/projects/#{project.id}/repository/compare", user), from: sample_commit.id, to: sample_commit.parent_id it_behaves_like '404 response' do
expect(response).to have_http_status(200) let(:request) { get api(route) }
expect(json_response['commits']).to be_empty let(:message) { '404 Project Not Found' }
expect(json_response['diffs']).to be_empty end
expect(json_response['compare_same_ref']).to be_falsey
end end
it "compares commits in reverse order" do context 'when authenticated', 'as a developer' do
get api("/projects/#{project.id}/repository/compare", user), from: sample_commit.parent_id, to: sample_commit.id it_behaves_like 'repository compare' do
expect(response).to have_http_status(200) let(:current_user) { user }
expect(json_response['commits']).to be_present end
expect(json_response['diffs']).to be_present
end end
it "compares same refs" do context 'when authenticated', 'as a guest' do
get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'master' it_behaves_like '403 response' do
expect(response).to have_http_status(200) let(:request) { get api(route, guest) }
expect(json_response['commits']).to be_empty end
expect(json_response['diffs']).to be_empty
expect(json_response['compare_same_ref']).to be_truthy
end end
end end
describe 'GET /projects/:id/repository/contributors' do describe 'GET /projects/:id/repository/contributors' do
it 'returns valid data' do let(:route) { "/projects/#{project.id}/repository/contributors" }
get api("/projects/#{project.id}/repository/contributors", user)
expect(response).to have_http_status(200) shared_examples_for 'repository contributors' do
expect(json_response).to be_an Array it 'returns valid data' do
contributor = json_response.first get api(route, current_user)
expect(contributor['email']).to eq('tiagonbotelho@hotmail.com')
expect(contributor['name']).to eq('tiagonbotelho') expect(response).to have_http_status(200)
expect(contributor['commits']).to eq(1) expect(json_response).to be_an Array
expect(contributor['additions']).to eq(0)
expect(contributor['deletions']).to eq(0) first_contributor = json_response.first
expect(first_contributor['email']).to eq('tiagonbotelho@hotmail.com')
expect(first_contributor['name']).to eq('tiagonbotelho')
expect(first_contributor['commits']).to eq(1)
expect(first_contributor['additions']).to eq(0)
expect(first_contributor['deletions']).to eq(0)
end
end
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository contributors' do
let(:project) { create(:project, :public) }
let(:current_user) { nil }
end
end
context 'when unauthenticated', 'and project is private' do
it_behaves_like '404 response' do
let(:request) { get api(route) }
let(:message) { '404 Project Not Found' }
end
end
context 'when authenticated', 'as a developer' do
it_behaves_like 'repository contributors' do
let(:current_user) { user }
end
end
context 'when authenticated', 'as a guest' do
it_behaves_like '403 response' do
let(:request) { get api(route, guest) }
end
end end
end end
end end
shared_context 'disabled repository' do
before do
project.project_feature.update_attributes!(
repository_access_level: ProjectFeature::DISABLED,
merge_requests_access_level: ProjectFeature::DISABLED,
builds_access_level: ProjectFeature::DISABLED
)
expect(project.feature_available?(:repository, current_user)).to be false
end
end
# Specs for status checking.
#
# Requires an API request:
# let(:request) { get api("/projects/#{project.id}/repository/branches", user) }
shared_examples_for '400 response' do
before do
# Fires the request
request
end
it 'returns 400' do
expect(response).to have_http_status(400)
end
end
shared_examples_for '403 response' do
before do
# Fires the request
request
end
it 'returns 403' do
expect(response).to have_http_status(403)
end
end
shared_examples_for '404 response' do
let(:message) { nil }
before do
# Fires the request
request
end
it 'returns 404' do
expect(response).to have_http_status(404)
expect(json_response).to be_an Object
if message.present?
expect(json_response['message']).to eq(message)
end
end
end
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