git-multirepo 1.0.0.beta27 → 1.0.0.beta29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +38 -38
- data/.rspec +2 -2
- data/Gemfile +4 -4
- data/Gemfile.lock +38 -38
- data/LICENSE +22 -22
- data/README.md +141 -141
- data/Rakefile +2 -2
- data/bin/multi +10 -10
- data/git-multirepo.gemspec +29 -29
- data/lib/commands.rb +11 -11
- data/lib/git-multirepo.rb +1 -3
- data/lib/info.rb +4 -4
- data/lib/multirepo/commands/add-command.rb +50 -51
- data/lib/multirepo/commands/branch-command.rb +59 -59
- data/lib/multirepo/commands/checkout-command.rb +139 -119
- data/lib/multirepo/commands/clone-command.rb +69 -69
- data/lib/multirepo/commands/command.rb +62 -62
- data/lib/multirepo/commands/fetch-command.rb +23 -23
- data/lib/multirepo/commands/init-command.rb +94 -51
- data/lib/multirepo/commands/install-command.rb +104 -87
- data/lib/multirepo/commands/open-command.rb +25 -25
- data/lib/multirepo/commands/remove-command.rb +48 -48
- data/lib/multirepo/commands/uninit-command.rb +19 -19
- data/lib/multirepo/commands/update-command.rb +53 -47
- data/lib/multirepo/config.rb +15 -15
- data/lib/multirepo/files/config-entry.rb +34 -34
- data/lib/multirepo/files/config-file.rb +33 -37
- data/lib/multirepo/files/lock-entry.rb +25 -25
- data/lib/multirepo/files/lock-file.rb +44 -39
- data/lib/multirepo/git/branch.rb +27 -27
- data/lib/multirepo/git/change.rb +10 -10
- data/lib/multirepo/git/commit.rb +18 -0
- data/lib/multirepo/git/git.rb +42 -42
- data/lib/multirepo/git/remote.rb +15 -15
- data/lib/multirepo/git/repo.rb +71 -66
- data/lib/multirepo/hooks/pre-commit-hook.rb +29 -25
- data/lib/multirepo/multirepo-exception.rb +5 -5
- data/lib/multirepo/utility/console.rb +51 -51
- data/lib/multirepo/utility/runner.rb +32 -32
- data/lib/multirepo/utility/utils.rb +66 -54
- data/resources/.gitconfig +3 -0
- data/resources/pre-commit +5 -5
- data/spec/integration/init_spec.rb +18 -22
- data/spec/spec_helper.rb +89 -89
- metadata +5 -7
- data/lib/multirepo/hooks/post-merge-hook.rb +0 -20
- data/lib/multirepo/hooks/prepare-commit-msg-hook.rb +0 -28
- data/resources/post-merge +0 -6
- data/resources/prepare-commit-msg +0 -6
data/lib/multirepo/git/remote.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
require_relative "git"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class Remote
|
5
|
-
attr_accessor :name
|
6
|
-
|
7
|
-
def initialize(repo, name)
|
8
|
-
@repo = repo
|
9
|
-
@name = name
|
10
|
-
end
|
11
|
-
|
12
|
-
def url
|
13
|
-
Git.run_in_working_dir(@repo.path, "config --get remote.#{@name}.url", Runner::Verbosity::NEVER_OUTPUT).strip
|
14
|
-
end
|
15
|
-
end
|
1
|
+
require_relative "git"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class Remote
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
def initialize(repo, name)
|
8
|
+
@repo = repo
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def url
|
13
|
+
Git.run_in_working_dir(@repo.path, "config --get remote.#{@name}.url", Runner::Verbosity::NEVER_OUTPUT).strip
|
14
|
+
end
|
15
|
+
end
|
16
16
|
end
|
data/lib/multirepo/git/repo.rb
CHANGED
@@ -1,67 +1,72 @@
|
|
1
|
-
require_relative "branch"
|
2
|
-
require_relative "remote"
|
3
|
-
require_relative "
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
attr_accessor :
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
branch
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
lines.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
Runner
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
Runner
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
Runner
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
1
|
+
require_relative "branch"
|
2
|
+
require_relative "remote"
|
3
|
+
require_relative "commit"
|
4
|
+
require_relative "change"
|
5
|
+
|
6
|
+
module MultiRepo
|
7
|
+
class Repo
|
8
|
+
attr_accessor :path
|
9
|
+
attr_accessor :basename
|
10
|
+
|
11
|
+
def initialize(path)
|
12
|
+
@path = path
|
13
|
+
@basename = Pathname.new(path).basename.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
# Inspection
|
17
|
+
|
18
|
+
def exists?
|
19
|
+
Git.is_inside_git_repo(@path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def current_branch
|
23
|
+
branch = Git.run_in_working_dir(@path, "rev-parse --abbrev-ref HEAD", Runner::Verbosity::NEVER_OUTPUT).strip
|
24
|
+
branch != "HEAD" ? branch : nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def head_hash
|
28
|
+
Git.run_in_working_dir(@path, "rev-parse HEAD", Runner::Verbosity::NEVER_OUTPUT).strip
|
29
|
+
end
|
30
|
+
|
31
|
+
def changes
|
32
|
+
output = Git.run_in_working_dir(@path, "status --porcelain", Runner::Verbosity::NEVER_OUTPUT)
|
33
|
+
lines = output.split("\n").each{ |f| f.strip }.delete_if{ |f| f == "" }
|
34
|
+
lines.map { |l| Change.new(l) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_clean?
|
38
|
+
return changes.count == 0
|
39
|
+
end
|
40
|
+
|
41
|
+
# Operations
|
42
|
+
|
43
|
+
def fetch
|
44
|
+
Git.run_in_working_dir(@path, "fetch --progress", Runner::Verbosity::ALWAYS_OUTPUT)
|
45
|
+
Runner.last_command_succeeded
|
46
|
+
end
|
47
|
+
|
48
|
+
def clone(url)
|
49
|
+
Git.run_in_current_dir("clone #{url} #{@path} --progress", Runner::Verbosity::ALWAYS_OUTPUT)
|
50
|
+
Runner.last_command_succeeded
|
51
|
+
end
|
52
|
+
|
53
|
+
def checkout(ref)
|
54
|
+
Git.run_in_working_dir(@path, "checkout #{ref}", Runner::Verbosity::OUTPUT_ON_ERROR)
|
55
|
+
Runner.last_command_succeeded
|
56
|
+
end
|
57
|
+
|
58
|
+
# Remotes and branches
|
59
|
+
|
60
|
+
def branch(name)
|
61
|
+
Branch.new(self, name)
|
62
|
+
end
|
63
|
+
|
64
|
+
def remote(name)
|
65
|
+
Remote.new(self, name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def commit(ref)
|
69
|
+
Commit.new(self, ref)
|
70
|
+
end
|
71
|
+
end
|
67
72
|
end
|
@@ -1,26 +1,30 @@
|
|
1
|
-
require "multirepo/files/config-file"
|
2
|
-
require "multirepo/files/lock-file"
|
3
|
-
require "multirepo/utility/utils"
|
4
|
-
require "multirepo/utility/console"
|
5
|
-
|
6
|
-
module MultiRepo
|
7
|
-
class PreCommitHook
|
8
|
-
def self.run
|
9
|
-
Config.instance.running_git_hook = true
|
10
|
-
|
11
|
-
Console.log_step("Performing pre-commit operations...")
|
12
|
-
|
13
|
-
dependencies_clean = Utils.ensure_dependencies_clean(ConfigFile.load)
|
14
|
-
|
15
|
-
if !dependencies_clean
|
16
|
-
Console.log_error("You must commit changes to your dependencies before you can commit this repo")
|
17
|
-
exit 1
|
18
|
-
end
|
19
|
-
|
20
|
-
LockFile.update
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
1
|
+
require "multirepo/files/config-file"
|
2
|
+
require "multirepo/files/lock-file"
|
3
|
+
require "multirepo/utility/utils"
|
4
|
+
require "multirepo/utility/console"
|
5
|
+
|
6
|
+
module MultiRepo
|
7
|
+
class PreCommitHook
|
8
|
+
def self.run
|
9
|
+
Config.instance.running_git_hook = true
|
10
|
+
|
11
|
+
Console.log_step("Performing pre-commit operations...")
|
12
|
+
|
13
|
+
dependencies_clean = Utils.ensure_dependencies_clean(ConfigFile.load)
|
14
|
+
|
15
|
+
if !dependencies_clean
|
16
|
+
Console.log_error("You must commit changes to your dependencies before you can commit this repo")
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
LockFile.update
|
21
|
+
LockFile.stage
|
22
|
+
Console.log_info("Updated and staged lock file with current HEAD revisions for all dependencies")
|
23
|
+
|
24
|
+
exit 0 # Success!
|
25
|
+
rescue StandardError => e
|
26
|
+
Console.log_error("Pre-commit hook failed to execute! #{e.message}")
|
27
|
+
exit 1 # Something went wrong!
|
28
|
+
end
|
29
|
+
end
|
26
30
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require "claide/informative_error"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class MultiRepoException < StandardError
|
5
|
-
end
|
1
|
+
require "claide/informative_error"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class MultiRepoException < StandardError
|
5
|
+
end
|
6
6
|
end
|
@@ -1,52 +1,52 @@
|
|
1
|
-
require "colored"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class Console
|
5
|
-
def self.log_step(message)
|
6
|
-
print_prefix
|
7
|
-
puts $stdout.isatty ? message.bold.green : message
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.log_substep(message)
|
11
|
-
print_prefix
|
12
|
-
puts $stdout.isatty ? message.blue : message
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.log_info(message)
|
16
|
-
print_prefix
|
17
|
-
puts $stdout.isatty ? message.white : message
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.log_warning(message)
|
21
|
-
print_prefix
|
22
|
-
puts $stdout.isatty ? message.yellow : message
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.log_error(message)
|
26
|
-
print_prefix
|
27
|
-
puts $stdout.isatty ? message.red : message
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.ask_yes_no(message)
|
31
|
-
answered = false
|
32
|
-
while !answered
|
33
|
-
print_prefix
|
34
|
-
print message
|
35
|
-
print " (y/n) "
|
36
|
-
|
37
|
-
case $stdin.gets.strip.downcase
|
38
|
-
when "y", "yes"
|
39
|
-
answered = true
|
40
|
-
return true
|
41
|
-
when "n", "no"
|
42
|
-
answered = true
|
43
|
-
return false
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.print_prefix
|
49
|
-
print $stdout.isatty ? "> ".white : "[multirepo] "
|
50
|
-
end
|
51
|
-
end
|
1
|
+
require "colored"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class Console
|
5
|
+
def self.log_step(message)
|
6
|
+
print_prefix
|
7
|
+
puts $stdout.isatty ? message.bold.green : message
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.log_substep(message)
|
11
|
+
print_prefix
|
12
|
+
puts $stdout.isatty ? message.blue : message
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.log_info(message)
|
16
|
+
print_prefix
|
17
|
+
puts $stdout.isatty ? message.white : message
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.log_warning(message)
|
21
|
+
print_prefix
|
22
|
+
puts $stdout.isatty ? message.yellow : message
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.log_error(message)
|
26
|
+
print_prefix
|
27
|
+
puts $stdout.isatty ? message.red : message
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.ask_yes_no(message)
|
31
|
+
answered = false
|
32
|
+
while !answered
|
33
|
+
print_prefix
|
34
|
+
print message
|
35
|
+
print " (y/n) "
|
36
|
+
|
37
|
+
case $stdin.gets.strip.downcase
|
38
|
+
when "y", "yes"
|
39
|
+
answered = true
|
40
|
+
return true
|
41
|
+
when "n", "no"
|
42
|
+
answered = true
|
43
|
+
return false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.print_prefix
|
49
|
+
print $stdout.isatty ? "> ".white : "[multirepo] "
|
50
|
+
end
|
51
|
+
end
|
52
52
|
end
|
@@ -1,33 +1,33 @@
|
|
1
|
-
require "open3"
|
2
|
-
require "multirepo/utility/console"
|
3
|
-
|
4
|
-
module MultiRepo
|
5
|
-
class Runner
|
6
|
-
class Verbosity
|
7
|
-
NEVER_OUTPUT = 0
|
8
|
-
ALWAYS_OUTPUT = 1
|
9
|
-
OUTPUT_ON_ERROR = 2
|
10
|
-
end
|
11
|
-
|
12
|
-
class << self
|
13
|
-
attr_accessor :last_command_succeeded
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.run(cmd, verbosity)
|
17
|
-
lines = []
|
18
|
-
Open3.popen2e(cmd) do |stdin, stdout_and_stderr, thread|
|
19
|
-
stdout_and_stderr.each do |line|
|
20
|
-
Console.log_info(line.rstrip) if verbosity == Verbosity::ALWAYS_OUTPUT || Config.instance.verbose
|
21
|
-
lines << line
|
22
|
-
end
|
23
|
-
@last_command_succeeded = thread.value.success?
|
24
|
-
end
|
25
|
-
|
26
|
-
output = lines.join("").rstrip
|
27
|
-
|
28
|
-
Console.log_error(output) if !@last_command_succeeded && verbosity == Verbosity::OUTPUT_ON_ERROR
|
29
|
-
|
30
|
-
return output
|
31
|
-
end
|
32
|
-
end
|
1
|
+
require "open3"
|
2
|
+
require "multirepo/utility/console"
|
3
|
+
|
4
|
+
module MultiRepo
|
5
|
+
class Runner
|
6
|
+
class Verbosity
|
7
|
+
NEVER_OUTPUT = 0
|
8
|
+
ALWAYS_OUTPUT = 1
|
9
|
+
OUTPUT_ON_ERROR = 2
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :last_command_succeeded
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.run(cmd, verbosity)
|
17
|
+
lines = []
|
18
|
+
Open3.popen2e(cmd) do |stdin, stdout_and_stderr, thread|
|
19
|
+
stdout_and_stderr.each do |line|
|
20
|
+
Console.log_info(line.rstrip) if verbosity == Verbosity::ALWAYS_OUTPUT || Config.instance.verbose
|
21
|
+
lines << line
|
22
|
+
end
|
23
|
+
@last_command_succeeded = thread.value.success?
|
24
|
+
end
|
25
|
+
|
26
|
+
output = lines.join("").rstrip
|
27
|
+
|
28
|
+
Console.log_error(output) if !@last_command_succeeded && verbosity == Verbosity::OUTPUT_ON_ERROR
|
29
|
+
|
30
|
+
return output
|
31
|
+
end
|
32
|
+
end
|
33
33
|
end
|
@@ -1,55 +1,67 @@
|
|
1
|
-
require "fileutils"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class Utils
|
5
|
-
def self.path_for_resource(resource_name)
|
6
|
-
gem_path = Gem::Specification.find_by_name("git-multirepo").gem_dir
|
7
|
-
File.join(gem_path, "resources/#{resource_name}")
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.is_multirepo_enabled(path)
|
11
|
-
File.exists?(File.join(path, ".multirepo"))
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.is_multirepo_tracked(path)
|
15
|
-
is_multirepo_enabled(path) && File.exists?(File.join(path, ".multirepo.lock"))
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.install_hook(name, path)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class Utils
|
5
|
+
def self.path_for_resource(resource_name)
|
6
|
+
gem_path = Gem::Specification.find_by_name("git-multirepo").gem_dir
|
7
|
+
File.join(gem_path, "resources/#{resource_name}")
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.is_multirepo_enabled(path)
|
11
|
+
File.exists?(File.join(path, ".multirepo"))
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.is_multirepo_tracked(path)
|
15
|
+
is_multirepo_enabled(path) && File.exists?(File.join(path, ".multirepo.lock"))
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.install_hook(name, path)
|
19
|
+
destination_path = File.join(path, ".git/hooks")
|
20
|
+
destination_file = File.join(destination_path, name)
|
21
|
+
FileUtils.cp(path_for_resource(name), destination_file)
|
22
|
+
FileUtils.chmod(0755, destination_file) # -rwxr-xr-x
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.sibling_repos
|
26
|
+
sibling_directories = Dir['../*/']
|
27
|
+
sibling_repos = sibling_directories.map{ |d| Repo.new(d) }.select{ |r| r.exists? }
|
28
|
+
sibling_repos.delete_if{ |r| Pathname.new(r.path).realpath == Pathname.new(".").realpath }
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.ensure_dependencies_clean(config_entries)
|
32
|
+
clean = true
|
33
|
+
config_entries.each do |e|
|
34
|
+
next unless e.repo.exists?
|
35
|
+
dependency_clean = e.repo.is_clean?
|
36
|
+
clean &= dependency_clean
|
37
|
+
Console.log_info("Dependency '#{e.repo.path}' is clean") if dependency_clean
|
38
|
+
Console.log_warning("Dependency '#{e.repo.path}' contains uncommitted changes") unless dependency_clean
|
39
|
+
end
|
40
|
+
return clean
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.ensure_working_copies_clean(repos)
|
44
|
+
clean = true
|
45
|
+
repos.each do |repo|
|
46
|
+
dependency_clean = repo.is_clean?
|
47
|
+
clean &= dependency_clean
|
48
|
+
Console.log_warning("Repo '#{repo.path}' contains uncommitted changes") unless dependency_clean
|
49
|
+
end
|
50
|
+
return clean
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.convert_to_windows_path(unix_path)
|
54
|
+
components = Pathname.new(unix_path).each_filename.to_a
|
55
|
+
components.join(File::ALT_SEPARATOR)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.append_if_missing(path, pattern, string_to_append)
|
59
|
+
unless File.exists?(path)
|
60
|
+
File.open(path, 'w') { |f| f.puts(string_to_append) }
|
61
|
+
else
|
62
|
+
string_located = File.readlines(path).grep(pattern).any?
|
63
|
+
File.open(path, 'a') { |f| f.puts(string_to_append) } unless string_located
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
55
67
|
end
|