caperoma 0.1.0 → 4.0.1
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 +5 -5
- data/.ruby-version +1 -0
- data/Capefile +48 -0
- data/Capefile.template +48 -0
- data/Capefile.test +20 -0
- data/Gemfile +25 -10
- data/Gemfile.lock +196 -77
- data/HELP +321 -0
- data/README.md +528 -0
- data/Rakefile +73 -18
- data/VERSION +1 -1
- data/bin/caperoma +47 -11
- data/caperoma.gemspec +144 -45
- data/config/crontab +10 -0
- data/config/schedule.rb +21 -0
- data/lib/caperoma.rb +409 -9
- data/lib/caperoma/models/account.rb +47 -0
- data/lib/caperoma/models/application_record.rb +5 -0
- data/lib/caperoma/models/branch.rb +6 -0
- data/lib/caperoma/models/project.rb +14 -0
- data/lib/caperoma/models/property.rb +5 -0
- data/lib/caperoma/models/report.rb +177 -0
- data/lib/caperoma/models/report_recipient.rb +6 -0
- data/lib/caperoma/models/reports/daily_report.rb +23 -0
- data/lib/caperoma/models/reports/retrospective_report.rb +19 -0
- data/lib/caperoma/models/reports/three_day_report.rb +19 -0
- data/lib/caperoma/models/task.rb +368 -0
- data/lib/caperoma/models/tasks/bug.rb +36 -0
- data/lib/caperoma/models/tasks/chore.rb +40 -0
- data/lib/caperoma/models/tasks/feature.rb +27 -0
- data/lib/caperoma/models/tasks/fix.rb +56 -0
- data/lib/caperoma/models/tasks/meeting.rb +40 -0
- data/lib/caperoma/models/tasks/modules/git.rb +65 -0
- data/lib/caperoma/models/tasks/task_with_commit.rb +40 -0
- data/lib/caperoma/models/tasks/task_with_separate_branch.rb +42 -0
- data/lib/caperoma/services/airbrake_email_processor.rb +47 -0
- data/lib/caperoma/services/pivotal_fetcher.rb +108 -0
- data/lib/caperoma/version.rb +9 -0
- data/spec/caperoma_spec.rb +3 -21
- data/spec/factories/accounts.rb +10 -0
- data/spec/factories/branches.rb +9 -0
- data/spec/factories/projects.rb +8 -0
- data/spec/factories/report_recipients.rb +7 -0
- data/spec/factories/reports.rb +16 -0
- data/spec/factories/tasks.rb +37 -0
- data/spec/features/bug_spec.rb +60 -0
- data/spec/features/chore_spec.rb +60 -0
- data/spec/features/command_unknown_spec.rb +14 -0
- data/spec/features/config_spec.rb +161 -0
- data/spec/features/feature_spec.rb +60 -0
- data/spec/features/finish_spec.rb +18 -0
- data/spec/features/fix_spec.rb +60 -0
- data/spec/features/meeting_spec.rb +22 -0
- data/spec/features/projects_spec.rb +17 -0
- data/spec/features/report_recipientss_spec.rb +117 -0
- data/spec/features/reports_spec.rb +65 -0
- data/spec/features/status_spec.rb +33 -0
- data/spec/features/version_spec.rb +11 -0
- data/spec/models/account_spec.rb +51 -0
- data/spec/models/branch_spec.rb +8 -0
- data/spec/models/bug_spec.rb +33 -0
- data/spec/models/chore_spec.rb +33 -0
- data/spec/models/daily_report_spec.rb +38 -0
- data/spec/models/feature_spec.rb +33 -0
- data/spec/models/fix_spec.rb +55 -0
- data/spec/models/meeting_spec.rb +33 -0
- data/spec/models/project_spec.rb +11 -0
- data/spec/models/report_recipient_spec.rb +22 -0
- data/spec/models/report_spec.rb +16 -0
- data/spec/models/retrospective_report_spec.rb +38 -0
- data/spec/models/task_spec.rb +613 -0
- data/spec/models/task_with_commit_spec.rb +105 -0
- data/spec/models/task_with_separate_branch_spec.rb +97 -0
- data/spec/models/three_day_report_spec.rb +49 -0
- data/spec/spec_helper.rb +26 -16
- data/spec/support/capefile_generator.rb +36 -0
- data/spec/support/database_cleaner.rb +21 -0
- data/spec/support/stubs.rb +178 -9
- metadata +283 -42
- data/.document +0 -5
- data/README.rdoc +0 -26
- data/lib/caperoma/credentials.rb +0 -13
- data/lib/caperoma/jira_client.rb +0 -57
- data/spec/caperoma/credentials_spec.rb +0 -25
- data/spec/caperoma/jira_spec.rb +0 -35
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe Chore, type: :model do
|
6
|
+
describe 'inheritence' do
|
7
|
+
it { expect(subject).to be_a_kind_of Task }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'private methods' do
|
11
|
+
describe '#issue_type' do
|
12
|
+
let!(:project) { create :project, chore_jira_task_id: '1234' }
|
13
|
+
|
14
|
+
let!(:task) { create :chore, project: project }
|
15
|
+
|
16
|
+
it { expect(task.send(:issue_type)).to eq '1234' }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#story_type' do
|
20
|
+
let!(:task) { create :chore }
|
21
|
+
|
22
|
+
it { expect(task.send(:story_type)).to eq 'chore' }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#this_is_a_type_a_user_wants_to_create' do
|
26
|
+
let!(:project) { create :project, create_chores_in_pivotal: true }
|
27
|
+
|
28
|
+
let!(:task) { build :chore, project: project }
|
29
|
+
|
30
|
+
it { expect(task.send(:this_is_a_type_a_user_wants_to_create?)).to be_truthy }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe DailyReport, type: :model do
|
6
|
+
describe 'relations' do
|
7
|
+
it { expect(subject).to have_many :tasks }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'callbacks' do
|
11
|
+
describe '::asskgn_unreported_tasks' do
|
12
|
+
let!(:daily_report1) { create :daily_report }
|
13
|
+
let!(:three_day_report1) { create :three_day_report }
|
14
|
+
|
15
|
+
let!(:task1) { create :task, daily_report: daily_report1, three_day_report: nil, finished_at: Time.now }
|
16
|
+
let!(:task2) { create :task, daily_report: daily_report1, three_day_report: three_day_report1, finished_at: Time.now }
|
17
|
+
let!(:task3) { create :task, daily_report: nil, three_day_report: nil, finished_at: Time.now }
|
18
|
+
let!(:task4) { create :task, daily_report: nil, three_day_report: nil, finished_at: nil }
|
19
|
+
|
20
|
+
specify do
|
21
|
+
new_report = create :daily_report
|
22
|
+
expect(new_report.tasks).to match_array [task3]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'message format' do
|
28
|
+
describe 'subject' do
|
29
|
+
let(:report) { create :daily_report }
|
30
|
+
|
31
|
+
specify do
|
32
|
+
Timecop.freeze(Time.parse('06/02/2015 15:06')) do
|
33
|
+
expect(report.send(:report_subject)).to eq 'Daily Report (Feb 6)'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe Feature, type: :model do
|
6
|
+
describe 'inheritence' do
|
7
|
+
it { expect(subject).to be_a_kind_of TaskWithSeparateBranch }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'private methods' do
|
11
|
+
describe '#issue_type' do
|
12
|
+
let!(:project) { create :project, feature_jira_task_id: '1234' }
|
13
|
+
|
14
|
+
let!(:task) { create :feature, project: project }
|
15
|
+
|
16
|
+
it { expect(task.send(:issue_type)).to eq '1234' }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#story_type' do
|
20
|
+
let!(:task) { create :feature }
|
21
|
+
|
22
|
+
it { expect(task.send(:story_type)).to eq 'feature' }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#this_is_a_type_a_user_wants_to_create' do
|
26
|
+
let!(:project) { create :project, create_features_in_pivotal: true }
|
27
|
+
|
28
|
+
let!(:task) { build :feature, project: project }
|
29
|
+
|
30
|
+
it { expect(task.send(:this_is_a_type_a_user_wants_to_create?)).to be_truthy }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe Fix, type: :model do
|
6
|
+
describe 'inheritence' do
|
7
|
+
it { expect(subject).to be_a_kind_of TaskWithCommit }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'methods' do
|
11
|
+
describe 'description' do
|
12
|
+
let!(:task) { create :fix, description: 'blah' }
|
13
|
+
|
14
|
+
it 'should append last commit name' do
|
15
|
+
allow(task).to receive(:git_last_commit_name).and_return('some great commit')
|
16
|
+
expect(task.description).to eq "blah\n(For: some great commit)"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'observers' do
|
22
|
+
describe '::update_parent_branch' do
|
23
|
+
let!(:task) { build :task_with_separate_branch }
|
24
|
+
|
25
|
+
it 'should get latest version of remote branch before switching' do
|
26
|
+
expect(task).to receive(:git_rebase_to_upstream)
|
27
|
+
task.save!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'private methods' do
|
33
|
+
describe '#issue_type' do
|
34
|
+
let!(:project) { create :project, fix_jira_task_id: '1234' }
|
35
|
+
|
36
|
+
let!(:task) { create :fix, project: project }
|
37
|
+
|
38
|
+
it { expect(task.send(:issue_type)).to eq '1234' }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#story_type' do
|
42
|
+
let!(:task) { create :fix }
|
43
|
+
|
44
|
+
it { expect(task.send(:story_type)).to eq 'chore' }
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#this_is_a_type_a_user_wants_to_create' do
|
48
|
+
let!(:project) { create :project, create_fixes_in_pivotal_as_chores: true }
|
49
|
+
|
50
|
+
let!(:task) { build :fix, project: project }
|
51
|
+
|
52
|
+
it { expect(task.send(:this_is_a_type_a_user_wants_to_create?)).to be_truthy }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe Meeting, type: :model do
|
6
|
+
describe 'inheritence' do
|
7
|
+
it { expect(subject).to be_a_kind_of Task }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'private methods' do
|
11
|
+
describe '#issue_type' do
|
12
|
+
let!(:project) { create :project, meeting_jira_task_id: '1234' }
|
13
|
+
|
14
|
+
let!(:task) { create :meeting, project: project }
|
15
|
+
|
16
|
+
it { expect(task.send(:issue_type)).to eq '1234' }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#story_type' do
|
20
|
+
let!(:task) { create :meeting }
|
21
|
+
|
22
|
+
it { expect(task.send(:story_type)).to eq 'chore' }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#this_is_a_type_a_user_wants_to_create' do
|
26
|
+
let!(:project) { create :project, create_meetings_in_pivotal_as_chores: true }
|
27
|
+
|
28
|
+
let!(:task) { build :meeting, project: project }
|
29
|
+
|
30
|
+
it { expect(task.send(:this_is_a_type_a_user_wants_to_create?)).to be_truthy }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe Project, type: :model do
|
6
|
+
it { expect(subject).to have_many :branches }
|
7
|
+
it { expect(subject).to have_many :chores }
|
8
|
+
it { expect(subject).to have_many :bugs }
|
9
|
+
it { expect(subject).to have_many :features }
|
10
|
+
it { expect(subject).to have_many :meetings }
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe ReportRecipient, type: :model do
|
6
|
+
describe 'validations' do
|
7
|
+
specify do
|
8
|
+
['me@gmail.com', 'dude.due@gmail.com'].each do |value|
|
9
|
+
expect(subject).to allow_value(value).for(:email)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
specify do
|
14
|
+
['12345', '', nil].each do |value|
|
15
|
+
expect(subject).not_to allow_value(value).for(:email)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it { expect(subject).to validate_uniqueness_of(:email) }
|
20
|
+
it { expect(subject).to validate_presence_of(:email) }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe Report, type: :model do
|
6
|
+
describe '#to_addresses' do
|
7
|
+
let!(:recipient1) { create :report_recipient, email: 'dude1@example.com' }
|
8
|
+
let!(:recipient2) { create :report_recipient, email: 'dude2@example.com' }
|
9
|
+
|
10
|
+
let!(:report) { build :report }
|
11
|
+
|
12
|
+
specify do
|
13
|
+
expect(report.send(:to_addresses)).to match_array ['dude1@example.com', 'dude2@example.com']
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe RetrospectiveReport, type: :model do
|
6
|
+
describe 'relations' do
|
7
|
+
it { expect(subject).to have_many :tasks }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'callbacks' do
|
11
|
+
describe '::asskgn_unreported_tasks' do
|
12
|
+
let!(:daily_report1) { create :daily_report }
|
13
|
+
let!(:three_day_report1) { create :three_day_report }
|
14
|
+
|
15
|
+
let!(:task1) { create :task, daily_report: daily_report1, three_day_report: nil, retrospective_report: nil, finished_at: Time.now }
|
16
|
+
let!(:task2) { create :task, daily_report: daily_report1, three_day_report: three_day_report1, retrospective_report: nil, finished_at: Time.now }
|
17
|
+
let!(:task3) { create :task, daily_report: nil, three_day_report: nil, retrospective_report: nil, finished_at: Time.now }
|
18
|
+
let!(:task4) { create :task, daily_report: nil, three_day_report: nil, retrospective_report: nil, finished_at: nil }
|
19
|
+
|
20
|
+
specify do
|
21
|
+
new_report = create :retrospective_report
|
22
|
+
expect(new_report.tasks).to match_array [task1, task2, task3]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'message format' do
|
28
|
+
describe 'subject' do
|
29
|
+
let(:report) { create :retrospective_report }
|
30
|
+
|
31
|
+
specify do
|
32
|
+
Timecop.freeze(Time.parse('06/02/2015 15:06')) do
|
33
|
+
expect(report.send(:report_subject)).to eq 'Weekly Report (Feb 2 - Feb 6)'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,613 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
RSpec.describe Task, type: :model do
|
6
|
+
describe 'relations' do
|
7
|
+
it { expect(subject).to belong_to :project }
|
8
|
+
it { expect(subject).to belong_to :daily_report }
|
9
|
+
it { expect(subject).to belong_to :three_day_report }
|
10
|
+
it { expect(subject).to belong_to :retrospective_report }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'validations' do
|
14
|
+
it { expect(subject).to validate_presence_of(:title) }
|
15
|
+
|
16
|
+
describe 'length' do
|
17
|
+
it { expect(subject).to allow_value(nil).for(:pivotal_id) }
|
18
|
+
it { expect(subject).to allow_value('123456').for(:pivotal_id) }
|
19
|
+
it { expect(subject).to allow_value('1234567').for(:pivotal_id) }
|
20
|
+
it { expect(subject).to allow_value('12345678').for(:pivotal_id) }
|
21
|
+
it { expect(subject).to allow_value('123456789').for(:pivotal_id) }
|
22
|
+
it { expect(subject).not_to allow_value('#12345678').for(:pivotal_id) }
|
23
|
+
it { expect(subject).not_to allow_value('12').for(:pivotal_id) }
|
24
|
+
it { expect(subject).not_to allow_value('123.45678').for(:pivotal_id) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'scopes' do
|
29
|
+
describe '::unfinished' do
|
30
|
+
let!(:started) { create :task, finished_at: nil }
|
31
|
+
let!(:finished) { create :task, finished_at: Time.now }
|
32
|
+
|
33
|
+
it 'should return tasks without finished_at time' do
|
34
|
+
expect(Task.unfinished).to eq [started]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '::finished' do
|
39
|
+
let!(:started) { create :task, finished_at: nil }
|
40
|
+
let!(:finished) { create :task, finished_at: Time.now }
|
41
|
+
|
42
|
+
it 'should return tasks without finished_at time' do
|
43
|
+
expect(Task.finished).to eq [finished]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'class_methods' do
|
49
|
+
describe '::finish_started' do
|
50
|
+
let!(:started) { create :task, finished_at: nil }
|
51
|
+
|
52
|
+
it 'should finish started tasks' do
|
53
|
+
Task.finish_started(nil)
|
54
|
+
|
55
|
+
expect(started.reload.finished_at).to be_present
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '::pause_started' do
|
60
|
+
let!(:started) { create :task, finished_at: nil }
|
61
|
+
|
62
|
+
it 'should finish started tasks' do
|
63
|
+
Task.pause_started(nil)
|
64
|
+
|
65
|
+
expect(started.reload.finished_at).to be_present
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '::abort_started' do
|
70
|
+
let!(:started) { create :task, finished_at: nil }
|
71
|
+
|
72
|
+
it 'should abort started tasks' do
|
73
|
+
Task.abort_started(nil)
|
74
|
+
|
75
|
+
expect(started.reload.finished_at).to be_present
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '::abort_started_without_time' do
|
80
|
+
let!(:started) { create :task, finished_at: nil }
|
81
|
+
|
82
|
+
it 'should abort started tasks without time' do
|
83
|
+
Task.abort_started_without_time(nil)
|
84
|
+
|
85
|
+
expect(started.reload.finished_at).to be_present
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'methods' do
|
91
|
+
context 'pivotal_id present' do
|
92
|
+
let!(:task) { create :task, finished_at: nil, pivotal_id: '12345678' }
|
93
|
+
describe '#finish' do
|
94
|
+
it 'should finish it and log time' do
|
95
|
+
expect(task).to receive :close_issue_on_jira
|
96
|
+
expect(task).to receive :log_work_to_jira
|
97
|
+
expect(task).to receive :finish_on_pivotal
|
98
|
+
task.finish(nil)
|
99
|
+
expect(task.finished_at).to be_present
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#pause' do
|
104
|
+
it 'should pause it and log time' do
|
105
|
+
expect(task).to receive :close_issue_on_jira
|
106
|
+
expect(task).to receive :log_work_to_jira
|
107
|
+
expect(task).to receive :finish_on_pivotal
|
108
|
+
task.pause(nil)
|
109
|
+
expect(task.finished_at).to be_present
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#abort' do
|
114
|
+
it 'should abort it and log time' do
|
115
|
+
expect(task).to receive :close_issue_on_jira
|
116
|
+
expect(task).to receive :log_work_to_jira
|
117
|
+
expect(task).to receive :finish_on_pivotal
|
118
|
+
task.abort(nil)
|
119
|
+
expect(task.finished_at).to be_present
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#abort_without_time' do
|
124
|
+
it 'should abort it and not log time' do
|
125
|
+
expect(task).to receive :close_issue_on_jira
|
126
|
+
expect(task).not_to receive :log_work_to_jira
|
127
|
+
expect(task).not_to receive :finish_on_pivotal
|
128
|
+
task.abort_without_time(nil)
|
129
|
+
expect(task.finished_at).to be_present
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'pivotal_id blank' do
|
135
|
+
let!(:task) { create :task, finished_at: nil, pivotal_id: nil }
|
136
|
+
describe '#finish' do
|
137
|
+
it 'should finish it and log time' do
|
138
|
+
expect(task).to receive :close_issue_on_jira
|
139
|
+
expect(task).to receive :log_work_to_jira
|
140
|
+
expect(task).not_to receive :finish_on_pivotal
|
141
|
+
task.finish(nil)
|
142
|
+
expect(task.finished_at).to be_present
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#pause' do
|
147
|
+
it 'should pause it and log time' do
|
148
|
+
expect(task).to receive :close_issue_on_jira
|
149
|
+
expect(task).to receive :log_work_to_jira
|
150
|
+
expect(task).not_to receive :finish_on_pivotal
|
151
|
+
task.pause(nil)
|
152
|
+
expect(task.finished_at).to be_present
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#abort' do
|
157
|
+
it 'should abort it and log time' do
|
158
|
+
expect(task).to receive :close_issue_on_jira
|
159
|
+
expect(task).to receive :log_work_to_jira
|
160
|
+
expect(task).not_to receive :finish_on_pivotal
|
161
|
+
task.abort(nil)
|
162
|
+
expect(task.finished_at).to be_present
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe '#abort_without_time' do
|
167
|
+
it 'should abort it and not log time' do
|
168
|
+
expect(task).to receive :close_issue_on_jira
|
169
|
+
expect(task).not_to receive :log_work_to_jira
|
170
|
+
expect(task).not_to receive :finish_on_pivotal
|
171
|
+
task.abort_without_time(nil)
|
172
|
+
expect(task.finished_at).to be_present
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# TODO: handle cases where jira/pt ids are present, but neither jira nor pt are set up.
|
178
|
+
end
|
179
|
+
|
180
|
+
describe 'observers' do
|
181
|
+
let!(:project) { create :project, jira_project_id: 135 }
|
182
|
+
before { expect(SecureRandom).to receive(:uuid).and_return '123' }
|
183
|
+
|
184
|
+
describe '::generate_uuid' do
|
185
|
+
let(:task) { build :task }
|
186
|
+
|
187
|
+
it 'should_generate_random_string' do
|
188
|
+
task.save
|
189
|
+
expect(task.uuid).to eq '123'
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '::set_start_time' do
|
194
|
+
let!(:timestamp) { Time.parse('5 April 2014') }
|
195
|
+
before { expect(Time).to receive(:now).and_return timestamp }
|
196
|
+
|
197
|
+
context 'no additional time' do
|
198
|
+
let(:task) { build :task }
|
199
|
+
it 'should set setarted_at time' do
|
200
|
+
task.save
|
201
|
+
expect(task.reload.started_at).to eq timestamp
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'additional time present' do
|
206
|
+
let(:task) { build :task, additional_time: '23' }
|
207
|
+
it 'should move started_at back to past by X minutes' do
|
208
|
+
task.save
|
209
|
+
expect(task.reload.started_at).to eq (timestamp - 23.minutes)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe '::create_issue_on_jira', :unstub_jira_creation do
|
215
|
+
context 'jira account present' do
|
216
|
+
let(:task) { create :task }
|
217
|
+
let!(:account) { create :account, type: '--jira' }
|
218
|
+
let(:faraday) { double('Faraday', post: response) }
|
219
|
+
let(:response) { double('Faraday', body: JIRA_ISSUE_CREATION_RESPONSE) }
|
220
|
+
|
221
|
+
it 'should create task in Jira after create' do
|
222
|
+
expect(Faraday).to receive(:new).and_return faraday
|
223
|
+
|
224
|
+
task.save
|
225
|
+
|
226
|
+
task.reload.tap do |task|
|
227
|
+
expect(task.jira_id).to eq '10000'
|
228
|
+
expect(task.jira_key).to eq 'TST-24'
|
229
|
+
expect(task.jira_url).to eq 'http://www.example.com/jira/rest/api/2/issue/10000'
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context 'jira account not present' do
|
235
|
+
let(:task) { create :task }
|
236
|
+
let(:faraday) { double('Faraday', post: response) }
|
237
|
+
let(:response) { double('Faraday', body: JIRA_ISSUE_CREATION_RESPONSE) }
|
238
|
+
|
239
|
+
it 'should not create task in Jira after create' do
|
240
|
+
allow(Faraday).to receive(:new).and_return faraday
|
241
|
+
expect(task).not_to receive :create_issue_on_jira
|
242
|
+
|
243
|
+
task.save
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe '::start_issue_on_jira' do
|
249
|
+
let(:task) { build :task, jira_key: jira_key }
|
250
|
+
|
251
|
+
context 'account present, jira id present' do
|
252
|
+
let!(:account) { create :account, type: '--jira' }
|
253
|
+
let!(:jira_key) { 'OK-1' }
|
254
|
+
|
255
|
+
it 'should start task in Jira after create' do
|
256
|
+
expect(task).to receive(:start_issue_on_jira)
|
257
|
+
|
258
|
+
task.save
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
context 'account not present, jira id not present' do
|
263
|
+
let!(:jira_key) { 'OK-1' }
|
264
|
+
|
265
|
+
it 'should start task in Jira after create' do
|
266
|
+
expect(task).not_to receive(:start_issue_on_jira)
|
267
|
+
|
268
|
+
task.save
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
context 'account present, jira id present' do
|
273
|
+
let!(:account) { create :account, type: '--jira' }
|
274
|
+
let!(:jira_key) { nil }
|
275
|
+
|
276
|
+
it 'should start task in Jira after create' do
|
277
|
+
expect(task).not_to receive(:start_issue_on_jira)
|
278
|
+
|
279
|
+
task.save
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
context 'account not present, jira id not present' do
|
284
|
+
let!(:jira_key) { nil }
|
285
|
+
|
286
|
+
it 'should start task in Jira after create' do
|
287
|
+
expect(task).not_to receive(:start_issue_on_jira)
|
288
|
+
|
289
|
+
task.save
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
describe '::create_issue_on_pivotal', :unstub_pivotal_creation do
|
295
|
+
context 'pivotal account present' do
|
296
|
+
let(:task) { build :task, pivotal_id: pt_id }
|
297
|
+
let!(:account) { create :account, type: '--pivotal' }
|
298
|
+
let(:faraday) { double('Faraday', post: response) }
|
299
|
+
let(:response) { double('Faraday', body: PIVOTAL_ISSUE_CREATION_RESPONSE) }
|
300
|
+
|
301
|
+
before { allow(task).to receive(:this_is_a_type_a_user_wants_to_create?).and_return(should_create) }
|
302
|
+
|
303
|
+
context 'PT id present but should not create' do
|
304
|
+
let(:pt_id) { '567890123' }
|
305
|
+
let(:should_create) { false }
|
306
|
+
|
307
|
+
it 'should not create task in Pivotal' do
|
308
|
+
task.save
|
309
|
+
|
310
|
+
task.reload.tap do |task|
|
311
|
+
expect(task.pivotal_id).to eq '567890123'
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
context 'PT id present but should create' do
|
317
|
+
let(:pt_id) { '567890123' }
|
318
|
+
let(:should_create) { true }
|
319
|
+
|
320
|
+
it 'should not create task in Pivotal' do
|
321
|
+
task.save
|
322
|
+
|
323
|
+
task.reload.tap do |task|
|
324
|
+
expect(task.pivotal_id).to eq '567890123'
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'PT id blank but should not create' do
|
330
|
+
let(:pt_id) { nil }
|
331
|
+
let(:should_create) { false }
|
332
|
+
|
333
|
+
it 'should not create task in Pivotal' do
|
334
|
+
task.save
|
335
|
+
|
336
|
+
task.reload.tap do |task|
|
337
|
+
expect(task.pivotal_id).to eq nil
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context 'PT id blank and should create' do
|
343
|
+
let(:pt_id) { nil }
|
344
|
+
let(:should_create) { true }
|
345
|
+
|
346
|
+
it 'should create task in Pivotal' do
|
347
|
+
expect(Faraday).to receive(:new).and_return faraday
|
348
|
+
task.save
|
349
|
+
|
350
|
+
task.reload.tap do |task|
|
351
|
+
expect(task.pivotal_id).to eq '12345678'
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
context 'pivotal account blank' do
|
358
|
+
let(:task) { build :task, pivotal_id: pt_id }
|
359
|
+
let(:faraday) { double('Faraday', post: response) }
|
360
|
+
let(:response) { double('Faraday', body: PIVOTAL_ISSUE_CREATION_RESPONSE) }
|
361
|
+
|
362
|
+
before { allow(task).to receive(:this_is_a_type_a_user_wants_to_create?).and_return(should_create) }
|
363
|
+
|
364
|
+
context 'PT id present but should not create' do
|
365
|
+
let(:pt_id) { '567890123' }
|
366
|
+
let(:should_create) { false }
|
367
|
+
|
368
|
+
it 'should not create task in Pivotal' do
|
369
|
+
task.save
|
370
|
+
|
371
|
+
task.reload.tap do |task|
|
372
|
+
expect(task.pivotal_id).to eq '567890123'
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
context 'PT id present but should create' do
|
378
|
+
let(:pt_id) { '567890123' }
|
379
|
+
let(:should_create) { true }
|
380
|
+
|
381
|
+
it 'should not create task in Pivotal' do
|
382
|
+
task.save
|
383
|
+
|
384
|
+
task.reload.tap do |task|
|
385
|
+
expect(task.pivotal_id).to eq '567890123'
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
context 'PT id blank but should not create' do
|
391
|
+
let(:pt_id) { nil }
|
392
|
+
let(:should_create) { false }
|
393
|
+
|
394
|
+
it 'should not create task in Pivotal' do
|
395
|
+
task.save
|
396
|
+
|
397
|
+
task.reload.tap do |task|
|
398
|
+
expect(task.pivotal_id).to eq nil
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
context 'PT id blank and should create' do
|
404
|
+
let(:pt_id) { nil }
|
405
|
+
let(:should_create) { true }
|
406
|
+
|
407
|
+
it 'should create task in Pivotal' do
|
408
|
+
allow(Faraday).to receive(:new).and_return faraday
|
409
|
+
task.save
|
410
|
+
|
411
|
+
task.reload.tap do |task|
|
412
|
+
expect(task.pivotal_id).to be_blank
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
describe '::start_issue_on_pivotal' do
|
420
|
+
let(:task) { build :task, pivotal_id: pivotal_id }
|
421
|
+
# before { allow(task).to receive(:this_is_a_type_a_user_wants_to_create?).and_return should_create_this_type }
|
422
|
+
|
423
|
+
context 'pt id present, pt account present' do
|
424
|
+
let(:pivotal_id) { '12345678' }
|
425
|
+
let!(:account) { create :account, type: '--pivotal' }
|
426
|
+
|
427
|
+
it 'should start task in pivotal after create' do
|
428
|
+
expect(task).to receive(:start_issue_on_pivotal)
|
429
|
+
|
430
|
+
task.save
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
context 'pt id blank, pt account present' do
|
435
|
+
let(:pivotal_id) { nil }
|
436
|
+
let!(:account) { create :account, type: '--pivotal' }
|
437
|
+
|
438
|
+
it 'should not start task in pivotal after create' do
|
439
|
+
expect(task).not_to receive(:start_issue_on_pivotal)
|
440
|
+
|
441
|
+
task.save
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
context 'pt id present, pt account blank' do
|
446
|
+
let(:pivotal_id) { '12345678' }
|
447
|
+
|
448
|
+
it 'should start task in pivotal after create' do
|
449
|
+
expect(task).not_to receive(:start_issue_on_pivotal)
|
450
|
+
|
451
|
+
task.save
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
context 'pt id blank, pt account blank' do
|
456
|
+
let(:pivotal_id) { nil }
|
457
|
+
|
458
|
+
it 'should not start task in pivotal after create' do
|
459
|
+
expect(task).not_to receive(:start_issue_on_pivotal)
|
460
|
+
|
461
|
+
task.save
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
describe '::output_jira_key', :unstub_key_output, :unstub_puts do
|
467
|
+
let(:task) { build :task, jira_key: jira_key }
|
468
|
+
|
469
|
+
context 'jira_key present' do
|
470
|
+
let(:jira_key) { 'TST-24' }
|
471
|
+
|
472
|
+
it 'should output ID to STDOUT' do
|
473
|
+
expect(STDOUT).to receive(:puts).with('TST-24')
|
474
|
+
task.save
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
context 'jira_key present' do
|
479
|
+
let(:jira_key) { nil }
|
480
|
+
|
481
|
+
it 'should not output ID to STDOUT' do
|
482
|
+
expect(STDOUT).not_to receive(:puts).with('TST-24')
|
483
|
+
task.save
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
describe 'private methods' do
|
490
|
+
let!(:project) { create :project, jira_project_id: '123' }
|
491
|
+
let!(:account) { create :account, type: '--jira', username: 'someuser' }
|
492
|
+
|
493
|
+
describe '#create_issue_on_jira_data' do
|
494
|
+
let!(:task) { create :task, title: 'dupis', description: 'bamis', project: project }
|
495
|
+
|
496
|
+
it 'should format hash' do
|
497
|
+
allow(task).to receive(:issue_type).and_return '492'
|
498
|
+
result = task.send(:create_issue_on_jira_data)
|
499
|
+
JSON.parse(result).tap do |format|
|
500
|
+
expect(format['fields']['project']['id']).to eq '123'
|
501
|
+
expect(format['fields']['issuetype']['id']).to eq '492'
|
502
|
+
expect(format['fields']['summary']).to eq 'dupis'
|
503
|
+
expect(format['fields']['assignee']['name']).to eq 'someuser'
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
describe '#start_issue_on_jira_data' do
|
509
|
+
let!(:project) { create :project, jira_transition_id_in_progress: '12345' }
|
510
|
+
|
511
|
+
let!(:task) { create :task, project: project }
|
512
|
+
|
513
|
+
it 'should format hash' do
|
514
|
+
result = task.send(:start_issue_on_jira_data)
|
515
|
+
JSON.parse(result).tap do |format|
|
516
|
+
expect(format['transition']['id']).to eq '12345'
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
describe '#close_issue_on_jira_data' do
|
522
|
+
let!(:project) { create :project, jira_transition_id_done: '12345' }
|
523
|
+
|
524
|
+
let!(:task) { create :task, project: project }
|
525
|
+
|
526
|
+
it 'should format hash' do
|
527
|
+
result = task.send(:close_issue_on_jira_data)
|
528
|
+
JSON.parse(result).tap do |format|
|
529
|
+
expect(format['transition']['id']).to eq '12345'
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
describe '#log_work_to_jira_data' do
|
535
|
+
let!(:task) { create :task }
|
536
|
+
|
537
|
+
it 'should format hash' do
|
538
|
+
allow(task).to receive(:current_time).and_return 'time'
|
539
|
+
allow(task).to receive(:time_spent).and_return 'spent'
|
540
|
+
result = task.send(:log_work_to_jira_data, 'some comment')
|
541
|
+
|
542
|
+
JSON.parse(result).tap do |format|
|
543
|
+
expect(format['comment']).to eq 'some comment'
|
544
|
+
expect(format['started']).to eq 'time'
|
545
|
+
expect(format['timeSpent']).to eq 'spent'
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
describe '#create_issue_on_pivotal_data' do
|
551
|
+
let!(:task) { create :task, title: 'dupis', description: 'bamis', project: project }
|
552
|
+
|
553
|
+
it 'should format hash' do
|
554
|
+
allow(task).to receive(:story_type).and_return 'chore'
|
555
|
+
result = task.send(:create_issue_on_pivotal_data)
|
556
|
+
JSON.parse(result).tap do |format|
|
557
|
+
expect(format['current_state']).to eq 'unstarted'
|
558
|
+
expect(format['estimate']).to eq 1
|
559
|
+
expect(format['name']).to eq 'dupis'
|
560
|
+
expect(format['story_type']).to eq 'chore'
|
561
|
+
end
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
describe '#finish_on_pivotal_data' do
|
566
|
+
let!(:task) { create :task }
|
567
|
+
|
568
|
+
it 'should format hash' do
|
569
|
+
allow(task).to receive(:story_type).and_return 'chore'
|
570
|
+
result = task.send(:finish_on_pivotal_data)
|
571
|
+
JSON.parse(result).tap do |format|
|
572
|
+
expect(format['current_state']).to eq 'finished'
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
describe '#start_issue_on_pivotal_data' do
|
578
|
+
let!(:task) { create :task }
|
579
|
+
|
580
|
+
it 'should format hash' do
|
581
|
+
allow(task).to receive(:story_type).and_return 'chore'
|
582
|
+
result = task.send(:start_issue_on_pivotal_data)
|
583
|
+
JSON.parse(result).tap do |format|
|
584
|
+
expect(format['current_state']).to eq 'started'
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
describe '#current_time' do
|
590
|
+
let!(:task) { create :task, project: project }
|
591
|
+
let!(:time) { Time.parse('5 April 2014') }
|
592
|
+
|
593
|
+
it 'should format time' do
|
594
|
+
allow(Time).to receive_message_chain(:now, :in_time_zone).and_return time
|
595
|
+
result = task.send(:current_time)
|
596
|
+
expect(result).to eq '2014-04-05T00:00:00.000+0000'
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
describe '#time_spent' do
|
601
|
+
let!(:task) { create :task, project: project }
|
602
|
+
let!(:start_time) { Time.parse('5 April 2014 1:30PM') }
|
603
|
+
let!(:finish_time) { Time.parse('5 April 2014 2:45PM') }
|
604
|
+
|
605
|
+
it 'should return formatted time difference' do
|
606
|
+
expect(task).to receive(:started_at).and_return start_time
|
607
|
+
expect(task).to receive(:finished_at).and_return finish_time
|
608
|
+
result = task.send(:time_spent)
|
609
|
+
expect(result).to eq '1h 15m'
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
end
|