redpomo-reloaded 0.0.13

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