git_multicast 0.3.0 → 0.4.0.pre

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 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