gerrit-cli 0.0.1

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.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Gerrit::Cli
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'gerrit-cli'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install gerrit-cli
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+ require "rspec/core/version"
5
+
6
+ desc "Run all specs"
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ t.rspec_opts = %w[--color --format documentation]
9
+ end
data/bin/gerrit ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
4
+
5
+ require 'logger'
6
+
7
+ require 'gerrit/cli/dispatcher'
8
+
9
+
10
+ logger = Logger.new(STDOUT)
11
+ logger.formatter = proc {|severity, datetime, progname, msg| "#{msg}\n" }
12
+
13
+ dispatcher = Gerrit::Cli::Dispatcher.new(logger)
14
+ dispatcher.run_command(ARGV)
@@ -0,0 +1,22 @@
1
+ # Copyright (C) 2012 VMware, Inc. All rights reserved.
2
+ require File.expand_path('../lib/gerrit/cli/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["VMware"]
6
+ gem.email = ["support@vmware.com"]
7
+ gem.description = "This provides a tool for easing common interactions" \
8
+ + " with Gerrit. It is mostly orthogonal to the `repo'" \
9
+ + " tool and tries not to interfere with your workflow."
10
+ gem.summary = "A simple cli for interacting with Gerrit."
11
+ gem.homepage = "http://www.cloudfoundry.org"
12
+
13
+ gem.files = Dir.glob("**/*")
14
+ gem.executables = ["gerrit"]
15
+ gem.test_files = Dir.glob("spec/**/*")
16
+ gem.name = "gerrit-cli"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = Gerrit::Cli::VERSION
19
+
20
+ gem.add_development_dependency("rake")
21
+ gem.add_development_dependency("rspec")
22
+ end
@@ -0,0 +1,52 @@
1
+ require 'logger'
2
+ require 'optparse'
3
+
4
+ module Gerrit
5
+ module Cli
6
+ module Command
7
+ end
8
+ end
9
+ end
10
+
11
+ class Gerrit::Cli::Command::Base
12
+
13
+ attr_reader :option_parser
14
+
15
+ def initialize(logger)
16
+ @logger = logger
17
+ @option_parser = OptionParser.new
18
+
19
+ setup_option_parser
20
+ end
21
+
22
+ def setup_option_parser
23
+ @option_parser.on('-h', '--help', 'Display usage') do
24
+ show_usage
25
+ exit 0
26
+ end
27
+
28
+ @option_parser.on('-v', '--verbose', 'Show debugging information') do
29
+ @logger.level = Logger::DEBUG
30
+ end
31
+ end
32
+
33
+ def run(argv)
34
+ raise NotImplementedError
35
+ end
36
+
37
+ def name
38
+ self.class.name.split('::').last.downcase
39
+ end
40
+
41
+ def summary
42
+ @option_parser.banner
43
+ end
44
+
45
+ def usage
46
+ "Usage: gerrit #{name} [options]\n\n" + @option_parser.help
47
+ end
48
+
49
+ def show_usage
50
+ @logger.info(usage())
51
+ end
52
+ end
@@ -0,0 +1,81 @@
1
+ require 'uri'
2
+
3
+ require 'gerrit/cli/command/base'
4
+ require 'gerrit/cli/constants'
5
+ require 'gerrit/cli/errors'
6
+
7
+ # A thin wrapper around git-clone that attempts to install commit-msg hooks
8
+ # that automatically insert the ChangeID lines used by Gerrit.
9
+ class Gerrit::Cli::Command::Clone < Gerrit::Cli::Command::Base
10
+ def initialize(logger, runner)
11
+ super(logger)
12
+
13
+ @runner = runner
14
+ end
15
+
16
+ def setup_option_parser
17
+ super
18
+
19
+ @option_parser.banner =
20
+ "Clone a Gerrit hosted repo and install commit-msg hooks."
21
+ end
22
+
23
+ def usage
24
+ "Usage: gerrit clone [options] <repo> [<dir>]\n\n" + @option_parser.help
25
+ end
26
+
27
+ def run(argv)
28
+ args = @option_parser.parse(argv)
29
+
30
+ repo_uri, repo_dir = nil, nil
31
+ case args.length
32
+ when 2
33
+ repo_uri, repo_dir = args
34
+ when 1
35
+ repo_uri = args[0]
36
+ else
37
+ raise Gerrit::Cli::UsageError.new("Incorrect number of arguments")
38
+ end
39
+
40
+ @runner.system!("git clone #{repo_uri} #{repo_dir}")
41
+
42
+ # At this point the uri must be valid, otherwise the clone would have
43
+ # failed
44
+ parsed_repo_uri = URI.parse(repo_uri)
45
+
46
+ unless repo_dir
47
+ if parsed_repo_uri.path =~ /\/([^\/]+?)(.git)?$/
48
+ repo_dir = $1
49
+ else
50
+ emsg = "Failed to determine the directory the repo was cloned into."
51
+ raise Gerrit::Cli::Error.new(emsg)
52
+ end
53
+ end
54
+
55
+ install_commit_hooks(parsed_repo_uri, repo_dir)
56
+ install_tracked_hooks(repo_dir)
57
+ end
58
+
59
+ def install_commit_hooks(parsed_repo_uri, repo_dir)
60
+ hook_src = "#{parsed_repo_uri.host}:hooks/commit-msg"
61
+ if parsed_repo_uri.user
62
+ hook_src = "#{parsed_repo_uri.user}@#{hook_src}"
63
+ end
64
+
65
+ hook_dst = "#{repo_dir}/.git/hooks"
66
+
67
+ gerrit_port = parsed_repo_uri.port || Gerrit::Cli::DEFAULT_GERRIT_PORT
68
+
69
+ @logger.info("\nInstalling commit-msg hooks into '#{hook_dst}'.")
70
+ @runner.system!("scp -p -P #{gerrit_port} #{hook_src} #{hook_dst}")
71
+ end
72
+
73
+ def install_tracked_hooks(repo_dir)
74
+ Dir.chdir(repo_dir) do
75
+ if File.executable?("git/install-hook-symlinks")
76
+ @logger.info("\nInstalling tracked git hooks: ")
77
+ @runner.system!("git/install-hook-symlinks")
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,49 @@
1
+ require 'gerrit/cli/command/base'
2
+ require 'gerrit/cli/errors'
3
+ require 'gerrit/cli/util'
4
+
5
+ class Gerrit::Cli::Command::Help < Gerrit::Cli::Command::Base
6
+
7
+ attr_reader :commands_summary
8
+
9
+ def initialize(logger, commands)
10
+ super(logger)
11
+
12
+ @commands = commands.dup.merge(self.name => self)
13
+
14
+ rows = @commands.keys.sort.map {|k| [k, @commands[k].summary] }
15
+ @commands_summary = Gerrit::Cli::Util.render_table(rows,
16
+ :delimiter => ' ')
17
+ end
18
+
19
+ def setup_option_parser
20
+ super
21
+
22
+ @option_parser.banner =
23
+ "Show a list of commands or display help for a specific command."
24
+ end
25
+
26
+ def usage
27
+ "Usage: gerrit help [options] [<command>]\n\n" \
28
+ + @option_parser.help \
29
+ + "\nAvailable commands:\n" \
30
+ + @commands_summary
31
+ end
32
+
33
+ def run(argv)
34
+ args = @option_parser.parse(argv)
35
+
36
+ case args.length
37
+ when 1
38
+ if command = @commands[args[0]]
39
+ command.show_usage
40
+ else
41
+ raise Gerrit::Cli::UsageError.new("Unknown command '#{args[0]}'")
42
+ end
43
+ when 0
44
+ show_usage
45
+ else
46
+ raise Gerrit::Cli::UsageError.new("Too many arguments")
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ require 'uri'
2
+
3
+ require 'gerrit/cli/command/base'
4
+ require 'gerrit/cli/constants'
5
+ require 'gerrit/cli/errors'
6
+
7
+ # Posts reviews to Gerrit. Assumes that your repo has at least one Gerrit
8
+ # remote.
9
+ class Gerrit::Cli::Command::Push < Gerrit::Cli::Command::Base
10
+ def initialize(logger, runner)
11
+ super(logger)
12
+
13
+ @branch = "master"
14
+ @runner = runner
15
+ end
16
+
17
+ def setup_option_parser
18
+ super
19
+
20
+ @option_parser.banner =
21
+ "Post changes from the current branch to Gerrit for review."
22
+
23
+ @option_parser.on('-b', '--branch BRANCH',
24
+ "The remote branch these changes should be merged into." \
25
+ + "Master is assumed by default.") do |branch|
26
+ @branch = branch
27
+ end
28
+ end
29
+
30
+ def usage
31
+ "Usage: gerrit push [options] [<remote>]\n\n" + @option_parser.help
32
+ end
33
+
34
+ def run(argv)
35
+ args = @option_parser.parse(argv)
36
+
37
+ remote = nil
38
+ case args.length
39
+ when 1
40
+ remote = args[0]
41
+ when 0
42
+ remote = "origin"
43
+ else
44
+ raise Gerrit::Cli::UsageError.new("Incorrect number of arguments")
45
+ end
46
+
47
+ topic = get_current_branch()
48
+
49
+ cmd = ["git push",
50
+ remote,
51
+ "HEAD:refs/for/#{@branch}/#{topic}"].join(" ")
52
+ @runner.system!(cmd)
53
+ end
54
+
55
+ def get_current_branch
56
+ @logger.debug("Getting current branch")
57
+ output = @runner.capture!("git symbolic-ref HEAD")
58
+ output.gsub(/^refs\/heads\//,"")
59
+ end
60
+ end
@@ -0,0 +1,5 @@
1
+ module Gerrit
2
+ module Cli
3
+ DEFAULT_GERRIT_PORT = 29418
4
+ end
5
+ end
@@ -0,0 +1,51 @@
1
+ require 'logger'
2
+ require 'gerrit/cli/shell_runner'
3
+ require 'gerrit/cli/command/clone'
4
+ require 'gerrit/cli/command/help'
5
+ require 'gerrit/cli/command/push'
6
+ require 'gerrit/cli/errors'
7
+
8
+ module Gerrit
9
+ module Cli
10
+ end
11
+ end
12
+
13
+ class Gerrit::Cli::Dispatcher
14
+ def initialize(logger=nil)
15
+ @logger = logger || Logger.new(STDOUT)
16
+ @logger.level = Logger::INFO
17
+
18
+ runner = Gerrit::Cli::ShellRunner.new(logger)
19
+
20
+ @commands = {
21
+ 'clone' => Gerrit::Cli::Command::Clone.new(logger, runner),
22
+ 'push' => Gerrit::Cli::Command::Push.new(logger, runner),
23
+ }
24
+
25
+ @commands['help'] = Gerrit::Cli::Command::Help.new(logger, @commands)
26
+ end
27
+
28
+ def run_command(argv)
29
+ if argv.empty?
30
+ @logger.info("Available Commands:")
31
+ @logger.info(@commands['help'].commands_summary)
32
+ else
33
+ args = argv.dup
34
+ command_name = args.shift
35
+ if command = @commands[command_name]
36
+ command.run(args)
37
+ else
38
+ @logger.error("ERROR: Unknown command '#{command_name}'")
39
+ @commands['help'].show_command_summaries
40
+ end
41
+ end
42
+ rescue Gerrit::Cli::UsageError => ue
43
+ @logger.error("ERROR: #{ue}\n")
44
+ command.show_usage
45
+ exit 1
46
+ rescue => e
47
+ @logger.error("ERROR: #{e}")
48
+ @logger.debug(e.backtrace.join("\n")) if e.backtrace
49
+ exit 1
50
+ end
51
+ end
@@ -0,0 +1,6 @@
1
+ module Gerrit
2
+ module Cli
3
+ class Error < StandardError; end
4
+ class UsageError < Error; end
5
+ end
6
+ end
@@ -0,0 +1,37 @@
1
+ require 'logger'
2
+
3
+ require 'gerrit/cli/errors'
4
+
5
+ module Gerrit
6
+ module Cli
7
+ end
8
+ end
9
+
10
+ class Gerrit::Cli::ShellRunner
11
+ def initialize(logger)
12
+ @logger = logger || Logger.new(STDOUT)
13
+ end
14
+
15
+ def system!(command)
16
+ @logger.debug("+ #{command}")
17
+
18
+ unless system(command)
19
+ st = $?.exitstatus
20
+ emsg = "Command '#{command}' exited with non-zero status (#{st})."
21
+ raise Gerrit::Cli::Error.new(emsg)
22
+ end
23
+ end
24
+
25
+ def capture!(command)
26
+ @logger.debug("+ #{command}")
27
+
28
+ out = `#{command}`
29
+ unless $?.success?
30
+ st = $?.exitstatus
31
+ emsg = "Command '#{command}' exited with non-zero status (#{st})."
32
+ raise Gerrit::Cli::Error.new(emsg)
33
+ end
34
+
35
+ out
36
+ end
37
+ end
@@ -0,0 +1,34 @@
1
+ module Gerrit
2
+ module Cli
3
+ end
4
+ end
5
+
6
+ module Gerrit::Cli::Util
7
+ class << self
8
+ def render_table(rows, opts={})
9
+ return "" if rows.empty?
10
+
11
+ max_col_lengths = []
12
+ rows.first.length.times { max_col_lengths << 0 }
13
+
14
+ # Compute maximum length of each column
15
+ rows.each do |row|
16
+ if row.length != max_col_lengths.length
17
+ raise ArgumentError, "Column mismatch"
18
+ end
19
+
20
+ row.each_with_index do |c, ii|
21
+ len = c.to_s.length
22
+ if len> max_col_lengths[ii]
23
+ max_col_lengths[ii] = len
24
+ end
25
+ end
26
+ end
27
+
28
+ delim = opts[:delimiter] || ' '
29
+ row_format = max_col_lengths.map {|len| "%-#{len}s" }.join(delim)
30
+
31
+ rows.map {|row| row_format % row }.join("\n")
32
+ end
33
+ end
34
+ end