git_multicast 0.3.0 → 0.4.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -4
- data/.travis.yml +1 -0
- data/Gemfile.lock +2 -2
- data/README.md +25 -3
- data/lib/git_multicast/cli.rb +1 -1
- data/lib/git_multicast/multicaster/clone.rb +20 -6
- data/lib/git_multicast/task/pool.rb +39 -0
- data/lib/git_multicast/task/runner.rb +16 -18
- data/lib/git_multicast/task.rb +3 -0
- data/lib/git_multicast/version.rb +1 -1
- data/spec/git_multicast/multicaster/clone_spec.rb +4 -5
- data/spec/git_multicast/task/pool_spec.rb +46 -0
- data/spec/git_multicast/task/runner_spec.rb +12 -19
- data/spec/git_multicast/task_spec.rb +8 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3aab03f01067ec2e758af176a40fcf275e2ec41d
|
4
|
+
data.tar.gz: 38e9dea36b46da178e404c17f928f62ef483c4fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de31fbdcd6ef73569320441bbb90d20a72d3e205c9d87e7418e0c55674bbdf7dbec255cb2b7fce5874e1ce73f2f42c05c94003183a903ff331e258a9d7f3c031
|
7
|
+
data.tar.gz: 343ce413175a6e587206ad2f618dcb02a0f98d5b83ad9ece2374c907dce4490b6f1806484385df5d3bfa11276897135f9ca1ce59dd8d388f1ef56248c13e3501
|
data/.rubocop.yml
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
Documentation:
|
2
2
|
Enabled: false
|
3
3
|
|
4
|
+
Style/Encoding:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Style/MultilineOperationIndentation:
|
8
|
+
Enabled: false
|
9
|
+
|
4
10
|
AllCops:
|
5
|
-
# Include gemspec and Rakefile
|
6
11
|
Include:
|
7
12
|
- '**/*.gemspec'
|
8
13
|
- '**/Rakefile'
|
9
|
-
|
10
|
-
Style/Encoding:
|
11
|
-
Enabled: false
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
git_multicast (0.
|
4
|
+
git_multicast (0.4.0.pre)
|
5
5
|
colorize (~> 0.7)
|
6
6
|
recursive-open-struct (~> 0.5.0)
|
7
7
|
thor (~> 0.19)
|
@@ -14,7 +14,7 @@ GEM
|
|
14
14
|
astrolabe (1.3.0)
|
15
15
|
parser (>= 2.2.0.pre.3, < 3.0)
|
16
16
|
coderay (1.1.0)
|
17
|
-
colorize (0.7.
|
17
|
+
colorize (0.7.4)
|
18
18
|
crack (0.4.2)
|
19
19
|
safe_yaml (~> 1.0.0)
|
20
20
|
diff-lcs (1.2.5)
|
data/README.md
CHANGED
@@ -18,11 +18,33 @@ just as long as cloning the larger one, and nothing more.
|
|
18
18
|
Actions currently supported:
|
19
19
|
|
20
20
|
* Git clone all repositories of an user or organization (github & bitbucket).
|
21
|
+
|
22
|
+
```sh
|
23
|
+
git_multicast clone username
|
24
|
+
```
|
25
|
+
|
21
26
|
* Git pull all repositories in a directory.
|
27
|
+
|
28
|
+
```sh
|
29
|
+
git_multicast clone username
|
30
|
+
```
|
31
|
+
|
22
32
|
* Git status all repositories in a directory.
|
23
33
|
|
34
|
+
```sh
|
35
|
+
git_multicast status
|
36
|
+
```
|
37
|
+
|
38
|
+
|
39
|
+
* Sends a custom git command to all repositories in a directory.
|
40
|
+
|
41
|
+
```sh
|
42
|
+
git_multicast cast "push --force origin master" # don't do this at home.
|
43
|
+
```
|
44
|
+
|
45
|
+
All actions allow for both `--verbose` and `--quiet` options that will control
|
46
|
+
how much output is shown for each command execution.
|
47
|
+
|
24
48
|
Actions to be supported:
|
25
49
|
|
26
|
-
* Git clone repositories from Gitlab
|
27
|
-
* Pass options to git pull. (e.g., force, rebase, dry-run, etc.)
|
28
|
-
* Pass options to git status. (e.g., show only those that have modifications)
|
50
|
+
* Git clone repositories from `Gitlab`.
|
data/lib/git_multicast/cli.rb
CHANGED
@@ -14,22 +14,36 @@ module GitMulticast
|
|
14
14
|
|
15
15
|
attr_reader :username, :dir
|
16
16
|
|
17
|
+
private
|
18
|
+
|
17
19
|
def tasks
|
18
20
|
RepositoryFetcher
|
19
21
|
.get_all_repos_from_user(username)
|
20
|
-
.map { |repo| Task.new(repo
|
22
|
+
.map { |repo| Task.new(description(repo), command(repo)) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def description(repo)
|
26
|
+
"Cloning #{repo.name}..."
|
21
27
|
end
|
22
28
|
|
23
29
|
def command(repo)
|
24
30
|
if repo.fork
|
25
|
-
|
26
|
-
"git clone #{repo.ssh_url} #{File.join(dir, repo.name)} && \
|
27
|
-
git -C \"#{File.join(dir, repo.name)}\" remote add upstream \
|
28
|
-
#{parent_repo.ssh_url} --fetch"
|
31
|
+
clone_repo_with_parent(repo)
|
29
32
|
else
|
30
|
-
|
33
|
+
clone(repo)
|
31
34
|
end
|
32
35
|
end
|
36
|
+
|
37
|
+
def clone_repo_with_parent(repo)
|
38
|
+
parent_repo = RepositoryFetcher.get_repo_parent(repo.url)
|
39
|
+
"git clone #{repo.ssh_url} #{File.join(dir, repo.name)} && \
|
40
|
+
git -C \"#{File.join(dir, repo.name)}\" remote add upstream \
|
41
|
+
#{parent_repo.ssh_url} --fetch"
|
42
|
+
end
|
43
|
+
|
44
|
+
def clone(repo)
|
45
|
+
"git clone #{repo.ssh_url} #{File.join(dir, repo.name)}"
|
46
|
+
end
|
33
47
|
end
|
34
48
|
end
|
35
49
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module GitMulticast
|
4
|
+
class Task
|
5
|
+
class Pool
|
6
|
+
def initialize(size)
|
7
|
+
@size = size
|
8
|
+
@queue = Queue.new
|
9
|
+
@pool = (1..size).map { Thread.new(&job_loop) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def schedule(*args, &blk)
|
13
|
+
queue << [blk, args]
|
14
|
+
end
|
15
|
+
|
16
|
+
def shutdown
|
17
|
+
size.times { schedule { throw :exit } }
|
18
|
+
pool.map(&:join)
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
attr_reader :size, :queue, :pool
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def job_loop
|
28
|
+
-> { catch(:exit) { loop(&run_job) } }
|
29
|
+
end
|
30
|
+
|
31
|
+
def run_job
|
32
|
+
lambda do
|
33
|
+
job, args = queue.pop
|
34
|
+
job.call(*args)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,37 +1,35 @@
|
|
1
1
|
module GitMulticast
|
2
2
|
class Task
|
3
3
|
class Runner
|
4
|
-
def initialize(tasks)
|
4
|
+
def initialize(tasks, pool_size: 20, pool: Pool.new(pool_size))
|
5
5
|
@tasks = tasks
|
6
|
+
@pool = pool
|
7
|
+
@result_queue = Queue.new
|
6
8
|
end
|
7
9
|
|
8
10
|
def run!
|
9
11
|
tasks
|
10
|
-
.map(&
|
11
|
-
.map(
|
12
|
+
.map(&wrap_with_notify)
|
13
|
+
.map(&schedule)
|
14
|
+
.map(&await)
|
12
15
|
end
|
13
16
|
|
14
17
|
protected
|
15
18
|
|
16
|
-
attr_reader :tasks
|
19
|
+
attr_reader :tasks, :result_queue, :pool
|
17
20
|
|
18
|
-
|
19
|
-
PoorMansFuture.new { task.call }
|
20
|
-
end
|
21
|
+
private
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
Thread.current[:output] = yield
|
26
|
-
end
|
27
|
-
end
|
23
|
+
def wrap_with_notify
|
24
|
+
-> (task) { -> (*) { result_queue << task.call } }
|
25
|
+
end
|
28
26
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
27
|
+
def schedule
|
28
|
+
-> (task) { pool.schedule([], &task) }
|
29
|
+
end
|
33
30
|
|
34
|
-
|
31
|
+
def await
|
32
|
+
-> (_) { result_queue.pop }
|
35
33
|
end
|
36
34
|
end
|
37
35
|
end
|
data/lib/git_multicast/task.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'task/result'
|
2
2
|
require_relative 'task/runner'
|
3
|
+
require_relative 'task/pool'
|
3
4
|
|
4
5
|
module GitMulticast
|
5
6
|
class Task
|
@@ -10,6 +11,8 @@ module GitMulticast
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def run!
|
14
|
+
puts description
|
15
|
+
|
13
16
|
r, w = IO.pipe
|
14
17
|
pid = spawn(command, out: w, err: w)
|
15
18
|
|
@@ -67,7 +67,7 @@ module GitMulticast
|
|
67
67
|
' /kifita/git_multicast'
|
68
68
|
|
69
69
|
expect(Task).to receive(:new)
|
70
|
-
.with(repo_name, command)
|
70
|
+
.with("Cloning #{repo_name}...", command)
|
71
71
|
|
72
72
|
execute!
|
73
73
|
end
|
@@ -78,14 +78,13 @@ module GitMulticast
|
|
78
78
|
|
79
79
|
it 'adds upstream remote' do
|
80
80
|
VCR.use_cassette('clone_repos') do
|
81
|
-
expect(Task).to receive(:new)
|
82
|
-
|
83
|
-
repo_name,
|
81
|
+
expect(Task).to receive(:new).with(
|
82
|
+
"Cloning #{repo_name}...",
|
84
83
|
"git clone git@github.com:rranelli/#{repo_name}.git " \
|
85
84
|
"/kifita/#{repo_name} && git -C \"/kifita/#{repo_name}\"" \
|
86
85
|
' remote add upstream ' \
|
87
86
|
"git@github.com:purcell/#{repo_name}.git --fetch"
|
88
|
-
|
87
|
+
)
|
89
88
|
|
90
89
|
execute!
|
91
90
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
describe GitMulticast::Task::Pool do
|
2
|
+
subject(:pool) { described_class.new(size) }
|
3
|
+
|
4
|
+
let(:size) { 5 }
|
5
|
+
|
6
|
+
it { is_expected.to be_truthy }
|
7
|
+
|
8
|
+
describe '#schedule' do
|
9
|
+
subject(:schedule) { pool.schedule(1, &appender) }
|
10
|
+
|
11
|
+
let(:result) { [] }
|
12
|
+
let(:appender) { -> (x) { result << x } }
|
13
|
+
|
14
|
+
it do
|
15
|
+
schedule
|
16
|
+
sleep(0.3)
|
17
|
+
|
18
|
+
expect(result).to eq([1])
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when scheduling many jobs' do
|
22
|
+
subject(:schedule) do
|
23
|
+
jobs.each { |(*args, job)| pool.schedule(*args, &job) }
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:append_and_sleep) { -> (x) { (result << x) && sleep(0.5) } }
|
27
|
+
|
28
|
+
let(:jobs) do
|
29
|
+
[
|
30
|
+
[1, append_and_sleep],
|
31
|
+
[2, append_and_sleep],
|
32
|
+
[3, append_and_sleep],
|
33
|
+
[4, append_and_sleep],
|
34
|
+
[5, append_and_sleep]
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'runs them in parallel' do
|
39
|
+
schedule
|
40
|
+
sleep(0.2)
|
41
|
+
|
42
|
+
expect(result).to contain_exactly(1, 2, 3, 4, 5)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -6,30 +6,15 @@ module GitMulticast
|
|
6
6
|
let(:tasks) { [hey_task, ho_task] }
|
7
7
|
|
8
8
|
# Since tasks quack like lambdas, I will be using them here.
|
9
|
-
let(:hey_task) { ->() { first_result } }
|
10
|
-
let(:ho_task) { ->() { second_result } }
|
9
|
+
let(:hey_task) { ->() { sleep(0.3) && first_result } }
|
10
|
+
let(:ho_task) { ->() { sleep(0.3) && second_result } }
|
11
11
|
|
12
|
-
let
|
13
|
-
let
|
14
|
-
|
15
|
-
let(:formatter) { Formatter::Standard.new }
|
16
|
-
|
17
|
-
before do
|
18
|
-
allow(Formatter::Standard).to receive(:new)
|
19
|
-
.and_return(formatter)
|
20
|
-
end
|
12
|
+
let(:first_result) { Task::Result.new(:one, 'Hey!', 1) }
|
13
|
+
let(:second_result) { Task::Result.new(:two, 'Ho!', 1) }
|
21
14
|
|
22
15
|
describe '#run!' do
|
23
16
|
subject(:run!) { runner.run! }
|
24
17
|
|
25
|
-
it 'creates a thread for each task'do
|
26
|
-
expect(Thread).to receive(:new)
|
27
|
-
.exactly(tasks.size).times
|
28
|
-
.and_call_original
|
29
|
-
|
30
|
-
run!
|
31
|
-
end
|
32
|
-
|
33
18
|
it 'calls each task' do
|
34
19
|
expect(hey_task).to receive(:call)
|
35
20
|
.and_call_original
|
@@ -37,6 +22,14 @@ module GitMulticast
|
|
37
22
|
.and_call_original
|
38
23
|
|
39
24
|
run!
|
25
|
+
|
26
|
+
sleep(0.5)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns an array with task results' do
|
30
|
+
timeout(0.5) do
|
31
|
+
expect(run!).to contain_exactly(first_result, second_result)
|
32
|
+
end
|
40
33
|
end
|
41
34
|
end
|
42
35
|
end
|
@@ -12,6 +12,8 @@ describe GitMulticast::Task do
|
|
12
12
|
let(:w) { pipe[1] }
|
13
13
|
|
14
14
|
before do
|
15
|
+
allow(STDOUT).to receive(:write)
|
16
|
+
|
15
17
|
allow(task).to receive(:spawn)
|
16
18
|
.and_return(pid)
|
17
19
|
allow(task).to receive(:wait2)
|
@@ -55,5 +57,11 @@ describe GitMulticast::Task do
|
|
55
57
|
|
56
58
|
run!
|
57
59
|
end
|
60
|
+
|
61
|
+
it 'writes description to STDOUT' do
|
62
|
+
expect(STDOUT).to receive(:write).with(description)
|
63
|
+
|
64
|
+
run!
|
65
|
+
end
|
58
66
|
end
|
59
67
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git_multicast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renan Ranelli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: recursive-open-struct
|
@@ -217,6 +217,7 @@ files:
|
|
217
217
|
- lib/git_multicast/repository_fetcher/bitbucket.rb
|
218
218
|
- lib/git_multicast/repository_fetcher/github.rb
|
219
219
|
- lib/git_multicast/task.rb
|
220
|
+
- lib/git_multicast/task/pool.rb
|
220
221
|
- lib/git_multicast/task/result.rb
|
221
222
|
- lib/git_multicast/task/runner.rb
|
222
223
|
- lib/git_multicast/version.rb
|
@@ -240,6 +241,7 @@ files:
|
|
240
241
|
- spec/git_multicast/repository_fetcher/bitbucket_spec.rb
|
241
242
|
- spec/git_multicast/repository_fetcher/github_spec.rb
|
242
243
|
- spec/git_multicast/repository_fetcher_spec.rb
|
244
|
+
- spec/git_multicast/task/pool_spec.rb
|
243
245
|
- spec/git_multicast/task/runner_spec.rb
|
244
246
|
- spec/git_multicast/task_spec.rb
|
245
247
|
- spec/spec_helper.rb
|
@@ -258,9 +260,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
258
260
|
version: '2.0'
|
259
261
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
260
262
|
requirements:
|
261
|
-
- - "
|
263
|
+
- - ">"
|
262
264
|
- !ruby/object:Gem::Version
|
263
|
-
version:
|
265
|
+
version: 1.3.1
|
264
266
|
requirements: []
|
265
267
|
rubyforge_project:
|
266
268
|
rubygems_version: 2.2.2
|