|
class CloneAll |
|
class Cloner |
|
|
|
def initialize(client, config) |
|
@client = client |
|
@config = config |
|
end |
|
|
|
# Clone labels from a repo |
|
def clone_labels(label_source_repo = config.label_source_repo) |
|
labels = Labels.new client.repo(label_source_repo).labels |
|
debug labels.names |
|
client.repos do |json| |
|
json.each do |repo_json| |
|
name = repo_json['name'] |
|
next if name == label_source_repo |
|
repo = client.repo(name) |
|
repo_labels = Labels.new repo.labels |
|
next if repo_labels == labels |
|
log |
|
new_labels = labels - repo_labels |
|
if ! new_labels.empty? |
|
log "[#{name}] Adding #{new_labels.map(&:name)}" |
|
new_labels.each {|rl| repo.create_label(rl.name, rl.color) } |
|
end |
|
pruned_labels = repo_labels - labels |
|
if ! pruned_labels.empty? |
|
log "[#{name}] Removing #{pruned_labels.map(&:name)}" |
|
pruned_labels.each {|rl| repo.delete_label(rl.name) } |
|
end |
|
end |
|
end |
|
end |
|
|
|
def clone_repos(update_all_repos = config.update_all_repos) |
|
download_repos(client.client_credentials) |
|
|
|
each_repo do |repo| |
|
name = repo['name'] |
|
# clone_url = repo['clone_url'] |
|
private_repo = repo['private'] == true |
|
full_name = repo['full_name'] |
|
if clone_repo(name, full_name, private_repo) || update_all_repos |
|
update_repo(name) |
|
end |
|
end |
|
end |
|
|
|
def print_collabs(repo_collabs = config.repo_collabs) |
|
client.repo(repo_collabs).collaborators.each do |collab| |
|
p collab["login"] |
|
end |
|
end |
|
|
|
# Print out team names and member repos |
|
def print_teams |
|
require 'pp' |
|
client.team_repos do |team, repos| |
|
pp [team, repos.map {|repo| repo['name'] }] |
|
end |
|
end |
|
|
|
def each_repo(&block) |
|
pids = [] |
|
downloaded_repos.each do |repo| |
|
pids << fork do |
|
block.call(repo) |
|
end |
|
end |
|
pids.each do |pid| |
|
Process.waitpid2(pid) |
|
end |
|
end |
|
|
|
def download_repos(client_credentials, client_options={:type => 'all'}) |
|
return unless download_repos? |
|
@json = [] |
|
client.repos do |json| |
|
names = json.map{|item| item['name'] } |
|
old_names = @json.map{|item| item['name'] } |
|
new_names = names - old_names |
|
log "Got: #{new_names}\tHad: #{old_names}" |
|
@json = @json | json |
|
end |
|
ensure |
|
# if JSON parsing fails, just write what we have |
|
save_repos(@json) |
|
end |
|
|
|
private |
|
|
|
attr_reader :client, :config |
|
|
|
def folder_name |
|
File.basename Dir.pwd |
|
end |
|
|
|
def sh(command) |
|
# system(command << " &> /dev/null") |
|
captured_output = '' |
|
captured_errors = '' |
|
status = :not_set |
|
name = folder_name |
|
Open3.popen3(command) do |stdin, stdout, stderr, wait_thr| |
|
captured_output << stdout.read.chomp |
|
captured_errors << stderr.read.chomp |
|
status = wait_thr.value |
|
end |
|
errors = captured_output.split("\n").grep(/error|fail/i) |
|
no_errors = true |
|
if errors.size > 0 |
|
no_errors = false |
|
log "errors from #{name}" |
|
log "\t" << errors.join("\n\t") |
|
end |
|
if captured_errors.size > 0 |
|
message = captured_errors.split("\n").first |
|
if message !~ /Already on 'master'/ |
|
no_errors = false |
|
log "\t ERRORS #{name.upcase}: #{message}" |
|
end |
|
end |
|
status.success? |
|
end |
|
|
|
def clone_repo(name, full_name, private_repo = false) |
|
# require 'fileutils' |
|
# FileUtils.rm_rf(name) if File.exist?(name) |
|
# return false |
|
return false if File.exist?(name) |
|
ssh_url = private_repo ? "git@github.com:#{full_name}.git" : "https://github.com/#{full_name}.git" |
|
clone_cmd = "git clone --recursive #{ssh_url}" |
|
if sh(clone_cmd) |
|
log "Cloned #{name}" |
|
true |
|
else |
|
warn "Clone failed. cmd: #{clone_cmd}" |
|
false |
|
end |
|
end |
|
|
|
def update_master(name) |
|
if sh("git diff --quiet head &>/dev/null") |
|
dep1 = sh("git branch -u origin/master") |
|
dep2 = sh("git checkout master && git pull --rebase") # status |
|
dep1 && dep2 |
|
else |
|
warn "Not updating; #{name} is dirty" |
|
false |
|
end |
|
end |
|
|
|
def install_deps |
|
if File.exist?("Gemfile") |
|
sh("bundle check || bundle") |
|
else |
|
true |
|
end |
|
end |
|
|
|
def update_repo(name) |
|
Dir.chdir(name) do |
|
dep1 = update_master(name) |
|
dep2 = install_deps |
|
if dep1 && dep2 |
|
log "Updated #{name}" |
|
end |
|
end |
|
end |
|
|
|
def download_repos? |
|
@update_repos_list || repos_file |
|
end |
|
|
|
def save_repos(json) |
|
return if json.nil? |
|
downloaded_json = downloaded_repos |
|
json = json.concat(downloaded_json).uniq {|element| element['full_name'] } |
|
log "Added #{json.size - downloaded_json.size} repos. Total: #{json.size}" |
|
File.write(repos_file, JSON.pretty_generate(json)) |
|
end |
|
|
|
def repos_file |
|
!File.exist?('repos.json') && File.write('repos.json', []) |
|
'repos.json' |
|
end |
|
|
|
def downloaded_repos |
|
Array(JSON.load(File.binread(repos_file))) |
|
end |
|
|
|
def debug(msg="") |
|
p msg |
|
end |
|
|
|
def log(msg="") |
|
STDOUT.puts msg |
|
end |
|
|
|
def warn(msg="") |
|
STDERR.puts msg |
|
end |
|
end |
|
|
|
Labels = Struct.new(:labels) do |
|
include Comparable |
|
def <=>(other) |
|
labels == other.labels |
|
end |
|
Label = Struct.new(:label) do |
|
include Comparable |
|
def <=>(other) |
|
name == other.name |
|
end |
|
def name; label['name']; end |
|
def url ; label['url']; end |
|
def color; label['color']; end |
|
end |
|
def labels |
|
@labels ||= self[:labels].map {|label| Label.new(label) } |
|
end |
|
def names; labels.map(&:name); end |
|
def urls; labels.map(&:url); end |
|
def colors; labels.map(&:color); end |
|
def -(other) |
|
other_names = other.names |
|
labels.reject {|label| other_names.include?(label.name) } |
|
end |
|
def ==(other) |
|
names == other.names |
|
end |
|
end |
|
end |