github-merge 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,25 @@
1
+ # -*- ruby -*-
2
+
3
+ require "autotest/restart"
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.testlib = "minitest/unit"
7
+ #
8
+ # at.extra_files << "../some/external/dependency.rb"
9
+ #
10
+ # at.libs << ":../some/external"
11
+ #
12
+ # at.add_exception "vendor"
13
+ #
14
+ # at.add_mapping(/dependency.rb/) do |f, _|
15
+ # at.files_matching(/test_.*rb$/)
16
+ # end
17
+ #
18
+ # %w(TestA TestB).each do |klass|
19
+ # at.extra_class_map[klass] = "test/test_misc.rb"
20
+ # end
21
+ # end
22
+
23
+ # Autotest.add_hook :run_command do |at|
24
+ # system "rake build"
25
+ # end
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org/"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,54 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ github-merge (1.0.0)
5
+ github_api (~> 0.9.4)
6
+ thor (~> 0.18.1)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.2.2)
12
+ faraday (0.8.7)
13
+ multipart-post (~> 1.1)
14
+ github_api (0.9.6)
15
+ faraday (~> 0.8.1)
16
+ hashie (>= 1.2)
17
+ multi_json (~> 1.4)
18
+ nokogiri (~> 1.5.2)
19
+ oauth2
20
+ hashie (2.0.3)
21
+ httpauth (0.2.0)
22
+ jwt (0.1.8)
23
+ multi_json (>= 1.5)
24
+ multi_json (1.7.2)
25
+ multi_xml (0.5.3)
26
+ multipart-post (1.2.0)
27
+ nokogiri (1.5.9)
28
+ oauth2 (0.9.1)
29
+ faraday (~> 0.8)
30
+ httpauth (~> 0.1)
31
+ jwt (~> 0.1.4)
32
+ multi_json (~> 1.0)
33
+ multi_xml (~> 0.5)
34
+ rack (~> 1.2)
35
+ rack (1.5.2)
36
+ rake (10.0.4)
37
+ rspec (2.13.0)
38
+ rspec-core (~> 2.13.0)
39
+ rspec-expectations (~> 2.13.0)
40
+ rspec-mocks (~> 2.13.0)
41
+ rspec-core (2.13.1)
42
+ rspec-expectations (2.13.0)
43
+ diff-lcs (>= 1.1.3, < 2.0)
44
+ rspec-mocks (2.13.1)
45
+ thor (0.18.1)
46
+
47
+ PLATFORMS
48
+ ruby
49
+
50
+ DEPENDENCIES
51
+ bundler (~> 1.3)
52
+ github-merge!
53
+ rake
54
+ rspec
data/History.txt ADDED
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2013-03-31
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Arthur Maltson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,10 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/github-merge
7
+ lib/github_merge/merge.rb
8
+ lib/github_merge/cli.rb
9
+ lib/github_merge.rb
10
+ test/test_merge.rb
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # github-merge
2
+
3
+ Script that merges multiple GitHub repositories into a new, single repository.
4
+
5
+ ## Installation
6
+
7
+ This is a CLI app, so you'll have to:
8
+
9
+ ```
10
+ $ gem install github-merge
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ `github-merge` uses a YAML based configuration that lists the
16
+ repositories to merge and the name (and optionally organization) of the
17
+ new combined repository. A sample configuration file:
18
+
19
+ ```yaml
20
+ merged organization: acme
21
+ merged repository: sinatra-templates
22
+ repositories:
23
+ - url: https://github.com/rkh/sinatra-template.git
24
+ sub directory: sinatra-base-template
25
+ - url: https://github.com/sinatra/heroku-sinatra-app.git
26
+ sub directory: sinatra-heroku-template
27
+ ```
28
+
29
+ You'd then merge the repositories:
30
+
31
+ ```
32
+ $ github-merge local sinatra-templates.yml
33
+ ```
34
+
35
+ ### Options
36
+
37
+ *[--all-svn]*
38
+
39
+ Pass this argument if the repositories being merged started their life
40
+ in Subversion and were subsequently migrated to Git. This is required
41
+ because the merge has to skip the initial commit because of a weird
42
+ git-svn issue that causes the `git filter-branch` to bomb (don't ask
43
+ me, it was on Stackoverflow and it works).
44
+
45
+ ### Technical Details
46
+
47
+ The merge process is done in the following steps
48
+
49
+ 1. Clone repositories.
50
+ 2. For each repository to be merged, execute a `git filter-branch` to
51
+ move the entire repository contents into the specified subdirectory.
52
+ 3. Create a new empty Git repository.
53
+ 4. Add each repository to be merged as a remote repository.
54
+ 5. Fetch and `git merge --no-edit <remote>/master` for each repository.
55
+
56
+ Note: a `git merge` is used to preserve the branching history of each
57
+ repository being merged.
58
+
59
+ ### Limitations
60
+
61
+ The following are limitations of github-merge that may, or may not, be
62
+ addressed in the future.
63
+
64
+ * Does not carry over tags
65
+ * Does not carry over active (unmerged) branches
66
+ * Does not merge repositories with only 1 commit
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
73
+ 4. Push to the branch (`git push origin my-new-feature`)
74
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = FileList['spec/**/*_spec.rb']
8
+ end
9
+
10
+ task :default => [:spec]
data/bin/github-merge ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/github_merge/cli'
4
+
5
+ MergeCli.start(ARGV)
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'github_merge'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "github-merge"
8
+ spec.version = Merge::VERSION
9
+ spec.authors = ["Arthur Maltson"]
10
+ spec.email = ["arthur.kalm@gmail.com"]
11
+ spec.description = %q{Script that merges multiple GitHub repositories into a new, single repository.}
12
+ spec.summary = %q{Split your project into lots of small Git repos and finding yourself creating cross repo Pull Requests? This is the gem for you.}
13
+ spec.homepage = "https://github.com/amaltson/github-merge"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "github_api", "~>0.9.4"
22
+ spec.add_dependency "thor", "~>0.18.1"
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ end
@@ -0,0 +1 @@
1
+ require 'github_merge/merge.rb'
@@ -0,0 +1,10 @@
1
+ require 'thor'
2
+ require_relative 'merge'
3
+
4
+ class MergeCli < Thor
5
+ desc 'local file.yml', %q{Locally merge GitHub repositories as specified in YAML file.}
6
+ option :all_svn, :type => :boolean
7
+ def local(file)
8
+ Merge.new(file, options).local!
9
+ end
10
+ end
@@ -0,0 +1,89 @@
1
+ class LocalMerge
2
+
3
+ OUT_DIR = "#{Dir.pwd}/merged"
4
+
5
+ def initialize(config, options)
6
+ @config = config
7
+ @options = options
8
+ end
9
+
10
+ def merge!
11
+ FileUtils.mkdir_p OUT_DIR
12
+ Dir.chdir OUT_DIR do
13
+ clone_repos
14
+ move_repos_to_subdir
15
+ create_empty_merged_repo
16
+ merge_repositories
17
+ end
18
+ end
19
+
20
+ def clone_repos
21
+ @config["repositories"].each do |repo|
22
+ `git clone #{repo["url"]} #{repo["sub directory"]}`
23
+ end
24
+ end
25
+
26
+ def move_repos_to_subdir
27
+ @config["repositories"].each do |repo|
28
+ git_filter_branch_move(repo["sub directory"])
29
+ end
30
+ end
31
+
32
+ def create_empty_merged_repo
33
+ puts 'Creating merged repository'
34
+ `git init #{merge_repo_name}`
35
+ end
36
+
37
+ def merge_repositories
38
+ Dir.chdir merge_repo_name do
39
+ @config["repositories"].each_with_index do |repo, index|
40
+ repo_name = repo["sub directory"]
41
+ `git remote add #{repo_name} ../#{repo_name}`
42
+ `git fetch #{repo_name}`
43
+ `git merge --no-edit #{repo_name}/master`
44
+ end
45
+ end
46
+ end
47
+
48
+ def git_filter_branch_move(subdir)
49
+ puts "Moving repository #{subdir} to subdirectory #{subdir}..."
50
+
51
+ sed = sed_command_to_use
52
+ Dir.chdir subdir do
53
+ %x[git filter-branch --index-filter \
54
+ 'git ls-files -s | #{sed} "s@\t@&#{subdir}/@" |
55
+ GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
56
+ git update-index --index-info &&
57
+ mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' #{beginning_sha}..HEAD]
58
+ end
59
+ end
60
+
61
+ def beginning_sha
62
+ if @options.all_svn?
63
+ `git log --pretty=format:%H --reverse`.split("\n")[1]
64
+ else
65
+ `git log --pretty=format:%H --reverse`.split("\n").first
66
+ end
67
+ end
68
+
69
+ def sed_command_to_use
70
+ if RbConfig::CONFIG['host_os'] =~ /darwin/
71
+ 'gsed'
72
+ else
73
+ 'sed'
74
+ end
75
+ end
76
+
77
+ def merge_repo_name
78
+ @config["merged repository"]
79
+ end
80
+
81
+ def merged?
82
+ merge_repo_dir = "#{OUT_DIR}/#{merge_repo_name}"
83
+ return false unless Dir.exist? merge_repo_dir
84
+ Dir.chdir merge_repo_dir do
85
+ return false unless Dir.exists? '.git'
86
+ return `git log`.split("\n").size > 0
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,27 @@
1
+ require 'yaml'
2
+ require 'rbconfig'
3
+ require 'fileutils'
4
+ require_relative 'local'
5
+ require_relative 'push'
6
+
7
+ class Merge
8
+ VERSION = "0.0.1"
9
+ MOVE_TREE_SCRIPT_PATH = "#{Dir.pwd}/lib/github_merge"
10
+
11
+ def initialize(file, options)
12
+ @file = file
13
+ @options = options
14
+ @config = YAML.load_file @file
15
+ @local_merge = LocalMerge.new(@config, @options)
16
+ @push_merge = PushMerge.new(@config, @options)
17
+ end
18
+
19
+ def local!
20
+ @local_merge.merge!
21
+ end
22
+
23
+ def push!
24
+ @local_merge.merge! unless @local_merge.merged?
25
+ @push_merge.push!
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ class PushMerge
2
+
3
+ def initialize(config, options)
4
+ @config = config
5
+ @options = options
6
+ end
7
+
8
+ def push!
9
+ github = initialize_github
10
+ end
11
+
12
+ def initialize_github
13
+ api_endpoint = config["host"] || "https://api.github.com"
14
+ oauth_token = config["oauth"]
15
+
16
+ Github.new do |config|
17
+ config.endpoint = api_endpoint
18
+ config.oauth_token = oauth_token
19
+ config.adapter = :net_http
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,41 @@
1
+ require 'rspec'
2
+ require 'github_merge/merge'
3
+ require 'fileutils'
4
+
5
+ describe Merge do
6
+ before :each do
7
+ options = double()
8
+ options.stub(:all_svn? => false)
9
+ @merge = Merge.new 'spec/sample-merge-config.yml', options
10
+ end
11
+
12
+ after :each do
13
+ FileUtils.rm_rf(LocalMerge::OUT_DIR)
14
+ end
15
+
16
+ it "shouldn't be merged by default" do
17
+ @merge.instance_variable_get("@local_merge").merged?.should be_false
18
+ end
19
+
20
+ it "should merge locally" do
21
+ @merge.local!
22
+
23
+ # Check clone and rename worked
24
+ %w{github-merge github}.each do |repo|
25
+ Dir.exists?("#{LocalMerge::OUT_DIR}/#{repo}").should be_true
26
+ Dir.exists?("#{LocalMerge::OUT_DIR}/#{repo}/#{repo}").should be_true
27
+ end
28
+
29
+ # check that the merge was successful
30
+ merged_dir = "#{LocalMerge::OUT_DIR}/merge-test"
31
+ Dir.exists?(merged_dir).should be_true
32
+ %w{github-merge github}.each do |repo|
33
+ Dir.exists?("#{merged_dir}/#{repo}").should be_true
34
+ end
35
+
36
+ @merge.instance_variable_get("@local_merge").merged?.should be_true
37
+ end
38
+
39
+ it "should merge local when pushing" do
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ host: https://api.github.com
2
+ oauth: oauth_token_here
3
+ merged organization: org
4
+ merged repository: merge-test
5
+ repositories:
6
+ - url: https://github.com/amaltson/github-merge.git
7
+ sub directory: github-merge
8
+ - url: https://github.com/amaltson/github-merge.git
9
+ sub directory: github
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: github-merge
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Arthur Maltson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: github_api
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.4
30
+ - !ruby/object:Gem::Dependency
31
+ name: thor
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.18.1
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.18.1
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: Script that merges multiple GitHub repositories into a new, single repository.
95
+ email:
96
+ - arthur.kalm@gmail.com
97
+ executables:
98
+ - github-merge
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - .autotest
103
+ - .gitignore
104
+ - Gemfile
105
+ - Gemfile.lock
106
+ - History.txt
107
+ - LICENSE.txt
108
+ - Manifest.txt
109
+ - README.md
110
+ - Rakefile
111
+ - bin/github-merge
112
+ - github-merge.gemspec
113
+ - lib/github_merge.rb
114
+ - lib/github_merge/cli.rb
115
+ - lib/github_merge/local.rb
116
+ - lib/github_merge/merge.rb
117
+ - lib/github_merge/push.rb
118
+ - spec/merge_spec.rb
119
+ - spec/sample-merge-config.yml
120
+ homepage: https://github.com/amaltson/github-merge
121
+ licenses:
122
+ - MIT
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 1.8.23
142
+ signing_key:
143
+ specification_version: 3
144
+ summary: Split your project into lots of small Git repos and finding yourself creating
145
+ cross repo Pull Requests? This is the gem for you.
146
+ test_files:
147
+ - spec/merge_spec.rb
148
+ - spec/sample-merge-config.yml