gerrit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e622e3bacf3ff603e41ef0aaad895a33c5c0c531
4
+ data.tar.gz: 463bc6a58c060e6ad3d8825fc108e9b0fcd3f1f6
5
+ SHA512:
6
+ metadata.gz: 25f0ee6364cd63cdc9d3a2519a6bccff966f03735b5bffba41400be186b23316a7df56b1f0bbf108322be73fc6fa41c4d488214ffe1825477dc95677e8b7ff8a
7
+ data.tar.gz: 6e95f4c7472f6ab0c5f422c44316cec1296665ca3f0a0fd6a9cd1b309237d50e20f809266e0710741bba71cede221dca108742e80995599eec8acf0871097c81
data/bin/gerrit ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gerrit/cli'
4
+
5
+ input = Gerrit::Input.new(STDIN)
6
+ output = Gerrit::Output.new(STDOUT)
7
+ exit Gerrit::CLI.new(input: input, output: output).run(ARGV)
data/lib/gerrit/cli.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'gerrit'
2
+
3
+ module Gerrit
4
+ # Command line application interface.
5
+ class CLI
6
+ # Set of semantic exit codes we can return.
7
+ #
8
+ # @see http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
9
+ module ExitCodes
10
+ OK = 0 # Successful execution
11
+ USAGE = 64 # User error (bad command line or invalid input)
12
+ SOFTWARE = 70 # Internal software error (bug)
13
+ CONFIG = 78 # Configuration error (invalid file or options)
14
+ end
15
+
16
+ # Create a CLI that outputs to the given output destination.
17
+ #
18
+ # @param input [Gerrit::Input]
19
+ # @param output [Gerrit::Output]
20
+ def initialize(input:, output:)
21
+ @ui = UI.new(input, output)
22
+ end
23
+
24
+ # Parses the given command-line arguments and executes appropriate logic
25
+ # based on those arguments.
26
+ #
27
+ # @param [Array<String>] arguments
28
+ # @return [Integer] exit status code
29
+ def run(arguments)
30
+ config = Configuration.load_applicable
31
+ run_command(config, arguments)
32
+
33
+ ExitCodes::OK
34
+ rescue => ex
35
+ ErrorHandler.new(@ui).handle(ex)
36
+ end
37
+
38
+ private
39
+
40
+ # Executes the appropriate command given the list of command line arguments.
41
+ #
42
+ # @param config [Gerrit::Configuration]
43
+ # @param ui [Gerrit::UI]
44
+ # @param arguments [Array<String>]
45
+ # @raise [Gerrit::Errors::GerritError] when any exceptional circumstance occurs
46
+ def run_command(config, arguments)
47
+ # Display help documentation by default
48
+ arguments = ['help'] if arguments.empty?
49
+
50
+ command_class = find_command(arguments)
51
+ command_class.new(config, @ui, arguments).run
52
+ end
53
+
54
+ # Finds the {Command} corresponding to the given set of arguments.
55
+ #
56
+ # @param [Array<String>] arguments
57
+ # @return [Class]
58
+ def find_command(arguments)
59
+ cmd = arguments.first
60
+
61
+ begin
62
+ require 'gerrit/command/base'
63
+ require "gerrit/command/#{Utils.snake_case(cmd)}"
64
+ rescue LoadError => ex
65
+ raise Errors::CommandInvalidError,
66
+ "`gerrit #{cmd}` is not a valid command"
67
+ end
68
+
69
+ Command.const_get(Utils.camel_case(cmd))
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,67 @@
1
+ require 'json'
2
+
3
+ module Gerrit
4
+ # Client for executing commands against the Gerrit server.
5
+ class Client
6
+ # Create a client using the given configuration settings.
7
+ #
8
+ # @param config [Gerrit::Configuration]
9
+ def initialize(config)
10
+ @config = config
11
+ end
12
+
13
+ # Executes a command against the Gerrit server, returning the output.
14
+ #
15
+ # @param command [Array<String>]
16
+ # @return [String]
17
+ def execute(command)
18
+ user = @config[:user]
19
+ host = @config[:host]
20
+ port = @config[:port]
21
+ ssh_cmd = %W[ssh -p #{port} #{user}@#{host} gerrit] + command
22
+
23
+ result = Subprocess.spawn(ssh_cmd)
24
+ unless result.success?
25
+ raise Errors::GerritCommandFailedError,
26
+ "Command `#{ssh_cmd.join(' ')}` failed:\n" \
27
+ "STATUS: #{result.status}\n" \
28
+ "STDOUT: #{result.stdout.inspect}\n" \
29
+ "STDERR: #{result.stderr.inspect}\n"
30
+ end
31
+
32
+ result.stdout
33
+ end
34
+
35
+ # Returns all groups visible to the user.
36
+ #
37
+ # @return [Array<String>]
38
+ def groups
39
+ execute(%w[ls-groups]).split("\n")
40
+ end
41
+
42
+ # Returns members associated with a group.
43
+ #
44
+ # @param group [String] full name of the group
45
+ # @param recursive [Boolean] whether to include members of sub-groups.
46
+ # @return [Array<String>]
47
+ def members(group, recursive: true)
48
+ flags = []
49
+ flags << '--recursive' if recursive
50
+ execute(%w[ls-members] + ["'#{group}'"] + flags)
51
+ end
52
+
53
+ # Returns basic information about a change.
54
+ def change(change_id_or_number)
55
+ rows = execute(%W[query --format=JSON
56
+ --current-patch-set
57
+ change:#{change_id_or_number}]).split("\n")[0..-2]
58
+
59
+ if rows.empty?
60
+ raise Errors::CommandFailedError,
61
+ "No change matches the id '#{change_id_or_number}'"
62
+ else
63
+ JSON.parse(rows.first)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,62 @@
1
+ require 'gerrit/client'
2
+
3
+ module Gerrit::Command
4
+ # Abstract base class of all commands.
5
+ #
6
+ # @abstract
7
+ class Base
8
+ # @param config [Gerrit::Configuration]
9
+ # @param ui [Gerrit::UI]
10
+ # @param arguments [Array<String>]
11
+ def initialize(config, ui, arguments)
12
+ @config = config
13
+ @ui = ui
14
+ @arguments = arguments
15
+ end
16
+
17
+ # Parses arguments and executes the command.
18
+ def run
19
+ # TODO: include a parse step here and remove duplicate parsing code from
20
+ # individual commands
21
+ execute
22
+ end
23
+
24
+ # Executes the command given the previously-parsed arguments.
25
+ def execute
26
+ raise NotImplementedError, 'Define `execute` in Command subclass'
27
+ end
28
+
29
+ private
30
+
31
+ # @return [Array<String>]
32
+ attr_reader :arguments
33
+
34
+ # @return [Gerrit::Configuration]
35
+ attr_reader :config
36
+
37
+ # @return [Gerrit::UI]
38
+ attr_reader :ui
39
+
40
+ # Returns a client for making requests to the Gerrit server.
41
+ #
42
+ # @return [Gerrit::Client]
43
+ def client
44
+ @client ||= Gerrit::Client.new(@config)
45
+ end
46
+
47
+ # Returns information about this repository.
48
+ #
49
+ # @return [Gerrit::Repo]
50
+ def repo
51
+ @repo ||= Gerrit::Repo.new(@config)
52
+ end
53
+
54
+ # Execute a process and return the result including status and output.
55
+ #
56
+ # @param args [Array<String>]
57
+ # @return [#status, #stdout, #stderr]
58
+ def spawn(args)
59
+ Subprocess.spawn(args)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,37 @@
1
+ module Gerrit::Command
2
+ # Check out a patchset locally.
3
+ class Checkout < Base
4
+ def execute
5
+ result = spawn(%W[git fetch #{repo.remote_url} #{change_refspec}])
6
+ if result.success?
7
+ spawn(%w[git checkout FETCH_HEAD])
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ # Returns the latest refspec for the given change number.
14
+ def change_refspec
15
+ change_md = change_metadata
16
+ change_number = change_md['number']
17
+ patchset = change_md['currentPatchSet']['number']
18
+
19
+ # Gerrit takes the last two digits of the change number to nest under a
20
+ # directory with that name so they don't exceed the per-directory file limit
21
+ prefix = change_number.rjust(2, '0').to_s[-2..-1]
22
+
23
+ "refs/changes/#{prefix}/#{change_number}/#{patchset}"
24
+ end
25
+
26
+ def change_metadata
27
+ change_num_or_id =
28
+ if arguments[1]
29
+ arguments[1]
30
+ else
31
+ ui.ask('Enter change number or Change-ID').argument(:required).read_string
32
+ end
33
+
34
+ client.change(change_num_or_id)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,10 @@
1
+ module Gerrit::Command
2
+ # List all groups the user can view.
3
+ class Groups < Base
4
+ def execute
5
+ client.groups.each do |group|
6
+ ui.print group
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module Gerrit::Command
2
+ # Displays help documentation.
3
+ class Help < Base
4
+ def execute
5
+ ui.print 'Usage: gerrit [command]'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,37 @@
1
+ module Gerrit::Command
2
+ # Lists members of a group.
3
+ #
4
+ # This allows you to list the members of a group by regex.
5
+ class Members < Base
6
+ def execute
7
+ ui.print client.members(find_group), newline: false
8
+ end
9
+
10
+ private
11
+
12
+ def find_group
13
+ matches = client.groups.grep(/#{search_term}/i)
14
+
15
+ if matches.empty?
16
+ ui.error 'No groups match the given name/regex'
17
+ raise Gerrit::Errors::CommandFailedError
18
+ elsif matches.size >= 2
19
+ ui.warning 'Multiple groups match the given regex:'
20
+ matches.each do |group|
21
+ ui.print group
22
+ end
23
+ raise Gerrit::Errors::CommandFailedError
24
+ end
25
+
26
+ matches[0]
27
+ end
28
+
29
+ def search_term
30
+ if arguments[1]
31
+ arguments[1]
32
+ else
33
+ ui.ask('Enter group name or regex').argument(:required).read_string
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ module Gerrit::Command
2
+ # Displays a list of all projects the user has permissions to see.
3
+ #
4
+ # This is a light wrapper around `ls-projects` since it will just append any
5
+ # additional arguments to the underlying command.
6
+ class Projects < Base
7
+ def execute
8
+ ui.print client.execute(%w[ls-projects] + arguments[1..-1]),
9
+ newline: false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module Gerrit::Command
2
+ # Displays version information.
3
+ class Version < Base
4
+ def execute
5
+ ui.info Gerrit::VERSION
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,84 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+
4
+ module Gerrit
5
+ # Stores runtime configuration for the application.
6
+ #
7
+ # This is intended to define helper methods for accessing configuration so
8
+ # this logic can be shared amongst the various components of the system.
9
+ class Configuration
10
+ # Name of the configuration file.
11
+ FILE_NAME = '.gerrit.yaml'
12
+
13
+ class << self
14
+ # Loads appropriate configuration file given the current working
15
+ # directory.
16
+ #
17
+ # @return [Gerrit::Configuration]
18
+ def load_applicable
19
+ current_directory = File.expand_path(Dir.pwd)
20
+ config_file = applicable_config_file(current_directory)
21
+
22
+ if config_file
23
+ from_file(config_file)
24
+ else
25
+ raise Errors::ConfigurationMissingError,
26
+ 'No configuration file was found'
27
+ end
28
+ end
29
+
30
+ # Loads a configuration from a file.
31
+ #
32
+ # @return [Gerrit::Configuration]
33
+ def from_file(config_file)
34
+ options =
35
+ if yaml = YAML.load_file(config_file)
36
+ yaml.to_hash
37
+ else
38
+ {}
39
+ end
40
+
41
+ new(options)
42
+ end
43
+
44
+ private
45
+
46
+ # Returns the first valid configuration file found, starting from the
47
+ # current working directory and ascending to ancestor directories.
48
+ #
49
+ # @param directory [String]
50
+ # @return [String, nil]
51
+ def applicable_config_file(directory)
52
+ Pathname.new(directory)
53
+ .enum_for(:ascend)
54
+ .map { |dir| dir + FILE_NAME }
55
+ .find do |config_file|
56
+ config_file if config_file.exist?
57
+ end
58
+ end
59
+ end
60
+
61
+ # Creates a configuration from the given options hash.
62
+ #
63
+ # @param options [Hash]
64
+ def initialize(options)
65
+ @options = options
66
+ end
67
+
68
+ # Access the configuration as if it were a hash.
69
+ #
70
+ # @param key [String, Symbol]
71
+ # @return [Array,Hash,Number,String]
72
+ def [](key)
73
+ @options[key.to_s]
74
+ end
75
+
76
+ # Compares this configuration with another.
77
+ #
78
+ # @param other [HamlLint::Configuration]
79
+ # @return [true,false] whether the given configuration is equivalent
80
+ def ==(other)
81
+ super || @options == other.instance_variable_get('@options')
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,7 @@
1
+ # Global application constants.
2
+ module Gerrit
3
+ EXECUTABLE_NAME = 'gerrit'
4
+
5
+ REPO_URL = 'https://github.com/sds/gerrit'
6
+ BUG_REPORT_URL = "#{REPO_URL}/issues"
7
+ end
@@ -0,0 +1,45 @@
1
+ module Gerrit
2
+ # Central location of all logic for how exceptions are presented to the user.
3
+ class ErrorHandler
4
+ # Creates exception handler that can display output to user via the given
5
+ # user interface.
6
+ #
7
+ # @param [Gerrit::UI] user interface to print output to
8
+ def initialize(ui)
9
+ @ui = ui
10
+ end
11
+
12
+ # Display appropriate output to the user for the given exception, returning
13
+ # a semantic exit status code.
14
+ #
15
+ # @return [Integer] exit status code
16
+ def handle(ex)
17
+ case ex
18
+ when Errors::UsageError
19
+ CLI::ExitCodes::USAGE
20
+ when Errors::ConfigurationError
21
+ ui.error ex.message
22
+ CLI::ExitCodes::CONFIG
23
+ else
24
+ print_unexpected_exception(ex)
25
+ CLI::ExitCodes::SOFTWARE
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :ui
32
+
33
+ def print_unexpected_exception(ex)
34
+ ui.bold_error ex.message
35
+ ui.error ex.backtrace.join("\n")
36
+ ui.warning 'Report this bug at ', newline: false
37
+ ui.info BUG_REPORT_URL
38
+ ui.newline
39
+ ui.info 'To help fix this issue, please include:'
40
+ ui.print '- The above stack trace'
41
+ ui.print '- Ruby version: ', newline: false
42
+ ui.info RUBY_VERSION
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ # Collection of errors that can be thrown by the application.
2
+ #
3
+ # This implements an exception hierarchy which exceptions to be grouped by type
4
+ # so the {ExceptionHandler} can display them appropriately.
5
+ module Gerrit::Errors
6
+ # Base class for all errors reported by this tool.
7
+ class GerritError < StandardError; end
8
+
9
+ # Base class for all errors that are a result of incorrect user usage.
10
+ class UsageError < GerritError; end
11
+
12
+ # Base class for all configuration-related errors.
13
+ class ConfigurationError < GerritError; end
14
+
15
+ # Raised when a configuration file is not present.
16
+ class ConfigurationMissingError < ConfigurationError; end
17
+
18
+ # Raised when a command has failed due to user error.
19
+ class CommandFailedError < UsageError; end
20
+
21
+ # Raised when invalid/non-existent command was used.
22
+ class CommandInvalidError < UsageError; end
23
+
24
+ # Raised when remote Gerrit command returned a non-zero exit status.
25
+ class GerritCommandFailedError < GerritError; end
26
+
27
+ # Raised when run in a directory not part of a valid git repository.
28
+ class InvalidGitRepo < UsageError; end
29
+ end
@@ -0,0 +1,18 @@
1
+ module Gerrit
2
+ # Provides interface for collecting input from the user.
3
+ class Input
4
+ # Creates an {Gerrit::Input} wrapping the given IO stream.
5
+ #
6
+ # @param [IO] input the input stream
7
+ def initialize(input)
8
+ @input = input
9
+ end
10
+
11
+ # Blocks until a line of input is returned from the input source.
12
+ #
13
+ # @return [String, nil]
14
+ def get
15
+ @input.gets
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module Gerrit
2
+ # Encapsulates all communication to an output source.
3
+ class Output
4
+ # Creates a {Gerrit::Output} which displays nothing.
5
+ #
6
+ # @return [Gerrit::Output]
7
+ def self.silent
8
+ new(File.open('/dev/null', 'w'))
9
+ end
10
+
11
+ # Creates a new {Gerrit::Output} instance.
12
+ #
13
+ # @param stream [IO] the output destination stream.
14
+ def initialize(stream)
15
+ @output_stream = stream
16
+ end
17
+
18
+ # Print the specified output.
19
+ #
20
+ # @param [String] output the output to display
21
+ def print(output)
22
+ @output_stream.print(output)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,71 @@
1
+ require 'pathname'
2
+
3
+ module Gerrit
4
+ # Exposes information about the current git repository.
5
+ class Repo
6
+ # @param config [Gerrit::Configuration]
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ # Returns the absolute path to the root of the current repository the
12
+ # current working directory resides within.
13
+ #
14
+ # @return [String]
15
+ # @raise [Gerrit::Errors::InvalidGitRepoError] if the current directory
16
+ # doesn't reside within a git repository
17
+ def root
18
+ @root ||=
19
+ begin
20
+ git_dir = Pathname.new(File.expand_path('.'))
21
+ .enum_for(:ascend)
22
+ .find do |path|
23
+ (path + '.git').exist?
24
+ end
25
+
26
+ unless git_dir
27
+ raise Errors::InvalidGitRepoError, 'no .git directory found'
28
+ end
29
+
30
+ git_dir.to_s
31
+ end
32
+ end
33
+
34
+ # Returns an absolute path to the .git directory for a repo.
35
+ #
36
+ # @return [String]
37
+ def git_dir
38
+ @git_dir ||=
39
+ begin
40
+ git_dir = File.expand_path('.git', root)
41
+
42
+ # .git could also be a file that contains the location of the git directory
43
+ unless File.directory?(git_dir)
44
+ git_dir = File.read(git_dir)[/^gitdir: (.*)$/, 1]
45
+
46
+ # Resolve relative paths
47
+ unless git_dir.start_with?('/')
48
+ git_dir = File.expand_path(git_dir, repo_dir)
49
+ end
50
+ end
51
+
52
+ git_dir
53
+ end
54
+ end
55
+
56
+ # Returns the project name for this repo.
57
+ #
58
+ # Uses the project name specified by the configuration, otherwise just uses
59
+ # the repo root directory.
60
+ #
61
+ # @return [String]
62
+ def project
63
+ @config[:project] || File.basename(root)
64
+ end
65
+
66
+ # Returns the Gerrit remote URL for this repo.
67
+ def remote_url
68
+ "ssh://#{@config[:user]}@#{@config[:host]}:#{@config[:port]}/#{project}"
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,53 @@
1
+ require 'childprocess'
2
+ require 'tempfile'
3
+
4
+ module Gerrit
5
+ # Manages execution of a child process, collecting the exit status and
6
+ # standard out/error output.
7
+ class Subprocess
8
+ # Encapsulates the result of a process.
9
+ #
10
+ # @attr_reader status [Integer] exit status code returned by process
11
+ # @attr_reader stdout [String] standard output stream output
12
+ # @attr_reader stderr [String] standard error stream output
13
+ Result = Struct.new(:status, :stdout, :stderr) do
14
+ def success?
15
+ status == 0
16
+ end
17
+ end
18
+
19
+ class << self
20
+ # Spawns a new process using the given array of arguments (the first
21
+ # element is the command).
22
+ #
23
+ # @param args [Array<String>]
24
+ # @return [Result]
25
+ def spawn(args)
26
+ process = ChildProcess.build(*args)
27
+
28
+ out, err = assign_output_streams(process)
29
+
30
+ process.start
31
+ process.wait
32
+
33
+ err.rewind
34
+ out.rewind
35
+
36
+ Result.new(process.exit_code, out.read, err.read)
37
+ end
38
+
39
+ private
40
+
41
+ # @param process [ChildProcess]
42
+ # @return [Array<IO>]
43
+ def assign_output_streams(process)
44
+ %w[out err].map do |stream_name|
45
+ ::Tempfile.new(stream_name).tap do |stream|
46
+ stream.sync = true
47
+ process.io.send("std#{stream_name}=", stream)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
data/lib/gerrit/ui.rb ADDED
@@ -0,0 +1,103 @@
1
+ require 'forwardable'
2
+ require 'tty'
3
+
4
+ module Gerrit
5
+ # Manages all interaction with the user.
6
+ class UI
7
+ extend Forwardable
8
+
9
+ def_delegators :@shell, :ask, :confirm
10
+
11
+ # Creates a {UI} that mediates between the given input/output streams.
12
+ #
13
+ # @param input [Gerrit::Input]
14
+ # @param output [Gerrit::Output]
15
+ def initialize(input, output)
16
+ @input = input
17
+ @output = output
18
+ @pastel = Pastel.new
19
+ @shell = TTY::Shell.new
20
+ end
21
+
22
+ # Get user input, stripping extraneous whitespace.
23
+ #
24
+ # @return [String, nil]
25
+ def user_input
26
+ if input = @input.get
27
+ input.strip
28
+ end
29
+ end
30
+
31
+ # Print the specified output.
32
+ #
33
+ # @param output [String]
34
+ # @param newline [Boolean] whether to append a newline
35
+ def print(output, newline: true)
36
+ @output.print(output)
37
+ @output.print("\n") if newline
38
+ end
39
+
40
+ # Print output in bold face.
41
+ #
42
+ # @param args [Array]
43
+ # @param kwargs [Hash]
44
+ def bold(*args, **kwargs)
45
+ print(@pastel.bold(*args), **kwargs)
46
+ end
47
+
48
+ # Print the specified output in a color indicative of error.
49
+ #
50
+ # @param args [Array]
51
+ # @param kwargs [Hash]
52
+ def error(args, **kwargs)
53
+ print(@pastel.red(*args), **kwargs)
54
+ end
55
+
56
+ # Print the specified output in a bold face and color indicative of error.
57
+ #
58
+ # @param args [Array]
59
+ # @param kwargs [Hash]
60
+ def bold_error(*args, **kwargs)
61
+ print(@pastel.bold.red(*args), **kwargs)
62
+ end
63
+
64
+ # Print the specified output in a color indicative of success.
65
+ #
66
+ # @param args [Array]
67
+ # @param kwargs [Hash]
68
+ def success(*args, **kwargs)
69
+ print(@pastel.green(*args), **kwargs)
70
+ end
71
+
72
+ # Print the specified output in a color indicative of a warning.
73
+ #
74
+ # @param args [Array]
75
+ # @param kwargs [Hash]
76
+ def warning(*args, **kwargs)
77
+ print(@pastel.yellow(*args), **kwargs)
78
+ end
79
+
80
+ # Print the specified output in a color indicating information.
81
+ #
82
+ # @param args [Array]
83
+ # @param kwargs [Hash]
84
+ def info(*args, **kwargs)
85
+ print(@pastel.cyan(*args), **kwargs)
86
+ end
87
+
88
+ # Print a blank line.
89
+ def newline
90
+ print('')
91
+ end
92
+
93
+ # Prints a table.
94
+ #
95
+ # Customize the table by passing a block and operating on the table object
96
+ # passed to that block to add rows and customize its appearance.
97
+ def table(&block)
98
+ t = TTY::Table.new
99
+ block.call(t)
100
+ print(t.render(:unicode))
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,30 @@
1
+ module Gerrit
2
+ # A miscellaneous set of utility functions.
3
+ module Utils
4
+ module_function
5
+
6
+ # Converts a string containing underscores/hyphens/spaces into CamelCase.
7
+ #
8
+ # @param [String] string
9
+ # @return [String]
10
+ def camel_case(string)
11
+ string.split(/_|-| /)
12
+ .map { |part| part.sub(/^\w/) { |c| c.upcase } }
13
+ .join
14
+ end
15
+
16
+ # Convert string containing camel case or spaces into snake case.
17
+ #
18
+ # @see stackoverflow.com/questions/1509915/converting-camel-case-to-underscore-case-in-ruby
19
+ #
20
+ # @param [String] string
21
+ # @return [String]
22
+ def snake_case(string)
23
+ string.gsub(/::/, '/')
24
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
25
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
26
+ .tr('-', '_')
27
+ .downcase
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ # Defines the gem version.
2
+ module Gerrit
3
+ VERSION = '0.1.0'
4
+ end
data/lib/gerrit.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'gerrit/constants'
2
+ require 'gerrit/errors'
3
+ require 'gerrit/error_handler'
4
+ require 'gerrit/configuration'
5
+ require 'gerrit/input'
6
+ require 'gerrit/output'
7
+ require 'gerrit/ui'
8
+ require 'gerrit/repo'
9
+ require 'gerrit/subprocess'
10
+ require 'gerrit/utils'
11
+ require 'gerrit/version'
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gerrit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shane da Silva
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: childprocess
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: tty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
41
+ description: Tool providing an effective CLI workflow with Gerrit
42
+ email:
43
+ - shane@dasilva.io
44
+ executables:
45
+ - gerrit
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - bin/gerrit
50
+ - lib/gerrit.rb
51
+ - lib/gerrit/cli.rb
52
+ - lib/gerrit/client.rb
53
+ - lib/gerrit/command/base.rb
54
+ - lib/gerrit/command/checkout.rb
55
+ - lib/gerrit/command/groups.rb
56
+ - lib/gerrit/command/help.rb
57
+ - lib/gerrit/command/members.rb
58
+ - lib/gerrit/command/projects.rb
59
+ - lib/gerrit/command/version.rb
60
+ - lib/gerrit/configuration.rb
61
+ - lib/gerrit/constants.rb
62
+ - lib/gerrit/error_handler.rb
63
+ - lib/gerrit/errors.rb
64
+ - lib/gerrit/input.rb
65
+ - lib/gerrit/output.rb
66
+ - lib/gerrit/repo.rb
67
+ - lib/gerrit/subprocess.rb
68
+ - lib/gerrit/ui.rb
69
+ - lib/gerrit/utils.rb
70
+ - lib/gerrit/version.rb
71
+ homepage: https://github.com/sds/gerrit
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 2.0.0
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.4.8
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Gerrit command line interface
95
+ test_files: []
96
+ has_rdoc: