Created
November 10, 2015 22:17
-
-
Save op-ct/8a76e97c70b56f3c1882 to your computer and use it in GitHub Desktop.
Octokit multi-repo thingamie
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source 'https://rubygems.org' | |
gem 'octokit' # github api | |
# native ruby git ops | |
gem 'rugged', git: 'git://github.com/libgit2/rugged.git', submodules: true | |
gem 'highline' # pretty prings | |
gem 'ruby-progressbar' | |
gem 'rake' | |
gem 'pry' # god-mode | |
gem 'pry-doc' | |
gem 'guard' # instant gratification (or disappointment) | |
gem 'guard-shell' | |
gem 'guard-rspec' | |
gem 'guard-rake' | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'octokit' | |
require 'highline' | |
require 'rugged' | |
require 'pry' # TODO: delete | |
# TODO: Re-namespace to ~Simp::DevTools::Foss::Sucker? # not nearly as fun | |
module Simp | |
module Devtools | |
module Github | |
end | |
end | |
end | |
# #TODO: refactor authenticated_github_client into separate class(Singleton?) | |
module Simp::Devtools::Github | |
class AuthenticatedClient | |
def initialize | |
Octokit.auto_paginate = true | |
@github_client = nil | |
end | |
def client | |
return @github_client if @github_client | |
begin | |
if !ENV.key? 'SIMPSUCKER_GITHUB_TOKEN' | |
fail 'env var SIMPSUCKER_GITHUB_TOKEN is empty!' | |
elsif ENV['SIMPSUCKER_GITHUB_TOKEN'].size != 40 | |
fail 'env var SIMPSUCKER_GITHUB_TOKEN does not contain a GitHub API token!' | |
end | |
client = Octokit::Client.new( :access_token => ENV['SIMPSUCKER_GITHUB_TOKEN'] ) | |
user = client.user | |
user.login | |
rescue Exception => e | |
line = '-'*71 | |
warnings = [ | |
line, | |
"An error (#{e.class}) was encountered when authenticating to GitHub.", | |
'Ensure the env var SIMPSUCKER_GITHUB_TOKEN contains a GitHub API token', | |
line, | |
'The original error message was:', | |
e.message, | |
line, | |
].map{ |x| HighLine.color x.gsub( /^.+/, 'WARNING: \0' ), HighLine::RED } | |
warn warnings | |
fail 'Could not authenticate with GitHub' | |
end | |
@github_client = client | |
end | |
end | |
end | |
module Simp::Devtools | |
class Sucker | |
def initialize( label='simpsucker-vanillas' ) | |
@label = label | |
@org = 'simp' | |
@verbose = 1 | |
@github_client = Simp::Devtools::Github::AuthenticatedClient.new.client | |
@data = OpenStruct.new | |
initialize_from_github | |
end | |
# cache API data we'll need later | |
def initialize_from_github | |
### @org_repos = Octokit.repos( "#{@org}/" ) | |
begin | |
@data.user = @github_client.user | |
@data.repos = @github_client.repositories | |
@data.org_repos = @github_client.organization_repositories( @org ) | |
@data.org_repo_names = @data.org_repos.map{ |x| x.full_name } | |
rescue Exception => e | |
binding.pry #TODO: better error-checking | |
end | |
end | |
def log_msg log, msg, severity = :info | |
severities = {:info => HighLine::BLUE, | |
:warn => HighLine::YELLOW, | |
:error => HighLine::RED} | |
msg = HighLine.color msg, severities.fetch( severity, HighLine::UNDERLINE ) | |
warn msg | |
log << msg | |
end | |
def warn msg | |
Kernel.warn msg if @verbose > 0 | |
end | |
def info msg | |
puts ::HighLine.color msg, HighLine::GRAY | |
end | |
def hooray msg | |
puts ::HighLine.color msg, HighLine::GREEN | |
end | |
# repo_name = full repo name, inclusing org | |
def carefully_fork_repo repo, problems | |
repo_name = repo.full_name | |
forked_repo = nil | |
# if we have a matching full name NOTE: can rename repos | |
our_matching_repos = @data.repos.select{ |r| r.name == repo.name } | |
if our_matching_repos.size > 0 | |
our_repo_name = our_matching_repos.first.full_name | |
info " repo exists as: #{our_repo_name}" | |
# get information on out own | |
# NOTE: we must query again, because @data.repos doesn't include parents | |
our_repo = @github_client.repo( our_repo_name ) | |
if !our_repo.fork? | |
log_msg problems, " repo exists but is not a fork: #{our_repo_name}", :error | |
elsif our_repo.parent.full_name != repo_name | |
log_msg problems, " fork exists but from another parent: #{our_repo.parent.full_name}", :error | |
else | |
info " repo exists with same parent" | |
forked_repo = our_repo | |
end | |
else | |
our_repo = @github_client.fork( repo_name ) # TODO: error checking | |
if our_repo.parent.full_name != repo_name | |
log_msg problems, " fork exists (as #{our_repo.name}) but from another parent: #{our_repo.parent.full_name}", :error | |
else | |
hooray "forked #{ repo_name }" | |
forked_repo = our_repo | |
end | |
end | |
forked_repo | |
end | |
# Ensure that all repos under an organization are forked into your own GitHub account | |
# repos = Array of Octokit repo objects (in org) to fork | |
# forks = Array of Octokit repo objects (in our repo) that were forked | |
def fork_these_repos repos | |
problems = [] | |
forks = [] | |
repos.each do |org_repo| | |
forked_repo = carefully_fork_repo( org_repo, problems ) | |
forks << forked_repo if forked_repo | |
end | |
if problems.size > 0 | |
warn "\n\n=== problems:" | |
warn problems | |
end | |
forks | |
end | |
def clone_these_forked_repos( forked_repos, path ) | |
pwd = Dir.pwd | |
forked_repos.each do |repo| | |
url = repo.ssh_url | |
parent_url = repo.parent.clone_url | |
begin | |
require 'ruby-progressbar' | |
require 'fileutils' | |
require 'highline/import' | |
local_repo_path = File.expand_path( repo.name, path ) | |
puts HighLine.color "CLONING #{url}\n to #{local_repo_path}!!!!", HighLine::BLUE | |
if File.exists? local_repo_path | |
[ "Directory already exists!", | |
"(for now, clones need to be fresh each time)!", | |
" #{local_repo_path}" ].each{ |m| puts HighLine.color m, HighLine::YELLOW } | |
exit unless HighLine.agree('Blow away the directory? (y/n) (n=exit)') | |
FileUtils.rm_rf local_repo_path | |
end | |
# TODO get total objects | |
progress_bar = ProgressBar.create(:title => "git (#{repo.name})", total: nil) | |
# FIXME: better auth scheme, allow straight SSH keys | |
auth = Rugged::Credentials::SshKeyFromAgent.new( username: 'git' ) | |
Rugged::Repository.clone_at( url, local_repo_path, | |
credentials: auth, | |
transfer_progress: lambda { |total_objects, indexed_objects, received_objects, local_objects, total_deltas, indexed_deltas, received_bytes| | |
#progress_bar.total = total_objects # redraws every update | |
progress_bar.progress = received_objects | |
} | |
) | |
puts | |
rescue Exception => e | |
puts | |
puts HighLine.color e.class.to_s, HighLine::RED+HighLine::BOLD | |
puts HighLine.color e.message, HighLine::RED | |
puts HighLine.color e.backtrace.join("\n"), HighLine::YELLOW | |
binding.pry | |
end | |
end | |
Dir.chdir pwd | |
end | |
# :everything, :modules, :rubygems | |
def suck( it, path ) | |
pwd = Dir.pwd | |
forks = [] | |
things_to_suck = [] | |
if it == :everything | |
things_to_suck = @data.org_repos | |
else | |
# FIXME: this is a silly option | |
simp_core = @github_client.repo( 'simp/simp-core' ) | |
things_to_suck = [@data.org_repos.first, simp_core] | |
end | |
forks = fork_these_repos( things_to_suck ) | |
local_repos = clone_these_forked_repos( forks, path ) | |
# TODO bail if not found | |
Dir.chdir path | |
binding.pry # TODO: delete | |
0 | |
end | |
end | |
end | |
desc 'Ensure gemspec-safe permissions on all files' | |
task :suck do | |
sucker = Simp::Devtools::Sucker.new | |
path = File.join( Dir.pwd, 'land_o_forks' ) | |
FileUtils.mkdir_p path | |
###sucker.suck :everything, path | |
sucker.suck :something, path | |
end | |
# ------------------------------------------------------------------------------ | |
# packaging tasks | |
# ------------------------------------------------------------------------------ | |
require 'rake/clean' | |
require 'find' | |
@package='simp-sucker' | |
@rakefile_dir=File.dirname(__FILE__) | |
CLEAN.include "#{@package}-*.gem" | |
CLEAN.include 'pkg' | |
CLEAN.include 'dist' | |
Find.find( @rakefile_dir ) do |path| | |
if File.directory? path | |
CLEAN.include path if File.basename(path) == 'tmp' | |
else | |
Find.prune | |
end | |
end | |
desc 'Ensure gemspec-safe permissions on all files' | |
task :chmod do | |
gemspec = File.expand_path( "#{@package}.gemspec", @rakefile_dir ).strip | |
spec = Gem::Specification::load( gemspec ) | |
spec.files.each do |file| | |
FileUtils.chmod 'go=r', file | |
end | |
end | |
desc 'run all RSpec tests' | |
task :spec do | |
Dir.chdir @rakefile_dir | |
sh 'bundle exec rspec spec' | |
end | |
namespace :pkg do | |
desc "build rubygem package for #{@package}" | |
task :gem => :chmod do | |
Dir.chdir @rakefile_dir | |
Dir['*.gemspec'].each do |spec_file| | |
cmd = %Q{SIMP_RPM_BUILD=1 bundle exec gem build "#{spec_file}"} | |
sh cmd | |
FileUtils.mkdir_p 'dist' | |
FileUtils.mv Dir.glob("#{@package}*.gem"), 'dist/' | |
end | |
end | |
desc "build and install rubygem package for #{@package}" | |
task :install_gem => [:clean, :gem] do | |
Dir.chdir @rakefile_dir | |
Dir.glob("dist/#{@package}*.gem") do |pkg| | |
sh %Q{bundle exec gem install #{pkg}} | |
end | |
end | |
end | |
# vim: syntax=ruby |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment