gerrit 0.1.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 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: