monotes 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ec9e3b9a6bd126d478f6ef382f615939bc1a369
4
- data.tar.gz: e499f5aea8d926a03ba5b42d3b3883f98b72c491
3
+ metadata.gz: 1230cb7946ec444383f76e8d171a2788fc1f081e
4
+ data.tar.gz: 0a44dc0b60cb8cb6e6b834cd771d26e0ff22e8dd
5
5
  SHA512:
6
- metadata.gz: 919d10152d8b060516d5375fd82f75bd558dab0ec13f0636909d27e972d19385e278cc3f61e27d45ba85cd2b7500c752ea4e900e8af6880f81b68584cfa6950a
7
- data.tar.gz: 06e90c47a48ff5bc1c876d6e2de095f87cccea58afa3bcbfa9707fee8e85c2cf1ddbdef591f5e28e907149dc39306081e216ee83a4202dc3d32b8cc91035d937
6
+ metadata.gz: b22e8efb7f377518417941e0972cf0528b3d651a17096dfd3c79ee5b38b405c444c600f1e3d68c5d604d810ae93dfabc63c4b654a1208c8c067f4f30b864f389
7
+ data.tar.gz: 184e1e2ab900e0c9bd95204cbfea993330044971069292b75765c2f54ce100a4960b887ad152044b5697b6e3d4cd864a320e5fa73cd5715830191ebd19af1d5e
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ -fd
2
+ --color
3
+ --tty
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.3"
4
+ - "2.0.0"
5
+ - "2.1.2"
6
+ - jruby-19mode # JRuby in 1.9 mode
7
+ - rbx
8
+ env:
9
+ - RUN=rake
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
+ [![Build
2
+ Status](https://travis-ci.org/schultyy/monotes.svg?branch=master)](https://travis-ci.org/schultyy/monotes)
1
3
  # Monotes
2
4
 
3
- TODO: Write a gem description
5
+ Monotes is a GitHub Issues commandline client.
4
6
 
5
7
  ## Installation
6
8
 
@@ -18,7 +20,34 @@ Or install it yourself as:
18
20
 
19
21
  ## Usage
20
22
 
21
- TODO: Write usage instructions here
23
+ ### Login to GitHub
24
+
25
+ ```bash
26
+ $ monotes login
27
+ Username: <your usename>
28
+ Password: <Password>
29
+ ```
30
+
31
+ ### Login with Two-Factor Authentication
32
+
33
+ ```bash
34
+ $ monotes login
35
+ Username: <your usename>
36
+ Password: <Password>
37
+ Your 2FA token: <Token>
38
+ ```
39
+
40
+ ### Download issues for repository
41
+
42
+ ```bash
43
+ $ monotes download 'schultyy/monotes'
44
+ ```
45
+
46
+ ### Browse downloaded issues
47
+
48
+ ```bash
49
+ $ monotes show 'schultyy/monotes'
50
+ ```
22
51
 
23
52
  ## Contributing
24
53
 
data/Rakefile CHANGED
@@ -1,2 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new(:spec)
2
4
 
5
+ task :default => [:spec]
data/bin/monotes ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'monotes'
3
+
4
+ Monotes::CLI::Application.start(ARGV)
data/lib/monotes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require "monotes/version"
2
+ require "monotes/cli/application"
2
3
 
3
4
  module Monotes
4
- # Your code goes here...
5
5
  end
@@ -0,0 +1,28 @@
1
+ require 'monotes/app_directory'
2
+
3
+ module Monotes
4
+ module IO
5
+ class FSDelegate
6
+ include Monotes::AppDirectory
7
+
8
+ #
9
+ # issues: Issues represented as Hash
10
+ #
11
+ def save(username, repository, issues)
12
+ if !File.directory?(app_path)
13
+ Dir.mkdir(app_path)
14
+ end
15
+ user_folder = File.join(app_path, username)
16
+ Dir.mkdir(user_folder) if !File.directory?(user_folder)
17
+ File.open(File.join(user_folder, "#{repository}.yaml"), "w") do |handle|
18
+ handle.write(issues.to_yaml)
19
+ end
20
+ end
21
+
22
+ def load(username, repository)
23
+ abs_path = File.join(app_path, username, "#{repository}.yaml")
24
+ YAML.load_file(abs_path)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ module Monotes
2
+ module AppDirectory
3
+ def app_path
4
+ File.expand_path("~/.monotes")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ module Monotes
2
+ class Authenticator
3
+ ACCESS_NOTE = "Monotes access token"
4
+ def initialize(api_client_klass)
5
+ @api_client_klass = api_client_klass
6
+ end
7
+
8
+ def get_oauth_token(username, password, &acquire_two_fa)
9
+ api_client = @api_client_klass.new(:login => username, :password => password)
10
+ begin
11
+ api_client.create_authorization(:scopes => scopes, :note => ACCESS_NOTE)
12
+ rescue Octokit::OneTimePasswordRequired
13
+ two_fa_token = yield acquire_two_fa
14
+ api_client.create_authorization(:scopes => scopes, :note => ACCESS_NOTE,
15
+ :headers => { "X-GitHub-OTP" => two_fa_token })
16
+ end
17
+ end
18
+ private
19
+ def scopes
20
+ ["user", "repo"]
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ require 'monotes/app_directory'
2
+
3
+ module Monotes
4
+ class BodyText
5
+ include Monotes::AppDirectory
6
+ FILENAME = "ISSUE_BODY_TEXT"
7
+
8
+ def initialize(title)
9
+ @title = title
10
+ end
11
+
12
+ def read
13
+ File.read(path)
14
+ end
15
+
16
+ def flush
17
+ File.delete(path)
18
+ end
19
+
20
+ def create_issue
21
+ edit_success = system "vim #{path}"
22
+ if edit_success
23
+ body_text = read
24
+ flush
25
+ Monotes::Models::Issue.new(:title => @title, :body => body_text)
26
+ else
27
+ nil
28
+ end
29
+ end
30
+
31
+ private
32
+ def path
33
+ File.join(app_path, FILENAME)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,122 @@
1
+ require 'thor'
2
+ require 'yaml'
3
+ require 'netrc'
4
+ require 'octokit'
5
+ require 'monotes/authenticator'
6
+ require 'monotes/issue_download'
7
+ require 'monotes/issue_repository'
8
+ require 'monotes/models/issue'
9
+ require 'monotes/app_directory'
10
+ require 'monotes/body_text'
11
+ require 'monotes/sync_list'
12
+
13
+ module Monotes
14
+ module CLI
15
+ class Application < Thor
16
+ include Monotes::AppDirectory
17
+
18
+ desc "login", "Login into GitHub"
19
+ def login
20
+ print "Username > "
21
+ username = STDIN.gets.chomp
22
+ validate!("username", username)
23
+ print "Password > "
24
+ password = STDIN.noecho(&:gets).chomp
25
+ validate!("password", password)
26
+ STDOUT.puts "\n"
27
+ authenticator = Monotes::Authenticator.new(Octokit::Client)
28
+ begin
29
+ oauth_token = authenticator.get_oauth_token(username, password) do
30
+ print "Two-Factor token > "
31
+ token = STDIN.gets.chomp
32
+ validate!("Two-Factor token", token)
33
+ token
34
+ end
35
+ rescue Octokit::Unauthorized => unauthorized
36
+ STDERR.puts "Unauthorized: #{unauthorized.message}"
37
+ exit 77
38
+ rescue Exception => e
39
+ fatal!(e)
40
+
41
+ else
42
+ write_to_netrc(username, oauth_token.token)
43
+ end
44
+ end
45
+
46
+ desc "download REPOSITORY", "Download issues for a repository"
47
+ def download(repository)
48
+ STDOUT.puts "Downloading issues for #{repository}..."
49
+ downloader = Monotes::IssueDownload.new(Octokit)
50
+ begin
51
+ issues = downloader.download(repository)
52
+ rescue Exception => exc
53
+ fatal!(exc)
54
+ end
55
+ repository = Monotes::IssueRepository.build(repository: repository)
56
+ repository.save(issues)
57
+ end
58
+
59
+ desc "show REPOSITORY", "Show downloaded issues"
60
+ def show(repository_name)
61
+ repository = Monotes::IssueRepository.build(repository: repository_name)
62
+ issues = repository.load
63
+ issues.map do |issue|
64
+ if issue.unsynced?
65
+ STDOUT.puts "(new) - #{issue.title}"
66
+ else
67
+ STDOUT.puts "#{issue.number} - #{issue.title}"
68
+ end
69
+ end
70
+ end
71
+
72
+ desc "create REPOSITORY TITLE", "Creates a new local issue"
73
+ def create(repository_name, title)
74
+ text = Monotes::BodyText.new(title)
75
+ issue = text.create_issue
76
+ repository = Monotes::IssueRepository.build(repository: repository_name)
77
+ repository.append(issue)
78
+ end
79
+
80
+ desc "sync REPOSITORY", "Synchronizes local issues with GitHub"
81
+ def sync(repository_name)
82
+ repository = Monotes::IssueRepository.build(repository: repository_name)
83
+ issues = repository.load
84
+ already_synced = issues.reject { |i| i.unsynced? }
85
+ adapter = Octokit::Client.new(netrc: true)
86
+ begin
87
+ sync_list = Monotes::SyncList.new(list: issues, repo: repository_name, adapter: adapter)
88
+ synced = sync_list.sync do |issue|
89
+ STDOUT.puts "Synced issue #{issue.title}"
90
+ end
91
+ rescue Exception => exc
92
+ fatal!(exc)
93
+ end
94
+ repository.save(already_synced.concat(synced))
95
+ end
96
+
97
+ private
98
+
99
+ def fatal!(exc)
100
+ STDERR.puts "FATAL: #{exc.message}"
101
+ exit 74
102
+ end
103
+
104
+ def validate!(name, param)
105
+ if param.nil? || param.empty?
106
+ STDERR.puts "Fatal: #{name} cannot be empty"
107
+ exit 74
108
+ end
109
+ end
110
+
111
+ def split_repository_identifier(repo)
112
+ repo.split('/')
113
+ end
114
+
115
+ def write_to_netrc(username, token)
116
+ netrc_handle = Netrc.read
117
+ netrc_handle["api.github.com"] = username, token
118
+ netrc_handle.save
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,17 @@
1
+ require 'monotes/models/issue'
2
+
3
+ module Monotes
4
+ class IssueDownload
5
+ def initialize(api_client)
6
+ @api_client = api_client
7
+ end
8
+
9
+ def download(repository)
10
+ raise ArgumentError, 'repository must not be nil' if repository.nil?
11
+
12
+ @api_client.list_issues(repository).map do |issue|
13
+ Monotes::Models::Issue.new(issue)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ require 'yaml'
2
+ require 'monotes/IO/fs_delegate'
3
+
4
+ module Monotes
5
+ class IssueRepository
6
+
7
+ def initialize(args)
8
+ @context = args.fetch(:context)
9
+ @repository = args.fetch(:repository)
10
+ end
11
+
12
+ def save(args)
13
+ issues = Array(args).map do |issue|
14
+ issue.to_hash
15
+ end
16
+ @context.save(*@repository.split('/'), issues)
17
+ end
18
+
19
+ def append(new_issue)
20
+ raise ArgumentError, 'issue must not be nil' if new_issue.nil?
21
+ issues = load
22
+ issues << new_issue
23
+ save(issues)
24
+ end
25
+
26
+ def load
27
+ @context.load(*@repository.split('/')).map do |issue_hash|
28
+ Monotes::Models::Issue.new(issue_hash)
29
+ end
30
+ end
31
+
32
+ def self.build(args)
33
+ context = Monotes::IO::FSDelegate.new
34
+ Monotes::IssueRepository.new(args.merge(:context => context))
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ require 'virtus'
2
+
3
+ module Monotes
4
+ module Models
5
+ class Issue
6
+ include Virtus.model
7
+ attribute :url, String
8
+ attribute :id, Fixnum, :default => 0
9
+ attribute :number, Fixnum, :default => 0
10
+ attribute :title, String
11
+ attribute :state, String
12
+ attribute :created_at, DateTime
13
+ attribute :updated_at, DateTime
14
+ attribute :body, String
15
+
16
+ def unsynced?
17
+ number == 0
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'monotes/models/issue'
2
+
3
+ module Monotes
4
+ class SyncList
5
+
6
+ def initialize(args)
7
+ @list = args.fetch(:list)
8
+ @adapter = args.fetch(:adapter)
9
+ @repository = args.fetch(:repo)
10
+ end
11
+
12
+ def sync
13
+ unsynced = @list.find_all {|issue| issue.unsynced? }
14
+ unsynced.map do |issue|
15
+ result = @adapter.create_issue(@repository, issue.title, issue.body)
16
+ yield(result) if block_given?
17
+ Monotes::Models::Issue.new(result.to_hash)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Monotes
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/monotes.gemspec CHANGED
@@ -18,6 +18,12 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "thor"
22
+ spec.add_dependency "octokit", "~> 3.0"
23
+ spec.add_dependency "netrc"
24
+ spec.add_dependency "virtus"
21
25
  spec.add_development_dependency "bundler", "~> 1.6"
22
26
  spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "factory_girl", "~> 4.4.0"
23
29
  end
data/spec/factories.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'monotes/models/issue'
2
+
3
+ FactoryGirl.define do
4
+ factory :issue, class: Monotes::Models::Issue do
5
+ end
6
+ end
@@ -0,0 +1,29 @@
1
+ require 'factory_girl'
2
+
3
+ RSpec.configure do |config|
4
+ config.filter_run :focus
5
+ config.run_all_when_everything_filtered = true
6
+
7
+ if config.files_to_run.one?
8
+ config.default_formatter = 'doc'
9
+ end
10
+
11
+ config.profile_examples = 10
12
+
13
+ config.order = :random
14
+
15
+ Kernel.srand config.seed
16
+
17
+ config.include FactoryGirl::Syntax::Methods
18
+ FactoryGirl.definition_file_paths = [File.expand_path('../factories', __FILE__)]
19
+ FactoryGirl.find_definitions
20
+
21
+ config.expect_with :rspec do |expectations|
22
+ expectations.syntax = :expect
23
+ end
24
+
25
+ config.mock_with :rspec do |mocks|
26
+ mocks.syntax = :expect
27
+ mocks.verify_partial_doubles = true
28
+ end
29
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'monotes/authenticator'
3
+ require 'octokit'
4
+
5
+ describe Monotes::Authenticator do
6
+ let(:api_client_mock_class) { double('Octokit::Client') }
7
+ let(:api_client_mock) { double('Octokit::Client instance') }
8
+ let(:username) { 'Jim' }
9
+ let(:password) { 'passw' }
10
+ let(:expected_oauth_token) { 'expected_oauth_token' }
11
+
12
+ context 'without 2FA' do
13
+ subject(:authenticator) { Monotes::Authenticator.new(api_client_mock_class) }
14
+
15
+ before do
16
+ allow(api_client_mock_class).to receive(:new).with(any_args).and_return(api_client_mock)
17
+ allow(api_client_mock).to receive(:create_authorization).with(any_args).and_return(expected_oauth_token)
18
+ end
19
+
20
+ it 'authenticates without asking for 2-FA token' do
21
+ actual_token = authenticator.get_oauth_token(username, password) { raise "2-FA Block was called" }
22
+ expect(actual_token).to eq expected_oauth_token
23
+ end
24
+ end
25
+ context 'with 2FA' do
26
+ let(:two_fa_token) { '2-factor token' }
27
+ subject(:authenticator) { Monotes::Authenticator.new(api_client_mock_class) }
28
+
29
+ before do
30
+ params = { :scopes => ["user", "repo"], :note => Monotes::Authenticator::ACCESS_NOTE }
31
+ params_with_2fa = params.merge(:headers => { "X-GitHub-OTP" => two_fa_token })
32
+ allow(api_client_mock_class).to receive(:new).with(any_args).and_return(api_client_mock)
33
+ allow(api_client_mock).to receive(:create_authorization).with(params).and_raise(Octokit::OneTimePasswordRequired)
34
+ allow(api_client_mock).to receive(:create_authorization).with(params_with_2fa).and_return(expected_oauth_token)
35
+ end
36
+
37
+ it 'authenticates and asks for 2-FA token' do
38
+ block_called = false
39
+ authenticator.get_oauth_token(username, password) { block_called = true; two_fa_token }
40
+ expect(block_called).to be true
41
+ end
42
+
43
+ it 'authenticates with 2-FA token' do
44
+ actual_token = authenticator.get_oauth_token(username, password) { two_fa_token }
45
+ expect(actual_token).to eq expected_oauth_token
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'monotes/issue_download'
3
+
4
+ describe Monotes::IssueDownload do
5
+ let(:octo_mock) { double('Octokit') }
6
+ let(:issue_list) { [attributes_for(:issue)] }
7
+ let(:repository) { 'franz/franz-repo' }
8
+ subject(:downloader) { Monotes::IssueDownload.new(octo_mock) }
9
+
10
+ context '#download' do
11
+ before do
12
+ allow(octo_mock).to receive(:list_issues).and_return(issue_list)
13
+ end
14
+ it 'returns a list of issues' do
15
+ expect(downloader.download(repository).length).to be > 0
16
+ end
17
+
18
+ it 'raises error when repository is nil' do
19
+ expect { downloader.download(nil) }.to raise_error(ArgumentError)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+ require 'monotes/issue_repository'
4
+
5
+ describe Monotes::IssueRepository do
6
+ let(:issues) { build_list(:issue, 2) }
7
+ let(:context) { double('fs context') }
8
+ let(:repository_name) { 'franz/franz-seins' }
9
+ let(:issue) { issues.first }
10
+ subject(:repository) { Monotes::IssueRepository.new(repository: repository_name, context: context) }
11
+
12
+ context '#initialize' do
13
+ it 'accepts context and repository' do
14
+ expect { Monotes::IssueRepository.new(context: context, repository: repository_name) }.to_not raise_error
15
+ end
16
+
17
+ it 'raises error when context not passed' do
18
+ expect { Monotes::IssueRepository.new(repository: repository_name) }.to raise_error
19
+ end
20
+
21
+ it 'raises error when repository not passed' do
22
+ expect { Monotes::IssueRepository.new(context: context) }.to raise_error
23
+ end
24
+ end
25
+
26
+ context '#save' do
27
+ before do
28
+ allow(context).to receive(:save)
29
+ end
30
+
31
+ it 'saves a single issue' do
32
+ repository.save(issue)
33
+ expect(context).to have_received(:save).with('franz', 'franz-seins', [issue.to_hash])
34
+ end
35
+ end
36
+
37
+ context '#load' do
38
+ before do
39
+ allow(context).to receive(:load).and_return(attributes_for_list(:issue, 2))
40
+ end
41
+
42
+ it 'returns a list of issues' do
43
+ expect(repository.load.length).to be > 0
44
+ end
45
+
46
+ context 'result set' do
47
+ context 'element' do
48
+ it 'is of type Issue' do
49
+ issue = repository.load.first
50
+ expect(issue.class).to eq Monotes::Models::Issue
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ context '#append' do
57
+ before do
58
+ allow(context).to receive(:save)
59
+ allow(context).to receive(:load).and_return(attributes_for_list(:issue, 1))
60
+ repository.append(build(:issue))
61
+ end
62
+
63
+ it 'loads issues' do
64
+ expect(context).to have_received(:load)
65
+ end
66
+
67
+ it 'saves with appended issue' do
68
+ expect(context).to have_received(:save)
69
+ end
70
+
71
+ it 'raises error when issue is nil' do
72
+ expect { repository.append(nil) }.to raise_error(ArgumentError)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+ require 'monotes/models/issue'
3
+ require 'monotes/sync_list'
4
+
5
+ describe Monotes::SyncList do
6
+ let(:issue) { Monotes::Models::Issue.new }
7
+ let(:adapter) { double('OctoKit') }
8
+ let(:repo_name) { 'alice/example' }
9
+
10
+ context '#initialize' do
11
+ it 'accepts a list of issues' do
12
+ expect do
13
+ Monotes::SyncList.new(list: build_list(:issue, 1),
14
+ adapter: adapter,
15
+ repo: repo_name)
16
+ end.to_not raise_error
17
+ end
18
+
19
+ it 'raises error if no list was passed' do
20
+ expect { Monotes::SyncList.new(adapter: adapter, repo: repo_name) }.to raise_error
21
+ end
22
+
23
+ it 'raises error if no adapter was passed' do
24
+ expect { Monotes::SyncList.new(list: [issue], repo: repo_name) }.to raise_error
25
+ end
26
+
27
+ it 'raises error if no repository name was passed' do
28
+ expect { Monotes::SyncList.new(list: [issue], adapter: adapter) }.to raise_error
29
+ end
30
+ end
31
+
32
+ context '#sync' do
33
+ let(:unsynced_issues) { build_list(:issue, 1, number: 0, title: 'foo', body:'bar') }
34
+ let(:synced_issues) { build_list(:issue, 1, number: 45, title: 'baz', body:'yadda yadda') }
35
+ let(:issue_result) { attributes_for(:issue, number: 1, id: 1) }
36
+
37
+ before(:each) do
38
+ allow(adapter).to receive(:create_issue) { issue_result }
39
+ end
40
+
41
+ context 'with unsynced issues' do
42
+ subject(:sync_list) { Monotes::SyncList.new(list: unsynced_issues, adapter: adapter, repo: repo_name) }
43
+
44
+ it 'calls adapter to create issue' do
45
+ sync_list.sync
46
+ expect(adapter).to have_received(:create_issue).with(repo_name, 'foo', 'bar')
47
+ end
48
+
49
+ it 'calls block for each issue' do
50
+ block_called = false
51
+ sync_list.sync { |issue| block_called = true }
52
+ expect(block_called).to be true
53
+ end
54
+
55
+ it 'calls block with result from adapter call' do
56
+ block_result = nil
57
+ sync_list.sync { |issue| block_result = issue }
58
+ expect(block_result).to eq issue_result
59
+ end
60
+
61
+ context 'after sync' do
62
+ context 'issue' do
63
+ it 'has number' do
64
+ result = sync_list.sync.first
65
+ expect(result.unsynced?).to be false
66
+ end
67
+ it 'has id' do
68
+ result = sync_list.sync.first
69
+ expect(result.id).to_not eq 0
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ context 'with synced and unsynced issues' do
76
+ subject(:sync_list) { Monotes::SyncList.new(list: unsynced_issues.concat(synced_issues), adapter: adapter, repo: repo_name) }
77
+
78
+ it 'calls adapter only for unsynced issue' do
79
+ sync_list.sync
80
+ expect(adapter).to have_received(:create_issue).with(repo_name, 'foo', 'bar').once
81
+ end
82
+ end
83
+ end
84
+ end
metadata CHANGED
@@ -1,15 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monotes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Schulte
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-17 00:00:00.000000000 Z
11
+ date: 2014-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: octokit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: netrc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: virtus
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
13
69
  - !ruby/object:Gem::Dependency
14
70
  name: bundler
15
71
  requirement: !ruby/object:Gem::Requirement
@@ -38,22 +94,69 @@ dependencies:
38
94
  - - ">="
39
95
  - !ruby/object:Gem::Version
40
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: factory_girl
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 4.4.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 4.4.0
41
125
  description: GitHub Issues commandline client
42
126
  email:
43
127
  - schulte@unexpected-co.de
44
- executables: []
128
+ executables:
129
+ - monotes
45
130
  extensions: []
46
131
  extra_rdoc_files: []
47
132
  files:
48
133
  - ".gitignore"
134
+ - ".rspec"
135
+ - ".travis.yml"
49
136
  - Gemfile
50
137
  - LICENSE
51
138
  - LICENSE.txt
52
139
  - README.md
53
140
  - Rakefile
141
+ - bin/monotes
54
142
  - lib/monotes.rb
143
+ - lib/monotes/IO/fs_delegate.rb
144
+ - lib/monotes/app_directory.rb
145
+ - lib/monotes/authenticator.rb
146
+ - lib/monotes/body_text.rb
147
+ - lib/monotes/cli/application.rb
148
+ - lib/monotes/issue_download.rb
149
+ - lib/monotes/issue_repository.rb
150
+ - lib/monotes/models/issue.rb
151
+ - lib/monotes/sync_list.rb
55
152
  - lib/monotes/version.rb
56
153
  - monotes.gemspec
154
+ - spec/factories.rb
155
+ - spec/spec_helper.rb
156
+ - spec/unit/authenticator_spec.rb
157
+ - spec/unit/issue_download_spec.rb
158
+ - spec/unit/issue_repository_spec.rb
159
+ - spec/unit/sync_list_spec.rb
57
160
  homepage: https://github.com/schultyy/monotes
58
161
  licenses:
59
162
  - MIT
@@ -78,5 +181,11 @@ rubygems_version: 2.1.11
78
181
  signing_key:
79
182
  specification_version: 4
80
183
  summary: GitHub Issues commandline client
81
- test_files: []
184
+ test_files:
185
+ - spec/factories.rb
186
+ - spec/spec_helper.rb
187
+ - spec/unit/authenticator_spec.rb
188
+ - spec/unit/issue_download_spec.rb
189
+ - spec/unit/issue_repository_spec.rb
190
+ - spec/unit/sync_list_spec.rb
82
191
  has_rdoc: