Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow creation of non-GitHub users as repo owners #1344

Merged
merged 44 commits into from
May 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2c588e0
Allowing creation of non-GitHub users as repo owners
andrew Apr 10, 2017
a2d5ef7
Merge branch 'master' into repository-owners
andrew Apr 11, 2017
4a99e5e
Add schema_plus for better index configuration
andrew Apr 11, 2017
22e220b
Merge branch 'master' into repository-owners
andrew Apr 12, 2017
a801f48
Update repo owner indexes
andrew Apr 12, 2017
aa9a4aa
Merge branch 'master' into repository-owners
andrew Apr 12, 2017
5cb8e9d
Merge branch 'master' into repository-owners
andrew Apr 13, 2017
80d3cdc
Merge branch 'master' into repository-owners
andrew Apr 18, 2017
2aa23fb
Remove duplicate gem
andrew Apr 18, 2017
b9a4813
Merge branch 'master' into repository-owners
andrew Apr 18, 2017
8c88fa7
Merge branch 'master' into repository-owners
andrew May 10, 2017
6e1783f
Merge branch 'master' into repository-owners
andrew May 11, 2017
a113c2c
Merge branch 'master' into repository-owners
andrew May 11, 2017
3b4de0c
Fix downloading self
andrew May 12, 2017
f9c86c4
Fix download_owner for user owned github repos
andrew May 12, 2017
3b12d11
Ensure orgs have a uuid
andrew May 12, 2017
889d134
TODOs
andrew May 12, 2017
e5d1d38
Eager load RepositoryHost::Gitlab in development
andrew May 12, 2017
e96ddb7
Fix downloading of GitLab repos
andrew May 12, 2017
e788012
Merge branch 'master' into repository-owners
andrew May 12, 2017
b7a4ae3
Fixed syncing repository users
andrew May 12, 2017
6759306
Downloading owner for gitlab repos
andrew May 12, 2017
a8cce63
Download owner for bitbucket repos
andrew May 12, 2017
3d14880
escape bitbucket uuids before querying api
andrew May 12, 2017
9349bc6
Removed extra brackets
andrew May 12, 2017
06c7d04
Handle the differences between users and orgs for gitlab and bitbucket
andrew May 12, 2017
161e4fd
Switch back to mainline gitlab gem
andrew May 12, 2017
09e7e2c
More eager loading of Gitlab modules for development
andrew May 12, 2017
bff5a9e
host agnostic create_org method
andrew May 12, 2017
90a0163
Remove Github specific methods from RepoOrg and RepoUser classes
andrew May 12, 2017
eb174fe
Merge branch 'master' into repository-owners
andrew May 15, 2017
01793b5
Fix spec
andrew May 15, 2017
a13738b
Added TODOS
andrew May 15, 2017
926643c
Added worker for downloading users
andrew May 15, 2017
eed4275
create org worker should take a host_type
andrew May 15, 2017
7cd6cf0
Added extra syncing of members for orgs
andrew May 15, 2017
be14a21
Fix syncing of orgs for github users
andrew May 15, 2017
bfa7006
download_repos method for bitbucket owners
andrew May 15, 2017
c9b1e3a
Update user worker should take a host_type
andrew May 15, 2017
657a321
Scraping of orgs and repos for gitlab users
andrew May 15, 2017
b935e82
Scrape bitbucket user orgs from profile pages
andrew May 15, 2017
80933c6
Fix copypasta error
andrew May 15, 2017
0312d97
More copy paster
andrew May 15, 2017
854b2c8
Fetch org methods for gitlab and bitbucket
andrew May 15, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ gem 'omniauth-bitbucket'
gem 'chartkick'
gem 'groupdate'
gem 'turbolinks'
gem 'gitlab', git: 'https://github.com/librariesio/gitlab'
gem 'gitlab'
gem 'bitbucket_rest_api', git: 'https://github.com/librariesio/bitbucket'
gem 'github-markup', require: 'github/markup'
gem 'commonmarker'
Expand Down
15 changes: 7 additions & 8 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@ GIT
nokogiri (>= 1.5.2)
simple_oauth

GIT
remote: https://github.com/librariesio/gitlab
revision: 69b59cd43b29c316b4f380610bb961ec398b22ee
specs:
gitlab (4.0.0)
httparty

GIT
remote: https://github.com/librariesio/payola
revision: 7d4026856edf0cbafc8a188748ba96ced7bad99b
Expand Down Expand Up @@ -242,6 +235,9 @@ GEM
mime-types (>= 1.19)
rugged (>= 0.25.1)
github-markup (1.6.0)
gitlab (4.0.0)
httparty
terminal-table (= 1.7.1)
globalid (0.4.0)
activesupport (>= 4.2.0)
groupdate (3.2.0)
Expand Down Expand Up @@ -524,6 +520,8 @@ GEM
stripe_event (1.6.0)
activesupport (>= 3.1)
stripe (>= 1.6, < 3.0)
terminal-table (1.7.1)
unicode-display_width (~> 1.1.1)
thor (0.19.4)
thread_safe (0.3.6)
tilt (2.0.7)
Expand All @@ -538,6 +536,7 @@ GEM
thread_safe (~> 0.1)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.1.3)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
Expand Down Expand Up @@ -594,7 +593,7 @@ DEPENDENCIES
gemoji
github-linguist
github-markup
gitlab!
gitlab
groupdate
highscore
hiredis
Expand Down
9 changes: 6 additions & 3 deletions app/models/concerns/github_identity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,17 @@ def update_repo_permissions

def download_self
return unless github_identity
RepositoryUser.create_from_github(OpenStruct.new({id: github_identity.uid, login: github_identity.nickname, type: 'User', host_type: 'GitHub'}))
RepositoryUpdateUserWorker.perform_async(nickname)
repository_user = RepositoryUser.create_from_host('GitHub', {id: github_identity.uid, login: github_identity.nickname, type: 'User', host_type: 'GitHub'})
if repository_user
github_identity.update_column(:repository_user_id, repository_user.id)
RepositoryUpdateUserWorker.perform_async('GitHub', nickname)
end
end

def download_orgs
return unless token
github_client.orgs.each do |org|
RepositoryCreateOrgWorker.perform_async(org.login)
RepositoryCreateOrgWorker.perform_async('GitHub', org.login)
end
rescue *RepositoryHost::Github::IGNORABLE_EXCEPTIONS
nil
Expand Down
4 changes: 3 additions & 1 deletion app/models/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ class Repository < ApplicationRecord
include RepoManifests
include RepositorySourceRank

# eager load this module to avoid clashing with Gitlab gem in development
RepositoryHost::Gitlab

STATUSES = ['Active', 'Deprecated', 'Unmaintained', 'Help Wanted', 'Removed']

API_FIELDS = [:full_name, :description, :fork, :created_at, :updated_at, :pushed_at, :homepage,
Expand Down Expand Up @@ -302,7 +305,6 @@ def github_id
end

def repository_host
RepositoryHost::Gitlab
@repository_host ||= RepositoryHost.const_get(host_type.capitalize).new(self)
end
end
4 changes: 4 additions & 0 deletions app/models/repository_host/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ def formatted_host
self.class.format(repository.host_type)
end

def repository_owner_class
RepositoryOwner.const_get(repository.host_type.capitalize)
end

def update_from_host(token = nil)
begin
r = self.class.fetch_repo(repository.id_or_name)
Expand Down
20 changes: 19 additions & 1 deletion app/models/repository_host/bitbucket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,25 @@ def download_forks(token = nil)
end

def download_owner
# not implemented yet
return if repository.owner && repository.repository_user_id && repository.owner.login == repository.owner_name
o = RepositoryOwner::Bitbucket.fetch_user(repository.owner_name)
if o.type == "team"
org = RepositoryOrganisation.create_from_host('Bitbucket', o)
if org
repository.repository_organisation_id = org.id
repository.repository_user_id = nil
repository.save
end
else
u = RepositoryUser.create_from_host('Bitbucket', o)
if u
repository.repository_user_id = u.id
repository.repository_organisation_id = nil
repository.save
end
end
rescue *IGNORABLE_EXCEPTIONS
nil
end

def create_webook(token = nil)
Expand Down
6 changes: 3 additions & 3 deletions app/models/repository_host/github.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def download_contributions(token = nil)
next unless c['id']
cont = existing_contributions.find{|cnt| cnt.repository_user.try(:uuid) == c.id }
unless cont
user = RepositoryUser.create_from_github(c)
user = RepositoryUser.create_from_host('GitHub', c)
cont = repository.contributions.find_or_create_by(repository_user: user)
end

Expand Down Expand Up @@ -127,14 +127,14 @@ def download_owner
return if repository.owner && repository.repository_user_id && repository.owner.login == repository.owner_name
o = api_client.user(repository.owner_name)
if o.type == "Organization"
go = RepositoryOrganisation.create_from_github(o.id)
go = RepositoryOrganisation.create_from_host('GitHub', o)
if go
repository.repository_organisation_id = go.id
repository.repository_user_id = nil
repository.save
end
else
u = RepositoryUser.create_from_github(o)
u = RepositoryUser.create_from_host('GitHub', o)
if u
repository.repository_user_id = u.id
repository.repository_organisation_id = nil
Expand Down
23 changes: 22 additions & 1 deletion app/models/repository_host/gitlab.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,28 @@ def download_forks(token = nil)
end

def download_owner
# not implemented yet
return if repository.owner && repository.repository_user_id && repository.owner.login == repository.owner_name
namespace = api_client.namespaces(search: repository.owner_name).try(:first)
return unless namespace
if namespace.kind == 'group'
o = RepositoryOwner::Gitlab.api_client.group(namespace.path)
org = RepositoryOrganisation.create_from_host('GitLab', o)
if org
repository.repository_organisation_id = org.id
repository.repository_user_id = nil
repository.save
end
elsif namespace.kind == 'user'
o = RepositoryOwner::Gitlab.fetch_user(namespace.path)
u = RepositoryUser.create_from_host('GitLab', o)
if u
repository.repository_user_id = u.id
repository.repository_organisation_id = nil
repository.save
end
end
rescue *IGNORABLE_EXCEPTIONS
nil
end

def create_webook(token = nil)
Expand Down
77 changes: 9 additions & 68 deletions app/models/repository_organisation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ class RepositoryOrganisation < ApplicationRecord
has_many :contributors, -> { group('repository_users.id').order("sum(contributions.count) DESC") }, through: :open_source_repositories, source: :contributors
has_many :projects, through: :open_source_repositories

# eager load this module to avoid clashing with Gitlab gem in development
RepositoryOwner::Gitlab

validates :uuid, presence: true
validates :login, uniqueness: {scope: :host_type}, if: lambda { self.login_changed? }
validates :uuid, uniqueness: {scope: :host_type}, if: lambda { self.uuid_changed? }

Expand All @@ -23,10 +27,10 @@ class RepositoryOrganisation < ApplicationRecord
scope :host, lambda{ |host_type| where('lower(repository_organisations.host_type) = ?', host_type.try(:downcase)) }

delegate :avatar_url, :repository_url, :top_favourite_projects, :top_contributors,
:to_s, :to_param, :github_id, to: :repository_owner
:to_s, :to_param, :github_id, :download_org_from_host, :download_orgs,
:download_org_from_host_by_login, :download_repos, to: :repository_owner

def repository_owner
RepositoryOwner::Gitlab
@repository_owner ||= RepositoryOwner.const_get(host_type.capitalize).new(self)
end

Expand All @@ -50,10 +54,6 @@ def company
nil
end

def github_client
AuthToken.client
end

def user_type
'Organisation'
end
Expand All @@ -66,46 +66,8 @@ def following
0
end

def self.create_from_github(login_or_id)
begin
r = AuthToken.client.org(login_or_id).to_hash
return false if r.blank?

org = nil
org_by_id = RepositoryOrganisation.host('GitHub').find_by_uuid(r[:id])
if r[:login].present?
org_by_login = RepositoryOrganisation.host('GitHub').where("lower(login) = ?", r[:login].downcase).first
else
org_by_login = nil
end

if org_by_id # its fine
if org_by_id.login.try(:downcase) == r[:login].try(:downcase)
org = org_by_id
else
if org_by_login && !org_by_login.download_from_github
org_by_login.destroy
end
org_by_id.login = r[:login]
org_by_id.save!
org = org_by_id
end
elsif org_by_login # conflict
if org_by_login.download_from_github_by_login
org = org_by_login if org_by_login.github_id == r[:id]
end
org_by_login.destroy if org.nil?
end
if org.nil?
org = RepositoryOrganisation.create!(uuid: r[:id], login: r[:login], host_type: 'GitHub')
end

org.assign_attributes r.slice(*RepositoryOrganisation::API_FIELDS)
org.save
org
rescue *RepositoryHost::Github::IGNORABLE_EXCEPTIONS
false
end
def self.create_from_host(host_type, org_hash)
RepositoryOwner.const_get(host_type.capitalize).create_org(org_hash)
end

def async_sync
Expand All @@ -115,31 +77,10 @@ def async_sync
def sync
download_from_github
download_repos
download_members
update_attributes(last_synced_at: Time.now)
end

def download_from_github
download_from_github_by(github_id)
end

def download_from_github_by_login
download_from_github_by(login)
end

def download_from_github_by(id_or_login)
RepositoryOrganisation.create_from_github(github_client.org(id_or_login))
rescue *RepositoryHost::Github::IGNORABLE_EXCEPTIONS
nil
end

def download_repos
github_client.org_repos(login).each do |repo|
CreateRepositoryWorker.perform_async('GitHub', repo.full_name)
end
rescue *RepositoryHost::Github::IGNORABLE_EXCEPTIONS
nil
end

def find_repositories
Repository.host(host_type).where('full_name ILIKE ?', "#{login}/%").update_all(repository_user_id: nil, repository_organisation_id: self.id)
end
Expand Down
64 changes: 63 additions & 1 deletion app/models/repository_owner/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,69 @@ def github_id
owner.uuid
end

def download_orgs
raise NotImplementedError
end

def download_repos
raise NotImplementedError
end

def self.format(host_type)
case host_type.try(:downcase)
when 'github'
'GitHub'
when 'gitlab'
'GitLab'
when 'bitbucket'
'Bitbucket'
end
end

def formatted_host
self.class.format(repository.host_type)
end

def download_user_from_host
download_user_from_host_by(owner.uuid)
end

def download_user_from_host_by_login
download_user_from_host_by(owner.login)
end

def download_user_from_host_by(id_or_login)
self.class.download_user_from_host(owner.host_type, id_or_login)
end

def self.download_user_from_host(host_type, id_or_login)
RepositoryUser.create_from_host(host_type, self.fetch_user(id_or_login))
end

def download_org_from_host
download_org_from_host_by(owner.uuid)
end

def download_org_from_host_by_login
download_org_from_host_by(owner.login)
end

def download_org_from_host_by(id_or_login)
self.class.download_org_from_host(owner.host_type, id_or_login)
end

def self.download_org_from_host(host_type, id_or_login)
RepositoryOrganisation.create_from_host(host_type, self.fetch_org(id_or_login))
end

def self.fetch_user(id_or_login)
raise NotImplementedError
end

def self.fetch_org(id_or_login)
raise NotImplementedError
end

private

def top_favourite_project_ids
Expand All @@ -45,7 +108,6 @@ def top_favourite_project_ids
end
end


def top_contributor_ids
Rails.cache.fetch [owner, "top_contributor_ids"], :expires_in => 1.week, race_condition_ttl: 2.minutes do
owner.contributors.visible.limit(50).pluck(:id)
Expand Down