Skip to content

Commit f450d12

Browse files
Shared repositories indicator (#1077)
Shared repositories indicator
1 parent 898e43b commit f450d12

File tree

10 files changed

+169
-6
lines changed

10 files changed

+169
-6
lines changed

lib/travis/api/v3/models/user.rb

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,24 @@ def repository_ids
3535
end
3636

3737
def repositories
38-
Models::Repository.where(owner_type: 'User', owner_id: id)
38+
Models::Repository.where(
39+
'((repositories.owner_type = ? AND repositories.owner_id = ?) OR repositories.id IN (?))'.freeze,
40+
'User'.freeze,
41+
id,
42+
shared_repositories_ids
43+
).order('id ASC')
44+
end
45+
46+
def organizations_repositories_ids
47+
@organizations_repositories_ids ||= organizations.empty? ? [] : Models::Repository.where(owner_id: organizations.pluck(:id)).pluck(:id)
48+
end
49+
50+
def access_repositories_ids
51+
@access_repositories_ids ||= permissions.pluck(:repository_id)
52+
end
53+
54+
def shared_repositories_ids
55+
access_repositories_ids - organizations_repositories_ids
3956
end
4057

4158
def token

lib/travis/api/v3/renderer/repository.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Travis::API::V3
22
class Renderer::Repository < ModelRenderer
33
representation(:minimal, :id, :name, :slug)
4-
representation(:standard, :id, :name, :slug, :description, :github_id, :vcs_id, :vcs_type, :github_language, :active, :private, :owner, :owner_name, :vcs_name, :default_branch, :starred, :managed_by_installation, :active_on_org, :migration_status, :history_migration_status)
4+
representation(:standard, :id, :name, :slug, :description, :github_id, :vcs_id, :vcs_type, :github_language, :active, :private, :owner, :owner_name, :vcs_name, :default_branch, :starred, :managed_by_installation, :active_on_org, :migration_status, :history_migration_status, :shared)
55
representation(:experimental, :id, :name, :slug, :description, :vcs_id, :vcs_type, :github_id, :github_language, :active, :private, :owner, :default_branch, :starred, :current_build, :last_started_build, :next_build_number)
66
representation(:internal, :id, :name, :slug, :github_id, :vcs_id, :vcs_type, :active, :private, :owner, :default_branch, :private_key, :token, :user_settings)
77
representation(:additional, :allow_migration)
@@ -50,6 +50,12 @@ def starred
5050
user.starred_repository_ids.include? id
5151
end
5252

53+
def shared
54+
return owner_name.downcase != access_control.user.login.downcase \
55+
&& access_control.user.shared_repositories_ids.include?(id) if access_control.user && owner_name
56+
false
57+
end
58+
5359
def email_subscribed
5460
return false unless user = access_control.user
5561
!user.email_unsubscribed_repository_ids.include?(id)

lib/travis/testing/factories.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@
7878
owner { User.find_by_login('josevalim') || FactoryBot.create(:user, :login => 'josevalim') }
7979
end
8080

81+
factory :sharedrepo, :parent => :repository_without_last_build do
82+
name { 'sharedrepo' }
83+
owner_name { 'sharedrepoowner' }
84+
owner_email { '[email protected]' }
85+
owner { User.find_by_login('sharedrepoowner') || FactoryBot.create(:user, :login => 'sharedrepoowner', :name => 'Sharedrepo Owner') }
86+
last_build_number { nil }
87+
last_build_started_at { nil }
88+
last_build_finished_at { nil }
89+
end
90+
8191
factory :event do
8292
repository { Repository.first || FactoryBot.create(:repository) }
8393
source { Build.first || FactoryBot.create(:build) }
@@ -87,6 +97,14 @@
8797
factory :permission do
8898
end
8999

100+
factory :sharedrepo_permission, class: Permission do
101+
user_id { (User.find_by_login('johndoe') || FactoryBot.create(:user_with_sharedrepo)).id }
102+
repository_id { Repository.find_by_name('sharedrepo').id }
103+
admin { false }
104+
push { true }
105+
pull { true }
106+
end
107+
90108
factory :membership, class: Travis::API::V3::Models::Membership do
91109
organization_id { FactoryBot.create(:org_v3).id }
92110
user_id { FactoryBot.create(:user).id }
@@ -101,6 +119,14 @@
101119
github_oauth_token { 'github_oauth_token' }
102120
end
103121

122+
factory :user_with_sharedrepo, class: User do
123+
name { 'John Doe' }
124+
login { 'johndoe' }
125+
email { '[email protected]' }
126+
tokens { [Token.new] }
127+
github_oauth_token { 'github_oauth_token' }
128+
end
129+
104130
factory :org, :class => 'Organization' do
105131
name { 'travis-ci' }
106132
login { 'travis-ci' }

lib/travis/testing/scenario.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
module Scenario
22
class << self
33
def default
4-
minimal, enginex = repositories :minimal, :enginex
4+
minimal, enginex, sharedrepo = repositories :minimal, :enginex, :sharedrepo
5+
sharedrepo_permission = permissions :sharedrepo_permission
56

67
build :repository => minimal,
78
:owner => minimal.owner,
@@ -66,6 +67,26 @@ def default
6667
{ :owner => minimal.owner, :worker => 'ruby3.worker.travis-ci.org:travis-ruby-4' }
6768
]
6869

70+
build :repository => sharedrepo,
71+
:owner => sharedrepo.owner,
72+
:number => 1,
73+
:config => { 'rvm' => ['1.8.7', '1.9.2'], 'gemfile' => ['test/Gemfile.rails-2.3.x', 'test/Gemfile.rails-3.0.x'] },
74+
:state => 'failed',
75+
:started_at => '2010-11-12 12:00:00',
76+
:finished_at => '2010-11-12 12:00:10',
77+
:commit => {
78+
:commit => '1a738d9d6f297c105ae2',
79+
:ref => 'refs/heads/develop',
80+
:branch => 'master',
81+
:message => 'add Gemfile',
82+
:committer_name => 'Sven Fuchs',
83+
:committer_email => '[email protected]',
84+
:committed_at => '2010-11-12 11:50:00',
85+
},
86+
:jobs => [
87+
{ :owner => sharedrepo.owner, :worker => 'ruby3.worker.travis-ci.org:travis-ruby-4' }
88+
]
89+
6990
build :repository => enginex,
7091
:owner => enginex.owner,
7192
:number => 1,
@@ -98,6 +119,13 @@ def repositories(*names)
98119
}
99120
end
100121

122+
def permissions(*names)
123+
names.map { |name|
124+
perm = FactoryBot.create(name)
125+
perm
126+
}
127+
end
128+
101129
def build(attributes)
102130
commit = attributes.delete(:commit)
103131
jobs = attributes.delete(:jobs)

spec/lib/model/permission_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
end
66

77
it 'returns matching permissions if two roles given as symbols' do
8-
expect(Permission.by_roles([:admin, :pull]).size).to eq(2)
8+
expect(Permission.by_roles([:admin, :pull]).size).to eq(3)
99
end
1010

1111
it 'returns a single permission if one role given' do

spec/v3/services/enterprise_license/find_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"license_id" => "12345675ad",
2424
"license_type" => "trial",
2525
"seats" => 20,
26-
"active_users" => 1,
26+
"active_users" => 3,
2727
"expiration_time" => "2018-08-18T00:00:00Z"
2828
}
2929
}

spec/v3/services/owner/find_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
"github_language" => nil,
9999
"active" => false,
100100
"private" => false,
101+
"shared" => false,
101102
"owner" => { "@href"=> "/v3/org/#{org.id}" },
102103
"default_branch" => {
103104
"@type" => "branch",
@@ -165,6 +166,7 @@
165166
"github_language" => nil,
166167
"active" => false,
167168
"private" => false,
169+
"shared" => false,
168170
"owner" => { "@href"=> "/v3/org/#{org.id}" },
169171
"default_branch" => {
170172
"@type" => "branch",

spec/v3/services/repositories/for_current_user_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"github_language" => nil,
6464
"active" => true,
6565
"private" => true,
66+
"shared" => false,
6667
"owner" => {
6768
"@type" => "user",
6869
"@href" => "/v3/user/#{repo.owner_id}",

spec/v3/services/repositories/for_owner_spec.rb

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
describe Travis::API::V3::Services::Repositories::ForOwner, set_app: true do
22
include Support::Formats
33
let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
4+
let(:sharedrepo) { Travis::API::V3::Models::Repository.where(owner_name: 'sharedrepoowner', name: 'sharedrepo').first }
45
let(:build) { repo.builds.first }
56
let(:jobs) { Travis::API::V3::Models::Build.find(build.id).jobs }
67

78
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
89
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
10+
11+
let(:token_collaborator) { Travis::Api::App::AccessToken.create(user: Travis::API::V3::Models::User.find_by_login('johndoe'), app_id: 1) }
12+
let(:headers_collaborator) {{ 'HTTP_AUTHORIZATION' => "token #{token_collaborator}" }}
913
before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) }
1014
before { repo.update_attribute(:private, true) }
1115
before { repo.update_attribute(:current_build, build) }
1216
after { repo.update_attribute(:private, false) }
17+
before { RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = 1024*1024 }
1318

1419
describe "sorting by default_branch.last_build" do
1520
let!(:repo2) { Travis::API::V3::Models::Repository.create!(owner_name: 'svenfuchs', owner: repo.owner, name: 'second-repo', default_branch_name: 'other-branch') }
@@ -33,7 +38,7 @@
3338
describe "private repository, private API, authenticated as user with access" do
3439
before { get("/v3/owner/svenfuchs/repos", {}, headers) }
3540
example { expect(last_response).to be_ok }
36-
example { expect(JSON.load(body)).to be == {
41+
example { puts JSON.load(body); expect(JSON.load(body)).to be == {
3742
"@type" => "repositories",
3843
"@href" => "/v3/owner/svenfuchs/repos",
3944
"@representation" => "standard",
@@ -83,6 +88,7 @@
8388
"github_language" => nil,
8489
"active" => true,
8590
"private" => true,
91+
"shared" => false,
8692
"owner" => {
8793
"@type" => "user",
8894
"id" => repo.owner_id,
@@ -134,6 +140,7 @@
134140
"github_language" =>nil,
135141
"active" =>true,
136142
"private" =>true,
143+
"shared" =>false,
137144
"owner" =>{
138145
"@type" =>"user",
139146
"id" =>1,
@@ -245,6 +252,7 @@
245252
"github_language" => nil,
246253
"active" => true,
247254
"private" => true,
255+
"shared" => false,
248256
"owner" => {
249257
"@type" => "user",
250258
"id" => 1,
@@ -413,6 +421,7 @@
413421
"@representation"=>"minimal",
414422
"name" => "master" },
415423
"starred" => false,
424+
"shared" => false,
416425
"managed_by_installation"=>false,
417426
"active_on_org" => nil,
418427
"migration_status" => nil,
@@ -446,6 +455,7 @@
446455
"github_language" => nil,
447456
"active" => true,
448457
"private" => false,
458+
"shared" => false,
449459
"owner" => {
450460
"@type" => "user",
451461
"id" => 1,
@@ -462,4 +472,76 @@
462472
"migration_status" => nil,
463473
"history_migration_status" => nil}]}
464474
end
475+
476+
describe "shared repository for collaborator, authenticated as user with access" do
477+
before { get("/v3/owner/johndoe/repos", {}, headers_collaborator) }
478+
example { expect(last_response).to be_ok }
479+
example { puts JSON.load(body); expect(JSON.load(body)).to be == {
480+
"@type" => "repositories",
481+
"@href" => "/v3/owner/johndoe/repos",
482+
"@representation" => "standard",
483+
"@pagination" => {
484+
"limit" => 100,
485+
"offset" => 0,
486+
"count" => 1,
487+
"is_first" => true,
488+
"is_last" => true,
489+
"next" => nil,
490+
"prev" => nil,
491+
"first" => {
492+
"@href" => "/v3/owner/johndoe/repos",
493+
"offset" => 0,
494+
"limit" => 100},
495+
"last" => {
496+
"@href" => "/v3/owner/johndoe/repos",
497+
"offset" => 0,
498+
"limit" => 100}},
499+
"repositories" => [{
500+
"@type" => "repository",
501+
"@href" => "/v3/repo/#{sharedrepo.id}",
502+
"@representation" => "standard",
503+
"@permissions" => {
504+
"read" => true,
505+
"activate" => true,
506+
"deactivate" => true,
507+
"migrate" => false,
508+
"star" => true,
509+
"unstar" => true,
510+
"create_request" => true,
511+
"create_cron" => true,
512+
"create_env_var" => true,
513+
"create_key_pair" => true,
514+
"delete_key_pair" => true,
515+
"admin" => false
516+
},
517+
"id" => sharedrepo.id,
518+
"name" => "sharedrepo",
519+
"slug" => "sharedrepoowner/sharedrepo",
520+
"description" => nil,
521+
"github_id" => sharedrepo.github_id,
522+
"vcs_id" => sharedrepo.vcs_id,
523+
"vcs_type" => sharedrepo.vcs_type,
524+
"owner_name" => "sharedrepoowner",
525+
"vcs_name" => "sharedrepo",
526+
"github_language" => nil,
527+
"active" => true,
528+
"private" => false,
529+
"shared" => true,
530+
"owner" => {
531+
"@type" => "user",
532+
"id" => sharedrepo.owner_id,
533+
"login" => "sharedrepoowner",
534+
"@href" => "/v3/user/#{sharedrepo.owner_id}" },
535+
"default_branch" => {
536+
"@type" => "branch",
537+
"@href" => "/v3/repo/#{sharedrepo.id}/branch/master",
538+
"@representation" => "minimal",
539+
"name" => "master"},
540+
"starred" => false,
541+
"managed_by_installation"=>false,
542+
"active_on_org" => nil,
543+
"migration_status" => nil,
544+
"history_migration_status" => nil
545+
}]}}
546+
end
465547
end

spec/v3/services/repository/find_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"github_language" => nil,
8686
"active" => true,
8787
"private" => opts[:private],
88+
"shared" => false,
8889
"owner" => {
8990
"id" => repo.owner_id,
9091
"login" => "svenfuchs",

0 commit comments

Comments
 (0)