git-multirepo 1.0.0.beta49 → 1.0.0.beta50

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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -2
  3. data/.gitbugtraq +3 -3
  4. data/.gitignore +38 -38
  5. data/.multirepo.meta +2 -2
  6. data/.rspec +2 -2
  7. data/.rubocop.yml +79 -79
  8. data/CHANGELOG.md +29 -25
  9. data/Gemfile +4 -4
  10. data/Gemfile.lock +42 -42
  11. data/LICENSE +22 -22
  12. data/README.md +154 -154
  13. data/Rakefile +1 -1
  14. data/bin/multi +11 -11
  15. data/docs/bug-repros/91565510-repro.sh +20 -20
  16. data/git-multirepo.gemspec +31 -31
  17. data/lib/git-multirepo.rb +3 -3
  18. data/lib/multirepo/commands/add-command.rb +51 -51
  19. data/lib/multirepo/commands/branch-command.rb +82 -82
  20. data/lib/multirepo/commands/checkout-command.rb +120 -120
  21. data/lib/multirepo/commands/clone-command.rb +68 -68
  22. data/lib/multirepo/commands/command.rb +90 -90
  23. data/lib/multirepo/commands/commands.rb +15 -0
  24. data/lib/multirepo/commands/do-command.rb +103 -103
  25. data/lib/multirepo/commands/graph-command.rb +43 -43
  26. data/lib/multirepo/commands/init-command.rb +121 -121
  27. data/lib/multirepo/commands/inspect-command.rb +39 -39
  28. data/lib/multirepo/commands/install-command.rb +153 -153
  29. data/lib/multirepo/commands/merge-command.rb +249 -225
  30. data/lib/multirepo/commands/open-command.rb +57 -57
  31. data/lib/multirepo/commands/remove-command.rb +48 -48
  32. data/lib/multirepo/commands/uninit-command.rb +18 -18
  33. data/lib/multirepo/commands/update-command.rb +106 -94
  34. data/lib/multirepo/config.rb +16 -16
  35. data/lib/multirepo/files/config-entry.rb +39 -39
  36. data/lib/multirepo/files/config-file.rb +46 -46
  37. data/lib/multirepo/files/lock-entry.rb +29 -29
  38. data/lib/multirepo/files/lock-file.rb +56 -56
  39. data/lib/multirepo/files/meta-file.rb +41 -41
  40. data/lib/multirepo/files/tracking-file.rb +9 -9
  41. data/lib/multirepo/files/tracking-files.rb +47 -47
  42. data/lib/multirepo/git/branch.rb +32 -32
  43. data/lib/multirepo/git/change.rb +11 -11
  44. data/lib/multirepo/git/commit.rb +7 -7
  45. data/lib/multirepo/git/git-runner.rb +56 -56
  46. data/lib/multirepo/git/git.rb +10 -10
  47. data/lib/multirepo/git/ref.rb +38 -38
  48. data/lib/multirepo/git/remote.rb +17 -17
  49. data/lib/multirepo/git/repo.rb +124 -124
  50. data/lib/multirepo/hooks/post-commit-hook.rb +23 -23
  51. data/lib/multirepo/hooks/pre-commit-hook.rb +35 -35
  52. data/lib/{info.rb → multirepo/info.rb} +5 -5
  53. data/lib/multirepo/logic/dependency.rb +6 -6
  54. data/lib/multirepo/logic/merge-descriptor.rb +95 -95
  55. data/lib/multirepo/logic/node.rb +72 -72
  56. data/lib/multirepo/logic/performer.rb +55 -55
  57. data/lib/multirepo/logic/revision-selector.rb +35 -35
  58. data/lib/multirepo/multirepo-exception.rb +6 -6
  59. data/lib/multirepo/utility/console.rb +52 -52
  60. data/lib/multirepo/utility/popen-runner.rb +27 -27
  61. data/lib/multirepo/utility/system-runner.rb +14 -14
  62. data/lib/multirepo/utility/utils.rb +95 -95
  63. data/lib/multirepo/utility/verbosity.rb +6 -6
  64. data/resources/.gitconfig +2 -2
  65. data/resources/post-commit +6 -6
  66. data/resources/pre-commit +6 -6
  67. data/spec/integration/init_spec.rb +19 -19
  68. data/spec/spec_helper.rb +89 -89
  69. metadata +33 -33
  70. data/lib/commands.rb +0 -15
@@ -1,51 +1,51 @@
1
- require "multirepo/utility/console"
2
- require "multirepo/files/config-file"
3
-
4
- module MultiRepo
5
- class AddCommand < Command
6
- self.command = "add"
7
- self.summary = "Track an additional dependency with multirepo."
8
-
9
- def self.options
10
- [['<path>', 'The relative path to the new dependency (e.g. ../MyNewDependency)']].concat(super)
11
- end
12
-
13
- def initialize(argv)
14
- @path = argv.shift_argument
15
- super
16
- end
17
-
18
- def validate!
19
- super
20
- help! "You must specify a repository to add as a dependency" unless @path
21
- end
22
-
23
- def run
24
- ensure_in_work_tree
25
- ensure_multirepo_enabled
26
- ensure_repo_valid
27
-
28
- config_file = ConfigFile.new(".")
29
- entry = ConfigEntry.new(Repo.new(@path))
30
-
31
- if config_file.entry_exists?(entry)
32
- Console.log_info("There is already an entry for '#{@path}' in the .multirepo file")
33
- else
34
- config_file.add_entry(entry)
35
- Console.log_step("Added '#{@path}' to the .multirepo file")
36
- end
37
- end
38
-
39
- def ensure_repo_valid
40
- fail MultiRepoException, "The provided path is not a direct sibling of the main repository" unless validate_is_sibling_repo(@path)
41
- fail MultiRepoException, "There is no folder at path '#{@path}'" unless Dir.exist?(@path)
42
- fail MultiRepoException, "'#{@path}' is not a repository" unless Repo.new(@path).exists?
43
- end
44
-
45
- def validate_is_sibling_repo(path)
46
- parent_dir = File.expand_path("..")
47
- path = File.expand_path("..", path)
48
- return parent_dir == path
49
- end
50
- end
51
- end
1
+ require "multirepo/utility/console"
2
+ require "multirepo/files/config-file"
3
+
4
+ module MultiRepo
5
+ class AddCommand < Command
6
+ self.command = "add"
7
+ self.summary = "Track an additional dependency with multirepo."
8
+
9
+ def self.options
10
+ [['<path>', 'The relative path to the new dependency (e.g. ../MyNewDependency)']].concat(super)
11
+ end
12
+
13
+ def initialize(argv)
14
+ @path = argv.shift_argument
15
+ super
16
+ end
17
+
18
+ def validate!
19
+ super
20
+ help! "You must specify a repository to add as a dependency" unless @path
21
+ end
22
+
23
+ def run
24
+ ensure_in_work_tree
25
+ ensure_multirepo_enabled
26
+ ensure_repo_valid
27
+
28
+ config_file = ConfigFile.new(".")
29
+ entry = ConfigEntry.new(Repo.new(@path))
30
+
31
+ if config_file.entry_exists?(entry)
32
+ Console.log_info("There is already an entry for '#{@path}' in the .multirepo file")
33
+ else
34
+ config_file.add_entry(entry)
35
+ Console.log_step("Added '#{@path}' to the .multirepo file")
36
+ end
37
+ end
38
+
39
+ def ensure_repo_valid
40
+ fail MultiRepoException, "The provided path is not a direct sibling of the main repository" unless validate_is_sibling_repo(@path)
41
+ fail MultiRepoException, "There is no folder at path '#{@path}'" unless Dir.exist?(@path)
42
+ fail MultiRepoException, "'#{@path}' is not a repository" unless Repo.new(@path).exists?
43
+ end
44
+
45
+ def validate_is_sibling_repo(path)
46
+ parent_dir = File.expand_path("..")
47
+ path = File.expand_path("..", path)
48
+ return parent_dir == path
49
+ end
50
+ end
51
+ end
@@ -1,82 +1,82 @@
1
- require "multirepo/utility/console"
2
- require "multirepo/git/git"
3
- require "multirepo/files/config-file"
4
- require "multirepo/files/tracking-files"
5
- require "multirepo/logic/performer"
6
-
7
- module MultiRepo
8
- class BranchCommand < Command
9
- self.command = "branch"
10
- self.summary = "Create and/or checkout a new branch for all repos."
11
-
12
- def self.options
13
- [
14
- ['<branch name>', 'The name of the branch to create and checkout.'],
15
- ['[--force]', 'Force creating the branch even if the repos contain uncommmitted changes.'],
16
- ['[--no-push]', 'Do not push the branch on creation.']
17
- ].concat(super)
18
- end
19
-
20
- def initialize(argv)
21
- @branch_name = argv.shift_argument
22
- @force = argv.flag?("force")
23
- @remote_tracking = argv.flag?("push", true)
24
- super
25
- end
26
-
27
- def validate!
28
- super
29
- help! "You must specify a branch name" unless @branch_name
30
- help! "Please provide a valid branch name" unless Git.valid_branch_name?(@branch_name)
31
- end
32
-
33
- def run
34
- ensure_in_work_tree
35
- ensure_multirepo_enabled
36
-
37
- Console.log_step("Branching...")
38
-
39
- main_repo = Repo.new(".")
40
-
41
- # Ensure the main repo is clean
42
- fail MultiRepoException, "Main repo is not clean; multi branch aborted" unless main_repo.clean?
43
-
44
- # Ensure dependencies are clean
45
- config_entries = ConfigFile.new(".").load_entries
46
- unless Utils.dependencies_clean?(config_entries)
47
- fail MultiRepoException, "Dependencies are not clean; multi branch aborted"
48
- end
49
-
50
- # Branch dependencies
51
- Performer.dependencies.each do |dependency|
52
- perform_branch(dependency.config_entry.repo)
53
- end
54
-
55
- # Branch the main repo
56
- perform_branch(main_repo)
57
-
58
- Console.log_step("Done!")
59
- end
60
-
61
- def perform_branch(repo)
62
- Console.log_substep("Branching '#{repo.path}' ...")
63
- Console.log_info("Creating and checking out branch #{@branch_name} ...")
64
-
65
- branch = repo.branch(@branch_name)
66
- branch.create unless branch.exists?
67
- branch.checkout
68
-
69
- if Utils.multirepo_enabled?(repo.path)
70
- Console.log_info("Updating and committing tracking files")
71
- tracking_files = TrackingFiles.new(repo.path)
72
- tracking_files.update
73
- tracking_files.commit("[multirepo] Post-branch tracking files update")
74
- end
75
-
76
- return unless @remote_tracking
77
-
78
- Console.log_info("Pushing #{@branch_name} to origin/#{@branch_name}")
79
- repo.branch(@branch_name).push
80
- end
81
- end
82
- end
1
+ require "multirepo/utility/console"
2
+ require "multirepo/git/git"
3
+ require "multirepo/files/config-file"
4
+ require "multirepo/files/tracking-files"
5
+ require "multirepo/logic/performer"
6
+
7
+ module MultiRepo
8
+ class BranchCommand < Command
9
+ self.command = "branch"
10
+ self.summary = "Create and/or checkout a new branch for all repos."
11
+
12
+ def self.options
13
+ [
14
+ ['<branch name>', 'The name of the branch to create and checkout.'],
15
+ ['[--force]', 'Force creating the branch even if the repos contain uncommmitted changes.'],
16
+ ['[--no-push]', 'Do not push the branch on creation.']
17
+ ].concat(super)
18
+ end
19
+
20
+ def initialize(argv)
21
+ @branch_name = argv.shift_argument
22
+ @force = argv.flag?("force")
23
+ @remote_tracking = argv.flag?("push", true)
24
+ super
25
+ end
26
+
27
+ def validate!
28
+ super
29
+ help! "You must specify a branch name" unless @branch_name
30
+ help! "Please provide a valid branch name" unless Git.valid_branch_name?(@branch_name)
31
+ end
32
+
33
+ def run
34
+ ensure_in_work_tree
35
+ ensure_multirepo_enabled
36
+
37
+ Console.log_step("Branching...")
38
+
39
+ main_repo = Repo.new(".")
40
+
41
+ # Ensure the main repo is clean
42
+ fail MultiRepoException, "Main repo is not clean; multi branch aborted" unless main_repo.clean?
43
+
44
+ # Ensure dependencies are clean
45
+ config_entries = ConfigFile.new(".").load_entries
46
+ unless Utils.dependencies_clean?(config_entries)
47
+ fail MultiRepoException, "Dependencies are not clean; multi branch aborted"
48
+ end
49
+
50
+ # Branch dependencies
51
+ Performer.dependencies.each do |dependency|
52
+ perform_branch(dependency.config_entry.repo)
53
+ end
54
+
55
+ # Branch the main repo
56
+ perform_branch(main_repo)
57
+
58
+ Console.log_step("Done!")
59
+ end
60
+
61
+ def perform_branch(repo)
62
+ Console.log_substep("Branching '#{repo.path}' ...")
63
+ Console.log_info("Creating and checking out branch #{@branch_name} ...")
64
+
65
+ branch = repo.branch(@branch_name)
66
+ branch.create unless branch.exists?
67
+ branch.checkout
68
+
69
+ if Utils.multirepo_enabled?(repo.path)
70
+ Console.log_info("Updating and committing tracking files")
71
+ tracking_files = TrackingFiles.new(repo.path)
72
+ tracking_files.update
73
+ tracking_files.commit("[multirepo] Post-branch tracking files update")
74
+ end
75
+
76
+ return unless @remote_tracking
77
+
78
+ Console.log_info("Pushing #{@branch_name} to origin/#{@branch_name}")
79
+ repo.branch(@branch_name).push
80
+ end
81
+ end
82
+ end
@@ -1,120 +1,120 @@
1
- require "multirepo/utility/console"
2
- require "multirepo/logic/revision-selector"
3
- require "multirepo/logic/performer"
4
-
5
- module MultiRepo
6
- class CheckoutCommand < Command
7
- self.command = "checkout"
8
- self.summary = "Checks out the specified commit or branch of the main repo and checks out matching versions of all dependencies."
9
-
10
- def self.options
11
- [
12
- ['<refname>', 'The main repo tag, branch or commit id to checkout.'],
13
- ['[--latest]', 'Checkout the HEAD of each dependency branch (as recorded in the lock file) instead of the exact required commits.'],
14
- ['[--exact]', 'Checkout the exact specified ref for each repo, regardless of what\'s stored in the lock file.']
15
- ].concat(super)
16
- end
17
-
18
- def initialize(argv)
19
- @ref_name = argv.shift_argument
20
- @checkout_latest = argv.flag?("latest")
21
- @checkout_exact = argv.flag?("exact")
22
- super
23
- end
24
-
25
- def validate!
26
- super
27
- help! "You must specify a branch or commit id to checkout" unless @ref_name
28
- unless validate_only_one_flag(@checkout_latest, @checkout_exact)
29
- help! "You can't provide more than one operation modifier (--latest, --exact, etc.)"
30
- end
31
- end
32
-
33
- def run
34
- ensure_in_work_tree
35
-
36
- # Find out the checkout mode based on command-line options
37
- mode = RevisionSelector.mode_for_args(@checkout_latest, @checkout_exact)
38
-
39
- strategy_name = RevisionSelectionMode.name_for_mode(mode)
40
- Console.log_step("Checking out #{@ref_name} and its dependencies using the '#{strategy_name}' strategy...")
41
-
42
- main_repo = Repo.new(".")
43
-
44
- unless proceed_if_merge_commit?(main_repo, @ref_name, mode)
45
- fail MultiRepoException, "Aborting checkout"
46
- end
47
-
48
- checkout_core(main_repo, mode)
49
-
50
- Console.log_step("Done!")
51
- end
52
-
53
- def checkout_core(main_repo, mode)
54
- initial_revision = main_repo.current_revision
55
- begin
56
- # Checkout first because the current ref might not be multirepo-enabled
57
- checkout_main_repo_step(main_repo)
58
- # Only then can we check for dependencies and make sure they are clean
59
- ensure_dependencies_clean_step
60
- rescue MultiRepoException => e
61
- Console.log_warning("Restoring working copy to #{initial_revision}")
62
- main_repo.checkout(initial_revision)
63
- raise e
64
- end
65
- dependencies_checkout_step(mode, @ref_name)
66
- end
67
-
68
- def checkout_main_repo_step(main_repo)
69
- Performer.perform_main_repo_checkout(main_repo, @ref_name)
70
- end
71
-
72
- def ensure_dependencies_clean_step
73
- unless Utils.dependencies_clean?(ConfigFile.new(".").load_entries)
74
- fail MultiRepoException, "Dependencies are not clean!"
75
- end
76
- end
77
-
78
- def dependencies_checkout_step(mode, ref_name = nil)
79
- Performer.dependencies.each do |dependency|
80
- # Find out the required dependency revision based on the checkout mode
81
- revision = RevisionSelector.revision_for_mode(mode, ref_name, dependency.lock_entry)
82
- perform_dependency_checkout(dependency.config_entry, revision)
83
- end
84
- end
85
-
86
- def proceed_if_merge_commit?(main_repo, ref_name, mode)
87
- return true unless main_repo.ref(ref_name).merge_commit?
88
-
89
- case mode
90
- when RevisionSelectionMode::AS_LOCK
91
- Console.log_error("The specified ref is a merge commit and an \"as-lock\" checkout was requested.")
92
- Console.log_error("The resulting checkout would most probably not result in a valid project state.")
93
- return false
94
- when RevisionSelectionMode::LATEST
95
- Console.log_warning("The specified ref is a merge commit and a \"latest\" checkout was requested.")
96
- Console.log_warning("The work branches recorded in the branch from which the merge was performed will be checked out.")
97
- end
98
-
99
- return true
100
- end
101
-
102
- def perform_dependency_checkout(config_entry, revision)
103
- dependency_name = config_entry.repo.basename
104
-
105
- # Make sure the repo exists on disk, and clone it if it doesn't
106
- # (in case the checked-out revision had an additional dependency)
107
- unless config_entry.repo.exists?
108
- Console.log_substep("Cloning missing dependency '#{config_entry.path}' from #{config_entry.url}")
109
- config_entry.repo.clone(config_entry.url)
110
- end
111
-
112
- # Checkout!
113
- if config_entry.repo.checkout(revision)
114
- Console.log_substep("Checked out #{dependency_name} '#{revision}'")
115
- else
116
- fail MultiRepoException, "Couldn't check out the appropriate version of dependency #{dependency_name}"
117
- end
118
- end
119
- end
120
- end
1
+ require "multirepo/utility/console"
2
+ require "multirepo/logic/revision-selector"
3
+ require "multirepo/logic/performer"
4
+
5
+ module MultiRepo
6
+ class CheckoutCommand < Command
7
+ self.command = "checkout"
8
+ self.summary = "Checks out the specified commit or branch of the main repo and checks out matching versions of all dependencies."
9
+
10
+ def self.options
11
+ [
12
+ ['<refname>', 'The main repo tag, branch or commit id to checkout.'],
13
+ ['[--latest]', 'Checkout the HEAD of each dependency branch (as recorded in the lock file) instead of the exact required commits.'],
14
+ ['[--exact]', 'Checkout the exact specified ref for each repo, regardless of what\'s stored in the lock file.']
15
+ ].concat(super)
16
+ end
17
+
18
+ def initialize(argv)
19
+ @ref_name = argv.shift_argument
20
+ @checkout_latest = argv.flag?("latest")
21
+ @checkout_exact = argv.flag?("exact")
22
+ super
23
+ end
24
+
25
+ def validate!
26
+ super
27
+ help! "You must specify a branch or commit id to checkout" unless @ref_name
28
+ unless validate_only_one_flag(@checkout_latest, @checkout_exact)
29
+ help! "You can't provide more than one operation modifier (--latest, --exact, etc.)"
30
+ end
31
+ end
32
+
33
+ def run
34
+ ensure_in_work_tree
35
+
36
+ # Find out the checkout mode based on command-line options
37
+ mode = RevisionSelector.mode_for_args(@checkout_latest, @checkout_exact)
38
+
39
+ strategy_name = RevisionSelectionMode.name_for_mode(mode)
40
+ Console.log_step("Checking out #{@ref_name} and its dependencies using the '#{strategy_name}' strategy...")
41
+
42
+ main_repo = Repo.new(".")
43
+
44
+ unless proceed_if_merge_commit?(main_repo, @ref_name, mode)
45
+ fail MultiRepoException, "Aborting checkout"
46
+ end
47
+
48
+ checkout_core(main_repo, mode)
49
+
50
+ Console.log_step("Done!")
51
+ end
52
+
53
+ def checkout_core(main_repo, mode)
54
+ initial_revision = main_repo.current_revision
55
+ begin
56
+ # Checkout first because the current ref might not be multirepo-enabled
57
+ checkout_main_repo_step(main_repo)
58
+ # Only then can we check for dependencies and make sure they are clean
59
+ ensure_dependencies_clean_step
60
+ rescue MultiRepoException => e
61
+ Console.log_warning("Restoring working copy to #{initial_revision}")
62
+ main_repo.checkout(initial_revision)
63
+ raise e
64
+ end
65
+ dependencies_checkout_step(mode, @ref_name)
66
+ end
67
+
68
+ def checkout_main_repo_step(main_repo)
69
+ Performer.perform_main_repo_checkout(main_repo, @ref_name)
70
+ end
71
+
72
+ def ensure_dependencies_clean_step
73
+ unless Utils.dependencies_clean?(ConfigFile.new(".").load_entries)
74
+ fail MultiRepoException, "Dependencies are not clean!"
75
+ end
76
+ end
77
+
78
+ def dependencies_checkout_step(mode, ref_name = nil)
79
+ Performer.dependencies.each do |dependency|
80
+ # Find out the required dependency revision based on the checkout mode
81
+ revision = RevisionSelector.revision_for_mode(mode, ref_name, dependency.lock_entry)
82
+ perform_dependency_checkout(dependency.config_entry, revision)
83
+ end
84
+ end
85
+
86
+ def proceed_if_merge_commit?(main_repo, ref_name, mode)
87
+ return true unless main_repo.ref(ref_name).merge_commit?
88
+
89
+ case mode
90
+ when RevisionSelectionMode::AS_LOCK
91
+ Console.log_error("The specified ref is a merge commit and an \"as-lock\" checkout was requested.")
92
+ Console.log_error("The resulting checkout would most probably not result in a valid project state.")
93
+ return false
94
+ when RevisionSelectionMode::LATEST
95
+ Console.log_warning("The specified ref is a merge commit and a \"latest\" checkout was requested.")
96
+ Console.log_warning("The work branches recorded in the branch from which the merge was performed will be checked out.")
97
+ end
98
+
99
+ return true
100
+ end
101
+
102
+ def perform_dependency_checkout(config_entry, revision)
103
+ dependency_name = config_entry.repo.basename
104
+
105
+ # Make sure the repo exists on disk, and clone it if it doesn't
106
+ # (in case the checked-out revision had an additional dependency)
107
+ unless config_entry.repo.exists?
108
+ Console.log_substep("Cloning missing dependency '#{config_entry.path}' from #{config_entry.url}")
109
+ config_entry.repo.clone(config_entry.url)
110
+ end
111
+
112
+ # Checkout!
113
+ if config_entry.repo.checkout(revision)
114
+ Console.log_substep("Checked out #{dependency_name} '#{revision}'")
115
+ else
116
+ fail MultiRepoException, "Couldn't check out the appropriate version of dependency #{dependency_name}"
117
+ end
118
+ end
119
+ end
120
+ end