octokom 0.0.2 → 0.0.3

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.
@@ -1,29 +1,64 @@
1
1
  module Octokom
2
2
  class Repository
3
- class << self
4
- def remote_path
5
- remote_url[/(\w+\/(\w+|\.)+)\.git$/, 1]
6
- end
7
-
8
- def current_branch
9
- `git rev-parse --abbrev-ref HEAD`.chomp
10
- end
11
-
12
- def unpushed_commits?
13
- !count_unpushed_commits.zero?
14
- end
15
-
16
- def count_unpushed_commits
17
- cmd = 'git log --branches --not --remotes --format=oneline'
18
- `#{cmd}`.chomp.split('\n').count
19
- end
20
-
21
- private
22
-
23
- def remote_url
24
- # TODO make "origin" configurable
25
- `git config --get remote.origin.url`.chomp
26
- end
3
+ include Octokom::Shell
4
+
5
+ def initialize(verbose)
6
+ @verbose = verbose
7
+ end
8
+
9
+ def repo_path
10
+ error('Git remote not defined') if remote_url.blank?
11
+ path = remote_url.split('/')[-2..-1]
12
+ path.join('/')[/(.*)\.git$/, 1]
13
+ end
14
+
15
+ def toplevel_path
16
+ git('rev-parse --show-toplevel')
17
+ end
18
+
19
+ # TODO Make base branch configurable.
20
+ def base_branch
21
+ 'master'
22
+ end
23
+
24
+ def head_branch
25
+ git('rev-parse --abbrev-ref HEAD')
26
+ end
27
+
28
+ def pending_commits?
29
+ current_sha1 = last_commits[/^\*\s((\w|-|_)*)\s+(\w{7})/, 3]
30
+ remote_sha1 = last_commits[/remotes\/origin\/#{head_branch}\s+(\w{7})/, 1]
31
+
32
+ return true if remote_sha1.blank?
33
+ current_sha1 != remote_sha1 ? true : false
34
+ end
35
+
36
+ def last_commit_message
37
+ git('log -1 --oneline')[/^\w+\s(.*)$/, 1]
38
+ end
39
+
40
+ def push(branch)
41
+ git("push origin #{branch}")
42
+ end
43
+
44
+ private
45
+
46
+ # TODO Make origin configurable.
47
+ def remote_url
48
+ @remote_url ||= git('config --get remote.origin.url')
49
+ end
50
+
51
+ def last_commits
52
+ @last_commits ||= git('branch -avvv')
53
+ end
54
+
55
+ def verbose?
56
+ !!@verbose
57
+ end
58
+
59
+ def git(cmd)
60
+ puts "git #{cmd}" if verbose?
61
+ `git #{cmd}`.chomp
27
62
  end
28
63
  end
29
64
  end
@@ -0,0 +1,22 @@
1
+ module Octokom
2
+ module Shell
3
+ def info(message)
4
+ puts "Info #{message}"
5
+ end
6
+
7
+ def error(message)
8
+ puts "Error #{message}"
9
+ exit(1)
10
+ end
11
+
12
+ # Print a waiting message before a long running task and replace
13
+ # the message as soon as the task has finished.
14
+ def task(message)
15
+ print "Waiting #{message}"
16
+ yield
17
+ print "\r"
18
+ print "Done #{message}"
19
+ puts
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,3 @@
1
1
  module Octokom
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  end
data/octokom.gemspec CHANGED
@@ -8,20 +8,22 @@ Gem::Specification.new do |gem|
8
8
  gem.version = Octokom::VERSION
9
9
  gem.authors = 'Martin Jagusch'
10
10
  gem.email = '_@mj.io'
11
- gem.description = 'Command line application for your every day GitHub workflow.'
11
+ gem.description = 'GitHub For Your Command Line'
12
12
  gem.summary = "octokom-#{Octokom::VERSION}"
13
13
  gem.homepage = 'https://github.com/mjio/octokom'
14
14
  gem.license = 'MIT'
15
15
 
16
+ gem.required_ruby_version = '>= 1.9.3'
17
+
16
18
  gem.files = `git ls-files`.split($/)
17
19
  gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
20
  gem.test_files = gem.files.grep(%r{^spec/})
19
21
  gem.require_paths = ['lib']
20
22
 
21
- gem.add_dependency 'clamp', '~> 0.6.1'
22
- gem.add_dependency 'octokit', '2.0.0.rc2'
23
- gem.add_dependency 'security', '~> 0.1.2'
23
+ gem.add_dependency 'clamp', '~> 0.6.3'
24
+ gem.add_dependency 'netrc', '~> 0.7.7'
25
+ gem.add_dependency 'octokit', '~> 2.7.1'
24
26
 
25
- gem.add_development_dependency 'rake', '~> 10.1.0'
26
- gem.add_development_dependency 'rspec', '~> 2.14.1'
27
+ gem.add_development_dependency 'rake', '~> 10.1.1'
28
+ gem.add_development_dependency 'rspec', '~> 3.0.0.beta2'
27
29
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Octokom::CLI do
4
+ it 'has a "issue" sub command' do
5
+ command = Octokom::CLI.find_subcommand('issue')
6
+ expect(command).to be_kind_of(Clamp::Subcommand::Definition)
7
+ end
8
+
9
+ it 'has a "pull-request" sub command' do
10
+ command = Octokom::CLI.find_subcommand('pull-request')
11
+ expect(command).to be_kind_of(Clamp::Subcommand::Definition)
12
+ end
13
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+ require 'octokit'
3
+
4
+ describe Octokom::Client do
5
+ let(:netrc) { {Octokom::Client::KEY => credentials} }
6
+
7
+ before do
8
+ allow(Netrc).to receive(:new) { netrc }
9
+ end
10
+
11
+ describe '#authenticate' do
12
+ context 'with valid netrc file' do
13
+ let(:credentials) { ['fox', 'chunky'] }
14
+
15
+ it 'parses the credentials' do
16
+ auth = Octokom::Client.authenticate
17
+ expect(auth.token).to eq('chunky')
18
+ end
19
+
20
+ it 'returns a client instance' do
21
+ auth = Octokom::Client.authenticate
22
+ expect(auth).to be_kind_of(Octokom::Client)
23
+ end
24
+
25
+ it 'handels invalid API tokens on GitHub'
26
+ end
27
+
28
+ context 'with invalid netrc file' do
29
+ let(:credentials) { [] }
30
+ let(:octokit) { double }
31
+ let(:auth) { double(:token => nil) }
32
+
33
+ before do
34
+ allow_any_instance_of(Octokom::Client).to receive(:ask_for_login) { 'fox' }
35
+ allow_any_instance_of(Octokom::Client).to receive(:ask_for_password) { 'bacon' }
36
+ allow(Octokit::Client).to receive(:new) { octokit }
37
+ allow(octokit).to receive(:create_authorization) { auth }
38
+ allow(netrc).to receive(:save) { true }
39
+ allow(STDOUT).to receive(:puts)
40
+ end
41
+
42
+ it 'initializes a new Octokit client' do
43
+ expect(Octokit::Client).to receive(:new).with(login: 'fox', password: 'bacon')
44
+ Octokom::Client.authenticate
45
+ end
46
+
47
+ it 'creates a authorization token' do
48
+ expect(octokit).to receive(:create_authorization)
49
+ Octokom::Client.authenticate
50
+ end
51
+
52
+ it 'creates a authorization token' do
53
+ expect(netrc).to receive(:save)
54
+ Octokom::Client.authenticate
55
+ end
56
+ end
57
+ end
58
+
59
+ describe '#client' do
60
+ let(:credentials) { ['fox', 'chunky'] }
61
+
62
+ it 'initializes a new Octokit client' do
63
+ auth = Octokom::Client.authenticate
64
+ expect(auth.client).to be_kind_of(Octokit::Client)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'octokom/command/issue'
3
+
4
+ describe Issue do
5
+ describe '#create' do
6
+ let(:git) { double(repo_path: 'user/repo') }
7
+ let(:auth) { double(client: client) }
8
+ let(:client) { double }
9
+
10
+ before do
11
+ allow(Octokom::Repository).to receive(:new) { git }
12
+ allow(Octokom::Client).to receive(:authenticate) { auth }
13
+ allow(client).to receive(:create_issue)
14
+ allow_any_instance_of(Octokom::Command).to receive(:print)
15
+ allow_any_instance_of(Octokom::Command).to receive(:puts)
16
+ end
17
+
18
+ subject(:cmd) { Issue.new('test') }
19
+
20
+ context 'when no "title" option is set' do
21
+ let(:options) { %w(create) }
22
+
23
+ it 'opens the editor' do
24
+ expect(Octokom::Editor).to receive(:open).with(git, nil, nil) { ['Bacon'] }
25
+
26
+ cmd.run(options)
27
+ end
28
+
29
+ it 'exits when no "title" can be parsed'
30
+ end
31
+
32
+ context 'when "title" option is set' do
33
+ let(:options) { %w(create --title Bacon) }
34
+
35
+ it 'creates a GitHub issue' do
36
+ expect(client).to receive(:create_issue).with('user/repo', 'Bacon', nil)
37
+
38
+ cmd.run(options)
39
+ end
40
+
41
+ context 'and "dry-run" tag is set' do
42
+ it 'does not create a GitHub issue' do
43
+ expect(client).to_not receive(:create_issue)
44
+
45
+ cmd.run(options.push('--dry-run'))
46
+ end
47
+ end
48
+
49
+ context 'and "editor" tag is set' do
50
+ it 'opens the editor' do
51
+ expect(Octokom::Editor).to receive(:open).with(git, 'Bacon', nil) { ['Bacon'] }
52
+
53
+ cmd.run(options.push('--editor'))
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,8 +1,7 @@
1
1
  require 'spec_helper'
2
+ require 'octokom/command/pull_request'
2
3
 
3
- describe Octokom::Command::PullRequest do
4
- it 'has a `create` sub command' do
5
- command = Octokom::Command::PullRequest.find_subcommand('create')
6
- expect(command).to be_kind_of(Clamp::Subcommand::Definition)
4
+ describe PullRequest do
5
+ describe '#create' do
7
6
  end
8
7
  end
@@ -1,8 +1,61 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Octokom::Command do
4
- it 'has a `pull-request` sub command' do
5
- command = Octokom::Command.find_subcommand('pull-request')
6
- expect(command).to be_kind_of(Clamp::Subcommand::Definition)
4
+ describe '#flag' do
5
+ subject(:cmd) do
6
+ class FlagCmd < Octokom::Command
7
+ flag ['--bacon'], 'Bacon'
8
+ execute { @bacon }
9
+ end
10
+
11
+ FlagCmd.new('test')
12
+ end
13
+
14
+ it 'returns true when the flag option is set' do
15
+ expect(cmd.run(['--bacon'])).to be(true)
16
+ end
17
+
18
+ it 'returns nil when the flag option is not set' do
19
+ expect(cmd.run([])).to be_nil
20
+ end
21
+ end
22
+
23
+ describe '#option' do
24
+ subject(:cmd) do
25
+ class OptionCmd < Octokom::Command
26
+ option ['--bacon'], 'Bacon'
27
+ execute { @bacon }
28
+ end
29
+
30
+ OptionCmd.new('test')
31
+ end
32
+
33
+ it 'returns the the option value' do
34
+ expect(cmd.run(['--bacon', '1'])).to eq('1')
35
+ end
36
+
37
+ it 'returns nil when the option is not set' do
38
+ expect(cmd.run([])).to be_nil
39
+ end
40
+ end
41
+
42
+ describe '#git' do
43
+ subject(:cmd) do
44
+ class GitCmd < Octokom::Command
45
+ execute { git }
46
+ end
47
+
48
+ GitCmd.new('test')
49
+ end
50
+
51
+ let(:git) { double }
52
+
53
+ before do
54
+ allow(Octokom::Repository).to receive(:new) { git }
55
+ end
56
+
57
+ it 'initializes a Repository instance' do
58
+ expect(cmd.run([])).to eq(git)
59
+ end
7
60
  end
8
61
  end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Octokom::Editor do
4
+ let(:repo) { double(toplevel_path: '~') }
5
+ let(:title) { 'Feature' }
6
+ let(:desc) { '...' }
7
+ let(:editor) { Octokom::Editor.new(repo, nil, nil) }
8
+
9
+ describe '#open_editor' do
10
+ before do
11
+ allow(editor).to receive(:editor_name) { 'vi' }
12
+ end
13
+
14
+ it 'build the command' do
15
+ expect(editor).to receive(:system).with(/^vi --nofork +6*+/)
16
+ editor.open_editor
17
+ end
18
+ end
19
+
20
+ describe '#parse_user_input' do
21
+ before do
22
+ allow(editor).to receive(:file_name) { './spec/support/OCTOKOM-123' }
23
+ end
24
+
25
+ it 'finds the title' do
26
+ expect(editor.parse_user_input[0]).to eq('Chunky Bacon')
27
+ end
28
+
29
+ it 'finds the description' do
30
+ expect(editor.parse_user_input[1]).to eq("Really\n remarkable!")
31
+ end
32
+ end
33
+ end
@@ -1,15 +1,72 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Octokom::Repository do
4
- subject(:repo) { Octokom::Repository }
4
+ subject(:repo) { Octokom::Repository.new(false) }
5
5
 
6
- describe '#remote_path' do
6
+ describe '#repo_path' do
7
+ context 'when a remote path is defined' do
8
+ before do
9
+ allow(repo).to receive(:remote_url) { 'https://github.com/fox-1/bacon.rb.git' }
10
+ end
11
+
12
+ it 'returns the GitHub repository path' do
13
+ expect(repo.repo_path).to eq('fox-1/bacon.rb')
14
+ end
15
+ end
16
+
17
+ context 'when no remote path is defined' do
18
+ let(:stdout) { double }
19
+
20
+ before do
21
+ allow(repo).to receive(:remote_url) { nil }
22
+ allow(stdout).to receive(:puts)
23
+ allow(repo).to receive(:puts) { |msg| stdout.puts(msg) }
24
+ end
25
+
26
+ it 'prints a error message and exits' do
27
+ expect(stdout).to receive(:puts).with(/Git remote not defined/)
28
+ expect { repo.repo_path }.to raise_error(SystemExit)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe '#pending_commits?' do
34
+ before do
35
+ allow(repo).to receive(:head_branch) { 'test-1' }
36
+ end
37
+
38
+ context 'with pending commits' do
39
+ before do
40
+ allow(repo).to receive(:last_commits) { load_example(:git_branch_pending_commits) }
41
+ end
42
+
43
+ specify { expect(repo.pending_commits?).to be(true) }
44
+ end
45
+
46
+ context 'with no pending commits' do
47
+ before do
48
+ allow(repo).to receive(:last_commits) { load_example(:git_branch_no_pending_commits) }
49
+ end
50
+
51
+ specify { expect(repo.pending_commits?).to be(false) }
52
+ end
53
+
54
+ context 'with no remote branch' do
55
+ before do
56
+ allow(repo).to receive(:last_commits) { load_example(:git_branch_no_remote) }
57
+ end
58
+
59
+ specify { expect(repo.pending_commits?).to be(true) }
60
+ end
61
+ end
62
+
63
+ describe '#last_commit_message' do
7
64
  before do
8
- allow(repo).to receive(:remote_url) { 'https://github.com/mjio/octokom.git' }
65
+ allow(repo).to receive(:git) { load_example(:git_log_commits) }
9
66
  end
10
67
 
11
- it 'returns GitHub remote path' do
12
- expect(repo.remote_path).to eq('mjio/octokom')
68
+ it 'returns the commit message' do
69
+ expect(repo.last_commit_message).to eq('Add all the features')
13
70
  end
14
71
  end
15
72
  end