git-multi 2.0.0 → 2.1.0
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/exe/git-multi +1 -1
- data/lib/git/multi/commands.rb +38 -32
- data/lib/git/multi/config.rb +31 -0
- data/lib/git/multi/report.rb +132 -0
- data/lib/git/multi/version.rb +1 -1
- data/lib/git/multi.rb +71 -53
- data/man/git-multi.1 +8 -3
- data/man/git-multi.erb +3 -0
- data/man/git-multi.html +10 -2
- metadata +4 -4
- data/lib/git/multi/settings.rb +0 -99
- data/lib/git/multi/utils.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1bda879ee8b1b3320c8d5490201645cf2f686f8e82cb8200fb1b0a2f8538588
|
4
|
+
data.tar.gz: 072b2cfb7ed429f2a8f78b969ce808a4a0365ab37575c86deceb02c2bbe85701
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2565edfd604e66bbcfeda950c83e5da58ac5f4fbda2173e1705dd56ff98ad8c04b2f757edcaa8c4a45e37e7ab184361db8b3ff2645c95f3b3fd1c100ab7f2279
|
7
|
+
data.tar.gz: 3d56e12752052a25dc64fed40684ae88125d6f330930efbd3a553b1874127a6d721e249306c1b8d2090f102b7cd836d565ca182dba2fd94412687232492dd846
|
data/exe/git-multi
CHANGED
@@ -21,7 +21,7 @@ when /\A--/
|
|
21
21
|
when '--version' then Git::Multi::Commands.version
|
22
22
|
when '--help' then Git::Multi::Commands.help
|
23
23
|
when '--html' then Git::Multi::Commands.html
|
24
|
-
when '--report' then Git::Multi::Commands.report
|
24
|
+
when '--report' then Git::Multi::Commands.report(multi_repo)
|
25
25
|
when '--count' then Git::Multi::Commands.count
|
26
26
|
when '--refresh' then Git::Multi::Commands.refresh
|
27
27
|
when '--json' then Git::Multi::Commands.json(multi_repo)
|
data/lib/git/multi/commands.rb
CHANGED
@@ -16,11 +16,17 @@ module Git
|
|
16
16
|
Kernel.exec "open #{Git::Multi::HTML_PAGE}"
|
17
17
|
end
|
18
18
|
|
19
|
-
def report
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
def report(multi_repo = nil)
|
20
|
+
case multi_repo
|
21
|
+
when nil
|
22
|
+
Report.home_status(Git::Multi::HOME)
|
23
|
+
Report.workarea_status(Git::Multi::WORKAREA)
|
24
|
+
Report.for(*MULTI_REPOS)
|
25
|
+
when *MULTI_REPOS
|
26
|
+
Report.for(multi_repo)
|
27
|
+
else
|
28
|
+
raise "Unknown multi repo: #{multi_repo}"
|
29
|
+
end
|
24
30
|
end
|
25
31
|
|
26
32
|
def count
|
@@ -71,14 +77,14 @@ module Git
|
|
71
77
|
end
|
72
78
|
|
73
79
|
def clone(multi_repo = nil)
|
74
|
-
Git::Multi.missing_repositories_for(multi_repo).each do |
|
75
|
-
FileUtils.mkdir_p
|
76
|
-
|
77
|
-
->(
|
78
|
-
Kernel.system "git clone -q #{
|
80
|
+
Git::Multi.missing_repositories_for(multi_repo).each do |repository|
|
81
|
+
FileUtils.mkdir_p repository.parent_dir # create multi-repo workarea
|
82
|
+
repository.just_do_it(
|
83
|
+
->(repo) {
|
84
|
+
Kernel.system "git clone -q #{repo.rels[:ssh].href.shellescape}"
|
79
85
|
},
|
80
|
-
->(
|
81
|
-
Kernel.system "git clone -q #{
|
86
|
+
->(repo) {
|
87
|
+
Kernel.system "git clone -q #{repo.rels[:ssh].href.shellescape}"
|
82
88
|
},
|
83
89
|
in: 'parent_dir'
|
84
90
|
)
|
@@ -98,33 +104,33 @@ module Git
|
|
98
104
|
end
|
99
105
|
|
100
106
|
def query(args = [], multi_repo = nil)
|
101
|
-
Git::Multi.repositories_for(multi_repo).each do |
|
102
|
-
|
103
|
-
->(
|
107
|
+
Git::Multi.repositories_for(multi_repo).each do |repository|
|
108
|
+
repository.just_do_it(
|
109
|
+
->(repo) {
|
104
110
|
args.each do |attribute|
|
105
|
-
puts "#{attribute}: #{
|
111
|
+
puts "#{attribute}: #{repo[attribute]}"
|
106
112
|
end
|
107
113
|
},
|
108
|
-
->(
|
109
|
-
print "#{
|
110
|
-
puts args.map { |attribute|
|
114
|
+
->(repo) {
|
115
|
+
print "#{repo.full_name}: "
|
116
|
+
puts args.map { |attribute| repo[attribute] }.join(' ')
|
111
117
|
},
|
112
118
|
)
|
113
119
|
end
|
114
120
|
end
|
115
121
|
|
116
122
|
def find(commands, multi_repo = nil)
|
117
|
-
Git::Multi.cloned_repositories_for(multi_repo).each do |
|
118
|
-
Dir.chdir(
|
123
|
+
Git::Multi.cloned_repositories_for(multi_repo).each do |repository|
|
124
|
+
Dir.chdir(repository.local_path) do
|
119
125
|
if repo.instance_eval(commands.join(' && '))
|
120
126
|
repo.just_do_it(
|
121
|
-
->(
|
122
|
-
->(
|
127
|
+
->(_repo) { nil },
|
128
|
+
->(repo) { puts repo.full_name },
|
123
129
|
)
|
124
130
|
end
|
125
131
|
rescue Octokit::NotFound
|
126
|
-
#
|
127
|
-
# consider running "git multi --stale"
|
132
|
+
# repository no longer exists on GitHub
|
133
|
+
# consider running "git multi --stale"!
|
128
134
|
end
|
129
135
|
end
|
130
136
|
end
|
@@ -134,8 +140,8 @@ module Git
|
|
134
140
|
Dir.chdir(repo.local_path) do
|
135
141
|
repo.instance_eval(commands.join(' ; '))
|
136
142
|
rescue Octokit::NotFound
|
137
|
-
#
|
138
|
-
# consider running "git multi --stale"
|
143
|
+
# repository no longer exists on GitHub
|
144
|
+
# consider running "git multi --stale"!
|
139
145
|
end
|
140
146
|
end
|
141
147
|
end
|
@@ -152,13 +158,13 @@ module Git
|
|
152
158
|
|
153
159
|
def system(args = [], multi_repo = nil)
|
154
160
|
cmd = args.map!(&:shellescape).join(' ')
|
155
|
-
Git::Multi.cloned_repositories_for(multi_repo).each do |
|
156
|
-
|
157
|
-
->(
|
161
|
+
Git::Multi.cloned_repositories_for(multi_repo).each do |repository|
|
162
|
+
repository.just_do_it(
|
163
|
+
->(_repo) {
|
158
164
|
Kernel.system cmd
|
159
165
|
},
|
160
|
-
->(
|
161
|
-
Kernel.system "#{cmd} 2>&1 | sed -e 's#^##{
|
166
|
+
->(repo) {
|
167
|
+
Kernel.system "#{cmd} 2>&1 | sed -e 's#^##{repo.full_name.shellescape}: #'"
|
162
168
|
},
|
163
169
|
in: 'local_path'
|
164
170
|
)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Git
|
2
|
+
module Multi
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def local_option(path, name, default = nil)
|
7
|
+
value = `git -C #{path} config --local --get #{name}`.chomp.freeze
|
8
|
+
value.empty? && default ? default : value
|
9
|
+
end
|
10
|
+
|
11
|
+
def local_list(filename, name)
|
12
|
+
list = `git config --file #{filename} --get-all #{name}`
|
13
|
+
list.split($RS).map(&:strip).map(&:freeze)
|
14
|
+
end
|
15
|
+
|
16
|
+
def global_option(name, default = nil)
|
17
|
+
value = `git config --global --get #{name}`.chomp.freeze
|
18
|
+
value.empty? && default ? default : value
|
19
|
+
end
|
20
|
+
|
21
|
+
def global_list(name, default = nil)
|
22
|
+
global_option(name, default).split(',').map(&:strip).map(&:freeze)
|
23
|
+
end
|
24
|
+
|
25
|
+
def env_var(name, default = nil)
|
26
|
+
value = ENV[name].dup.freeze
|
27
|
+
(value.nil? || value.empty?) && default ? default : value
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Git
|
2
|
+
module Multi
|
3
|
+
module Report
|
4
|
+
|
5
|
+
TICK = ['2714'.hex].pack('U*').green.freeze
|
6
|
+
CROSS = ['2718'.hex].pack('U*').red.freeze
|
7
|
+
ARROW = ['2794'.hex].pack('U*').blue.freeze
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def home_status(home)
|
12
|
+
directory_status(['${HOME}', home], home)
|
13
|
+
end
|
14
|
+
|
15
|
+
def workarea_status(workarea)
|
16
|
+
directory_status(['${WORKAREA}', abbreviate(workarea, :home)], workarea)
|
17
|
+
end
|
18
|
+
|
19
|
+
def owner_status(message, workarea, owner)
|
20
|
+
directory_status(
|
21
|
+
[
|
22
|
+
message,
|
23
|
+
File.join(abbreviate(workarea, :workarea), owner),
|
24
|
+
],
|
25
|
+
File.join(workarea, owner)
|
26
|
+
)
|
27
|
+
|
28
|
+
github_count = Git::Multi.repositories_for(owner).count
|
29
|
+
cloned_count = Git::Multi.cloned_repositories_for(owner).count
|
30
|
+
missing_count = (github_count - cloned_count)
|
31
|
+
subdir_count = Dir.new(workarea).git_repos(owner).count
|
32
|
+
surplus_count = (subdir_count - cloned_count)
|
33
|
+
|
34
|
+
setting_status(["\tGitHub ", "#{github_count} repositories"])
|
35
|
+
setting_status(["\tcloned ", cloned_count, "(#{missing_count} missing)"])
|
36
|
+
Git::Multi.missing_repositories_for(owner).each do |missing|
|
37
|
+
setting_status(["\tmissing", missing.full_name], false, false)
|
38
|
+
end
|
39
|
+
setting_status(["\tsubdirs", subdir_count, "(#{surplus_count} surplus)"])
|
40
|
+
end
|
41
|
+
|
42
|
+
def project_status(message, superproject)
|
43
|
+
github_count = Git::Multi.repositories_for(superproject).count
|
44
|
+
|
45
|
+
if github_count.zero?
|
46
|
+
setting_status([message, 'listed but not configured'], false, false)
|
47
|
+
else
|
48
|
+
setting_status([message], true)
|
49
|
+
Git::Multi.repositories_for(superproject).each do |repo|
|
50
|
+
if File.directory? repo.local_path
|
51
|
+
setting_status(["\tcloned ", repo.full_name], true)
|
52
|
+
else
|
53
|
+
setting_status(["\tmissing", repo.full_name], false, false)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def for(*multi_repos)
|
60
|
+
multi_repos.each do |multi_repo|
|
61
|
+
case (user = org = project = multi_repo)
|
62
|
+
when *USERS
|
63
|
+
owner_status("user \"#{user}\"", Git::Multi::WORKAREA, user)
|
64
|
+
when *ORGANIZATIONS
|
65
|
+
owner_status("org \"#{org}\"", Git::Multi::WORKAREA, org)
|
66
|
+
when *SUPERPROJECTS
|
67
|
+
project_status("superproject \"#{project}\"", project)
|
68
|
+
else
|
69
|
+
raise "Unknown multi repo: #{multi_repo}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private_class_method def describe(token)
|
75
|
+
if token.nil?
|
76
|
+
'(nil)'
|
77
|
+
elsif token.empty?
|
78
|
+
'(empty)'
|
79
|
+
else
|
80
|
+
"#{'*' * 36}#{token[36..-1]}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private_class_method def symbolize(token)
|
85
|
+
case token
|
86
|
+
when Git::Multi.env_var('OCTOKIT_ACCESS_TOKEN')
|
87
|
+
then '${OCTOKIT_ACCESS_TOKEN}'
|
88
|
+
when Git::Multi.global_option('github.token')
|
89
|
+
then 'github.token'
|
90
|
+
else '(unset)'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private_class_method def abbreviate(directory, root_dir = nil)
|
95
|
+
case root_dir
|
96
|
+
when :home
|
97
|
+
then directory.gsub(Git::Multi::HOME, '${HOME}')
|
98
|
+
when :workarea
|
99
|
+
then directory.gsub(Git::Multi::WORKAREA, '${WORKAREA}')
|
100
|
+
else abbreviate(abbreviate(directory, :workarea), :home)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private_class_method def setting_status(messages, valid = false, optional = true)
|
105
|
+
fields = messages.compact.join(' - ')
|
106
|
+
icon = valid ? TICK : optional ? ARROW : CROSS
|
107
|
+
puts "#{icon} #{fields}"
|
108
|
+
end
|
109
|
+
|
110
|
+
private_class_method def file_status(file, message = 'File')
|
111
|
+
setting_status(
|
112
|
+
[
|
113
|
+
message,
|
114
|
+
abbreviate(file),
|
115
|
+
File.file?(file) ? "#{File.size(file).commify} bytes" : nil,
|
116
|
+
],
|
117
|
+
file && !file.empty? && File.file?(file),
|
118
|
+
false
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
private_class_method def directory_status(messages, directory)
|
123
|
+
setting_status(
|
124
|
+
messages,
|
125
|
+
directory && !directory.empty? && File.directory?(directory),
|
126
|
+
false
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/git/multi/version.rb
CHANGED
data/lib/git/multi.rb
CHANGED
@@ -15,9 +15,9 @@ require 'ext/sawyer/resource'
|
|
15
15
|
|
16
16
|
require 'git/hub'
|
17
17
|
|
18
|
-
require 'git/multi/
|
18
|
+
require 'git/multi/config'
|
19
|
+
require 'git/multi/report'
|
19
20
|
require 'git/multi/version'
|
20
|
-
require 'git/multi/settings'
|
21
21
|
require 'git/multi/commands'
|
22
22
|
|
23
23
|
module Git
|
@@ -26,16 +26,23 @@ module Git
|
|
26
26
|
HOME = Dir.home
|
27
27
|
|
28
28
|
DEFAULT_WORKAREA = File.join(HOME, 'Workarea')
|
29
|
-
WORKAREA =
|
29
|
+
WORKAREA = global_option('git.multi.workarea', DEFAULT_WORKAREA)
|
30
30
|
|
31
31
|
DEFAULT_TOKEN = env_var('OCTOKIT_ACCESS_TOKEN') # same as Octokit
|
32
|
-
TOKEN =
|
32
|
+
TOKEN = global_option('github.token', DEFAULT_TOKEN)
|
33
33
|
|
34
|
-
|
35
|
-
REPOSITORIES = File.join(CACHE, 'repositories.byte')
|
34
|
+
GIT_MULTI_DIR = File.join(HOME, '.git', 'multi')
|
36
35
|
|
37
|
-
|
38
|
-
|
36
|
+
FileUtils.mkdir_p(GIT_MULTI_DIR) # ensure `~/.git/multi` directory exists
|
37
|
+
|
38
|
+
GITHUB_CACHE = File.join(GIT_MULTI_DIR, 'repositories.byte')
|
39
|
+
SUPERPROJECTS_CONFIG = File.join(GIT_MULTI_DIR, 'superprojects.config')
|
40
|
+
|
41
|
+
USERS = global_list('git.multi.users')
|
42
|
+
ORGANIZATIONS = global_list('git.multi.organizations')
|
43
|
+
SUPERPROJECTS = global_list('git.multi.superprojects')
|
44
|
+
|
45
|
+
MULTI_REPOS = (USERS + ORGANIZATIONS + SUPERPROJECTS)
|
39
46
|
|
40
47
|
MAN_PAGE = File.expand_path('../../man/git-multi.1', __dir__)
|
41
48
|
HTML_PAGE = File.expand_path('../../man/git-multi.html', __dir__)
|
@@ -47,7 +54,11 @@ module Git
|
|
47
54
|
#
|
48
55
|
|
49
56
|
def valid?(multi_repo)
|
50
|
-
|
57
|
+
MULTI_REPOS.include? multi_repo
|
58
|
+
end
|
59
|
+
|
60
|
+
def full_names_for(superproject)
|
61
|
+
local_list(SUPERPROJECTS_CONFIG, "superproject.#{superproject}.repo")
|
51
62
|
end
|
52
63
|
|
53
64
|
#
|
@@ -69,16 +80,16 @@ module Git
|
|
69
80
|
).flatten
|
70
81
|
end
|
71
82
|
|
72
|
-
def local_repositories_for(
|
73
|
-
case
|
83
|
+
def local_repositories_for(owner = nil)
|
84
|
+
case owner
|
74
85
|
when nil
|
75
|
-
local_repositories
|
86
|
+
local_repositories # all of them
|
76
87
|
when *USERS
|
77
88
|
@local_user_repositories[owner]
|
78
89
|
when *ORGANIZATIONS
|
79
90
|
@local_org_repositories[owner]
|
80
91
|
else
|
81
|
-
raise "Unknown
|
92
|
+
raise "Unknown owner: #{owner}"
|
82
93
|
end
|
83
94
|
end
|
84
95
|
|
@@ -101,16 +112,16 @@ module Git
|
|
101
112
|
).flatten
|
102
113
|
end
|
103
114
|
|
104
|
-
def github_repositories_for(
|
105
|
-
case
|
115
|
+
def github_repositories_for(owner = nil)
|
116
|
+
case owner
|
106
117
|
when nil
|
107
|
-
github_repositories
|
118
|
+
github_repositories # all of them
|
108
119
|
when *USERS
|
109
120
|
@github_user_repositories[owner]
|
110
121
|
when *ORGANIZATIONS
|
111
122
|
@github_org_repositories[owner]
|
112
123
|
else
|
113
|
-
raise "Unknown
|
124
|
+
raise "Unknown owner: #{owner}"
|
114
125
|
end
|
115
126
|
end
|
116
127
|
|
@@ -119,9 +130,7 @@ module Git
|
|
119
130
|
#
|
120
131
|
|
121
132
|
def refresh_repositories
|
122
|
-
File.
|
123
|
-
|
124
|
-
File.open(REPOSITORIES, 'wb') do |file|
|
133
|
+
File.open(GITHUB_CACHE, 'wb') do |file|
|
125
134
|
Marshal.dump(github_repositories, file)
|
126
135
|
end
|
127
136
|
end
|
@@ -151,22 +160,22 @@ module Git
|
|
151
160
|
end
|
152
161
|
|
153
162
|
def repositories
|
154
|
-
if File.size?(
|
163
|
+
if File.size?(GITHUB_CACHE)
|
155
164
|
# rubocop:disable Security/MarshalLoad
|
156
|
-
@repositories ||= Marshal.load(File.read(
|
157
|
-
|
158
|
-
# ensure '
|
159
|
-
|
160
|
-
# adorn '
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
# fix '
|
165
|
-
|
165
|
+
@repositories ||= Marshal.load(File.read(GITHUB_CACHE)).tap do |repos|
|
166
|
+
repos.each_with_index do |repo, index|
|
167
|
+
# ensure 'repo' has handle on an Octokit client
|
168
|
+
repo.client = Git::Hub.send(:client)
|
169
|
+
# adorn 'repo', which is a Sawyer::Resource
|
170
|
+
repo.parent_dir = Pathname.new(File.join(WORKAREA, repo.owner.login))
|
171
|
+
repo.local_path = Pathname.new(File.join(WORKAREA, repo.full_name))
|
172
|
+
repo.fractional_index = "#{index + 1}/#{repos.count}"
|
173
|
+
# fix 'repo' => https://github.com/octokit/octokit.rb/issues/727
|
174
|
+
repo.compliant_ssh_url = 'ssh://' + repo.ssh_url.split(':', 2).join('/')
|
166
175
|
# remove optional '.git' suffix from 'git@github.com:pvdb/git-multi.git'
|
167
|
-
|
168
|
-
# extend '
|
169
|
-
|
176
|
+
repo.abbreviated_ssh_url = repo.ssh_url.chomp('.git')
|
177
|
+
# extend 'repo' with 'just do it' capabilities
|
178
|
+
repo.extend Nike
|
170
179
|
end
|
171
180
|
end
|
172
181
|
# rubocop:enable Security/MarshalLoad
|
@@ -181,12 +190,20 @@ module Git
|
|
181
190
|
#
|
182
191
|
|
183
192
|
def repositories_for(multi_repo = nil)
|
184
|
-
|
185
|
-
|
186
|
-
|
193
|
+
case (owner = superproject = multi_repo)
|
194
|
+
when nil
|
195
|
+
repositories # all of them
|
196
|
+
when *USERS, *ORGANIZATIONS
|
197
|
+
repositories.find_all { |repository|
|
198
|
+
repository.owner.login == owner
|
199
|
+
}
|
200
|
+
when *SUPERPROJECTS
|
201
|
+
full_names = full_names_for(superproject)
|
187
202
|
repositories.find_all { |repository|
|
188
|
-
repository.
|
203
|
+
full_names.include?(repository.full_name)
|
189
204
|
}
|
205
|
+
else
|
206
|
+
raise "Unknown multi repo: #{multi_repo}"
|
190
207
|
end
|
191
208
|
end
|
192
209
|
|
@@ -212,40 +229,41 @@ module Git
|
|
212
229
|
|
213
230
|
def excess_repositories_for(multi_repo = nil)
|
214
231
|
repository_full_names = repositories_for(multi_repo).map(&:full_name)
|
215
|
-
local_repositories_for(multi_repo).reject { |
|
216
|
-
repository_full_names.include?
|
232
|
+
local_repositories_for(multi_repo).reject { |repo|
|
233
|
+
repository_full_names.include? repo.full_name
|
217
234
|
}
|
218
235
|
end
|
219
236
|
|
220
237
|
def stale_repositories_for(multi_repo = nil)
|
221
238
|
repository_full_names = github_repositories_for(multi_repo).map(&:full_name)
|
222
|
-
repositories_for(multi_repo).reject { |
|
223
|
-
repository_full_names.include?
|
239
|
+
repositories_for(multi_repo).reject { |repo|
|
240
|
+
repository_full_names.include? repo.full_name
|
224
241
|
}
|
225
242
|
end
|
226
243
|
|
227
244
|
def spurious_repositories_for(multi_repo = nil)
|
228
|
-
cloned_repositories_for(multi_repo).find_all { |
|
229
|
-
origin_url =
|
245
|
+
cloned_repositories_for(multi_repo).find_all { |repo|
|
246
|
+
origin_url = local_option(repo.local_path, 'remote.origin.url')
|
247
|
+
|
230
248
|
![
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
249
|
+
repo.clone_url,
|
250
|
+
repo.ssh_url,
|
251
|
+
repo.compliant_ssh_url,
|
252
|
+
repo.abbreviated_ssh_url,
|
253
|
+
repo.git_url,
|
236
254
|
].include? origin_url
|
237
255
|
}
|
238
256
|
end
|
239
257
|
|
240
258
|
def missing_repositories_for(multi_repo = nil)
|
241
|
-
repositories_for(multi_repo).find_all { |
|
242
|
-
!File.directory?
|
259
|
+
repositories_for(multi_repo).find_all { |repo|
|
260
|
+
!File.directory? repo.local_path
|
243
261
|
}
|
244
262
|
end
|
245
263
|
|
246
264
|
def cloned_repositories_for(multi_repo = nil)
|
247
|
-
repositories_for(multi_repo).find_all { |
|
248
|
-
File.directory?
|
265
|
+
repositories_for(multi_repo).find_all { |repo|
|
266
|
+
File.directory? repo.local_path
|
249
267
|
}
|
250
268
|
end
|
251
269
|
|
data/man/git-multi.1
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
.\" Title: git-multi
|
3
3
|
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
|
4
4
|
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
5
|
-
.\" Date: 11/
|
5
|
+
.\" Date: 11/12/2018
|
6
6
|
.\" Manual: Git Manual
|
7
7
|
.\" Source: Git 2.19.1.542.gc4df23f792.dirty
|
8
8
|
.\" Language: English
|
9
9
|
.\"
|
10
|
-
.TH "GIT\-MULTI" "1" "11/
|
10
|
+
.TH "GIT\-MULTI" "1" "11/12/2018" "Git 2\&.19\&.1\&.542\&.gc4df23" "Git Manual"
|
11
11
|
.\" -----------------------------------------------------------------
|
12
12
|
.\" * Define some portability stuff
|
13
13
|
.\" -----------------------------------------------------------------
|
@@ -31,7 +31,7 @@
|
|
31
31
|
git-multi \- execute the same git command in multiple repositories
|
32
32
|
.SH "VERSION"
|
33
33
|
.sp
|
34
|
-
This is \fBv2\&.
|
34
|
+
This is \fBv2\&.1\&.0\fR of \fIgit multi\fR \&... hooray!
|
35
35
|
.SH "SYNOPSIS"
|
36
36
|
.sp
|
37
37
|
There are some options for \fBgit multi\fR itself, in which case it is invoked as follows:
|
@@ -539,6 +539,11 @@ root directory where repos will been cloned
|
|
539
539
|
.RS 4
|
540
540
|
local, binary cache of GitHub repository metadata
|
541
541
|
.RE
|
542
|
+
.PP
|
543
|
+
\fB${HOME}/\&.git/multi/superprojects\&.config\fR
|
544
|
+
.RS 4
|
545
|
+
definitions for so\-called "superproject" multi repos
|
546
|
+
.RE
|
542
547
|
.SH "REFERENCES"
|
543
548
|
.sp
|
544
549
|
.RS 4
|
data/man/git-multi.erb
CHANGED
@@ -248,6 +248,9 @@ FILES
|
|
248
248
|
`${HOME}/.git/multi/repositories.byte`::
|
249
249
|
local, binary cache of GitHub repository metadata
|
250
250
|
|
251
|
+
`${HOME}/.git/multi/superprojects.config`::
|
252
|
+
definitions for so-called "superproject" multi repos
|
253
|
+
|
251
254
|
REFERENCES
|
252
255
|
----------
|
253
256
|
|
data/man/git-multi.html
CHANGED
@@ -748,7 +748,7 @@ git-multi(1) Manual Page
|
|
748
748
|
<div class="sect1">
|
749
749
|
<h2 id="_version">VERSION</h2>
|
750
750
|
<div class="sectionbody">
|
751
|
-
<div class="paragraph"><p>This is <code>v2.
|
751
|
+
<div class="paragraph"><p>This is <code>v2.1.0</code> of <em>git multi</em> … hooray!</p></div>
|
752
752
|
</div>
|
753
753
|
</div>
|
754
754
|
<div class="sect1">
|
@@ -1168,6 +1168,14 @@ git multi --json | jq -r '.[] | select(.fork == true) | .full_name'</code></pre>
|
|
1168
1168
|
local, binary cache of GitHub repository metadata
|
1169
1169
|
</p>
|
1170
1170
|
</dd>
|
1171
|
+
<dt class="hdlist1">
|
1172
|
+
<code>${HOME}/.git/multi/superprojects.config</code>
|
1173
|
+
</dt>
|
1174
|
+
<dd>
|
1175
|
+
<p>
|
1176
|
+
definitions for so-called "superproject" multi repos
|
1177
|
+
</p>
|
1178
|
+
</dd>
|
1171
1179
|
</dl></div>
|
1172
1180
|
</div>
|
1173
1181
|
</div>
|
@@ -1201,7 +1209,7 @@ the <code>jq</code> command-line utility:
|
|
1201
1209
|
<div id="footer">
|
1202
1210
|
<div id="footer-text">
|
1203
1211
|
Last updated
|
1204
|
-
2018-11-
|
1212
|
+
2018-11-12 14:05:11 GMT
|
1205
1213
|
</div>
|
1206
1214
|
</div>
|
1207
1215
|
</body>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-multi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Vandenberk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: octokit
|
@@ -97,9 +97,9 @@ files:
|
|
97
97
|
- lib/git/hub.rb
|
98
98
|
- lib/git/multi.rb
|
99
99
|
- lib/git/multi/commands.rb
|
100
|
+
- lib/git/multi/config.rb
|
100
101
|
- lib/git/multi/gemspec.rb
|
101
|
-
- lib/git/multi/
|
102
|
-
- lib/git/multi/utils.rb
|
102
|
+
- lib/git/multi/report.rb
|
103
103
|
- lib/git/multi/version.rb
|
104
104
|
- man/git-multi.1
|
105
105
|
- man/git-multi.erb
|
data/lib/git/multi/settings.rb
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
module Git
|
2
|
-
module Multi
|
3
|
-
module Settings
|
4
|
-
|
5
|
-
TICK = ['2714'.hex].pack('U*').green.freeze
|
6
|
-
CROSS = ['2718'.hex].pack('U*').red.freeze
|
7
|
-
ARROW = ['2794'.hex].pack('U*').blue.freeze
|
8
|
-
|
9
|
-
module_function
|
10
|
-
|
11
|
-
def setting_status(messages, valid = false, optional = true)
|
12
|
-
fields = messages.compact.join(' - ')
|
13
|
-
icon = valid ? TICK : optional ? ARROW : CROSS
|
14
|
-
puts "#{icon} #{fields}"
|
15
|
-
end
|
16
|
-
|
17
|
-
def file_status(file, message = 'File')
|
18
|
-
setting_status(
|
19
|
-
[
|
20
|
-
message,
|
21
|
-
abbreviate(file),
|
22
|
-
File.file?(file) ? "#{File.size(file).commify} bytes" : nil,
|
23
|
-
],
|
24
|
-
file && !file.empty? && File.file?(file),
|
25
|
-
false
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
def directory_status(messages, directory)
|
30
|
-
setting_status(
|
31
|
-
messages,
|
32
|
-
directory && !directory.empty? && File.directory?(directory),
|
33
|
-
false
|
34
|
-
)
|
35
|
-
end
|
36
|
-
|
37
|
-
def workarea_status(message, workarea, owner)
|
38
|
-
directory_status(
|
39
|
-
[
|
40
|
-
message,
|
41
|
-
File.join(abbreviate(workarea, :workarea), owner),
|
42
|
-
],
|
43
|
-
File.join(workarea, owner)
|
44
|
-
)
|
45
|
-
|
46
|
-
github_count = Git::Multi.repositories_for(owner).count
|
47
|
-
cloned_count = Git::Multi.cloned_repositories_for(owner).count
|
48
|
-
missing_count = (github_count - cloned_count)
|
49
|
-
subdir_count = Dir.new(workarea).git_repos(owner).count
|
50
|
-
surplus_count = (subdir_count - cloned_count)
|
51
|
-
|
52
|
-
setting_status(["\tGitHub ", github_count])
|
53
|
-
setting_status(["\tcloned ", cloned_count, "(#{missing_count} missing)"])
|
54
|
-
Git::Multi.missing_repositories_for(owner).each do |missing|
|
55
|
-
setting_status(["\tmissing", missing.full_name], false, false)
|
56
|
-
end
|
57
|
-
setting_status(["\tsubdirs", subdir_count, "(#{surplus_count} surplus)"])
|
58
|
-
end
|
59
|
-
|
60
|
-
def user_status(user)
|
61
|
-
setting_status(['User', user], user && !user.empty?)
|
62
|
-
end
|
63
|
-
|
64
|
-
def organization_status(orgs)
|
65
|
-
orgs.each do |org|
|
66
|
-
setting_status(['Organization', org], org && !org.empty?, true)
|
67
|
-
setting_status(['Organization', 'member?'], Git::Hub.orgs.include?(org), !Git::Hub.connected?)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def token_status(token)
|
72
|
-
setting_status(['Token', symbolize(token), describe(token)], !token.nil? && !token.empty?)
|
73
|
-
setting_status(['Token', 'valid?'], !token.nil? && !token.empty? && Git::Hub.login, !Git::Hub.connected?)
|
74
|
-
setting_status(['Token', "owned by #{Git::Multi::USER}?"], Git::Hub.login == Git::Multi::USER, !Git::Hub.connected?)
|
75
|
-
end
|
76
|
-
|
77
|
-
def home_status(home)
|
78
|
-
directory_status(['${HOME}', home], home)
|
79
|
-
end
|
80
|
-
|
81
|
-
def main_workarea_status(workarea)
|
82
|
-
directory_status(['${WORKAREA}', abbreviate(workarea, :home)], workarea)
|
83
|
-
end
|
84
|
-
|
85
|
-
def user_workarea_status(users)
|
86
|
-
users.each do |user|
|
87
|
-
workarea_status("Workarea (user: #{user})", Git::Multi::WORKAREA, user)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def organization_workarea_status(orgs)
|
92
|
-
orgs.each do |org|
|
93
|
-
workarea_status("Workarea (org: #{org})", Git::Multi::WORKAREA, org)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
data/lib/git/multi/utils.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
module Git
|
2
|
-
module Multi
|
3
|
-
|
4
|
-
module Settings
|
5
|
-
|
6
|
-
module_function
|
7
|
-
|
8
|
-
def describe(token)
|
9
|
-
if token.nil?
|
10
|
-
'(nil)'
|
11
|
-
elsif token.empty?
|
12
|
-
'(empty)'
|
13
|
-
else
|
14
|
-
"#{'*' * 36}#{token[36..-1]}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def symbolize(token)
|
19
|
-
case token
|
20
|
-
when Git::Multi.env_var('OCTOKIT_ACCESS_TOKEN')
|
21
|
-
then '${OCTOKIT_ACCESS_TOKEN}'
|
22
|
-
when Git::Multi.git_option('github.token')
|
23
|
-
then 'github.token'
|
24
|
-
else '(unset)'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def abbreviate(directory, root_dir = nil)
|
29
|
-
case root_dir
|
30
|
-
when :home
|
31
|
-
then directory.gsub(Git::Multi::HOME, '${HOME}')
|
32
|
-
when :workarea
|
33
|
-
then directory.gsub(Git::Multi::WORKAREA, '${WORKAREA}')
|
34
|
-
else abbreviate(abbreviate(directory, :workarea), :home)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
module_function
|
41
|
-
|
42
|
-
def git_option(name, default = nil)
|
43
|
-
value = `git config #{name}`.chomp.freeze
|
44
|
-
value.empty? && default ? default : value
|
45
|
-
end
|
46
|
-
|
47
|
-
def git_list(name, default = nil)
|
48
|
-
git_option(name, default).split(',').map(&:strip)
|
49
|
-
end
|
50
|
-
|
51
|
-
def env_var(name, default = nil)
|
52
|
-
value = ENV[name].freeze
|
53
|
-
(value.nil? || value.empty?) && default ? default : value
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|