redpomo-reloaded 0.0.13

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/Dockerfile +5 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +139 -0
  5. data/Guardfile +23 -0
  6. data/LICENSE +22 -0
  7. data/README.md +176 -0
  8. data/Rakefile +6 -0
  9. data/bin/redpomo +7 -0
  10. data/docker-compose.yml +7 -0
  11. data/lib/redpomo.rb +10 -0
  12. data/lib/redpomo/cli.rb +172 -0
  13. data/lib/redpomo/config.rb +26 -0
  14. data/lib/redpomo/entries_printer.rb +33 -0
  15. data/lib/redpomo/entry.rb +65 -0
  16. data/lib/redpomo/file_cache.rb +44 -0
  17. data/lib/redpomo/fuzzy_converter.rb +68 -0
  18. data/lib/redpomo/issue.rb +38 -0
  19. data/lib/redpomo/null_cache.rb +9 -0
  20. data/lib/redpomo/numeric_ext.rb +30 -0
  21. data/lib/redpomo/task.rb +103 -0
  22. data/lib/redpomo/task_list.rb +61 -0
  23. data/lib/redpomo/templates/config.yml +47 -0
  24. data/lib/redpomo/templates/issue_stub.textile +7 -0
  25. data/lib/redpomo/tracker.rb +175 -0
  26. data/lib/redpomo/ui.rb +73 -0
  27. data/lib/redpomo/version.rb +3 -0
  28. data/redpomo.gemspec +33 -0
  29. data/spec/file_cache_spec.rb +22 -0
  30. data/spec/fixtures/add_results.txt +4 -0
  31. data/spec/fixtures/cassettes/cli_add.yml +102 -0
  32. data/spec/fixtures/cassettes/cli_close.yml +50 -0
  33. data/spec/fixtures/cassettes/cli_pull.yml +1222 -0
  34. data/spec/fixtures/cassettes/cli_push.yml +297 -0
  35. data/spec/fixtures/cassettes/close_issue.yml +50 -0
  36. data/spec/fixtures/cassettes/create_issue.yml +102 -0
  37. data/spec/fixtures/cassettes/issues.yml +449 -0
  38. data/spec/fixtures/cassettes/push_entry.yml +55 -0
  39. data/spec/fixtures/close_results.txt +2 -0
  40. data/spec/fixtures/config.yml +16 -0
  41. data/spec/fixtures/printer_output.txt +16 -0
  42. data/spec/fixtures/proper_timelog.csv +4 -0
  43. data/spec/fixtures/pull_results.txt +20 -0
  44. data/spec/fixtures/tasks.txt +3 -0
  45. data/spec/fixtures/timelog.csv +6 -0
  46. data/spec/integration/add_spec.rb +29 -0
  47. data/spec/integration/init_spec.rb +33 -0
  48. data/spec/lib/redpomo/cli_spec.rb +91 -0
  49. data/spec/lib/redpomo/entry_spec.rb +23 -0
  50. data/spec/lib/redpomo/fuzzy_converter_spec.rb +65 -0
  51. data/spec/lib/redpomo/task_spec.rb +39 -0
  52. data/spec/lib/redpomo/tracker_spec.rb +72 -0
  53. data/spec/spec_helper.rb +28 -0
  54. data/spec/support/cli_helpers.rb +76 -0
  55. data/spec/support/fixtures.rb +24 -0
  56. data/spec/support/ruby_ext.rb +20 -0
  57. data/spec/tmp/REDME.md +0 -0
  58. metadata +296 -0
@@ -0,0 +1,2 @@
1
+ Make screenshot #838 @cantiere
2
+ Another task @home
@@ -0,0 +1,16 @@
1
+ cache: false
2
+ trackers:
3
+ cantiere:
4
+ url: "https://project.cantierecreativo.net"
5
+ token: "CANTIERE_TOKEN"
6
+ default_project_id: "cc"
7
+ closed_status_id: 5
8
+ default_priority_id: 4
9
+ priority_ids: [ 16, 6, 5 ]
10
+ welaika:
11
+ url: "http://code.welaika.com"
12
+ token: "WELAIKA_TOKEN"
13
+ default_project_id: "welaika"
14
+ closed_status_id: 5
15
+ default_priority_id: 4
16
+ priority_ids: [ 7, 6, 5 ]
@@ -0,0 +1,16 @@
1
+ +----------+------------+---------+----------------------------+----------+-------+-------+
2
+ | Wednesday 05/02/12 - 5 mins |
3
+ +----------+------------+---------+----------------------------+----------+-------+-------+
4
+ | Context | Project | Issue # | Description | Duration | From | To |
5
+ +----------+------------+---------+----------------------------+----------+-------+-------+
6
+ | cantiere | giunti-web | | Layout homepage e contatti | 5 mins | 08:10 | 08:15 |
7
+ +----------+------------+---------+----------------------------+----------+-------+-------+
8
+
9
+ +---------+---------+---------+-------------+----------+-------+-------+
10
+ | Friday 05/04/12 - 5 mins |
11
+ +---------+---------+---------+-------------+----------+-------+-------+
12
+ | Context | Project | Issue # | Description | Duration | From | To |
13
+ +---------+---------+---------+-------------+----------+-------+-------+
14
+ | welaika | | 3293 | Ricette | 5 mins | 15:04 | 15:09 |
15
+ +---------+---------+---------+-------------+----------+-------+-------+
16
+
@@ -0,0 +1,4 @@
1
+ esportazione #1036 +giunti-web @cantiere,2012-05-15 23:10:44 +0000,10
2
+ Dialog Partner aggiuntivi #1016 @cantiere,2012-05-16 08:42:51 +0000,25
3
+ Dialog Partner aggiuntivi #1016 @cantiere,2012-05-16 09:21:35 +0000,25
4
+ Scorrimento barra orizzontale #1059 @cantiere,2012-05-16 10:01:09 +0000,25
@@ -0,0 +1,20 @@
1
+ Another task @home
2
+ mailchimp #1006 +flor @cantiere
3
+ gestione utenti #987 +giunti-web @cantiere
4
+ Documentazione server su Wiki #986 +giunti-web @cantiere
5
+ Form richiesta kit #985 +giunti-web @cantiere
6
+ Invia libro ad un amico #976 +giunti-web @cantiere
7
+ 2012-04-04 Immagini promo per chrome #859 +zazit @cantiere
8
+ (C) 2012-04-04 Correzioni frase e logo zazit #858 +zazit @cantiere
9
+ (B) 2012-04-02 icone per safari #839 +zazit @cantiere
10
+ (B) 2012-04-02 icona per chrome market #837 +zazit @cantiere
11
+ Rel Canonical e rel author #820 +railsyard @cantiere
12
+ DSL backend per la gestione dei model #731 +railsyard @cantiere
13
+ paradosso zazit #728 +zazit @cantiere
14
+ (B) New Users iOS #3316 +dashboard-fiat @welaika
15
+ Orlando Locator #3296 +olasagasti @welaika
16
+ Il Paniere #3295 +olasagasti @welaika
17
+ Scheda Prodotto #3294 +olasagasti @welaika
18
+ Ricette #3293 +olasagasti @welaika
19
+ Some users have mentioned that the intranet wiki does not support 'table' markup. Can that be updated to work? #3286 +orchid @welaika
20
+ Issue with the blog emails #3269 +orchid @welaika
@@ -0,0 +1,3 @@
1
+ Make screenshot #838 @cantiere
2
+ Fix #3290 @welaika
3
+ Another task @home
@@ -0,0 +1,6 @@
1
+ Export data created by Pomodoro on 2012-05-04 16:12:17 +0000
2
+
3
+ Description, When, Duration, externalInterruptions, internalInterruptions
4
+
5
+ Layout homepage e contatti +giunti-web @cantiere, 2012-05-02 08:10:08 +0000, 5, 0, 0
6
+ Ricette #3293 @welaika, 2012-05-04 15:04:57 +0000, 5, 0, 0
@@ -0,0 +1,29 @@
1
+ require 'tempfile'
2
+ require 'spec_helper'
3
+
4
+ describe "redpomo add" do
5
+
6
+ let(:config_path) { tmp_path('redpomo') }
7
+
8
+ it "opens up a template file with REDPOMO_EDITOR as highest priority" do
9
+ redpomo "add", :env => {"EDITOR" => "echo editor", "VISUAL" => "echo visual", "REDPOMO_EDITOR" => "echo redpomo_editor"}
10
+ out.should =~ /^redpomo_editor .*issue.*\.textile/
11
+ end
12
+
13
+ it "opens up a template file with VISUAL as 2nd highest priority" do
14
+ redpomo "add", :env => {"EDITOR" => "echo editor", "VISUAL" => "echo visual", "REDPOMO_EDITOR" => ""}
15
+ out.should =~ /^visual .*issue.*\.textile/
16
+ end
17
+
18
+ it "opens up a template file with EDITOR as 3rd highest priority" do
19
+ redpomo "add", :env => {"EDITOR" => "echo editor", "VISUAL" => "", "REDPOMO_EDITOR" => ""}
20
+ out.should =~ /^editor .*issue.*\.textile/
21
+ end
22
+
23
+ it "complains if no EDITOR is set" do
24
+ redpomo "add", :env => {"EDITOR" => "", "VISUAL" => "", "REDPOMO_EDITOR" => ""}
25
+ out.should include "set $EDITOR or $REDPOMO_EDITOR"
26
+ end
27
+
28
+ end
29
+
@@ -0,0 +1,33 @@
1
+ require 'tempfile'
2
+ require 'spec_helper'
3
+
4
+ describe "redpomo init" do
5
+
6
+ let(:config_path) { tmp_path('redpomo') }
7
+
8
+ it "generates a .redpomo config file" do
9
+ redpomo "init #{config_path}", env: { "EDITOR" => "echo editor" }
10
+ expect(File.exists?(config_path)).to be true
11
+ end
12
+
13
+ it "opens the config with REDPOMO_EDITOR as highest priority" do
14
+ redpomo "init #{config_path}", :env => {"EDITOR" => "echo editor", "VISUAL" => "echo visual", "REDPOMO_EDITOR" => "echo redpomo_editor"}
15
+ out.should == "redpomo_editor #{config_path}"
16
+ end
17
+
18
+ it "opens the config with VISUAL as 2nd highest priority" do
19
+ redpomo "init #{config_path}", :env => {"EDITOR" => "echo editor", "VISUAL" => "echo visual", "REDPOMO_EDITOR" => ""}
20
+ out.should == "visual #{config_path}"
21
+ end
22
+
23
+ it "opens the config with EDITOR as 3rd highest priority" do
24
+ redpomo "init #{config_path}", :env => {"EDITOR" => "echo editor", "VISUAL" => "", "REDPOMO_EDITOR" => ""}
25
+ out.should == "editor #{config_path}"
26
+ end
27
+
28
+ it "complains if no EDITOR is set" do
29
+ redpomo "init #{config_path}", :env => {"EDITOR" => "", "VISUAL" => "", "REDPOMO_EDITOR" => ""}
30
+ out.should include "set $EDITOR or $REDPOMO_EDITOR"
31
+ end
32
+
33
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+ require 'launchy'
3
+ require 'applescript'
4
+ require 'redpomo/cli'
5
+ require 'fileutils'
6
+
7
+ describe Redpomo::CLI do
8
+
9
+ let(:todo_path) {
10
+ file = File.open(tmp('tasks.txt'), 'w')
11
+ file.write read_fixture("tasks.txt")
12
+ file.close
13
+ file.path
14
+ }
15
+
16
+ let(:config_path) {
17
+ config = YAML::load_file fixture("config.yml")
18
+ config["todo"] = todo_path
19
+ file = File.open(tmp('config.yml'), 'w')
20
+ file.write config.to_yaml
21
+ file.close
22
+ file.path
23
+ }
24
+
25
+ describe "push LOG" do
26
+ it "pushes the specified timelog to remote trackers" do
27
+ VCR.use_cassette('cli_push') do
28
+ cli_redpomo "push #{fixture("timelog.csv")}"
29
+ out.strip.should == "Pushed 2 time entries"
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "push -n LOG" do
35
+ it "pushes the specified timelog to remote trackers" do
36
+ VCR.use_cassette('cli_push') do
37
+ cli_redpomo "push -n #{fixture("timelog.csv")}"
38
+ out.should == read_fixture("printer_output.txt")
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "start ISSUE" do
44
+ it "starts the specified issue on Pomodoro.app" do
45
+ AppleScript.expects(:execute).with('tell application "Pomodoro" to start "Make screenshot #838 @cantiere"')
46
+ cli_redpomo "start 1"
47
+ end
48
+ end
49
+
50
+ describe "open ISSUE" do
51
+ it "shows the specified issue on the browser" do
52
+ Launchy.expects(:open).with('https://project.cantierecreativo.net/issues/838')
53
+ cli_redpomo "open 1"
54
+ end
55
+ end
56
+
57
+ describe "close ISSUE" do
58
+ it "closes issue on remote tracker and marks current task as done" do
59
+ VCR.use_cassette('cli_close') do
60
+ cli_redpomo "close 2 -m bar"
61
+ File.read(todo_path).should == read_fixture("close_results.txt")
62
+ out.strip.should == 'Issue updated, see it at http://code.welaika.com/issues/3290'
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "pull" do
68
+ it "fetches all the trackers and converts the issues in todo tasks" do
69
+ VCR.use_cassette('cli_pull') do
70
+ cli_redpomo "pull"
71
+ File.read(todo_path).should == read_fixture("pull_results.txt")
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "add" do
77
+ it "creates a new task, adds it the list, and pushes it to the tracker" do
78
+ VCR.use_cassette('cli_add') do
79
+ cli_redpomo ["add", "foobar +olasagasti @welaika"]
80
+ File.read(todo_path).should == read_fixture("add_results.txt")
81
+ out.strip.should == 'Issue created, see it at http://code.welaika.com/issues/3397'
82
+ end
83
+ end
84
+ end
85
+
86
+ after(:each) do
87
+ File.unlink(todo_path)
88
+ File.unlink(config_path)
89
+ end
90
+
91
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require 'redpomo/entry'
3
+
4
+ describe Redpomo::Entry do
5
+
6
+ describe "#csv_rows" do
7
+
8
+ it "parses Pomodoro's classic invalid CSV format" do
9
+ text = File.read(fixture("timelog.csv"))
10
+ rows = Redpomo::Entry.csv_rows(text)
11
+ expect(rows.size).to eq(2)
12
+ end
13
+
14
+ it "parses my Pomodoro fork proper CSV format" do
15
+ text = File.read(fixture("proper_timelog.csv"))
16
+ rows = Redpomo::Entry.csv_rows(text)
17
+ expect(rows.size).to eq(4)
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+ require 'redpomo/fuzzy_converter'
3
+
4
+ describe Redpomo::FuzzyConverter do
5
+
6
+ let(:converted_entries) do
7
+ Redpomo::FuzzyConverter.convert(entries)
8
+ end
9
+
10
+ describe "#convert" do
11
+
12
+ context "if there's up to 1.5h of untracked time between entries" do
13
+ let(:entries) do
14
+ [
15
+ Redpomo::Entry.new("foo", DateTime.parse('5th feb 2012 09:00:00'), 25.minutes),
16
+ Redpomo::Entry.new("bar", DateTime.parse('5th feb 2012 10:00:00'), 25.minutes),
17
+ ]
18
+ end
19
+ it "fills up time between entries" do
20
+ converted_entries.first.duration.should == 1.hour
21
+ end
22
+ end
23
+
24
+ context "if there's more than 1.5h of untracked time between entries" do
25
+ let(:entries) do
26
+ [
27
+ Redpomo::Entry.new("foo", DateTime.parse('5th feb 2012 09:00:00'), 25.minutes),
28
+ Redpomo::Entry.new("bar", DateTime.parse('5th feb 2012 12:00:00'), 25.minutes),
29
+ ]
30
+ end
31
+ it "it adds 1.5 hours between entries" do
32
+ converted_entries.first.duration.should == (25.minutes + 1.5.hour)
33
+ end
34
+ end
35
+
36
+ context "on multiple consecutive entries with the same task" do
37
+ context "in the same day" do
38
+ let(:entries) do
39
+ [
40
+ Redpomo::Entry.new("foo", DateTime.parse('5th feb 2012 09:00:00'), 25.minutes),
41
+ Redpomo::Entry.new("foo", DateTime.parse('5th feb 2012 09:30:00'), 25.minutes),
42
+ Redpomo::Entry.new("bar", DateTime.parse('5th feb 2012 12:00:00'), 25.minutes),
43
+ ]
44
+ end
45
+ it "it joins them" do
46
+ converted_entries.first.duration.should == (30.minutes + 25.minutes + 1.5.hour)
47
+ end
48
+ end
49
+ context "on different days" do
50
+ let(:entries) do
51
+ [
52
+ Redpomo::Entry.new("foo", DateTime.parse('5th feb 2012 09:00:00'), 25.minutes),
53
+ Redpomo::Entry.new("foo", DateTime.parse('6th feb 2012 09:30:00'), 25.minutes),
54
+ ]
55
+ end
56
+ it "it keeps them separated" do
57
+ expect(converted_entries.size).to eq(2)
58
+ converted_entries.first.duration.should == 25.minutes
59
+ converted_entries.last.duration.should == 25.minutes
60
+ end
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'redpomo/task'
3
+
4
+ describe Redpomo::Task do
5
+
6
+ describe ".orig" do
7
+ it "returns the original line" do
8
+ Redpomo::Task.new(stub, "Foo bar #123 +one @two").orig.should == "Foo bar #123 +one @two"
9
+ end
10
+ end
11
+
12
+ describe ".url" do
13
+ context "if there's an issue" do
14
+ it "returns the URL to the issue" do
15
+ tracker = stub(base_url: "http://foo.bar")
16
+ task = Redpomo::Task.new(stub, "Foo #123 +project @tracker")
17
+ task.stubs(:tracker).returns(tracker)
18
+ task.url.should == "http://foo.bar/issues/123"
19
+ end
20
+ end
21
+ context "if there's a project" do
22
+ it "returns the URL to the project" do
23
+ tracker = stub(base_url: "http://foo.bar")
24
+ task = Redpomo::Task.new(stub, "Foo +project @tracker")
25
+ task.stubs(:tracker).returns(tracker)
26
+ task.url.should == "http://foo.bar/projects/project"
27
+ end
28
+ end
29
+ context "else" do
30
+ it "returns the URL to the tracker default project" do
31
+ tracker = stub(base_url: "http://foo.bar", default_project: 'bar')
32
+ task = Redpomo::Task.new(stub, "Foo @tracker")
33
+ task.stubs(:tracker).returns(tracker)
34
+ task.url.should == "http://foo.bar/projects/bar"
35
+ end
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'redpomo/tracker'
3
+
4
+ describe Redpomo::Tracker do
5
+
6
+ subject do
7
+ Redpomo::Tracker.new(
8
+ "welaika",
9
+ url: "http://code.welaika.com",
10
+ token: "WELAIKA_TOKEN",#"WELAIKA_TOKEN",
11
+ closed_status_id: "5"
12
+ )
13
+ end
14
+
15
+ describe ".close_issue!" do
16
+ it "closes the issue with the specified message" do
17
+ VCR.use_cassette('close_issue') do
18
+ lambda {
19
+ subject.close_issue!("3290", "foobar")
20
+ }.should_not raise_error
21
+ end
22
+ end
23
+ end
24
+
25
+ describe ".issues" do
26
+ it "creates an Issue for each remote issue" do
27
+ VCR.use_cassette('issues') do
28
+ issues = subject.issues
29
+ expect(issues.size).to eq(7)
30
+ issues.first.tracker.should == subject
31
+ issues.first.project_id.should == 'dashboard-fiat'
32
+ issues.first.issue_id.should == 3316
33
+ issues.first.due_date.should be_nil
34
+ end
35
+ end
36
+ end
37
+
38
+ describe ".push_entry!" do
39
+ it "creates a TimeEntry" do
40
+ VCR.use_cassette('push_entry') do
41
+ task = stub(
42
+ issue: 3392,
43
+ text: "Foobar"
44
+ )
45
+ entry = stub(
46
+ to_task: task,
47
+ datetime: Date.new(2012, 1, 1),
48
+ duration: 5
49
+ )
50
+ result = subject.push_entry!(entry)
51
+ result["time_entry"]["issue"]["id"].should == 3392
52
+ end
53
+ end
54
+ end
55
+
56
+ describe ".create_issue!" do
57
+ it "creates an Issue" do
58
+ VCR.use_cassette('create_issue') do
59
+ issue = stub(
60
+ subject: "foo",
61
+ description: "bar",
62
+ due_date: Date.new(2012, 12, 1),
63
+ project_id: "olasagasti",
64
+ priority_id: 5
65
+ )
66
+ result = subject.create_issue!(issue)
67
+ result["issue"]["id"].should be_present
68
+ end
69
+ end
70
+ end
71
+
72
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'active_support/core_ext/object'
4
+
5
+ if ENV['SIMPLECOV']
6
+ require 'simplecov'
7
+ SimpleCov.start
8
+ end
9
+
10
+ Bundler.require(:default, :development)
11
+
12
+ require 'support/ruby_ext'
13
+ require 'support/cli_helpers'
14
+ require 'support/fixtures'
15
+
16
+ RSpec.configure do |config|
17
+ config.mock_framework = :mocha
18
+ config.include Spec::CLIHelpers
19
+ config.include Spec::Fixtures
20
+ end
21
+
22
+ VCR.configure do |c|
23
+ c.cassette_library_dir = 'spec/fixtures/cassettes'
24
+ c.hook_into :webmock
25
+ c.default_cassette_options = {
26
+ match_requests_on: [:method, :host, :path, :body]
27
+ }
28
+ end