git_multicast 0.1.0 → 0.2.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/Gemfile.lock +17 -1
- data/README.md +1 -1
- data/git_multicast.gemspec +1 -0
- data/lib/git_multicast.rb +3 -8
- data/lib/git_multicast/adapter.rb +2 -0
- data/lib/git_multicast/{adapters → adapter}/bitbucket.rb +1 -1
- data/lib/git_multicast/{adapters → adapter}/github.rb +1 -1
- data/lib/git_multicast/cli.rb +38 -6
- data/lib/git_multicast/formatter.rb +6 -0
- data/lib/git_multicast/formatter/full.rb +18 -0
- data/lib/git_multicast/formatter/quiet.rb +13 -0
- data/lib/git_multicast/formatter/standard.rb +29 -0
- data/lib/git_multicast/formatter/status.rb +17 -0
- data/lib/git_multicast/multicaster.rb +31 -0
- data/lib/git_multicast/multicaster/clone.rb +35 -0
- data/lib/git_multicast/multicaster/pull.rb +30 -0
- data/lib/git_multicast/multicaster/status.rb +30 -0
- data/lib/git_multicast/repository_fetcher.rb +5 -2
- data/lib/git_multicast/task.rb +5 -3
- data/lib/git_multicast/task/result.rb +13 -0
- data/lib/git_multicast/task/runner.rb +38 -0
- data/lib/git_multicast/version.rb +1 -1
- data/spec/git_multicast/{adapters → adapter}/bitbucket_spec.rb +7 -3
- data/spec/git_multicast/cli_spec.rb +3 -3
- data/spec/git_multicast/formatter/full_spec.rb +32 -0
- data/spec/git_multicast/formatter/quiet_spec.rb +30 -0
- data/spec/git_multicast/formatter/standard_spec.rb +31 -0
- data/spec/git_multicast/formatter/status_spec.rb +32 -0
- data/spec/git_multicast/multicaster/clone_spec.rb +97 -0
- data/spec/git_multicast/multicaster/pull_spec.rb +41 -0
- data/spec/git_multicast/multicaster/status_spec.rb +41 -0
- data/spec/git_multicast/repository_fetcher_spec.rb +3 -3
- data/spec/git_multicast/task/runner_spec.rb +44 -0
- data/spec/git_multicast/task_spec.rb +8 -5
- metadata +39 -18
- data/lib/git_multicast/.rubocop.yml +0 -11
- data/lib/git_multicast/adapters.rb +0 -7
- data/lib/git_multicast/cloner.rb +0 -36
- data/lib/git_multicast/output_formatter.rb +0 -30
- data/lib/git_multicast/puller.rb +0 -28
- data/lib/git_multicast/statuser.rb +0 -28
- data/lib/git_multicast/task_result.rb +0 -7
- data/lib/git_multicast/task_runner.rb +0 -40
- data/spec/git_multicast/cloner_spec.rb +0 -94
- data/spec/git_multicast/output_formatter_spec.rb +0 -30
- data/spec/git_multicast/puller_spec.rb +0 -39
- data/spec/git_multicast/statuser_spec.rb +0 -39
- data/spec/git_multicast/task_runner_spec.rb +0 -53
@@ -0,0 +1,38 @@
|
|
1
|
+
module GitMulticast
|
2
|
+
class Task
|
3
|
+
class Runner
|
4
|
+
def initialize(tasks)
|
5
|
+
@tasks = tasks
|
6
|
+
end
|
7
|
+
|
8
|
+
def run!
|
9
|
+
tasks
|
10
|
+
.map(&method(:future))
|
11
|
+
.map(&:get)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
attr_reader :tasks
|
17
|
+
|
18
|
+
def future(task)
|
19
|
+
PoorMansFuture.new { task.call }
|
20
|
+
end
|
21
|
+
|
22
|
+
class PoorMansFuture
|
23
|
+
def initialize
|
24
|
+
@thread = Thread.new do
|
25
|
+
Thread.current[:output] = yield
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def get
|
30
|
+
thread.join
|
31
|
+
thread[:output]
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :thread
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module GitMulticast
|
2
|
-
describe
|
2
|
+
describe Adapter::Bitbucket do
|
3
3
|
subject(:adapter) { described_class.new(repo) }
|
4
4
|
|
5
5
|
describe '#adapt' do
|
@@ -13,8 +13,12 @@ module GitMulticast
|
|
13
13
|
# I know this is ugly, but well...
|
14
14
|
it do
|
15
15
|
VCR.use_cassette('bitbucket_repo') do
|
16
|
-
expect(adapt.url).to eq(
|
17
|
-
|
16
|
+
expect(adapt.url).to eq(
|
17
|
+
'https://bitbucket.org/api/2.0/repositories/rranelli/cronofaker'
|
18
|
+
)
|
19
|
+
expect(adapt.ssh_url).to eq(
|
20
|
+
'ssh://git@bitbucket.org/rranelli/cronofaker.git'
|
21
|
+
)
|
18
22
|
expect(adapt.name).to eq('CronoFaker')
|
19
23
|
expect(adapt.fork).to be_falsy
|
20
24
|
expect(adapt.parent).to be_nil
|
@@ -16,7 +16,7 @@ module GitMulticast
|
|
16
16
|
subject(:pull) { cli.pull }
|
17
17
|
|
18
18
|
it do
|
19
|
-
expect(
|
19
|
+
expect(Multicaster::Pull).to receive_message_chain(:new, :execute!)
|
20
20
|
|
21
21
|
pull
|
22
22
|
end
|
@@ -26,7 +26,7 @@ module GitMulticast
|
|
26
26
|
subject(:status) { cli.status }
|
27
27
|
|
28
28
|
it do
|
29
|
-
expect(
|
29
|
+
expect(Multicaster::Status).to receive_message_chain(:new, :execute!)
|
30
30
|
|
31
31
|
status
|
32
32
|
end
|
@@ -38,7 +38,7 @@ module GitMulticast
|
|
38
38
|
let(:username) { 'someone' }
|
39
39
|
|
40
40
|
it do
|
41
|
-
expect(
|
41
|
+
expect(Multicaster::Clone).to receive_message_chain(:new, :execute!)
|
42
42
|
|
43
43
|
clone
|
44
44
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module GitMulticast
|
2
|
+
class Formatter
|
3
|
+
describe Full do
|
4
|
+
subject(:formatter) { described_class.new }
|
5
|
+
|
6
|
+
let(:name) { 'some action' }
|
7
|
+
let(:exit_status) { 0 }
|
8
|
+
let(:result_string) { 'stuff to be done' }
|
9
|
+
|
10
|
+
let(:result) { Task::Result.new(name, result_string, exit_status) }
|
11
|
+
|
12
|
+
describe '#format' do
|
13
|
+
subject(:format) { formatter.format(result) }
|
14
|
+
|
15
|
+
it do
|
16
|
+
is_expected.to match(/\[Success\]/)
|
17
|
+
.and match(/#{name}/)
|
18
|
+
.and match(/#{result}/)
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when exit_status is not 0' do
|
22
|
+
let(:exit_status) { 999 }
|
23
|
+
|
24
|
+
it do
|
25
|
+
is_expected.to match(/\[Error\]/)
|
26
|
+
.and match(/#{result}/)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module GitMulticast
|
2
|
+
class Formatter
|
3
|
+
describe Quiet do
|
4
|
+
subject(:formatter) { described_class.new }
|
5
|
+
|
6
|
+
let(:name) { 'some action' }
|
7
|
+
let(:status) { 0 }
|
8
|
+
let(:result_string) { 'stuff to be done' }
|
9
|
+
|
10
|
+
let(:result) { Task::Result.new(name, result_string, status) }
|
11
|
+
|
12
|
+
describe '#format' do
|
13
|
+
subject(:format) { formatter.format(result) }
|
14
|
+
|
15
|
+
it do
|
16
|
+
is_expected.to match(/^$/)
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when exit_status is not 0' do
|
20
|
+
let(:status) { 999 }
|
21
|
+
|
22
|
+
it do
|
23
|
+
is_expected.to match(/\[Error\]/)
|
24
|
+
.and match(/#{result}/)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module GitMulticast
|
2
|
+
class Formatter
|
3
|
+
describe Standard do
|
4
|
+
subject(:formatter) { described_class.new }
|
5
|
+
|
6
|
+
let(:name) { 'some action' }
|
7
|
+
let(:exit_status) { 0 }
|
8
|
+
let(:result_string) { 'stuff to be done' }
|
9
|
+
|
10
|
+
let(:result) { Task::Result.new(name, result_string, exit_status) }
|
11
|
+
|
12
|
+
describe '#format' do
|
13
|
+
subject(:format) { formatter.format(result) }
|
14
|
+
|
15
|
+
it do
|
16
|
+
is_expected.to match(/\[Success\]/)
|
17
|
+
.and match(/#{name}/)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when exit_status is not 0' do
|
21
|
+
let(:exit_status) { 999 }
|
22
|
+
|
23
|
+
it do
|
24
|
+
is_expected.to match(/\[Error\]/)
|
25
|
+
.and match(/#{result}/)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module GitMulticast
|
2
|
+
class Formatter
|
3
|
+
describe Status do
|
4
|
+
subject(:formatter) { described_class.new }
|
5
|
+
|
6
|
+
let(:name) { 'some action' }
|
7
|
+
let(:exit_status) { 0 }
|
8
|
+
let(:result_string) { '"git add' }
|
9
|
+
|
10
|
+
let(:result) { Task::Result.new(name, result_string, exit_status) }
|
11
|
+
|
12
|
+
describe '#format' do
|
13
|
+
subject(:format) { formatter.format(result) }
|
14
|
+
|
15
|
+
it do
|
16
|
+
is_expected.to match(/\[No Changes\]/)
|
17
|
+
.and match(/#{name}/)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when there are changes in the working directory' do
|
21
|
+
let(:result_string) { '"git add ' }
|
22
|
+
|
23
|
+
it do
|
24
|
+
is_expected.to match(/\[Changes\]/)
|
25
|
+
.and match(/#{name}/)
|
26
|
+
.and match(/#{result}/)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module GitMulticast
|
2
|
+
class Multicaster
|
3
|
+
describe Clone do
|
4
|
+
subject(:cloner) { described_class.new(username, dir) }
|
5
|
+
|
6
|
+
let(:username) { 'rranelli' }
|
7
|
+
let(:dir) { '/kifita/' }
|
8
|
+
|
9
|
+
let(:repo_name) { 'git_multicast' }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(task).to receive(:spawn)
|
13
|
+
.and_return(pid)
|
14
|
+
allow(task).to receive(:wait)
|
15
|
+
.and_return(['', 0])
|
16
|
+
|
17
|
+
allow(Task).to receive(:new)
|
18
|
+
.and_return(task)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:task) { instance_double(Task, call: result) }
|
22
|
+
let(:result) { Task::Result.new(repo_name, 'success', 0) }
|
23
|
+
|
24
|
+
let(:pid) { 42 }
|
25
|
+
|
26
|
+
describe '#execute!' do
|
27
|
+
subject(:execute!) { cloner.execute! }
|
28
|
+
|
29
|
+
it do
|
30
|
+
VCR.use_cassette('clone_repos') do
|
31
|
+
expect(RepositoryFetcher).to receive(:get_all_repos_from_user)
|
32
|
+
.with(username)
|
33
|
+
.and_call_original
|
34
|
+
|
35
|
+
execute!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'creates a task for each fetched repository' do
|
40
|
+
VCR.use_cassette('clone_repos') do
|
41
|
+
expect(Task).to receive(:new).exactly(43).times
|
42
|
+
|
43
|
+
execute!
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'creates a task runner and asks it to run all tasks' do
|
48
|
+
VCR.use_cassette('clone_repos') do
|
49
|
+
expect(Task::Runner).to receive_message_chain(:new, :run!)
|
50
|
+
.and_return([])
|
51
|
+
|
52
|
+
execute!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'spawns a clone job for each repo' do
|
57
|
+
VCR.use_cassette('clone_repos') do
|
58
|
+
expect(task).to receive(:call).exactly(43).times
|
59
|
+
|
60
|
+
execute!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'spawns a clone with the right parameters' do
|
65
|
+
VCR.use_cassette('clone_repos') do
|
66
|
+
command = "git clone git@github.com:rranelli/#{repo_name}.git" \
|
67
|
+
' /kifita/git_multicast'
|
68
|
+
|
69
|
+
expect(Task).to receive(:new)
|
70
|
+
.with(repo_name, command)
|
71
|
+
|
72
|
+
execute!
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when repo is a fork'do
|
77
|
+
let(:repo_name) { 'emacs.d' }
|
78
|
+
|
79
|
+
it 'adds upstream remote' do
|
80
|
+
VCR.use_cassette('clone_repos') do
|
81
|
+
expect(Task).to receive(:new)
|
82
|
+
.with(
|
83
|
+
repo_name,
|
84
|
+
"git clone git@github.com:rranelli/#{repo_name}.git " \
|
85
|
+
"/kifita/#{repo_name} && git -C \"/kifita/#{repo_name}\"" \
|
86
|
+
' remote add upstream ' \
|
87
|
+
"git@github.com:purcell/#{repo_name}.git --fetch"
|
88
|
+
)
|
89
|
+
|
90
|
+
execute!
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GitMulticast
|
2
|
+
class Multicaster
|
3
|
+
describe Pull do
|
4
|
+
subject(:puller) { described_class.new(dir) }
|
5
|
+
|
6
|
+
let(:dir) { '/home/' }
|
7
|
+
let(:entries) { %w(one two) }
|
8
|
+
|
9
|
+
let(:task) { instance_double(Task, call: result) }
|
10
|
+
let(:result) { Task::Result.new('fitas', 'success', 0) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(File).to receive(:directory?).and_return(true)
|
14
|
+
allow(Dir).to receive(:entries).and_return(entries)
|
15
|
+
|
16
|
+
allow(Task).to receive(:new)
|
17
|
+
.and_return(task)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#execute!' do
|
21
|
+
subject(:execute!) { puller.execute! }
|
22
|
+
|
23
|
+
it 'creates a task for each repository' do
|
24
|
+
entries.each do |entry|
|
25
|
+
expect(Task).to receive(:new)
|
26
|
+
.with(entry, "git -C #{entry} pull -r origin")
|
27
|
+
end
|
28
|
+
|
29
|
+
execute!
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'runs tasks using a runner' do
|
33
|
+
expect(Task::Runner).to receive(:new)
|
34
|
+
.with([task, task]).and_call_original
|
35
|
+
|
36
|
+
execute!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GitMulticast
|
2
|
+
class Multicaster
|
3
|
+
describe Status do
|
4
|
+
subject(:statuser) { described_class.new(dir) }
|
5
|
+
|
6
|
+
let(:dir) { '/ki/fita/' }
|
7
|
+
let(:entries) { %w(fita1 fita2) }
|
8
|
+
|
9
|
+
let(:task) { instance_double(Task, call: result) }
|
10
|
+
let(:result) { Task::Result.new('fitas', 'success', 0) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(File).to receive(:directory?).and_return(true)
|
14
|
+
allow(Dir).to receive(:entries).and_return(entries)
|
15
|
+
|
16
|
+
allow(Task).to receive(:new)
|
17
|
+
.and_return(task)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#execute!' do
|
21
|
+
subject(:execute!) { statuser.execute! }
|
22
|
+
|
23
|
+
it 'creates a task for each repository' do
|
24
|
+
entries.each do |entry|
|
25
|
+
expect(Task).to receive(:new)
|
26
|
+
.with(entry, "cd #{entry} && git status")
|
27
|
+
end
|
28
|
+
|
29
|
+
execute!
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'runs tasks using a runner' do
|
33
|
+
expect(Task::Runner).to receive(:new)
|
34
|
+
.with([task, task]).and_call_original
|
35
|
+
|
36
|
+
execute!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -14,7 +14,7 @@ module GitMulticast
|
|
14
14
|
VCR.use_cassette('repos_from_all_services') do
|
15
15
|
fetchers.each do |fetcher|
|
16
16
|
expect(fetcher).to receive(:get_all_repos_from_user)
|
17
|
-
|
17
|
+
.with(username).and_call_original
|
18
18
|
end
|
19
19
|
|
20
20
|
get_all_repos_from_user
|
@@ -50,7 +50,7 @@ module GitMulticast
|
|
50
50
|
|
51
51
|
it 'adapts with the right adapter' do
|
52
52
|
VCR.use_cassette('github_repo') do
|
53
|
-
expect(
|
53
|
+
expect(Adapter::Github).to receive_message_chain(
|
54
54
|
:new, :adapt, :parent
|
55
55
|
)
|
56
56
|
|
@@ -99,7 +99,7 @@ module GitMulticast
|
|
99
99
|
|
100
100
|
it 'adapts with the right adapter' do
|
101
101
|
VCR.use_cassette('bitbucket_repo') do
|
102
|
-
expect(
|
102
|
+
expect(Adapter::Bitbucket).to receive(:new).and_return(bb_adapter)
|
103
103
|
expect(bb_adapter).to receive(:adapt)
|
104
104
|
|
105
105
|
get_repo
|