mirror_github 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ config.yml
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
6
+
data/BSD-LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ Copyright 2011 Singlebrook Technology, Inc. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are
4
+ permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of
7
+ conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
10
+ of conditions and the following disclaimer in the documentation and/or other materials
11
+ provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
14
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
15
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
16
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
21
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
+
23
+ The views and conclusions contained in the software and documentation are those of the
24
+ authors and should not be interpreted as representing official policies, either expressed
25
+ or implied, of Singlebrook Technology.
26
+
27
+ ===============
28
+ This Simplified BSD License courtesy of http://en.wikipedia.org/wiki/BSD_license
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,23 @@
1
+ = Mirror Github
2
+
3
+ This script will cycle through all repositories belonging to an organization and clone a mirror of them to a specified directory.
4
+
5
+ A mirror is a bare repository that is suitable for future cloning, if necessary.
6
+
7
+ == Installation
8
+
9
+ gem install mirror_github
10
+
11
+ Create a mirror_github_config.yml that contains your GitHub username, password, and organization name. There is a config_example.yml file that demonstrates the structure. It will look something like this:
12
+
13
+ github:
14
+ username: johnnytest
15
+ password: sOOperSecret
16
+ org: my_orgs_github_account_name
17
+
18
+ Obviously, the user credentials you define in this file need to have access to the specified organization.
19
+
20
+ Then:
21
+
22
+ mirror_github --config-file=/path/to/your/mirror_github_config.yml --backup-dir=/path/to/github/mirror/directory
23
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/bin/mirror_github ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
5
+
6
+ require 'mirror_github'
7
+
8
+ github_mirror = MirrorGithub::Base.new(ARGV)
9
+ github_mirror.mirror_all
@@ -0,0 +1,49 @@
1
+ module MirrorGithub
2
+
3
+ class Base
4
+
5
+ def initialize(args = nil)
6
+ parse_arguments(args)
7
+ end
8
+
9
+ # Backs up all repositories from the organization defined in the config.
10
+ def mirror_all
11
+ puts "Mirroring #{github_connection.repositories.size} repositories..."
12
+ github_connection.repositories.each do |repo|
13
+ puts "Beginning #{repo.name}"
14
+ mirror repo
15
+ puts "Finished #{repo.name}"
16
+ puts ""
17
+ end
18
+ end
19
+
20
+ # Creates a new mirroir repository at the target directory (if necessary)
21
+ # and fetches any updates.
22
+ def mirror(repository)
23
+ git = Git.new(config.backup_directory, repository)
24
+ git.create_mirror unless git.mirror_exists?
25
+ git.update_mirror
26
+ end
27
+
28
+ def config
29
+ @config ||= Configuration.new
30
+ end
31
+
32
+ def github_connection
33
+ @github_connection ||= Github.new(config.username, config.password, config.org)
34
+ end
35
+
36
+ def parse_arguments(args)
37
+ args.each do |arg|
38
+ option, value = arg.split('=').map { |v| v.chomp.strip }
39
+ next unless option && value
40
+ case option
41
+ when "--config-file" then Configuration.config_file_path = value
42
+ when "--backup-dir" then config.backup_directory = value
43
+ end
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,42 @@
1
+ require 'yaml'
2
+
3
+ module MirrorGithub
4
+ class Configuration
5
+
6
+ class << self
7
+ def config_file_path
8
+ @config_file_path ||= File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config.yml'))
9
+ end
10
+
11
+ def config_file_path=(val)
12
+ @config_file_path = File.expand_path(val)
13
+ end
14
+ end
15
+
16
+ attr_accessor :username, :password, :org, :backup_directory
17
+
18
+ def initialize
19
+ load_config
20
+ end
21
+
22
+ def backup_directory=(val)
23
+ @backup_directory = File.expand_path(val)
24
+ end
25
+
26
+ private
27
+
28
+ def load_config
29
+ raise "Please create a config.yml file at #{Configuration.config_file_path}, see test/config_example.yml for an example." unless File.exists?(Configuration.config_file_path)
30
+ config_file = YAML::load_file(Configuration.config_file_path)
31
+ if config_file['github']
32
+ self.username = config_file['github']['username']
33
+ self.password = config_file['github']['password']
34
+ self.org = config_file['github']['org']
35
+ end
36
+ if config_file['system']
37
+ self.backup_directory = config_file['system']['backup_directory']
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ module MirrorGithub
2
+
3
+ class Git
4
+ attr_accessor :repository
5
+ attr_writer :target_dir
6
+
7
+ # Takes a target_dir string and a Repository class
8
+ def initialize(target_dir, repository)
9
+ self.target_dir = target_dir
10
+ raise "GitHub backup directory, #{self.target_dir}, does not exist!" unless File.directory?(self.target_dir)
11
+
12
+ self.repository = repository
13
+ end
14
+
15
+ def create_mirror
16
+ `#{go_to_target_dir} && git clone --mirror #{repository.ssh_url} #{mirror_directory}`
17
+ end
18
+
19
+ def go_to_target_dir
20
+ "cd #{target_dir}"
21
+ end
22
+
23
+ def go_to_mirror_dir
24
+ "cd #{File.join(target_dir, mirror_directory)}"
25
+ end
26
+
27
+ def mirror_directory
28
+ "#{repository.name}.git"
29
+ end
30
+
31
+ def mirror_exists?
32
+ File.exists? File.join(target_dir, "#{mirror_directory}")
33
+ end
34
+
35
+ def target_dir
36
+ File.expand_path(@target_dir)
37
+ end
38
+
39
+ def update_mirror
40
+ `#{go_to_mirror_dir} && git fetch`
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,37 @@
1
+ require 'rest_client'
2
+ require 'json'
3
+
4
+ module MirrorGithub
5
+ class Github
6
+
7
+ class << self
8
+ def api_url
9
+ 'https://api.github.com'
10
+ end
11
+ end
12
+
13
+ attr_accessor :connection, :username, :password, :org
14
+
15
+ def initialize(username, password, org = nil)
16
+ self.username = username
17
+ self.password = password
18
+ self.org = org
19
+ self.connection = RestClient::Resource.new Github.api_url, :user => username, :password => password
20
+ end
21
+
22
+ # Return a list of the current repositories for an organization
23
+ def repositories
24
+ return [] unless org
25
+ JSON::parse(connection["orgs/#{org}/repos"].get).collect do |repo_hash|
26
+ Repository.new(:ssh_url => repo_hash['ssh_url'],
27
+ :private => repo_hash['private'],
28
+ :created_at => repo_hash["created_at"],
29
+ :pushed_at => repo_hash["pushed_at"],
30
+ :name => repo_hash["name"])
31
+ end
32
+ end
33
+
34
+
35
+
36
+ end
37
+ end
@@ -0,0 +1,13 @@
1
+ module MirrorGithub
2
+ class Repository
3
+ attr_accessor :ssh_url, :html_url, :private, :created_at, :pushed_at, :name
4
+ alias :private? :private
5
+
6
+ def initialize(input = {})
7
+ input.each do |k, v|
8
+ self.send("#{k}=", v)
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module MirrorGithub
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,9 @@
1
+ # Make sure our lib is in our load path
2
+ $: << File.expand_path(File.dirname(__FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'mirror_github/base'
6
+ require 'mirror_github/configuration'
7
+ require 'mirror_github/repository'
8
+ require 'mirror_github/github'
9
+ require 'mirror_github/git'
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mirror_github/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "mirror_github"
7
+ s.version = MirrorGithub::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Casey Dreier"]
10
+ s.email = ["casey.dreier@gmail.com"]
11
+ s.homepage = "https://github.com/singlebrook/mirror_github"
12
+ s.summary = %q{Command-line library for mirroring an Organization's GitHub repositories}
13
+ s.description = %q{Command-line library for mirroring an Organization's GitHub repositories}
14
+ s.license = 'BSD'
15
+
16
+ s.rubyforge_project = "mirror_github"
17
+
18
+ s.add_dependency 'rest-client'
19
+
20
+ s.add_development_dependency 'fakeweb'
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,7 @@
1
+ github:
2
+ username: johnnytest
3
+ password: sOOperSecret
4
+ org: singlebrook
5
+
6
+ system:
7
+ backup_directory: /var/backups/github
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ class MirrorGithub::ConfigurationTest < Test::Unit::TestCase
4
+
5
+ def test_config_file_default
6
+ assert_not_nil MirrorGithub::Configuration.config_file_path
7
+ end
8
+
9
+ def test_loads_config_file
10
+ MirrorGithub::Configuration.config_file_path = File.join(File.expand_path(File.dirname(__FILE__)), 'config_example.yml')
11
+ config = MirrorGithub::Configuration.new
12
+ assert config.username
13
+ assert config.password
14
+ assert config.org
15
+ end
16
+
17
+ end
@@ -0,0 +1,56 @@
1
+ [
2
+ {
3
+ "html_url": "https://github.com/test/project_proposal_application",
4
+ "url": "https://api.github.com/repos/test/project_proposal_application",
5
+ "homepage": "",
6
+ "watchers": 2,
7
+ "language": "Ruby",
8
+ "clone_url": "https://github.com/test/project_proposal_application.git",
9
+ "git_url": "git://github.com/test/project_proposal_application.git",
10
+ "master_branch": null,
11
+ "fork": false,
12
+ "pushed_at": "2011-01-19T22:18:40Z",
13
+ "created_at": "2011-01-04T20:28:33Z",
14
+ "open_issues": 0,
15
+ "private": true,
16
+ "size": 380,
17
+ "ssh_url": "git@github.com:test/project_proposal_application.git",
18
+ "owner": {
19
+ "url": "https://api.github.com/users/test",
20
+ "avatar_url": "https://secure.gravatar.com/avatar/3.png",
21
+ "login": "test",
22
+ "id": 99999
23
+ },
24
+ "forks": 0,
25
+ "description": "An interactive proposal application for potential clients",
26
+ "name": "project_proposal_application",
27
+ "svn_url": "https://svn.github.com/test/project_proposal_application"
28
+ },
29
+ {
30
+ "html_url": "https://github.com/test/capistrano_drupal",
31
+ "url": "https://api.github.com/repos/test/capistrano_drupal",
32
+ "homepage": "",
33
+ "watchers": 4,
34
+ "language": "Ruby",
35
+ "clone_url": "https://github.com/test/capistrano_drupal.git",
36
+ "git_url": "git://github.com/test/capistrano_drupal.git",
37
+ "master_branch": null,
38
+ "fork": false,
39
+ "pushed_at": "2011-02-04T22:18:54Z",
40
+ "created_at": "2011-02-03T01:44:44Z",
41
+ "open_issues": 0,
42
+ "private": false,
43
+ "size": 156,
44
+ "ssh_url": "git@github.com:test/capistrano_drupal.git",
45
+ "owner": {
46
+ "url": "https://api.github.com/users/test",
47
+ "avatar_url": "https://secure.gravatar.com/avatar/343cbf1f96d4fe3b85.png",
48
+ "login": "test",
49
+ "id": 99999
50
+ },
51
+ "forks": 1,
52
+ "description": "A Capistrano deployment setup for Drupal projects.",
53
+ "name": "capistrano_drupal",
54
+ "svn_url": "https://svn.github.com/test/capistrano_drupal"
55
+ }
56
+ ]
data/test/git_test.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ class MirrorGithub::GitTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @tmp_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'tmp'))
7
+ Dir.mkdir(@tmp_dir) unless File.directory?(@tmp_dir)
8
+ end
9
+
10
+ def test_initialize
11
+ r = MirrorGithub::Repository.new(:ssh_url => 'ssh://git@github.com:test')
12
+ git = MirrorGithub::Git.new(@tmp_dir, r)
13
+ end
14
+
15
+ def test_initialize_raises_error_if_directory_does_not_exist
16
+ r = MirrorGithub::Repository.new(:ssh_url => 'ssh://git@github.com:test')
17
+ assert_raise RuntimeError do
18
+ MirrorGithub::Git.new('sdfl9ij390', r)
19
+ end
20
+ end
21
+
22
+ def teardown
23
+ Dir.delete(@tmp_dir)
24
+ end
25
+
26
+ end
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+ require 'fakeweb'
3
+
4
+ class MirrorGithub::GithubTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ FakeWeb.allow_net_connect = false
8
+ FakeWeb.register_uri(:get, MirrorGithub::Github.api_url, :body => "Unauthorized", :status => ["401", "Unauthorized"])
9
+ FakeWeb.register_uri(:get, 'https://johnnytest:sOOperSecret@api.github.com/orgs/parent_org/repos', :body => organization_json, :content_type => "application/json")
10
+ end
11
+
12
+ def teardown
13
+ FakeWeb.allow_net_connect = true
14
+ end
15
+
16
+ def test_repositories
17
+ github = MirrorGithub::Github.new('johnnytest', 'sOOperSecret', 'parent_org')
18
+ assert github.repositories.respond_to?(:size)
19
+ assert github.repositories.size > 0
20
+ assert !github.repositories.map {|r| r.ssh_url }.compact.empty?
21
+ end
22
+
23
+ def organization_json
24
+ @org_contents ||= File.open(File.join(File.expand_path(File.dirname(__FILE__)), 'fixtures', 'repositories_listing.json')).read
25
+ end
26
+
27
+ end
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ class MirrorGithub::RepositoryTest < Test::Unit::TestCase
4
+
5
+ def test_initialize
6
+ r = MirrorGithub::Repository.new(:ssh_url => "ssh_url", :private => true)
7
+ assert_equal "ssh_url", r.ssh_url
8
+ assert_equal true, r.private?
9
+ end
10
+
11
+ end
@@ -0,0 +1,6 @@
1
+ # Make sure our lib is in our load path
2
+ $: << File.expand_path(File.dirname(__FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'lib/mirror_github'
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mirror_github
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Casey Dreier
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-12 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rest-client
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: fakeweb
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ description: Command-line library for mirroring an Organization's GitHub repositories
50
+ email:
51
+ - casey.dreier@gmail.com
52
+ executables:
53
+ - mirror_github
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - .gitignore
60
+ - BSD-LICENSE
61
+ - Gemfile
62
+ - README.rdoc
63
+ - Rakefile
64
+ - bin/mirror_github
65
+ - lib/mirror_github.rb
66
+ - lib/mirror_github/base.rb
67
+ - lib/mirror_github/configuration.rb
68
+ - lib/mirror_github/git.rb
69
+ - lib/mirror_github/github.rb
70
+ - lib/mirror_github/repository.rb
71
+ - lib/mirror_github/version.rb
72
+ - mirror_github.gemspec
73
+ - test/config_example.yml
74
+ - test/configuration_test.rb
75
+ - test/fixtures/repositories_listing.json
76
+ - test/git_test.rb
77
+ - test/github_test.rb
78
+ - test/repository_test.rb
79
+ - test/test_helper.rb
80
+ has_rdoc: true
81
+ homepage: https://github.com/singlebrook/mirror_github
82
+ licenses:
83
+ - BSD
84
+ post_install_message:
85
+ rdoc_options: []
86
+
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ requirements: []
108
+
109
+ rubyforge_project: mirror_github
110
+ rubygems_version: 1.6.2
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: Command-line library for mirroring an Organization's GitHub repositories
114
+ test_files: []
115
+