octokom 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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