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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fcd2ce8c7a7c7b5c661a85f2cc4f6eb9d4160cd0
4
- data.tar.gz: 2078820519daa9dbad320b526a841d51d576016a
3
+ metadata.gz: 3aab03f01067ec2e758af176a40fcf275e2ec41d
4
+ data.tar.gz: 38e9dea36b46da178e404c17f928f62ef483c4fd
5
5
  SHA512:
6
- metadata.gz: 3122aad848355fb6ea23aaaa6f5108cb090b5b9a7fc6dd22b6742a8b5759f7c786a4938dffd1bd38dd5e82834ae532f9100b106860809dfc56b5a34f1dbdd284
7
- data.tar.gz: 3886bb80fce62fbd54790536cf2d04cde3dc2b45905058686162627335744cb1c21a81948f18ef8c8c90d6599eec25c3bc145eec14a7ca70bfbde333cb3e0a39
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
@@ -3,4 +3,5 @@ rvm:
3
3
  - '2.0.0'
4
4
  - '2.1.0'
5
5
  - '2.1.5'
6
+ - '2.2'
6
7
  script: bundle exec rspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- git_multicast (0.3.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.3)
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`.
@@ -47,7 +47,7 @@ module GitMulticast
47
47
  puts multicaster(:status).new(Dir.pwd).execute!
48
48
  end
49
49
 
50
- desc 'version', 'Show thor_app version'
50
+ desc 'version', 'Show git_multicast version'
51
51
  def version
52
52
  puts GitMulticast::VERSION
53
53
  end
@@ -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.name, command(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
- parent_repo = RepositoryFetcher.get_repo_parent(repo.url)
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
- "git clone #{repo.ssh_url} #{File.join(dir, repo.name)}"
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(&method(:future))
11
- .map(&:get)
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
- def future(task)
19
- PoorMansFuture.new { task.call }
20
- end
21
+ private
21
22
 
22
- class PoorMansFuture
23
- def initialize
24
- @thread = Thread.new do
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
- def get
30
- thread.join
31
- thread[:output]
32
- end
27
+ def schedule
28
+ -> (task) { pool.schedule([], &task) }
29
+ end
33
30
 
34
- attr_reader :thread
31
+ def await
32
+ -> (_) { result_queue.pop }
35
33
  end
36
34
  end
37
35
  end
@@ -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
 
@@ -1,3 +1,3 @@
1
1
  module GitMulticast
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0.pre'
3
3
  end
@@ -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
- .with(
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!(:first_result) { Task::Result.new(:one, 'Hey!', 1) }
13
- let!(:second_result) { Task::Result.new(:two, 'Ho!', 1) }
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.3.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: 2014-12-30 00:00:00.000000000 Z
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: '0'
265
+ version: 1.3.1
264
266
  requirements: []
265
267
  rubyforge_project:
266
268
  rubygems_version: 2.2.2