caperoma 4.0.1 → 5.0.0

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/Capefile +6 -6
  3. data/Capefile.template +4 -1
  4. data/Gemfile +1 -5
  5. data/Gemfile.lock +3 -45
  6. data/HELP +84 -13
  7. data/README.md +165 -29
  8. data/Rakefile +25 -22
  9. data/VERSION +1 -1
  10. data/bin/caperoma +6 -9
  11. data/caperoma.gemspec +15 -13
  12. data/config/crontab +0 -2
  13. data/config/schedule.rb +17 -19
  14. data/config/unschedule.rb +3 -0
  15. data/images/circle.png +0 -0
  16. data/images/report.png +0 -0
  17. data/lib/caperoma.rb +308 -98
  18. data/lib/caperoma/models/account.rb +1 -1
  19. data/lib/caperoma/models/project.rb +1 -2
  20. data/lib/caperoma/models/report.rb +15 -15
  21. data/lib/caperoma/models/task.rb +203 -46
  22. data/lib/caperoma/models/tasks/chore.rb +2 -0
  23. data/lib/caperoma/models/tasks/feature.rb +1 -0
  24. data/lib/caperoma/models/tasks/fix.rb +2 -0
  25. data/lib/caperoma/models/tasks/meeting.rb +2 -0
  26. data/lib/caperoma/models/tasks/modules/git.rb +94 -15
  27. data/lib/caperoma/models/tasks/task_with_commit.rb +8 -5
  28. data/lib/caperoma/models/tasks/task_with_separate_branch.rb +6 -4
  29. data/spec/caperoma_spec.rb +558 -2
  30. data/spec/factories/accounts.rb +1 -1
  31. data/spec/factories/projects.rb +1 -1
  32. data/spec/factories/report_recipients.rb +1 -1
  33. data/spec/factories/reports.rb +1 -1
  34. data/spec/factories/tasks.rb +1 -2
  35. data/spec/features/command_unknown_spec.rb +0 -1
  36. data/spec/features/feature_spec.rb +64 -44
  37. data/spec/features/init_spec.rb +20 -0
  38. data/spec/features/status_spec.rb +12 -11
  39. data/spec/models/project_spec.rb +0 -1
  40. data/spec/models/task_spec.rb +811 -27
  41. data/spec/models/task_with_commit_spec.rb +0 -4
  42. data/spec/models/task_with_separate_branch_spec.rb +4 -4
  43. data/spec/models/three_day_report_spec.rb +2 -3
  44. data/spec/spec_helper.rb +2 -0
  45. data/spec/support/capefile_generator.rb +35 -27
  46. data/spec/support/stubs.rb +7 -74
  47. metadata +47 -24
  48. data/lib/caperoma/models/branch.rb +0 -6
  49. data/lib/caperoma/services/airbrake_email_processor.rb +0 -47
  50. data/lib/caperoma/services/pivotal_fetcher.rb +0 -108
  51. data/spec/factories/branches.rb +0 -9
  52. data/spec/models/branch_spec.rb +0 -8
data/Rakefile CHANGED
@@ -21,25 +21,25 @@ Juwelier::Tasks.new do |gem|
21
21
  gem.license = 'MIT'
22
22
  gem.summary = %(Automate your workflow with Ruby / Git / Jira / PivotalTracker.)
23
23
  gem.description = <<-EOF
24
- Caperoma automates many decisions related to the programming that you often don't realize, and which you can forget hundreds of times during the time of working on the project:
25
- - pulling the latest code from upstream before you start working,
26
- - remembering from which branch you started the feature to later make a pull request into it,
27
- - creating & starting tasks in Jira,
28
- - creating & starting tasks in Pivotal,
29
- - naming branches,
30
- - adding Jira ID into the branch name,
31
- - style guide checks,
32
- - commits,
33
- - naming commits,
34
- - adding Jira ID into commit name,
35
- - adding Pivotal ID into commit name,
36
- - git pushes,
37
- - pull requests into correct branches,
38
- - stopping tasks in Jira,
39
- - stopping tasks in Pivotal,
40
- - tracking time,
41
- - logging time to Jira,
42
- - switching back into the original branch and much more.
24
+ Caperoma automates many decisions related to the programming that you often don't realize, and which you can forget hundreds of times during the time of working on the project:
25
+ pulling the latest code from upstream before you start working,
26
+ remembering from which branch you started the feature to later make a pull request into it,
27
+ creating & starting tasks in Jira,
28
+ creating & starting tasks in Pivotal,
29
+ naming branches,
30
+ adding Jira ID into the branch name,
31
+ style guide checks,
32
+ commits,
33
+ naming commits,
34
+ adding Jira ID into commit name,
35
+ adding Pivotal ID into commit name,
36
+ git pushes,
37
+ pull requests into correct branches,
38
+ stopping tasks in Jira,
39
+ stopping tasks in Pivotal,
40
+ tracking time,
41
+ logging time to Jira,
42
+ switching back into the original branch and much more.
43
43
  EOF
44
44
  gem.files += FileList['lib/**/*', 'bin/*', '[A-Za-z.]*', 'spec/**/*', 'config/*'].to_a
45
45
  gem.bindir = 'bin'
@@ -56,18 +56,21 @@ Juwelier::Tasks.new do |gem|
56
56
  gem.add_runtime_dependency 'rubocop', '~> 0.73.0'
57
57
  gem.add_runtime_dependency 'sqlite3', '~> 1.4.1'
58
58
  gem.add_runtime_dependency 'time_difference', '~> 0.7.0'
59
+ gem.add_runtime_dependency 'whenever', '~> 1.0.0'
59
60
 
60
61
  gem.add_development_dependency 'bundler'
61
62
  gem.add_development_dependency 'database_cleaner', '~> 1.7.0'
62
- gem.add_development_dependency 'factory_bot_rails', '~> 5.0.2'
63
+ gem.add_development_dependency 'factory_girl', '~> 4.9.0'
63
64
  gem.add_development_dependency 'rdoc', '~> 6.1.1'
64
65
  gem.add_development_dependency 'rspec', '~> 3.8.0'
65
66
  gem.add_development_dependency 'shoulda', '~> 2.11.3'
66
67
  gem.add_development_dependency 'shoulda-matchers', '~> 4.1.0'
67
68
  gem.add_development_dependency 'timecop', '~> 0.9.1'
68
69
 
69
- gem.requirements << 'sqlite'
70
- gem.requirements << 'git'
70
+ gem.requirements << 'Ruby 2.4 or higher'
71
+ gem.requirements << 'SQLite'
72
+ gem.requirements << 'Git'
73
+ gem.requirements << 'Crontab'
71
74
 
72
75
  gem.extra_rdoc_files = ['README.md', 'HELP']
73
76
  gem.version = File.exist?('VERSION') ? File.read('VERSION') : ''
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.0.1
1
+ 5.0.0
@@ -12,19 +12,14 @@ when 'setup'
12
12
  Caperoma.setup
13
13
  when 'get_jira_issue_type_ids'
14
14
  Caperoma.get_jira_issue_type_ids
15
+ when 'get_jira_transition_ids'
16
+ Caperoma.get_jira_transition_ids
17
+ when 'get_jira_project_ids'
18
+ Caperoma.get_jira_project_ids
15
19
  when 'init'
16
20
  Caperoma.init
17
- when 'copy_airbrake_emails_to_pivotal'
18
- AirbrakeEmailProcessor.new.process
19
21
  when 'projects'
20
22
  Project.all.each { |project| puts "#{project.id}) #{project.folder_path} (jira_project_id: #{project.jira_project_id}, pivotal_tracker_project_id: #{project.pivotal_tracker_project_id})" }
21
- when 'get_jira_issue_type_ids'
22
- Caperoma.sync
23
- when 'from_pivotal' # removing
24
- puts 'Starting a task from Pivotal'
25
- action, story_id = ARGV
26
- PivotalFetcher.process(story_id)
27
- puts 'A task from Pivotal is started'
28
23
  when /^(chore|bug|feature|fix|meeting)$/
29
24
  Caperoma.create_task(ARGV)
30
25
  when 'finish'
@@ -49,6 +44,8 @@ when 'recipients'
49
44
  Caperoma.manage_recipients(ARGV)
50
45
  when 'report'
51
46
  Caperoma.manage_reports(ARGV)
47
+ when 'delete_tasks'
48
+ Task.destroy_all
52
49
  else
53
50
  help
54
51
  end
@@ -2,17 +2,17 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: caperoma 4.0.1 ruby lib
5
+ # stub: caperoma 5.0.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "caperoma".freeze
9
- s.version = "4.0.1"
9
+ s.version = "5.0.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Serge Vinogradoff".freeze]
14
- s.date = "2019-07-22"
15
- s.description = " Caperoma automates many decisions related to the programming that you often don't realize, and which you can forget hundreds of times during the time of working on the project: \n - pulling the latest code from upstream before you start working,\n - remembering from which branch you started the feature to later make a pull request into it,\n - creating & starting tasks in Jira,\n - creating & starting tasks in Pivotal,\n - naming branches,\n - adding Jira ID into the branch name,\n - style guide checks,\n - commits,\n - naming commits,\n - adding Jira ID into commit name,\n - adding Pivotal ID into commit name,\n - git pushes,\n - pull requests into correct branches,\n - stopping tasks in Jira,\n - stopping tasks in Pivotal,\n - tracking time,\n - logging time to Jira,\n - switching back into the original branch and much more.\n".freeze
14
+ s.date = "2019-07-27"
15
+ s.description = " Caperoma automates many decisions related to the programming that you often don't realize, and which you can forget hundreds of times during the time of working on the project:\n pulling the latest code from upstream before you start working,\n remembering from which branch you started the feature to later make a pull request into it,\n creating & starting tasks in Jira,\n creating & starting tasks in Pivotal,\n naming branches,\n adding Jira ID into the branch name,\n style guide checks,\n commits,\n naming commits,\n adding Jira ID into commit name,\n adding Pivotal ID into commit name,\n git pushes,\n pull requests into correct branches,\n stopping tasks in Jira,\n stopping tasks in Pivotal,\n tracking time,\n logging time to Jira,\n switching back into the original branch and much more.\n".freeze
16
16
  s.email = "sergevinogradoff.caperoma@gmail.com".freeze
17
17
  s.executables = ["caperoma".freeze]
18
18
  s.extra_rdoc_files = [
@@ -35,10 +35,12 @@ Gem::Specification.new do |s|
35
35
  "caperoma.gemspec",
36
36
  "config/crontab",
37
37
  "config/schedule.rb",
38
+ "config/unschedule.rb",
39
+ "images/circle.png",
40
+ "images/report.png",
38
41
  "lib/caperoma.rb",
39
42
  "lib/caperoma/models/account.rb",
40
43
  "lib/caperoma/models/application_record.rb",
41
- "lib/caperoma/models/branch.rb",
42
44
  "lib/caperoma/models/project.rb",
43
45
  "lib/caperoma/models/property.rb",
44
46
  "lib/caperoma/models/report.rb",
@@ -55,12 +57,9 @@ Gem::Specification.new do |s|
55
57
  "lib/caperoma/models/tasks/modules/git.rb",
56
58
  "lib/caperoma/models/tasks/task_with_commit.rb",
57
59
  "lib/caperoma/models/tasks/task_with_separate_branch.rb",
58
- "lib/caperoma/services/airbrake_email_processor.rb",
59
- "lib/caperoma/services/pivotal_fetcher.rb",
60
60
  "lib/caperoma/version.rb",
61
61
  "spec/caperoma_spec.rb",
62
62
  "spec/factories/accounts.rb",
63
- "spec/factories/branches.rb",
64
63
  "spec/factories/projects.rb",
65
64
  "spec/factories/report_recipients.rb",
66
65
  "spec/factories/reports.rb",
@@ -72,6 +71,7 @@ Gem::Specification.new do |s|
72
71
  "spec/features/feature_spec.rb",
73
72
  "spec/features/finish_spec.rb",
74
73
  "spec/features/fix_spec.rb",
74
+ "spec/features/init_spec.rb",
75
75
  "spec/features/meeting_spec.rb",
76
76
  "spec/features/projects_spec.rb",
77
77
  "spec/features/report_recipientss_spec.rb",
@@ -79,7 +79,6 @@ Gem::Specification.new do |s|
79
79
  "spec/features/status_spec.rb",
80
80
  "spec/features/version_spec.rb",
81
81
  "spec/models/account_spec.rb",
82
- "spec/models/branch_spec.rb",
83
82
  "spec/models/bug_spec.rb",
84
83
  "spec/models/chore_spec.rb",
85
84
  "spec/models/daily_report_spec.rb",
@@ -102,7 +101,7 @@ Gem::Specification.new do |s|
102
101
  s.homepage = "http://github.com/zoopyserg/caperoma".freeze
103
102
  s.licenses = ["MIT".freeze]
104
103
  s.post_install_message = "Thanks for installing Caperoma! \n Run `caperoma setup` to create the database for your work.".freeze
105
- s.requirements = ["sqlite".freeze, "git".freeze]
104
+ s.requirements = ["Ruby 2.4 or higher".freeze, "SQLite".freeze, "Git".freeze, "Crontab".freeze]
106
105
  s.rubygems_version = "3.0.4".freeze
107
106
  s.summary = "Automate your workflow with Ruby / Git / Jira / PivotalTracker.".freeze
108
107
 
@@ -121,9 +120,10 @@ Gem::Specification.new do |s|
121
120
  s.add_runtime_dependency(%q<rubocop>.freeze, ["~> 0.73.0"])
122
121
  s.add_runtime_dependency(%q<sqlite3>.freeze, ["~> 1.4.1"])
123
122
  s.add_runtime_dependency(%q<time_difference>.freeze, ["~> 0.7.0"])
123
+ s.add_runtime_dependency(%q<whenever>.freeze, ["~> 1.0.0"])
124
124
  s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
125
125
  s.add_development_dependency(%q<database_cleaner>.freeze, ["~> 1.7.0"])
126
- s.add_development_dependency(%q<factory_bot_rails>.freeze, ["~> 5.0.2"])
126
+ s.add_development_dependency(%q<factory_girl>.freeze, ["~> 4.9.0"])
127
127
  s.add_development_dependency(%q<rdoc>.freeze, ["~> 6.1.1"])
128
128
  s.add_development_dependency(%q<rspec>.freeze, ["~> 3.8.0"])
129
129
  s.add_development_dependency(%q<shoulda>.freeze, ["~> 2.11.3"])
@@ -141,9 +141,10 @@ Gem::Specification.new do |s|
141
141
  s.add_dependency(%q<rubocop>.freeze, ["~> 0.73.0"])
142
142
  s.add_dependency(%q<sqlite3>.freeze, ["~> 1.4.1"])
143
143
  s.add_dependency(%q<time_difference>.freeze, ["~> 0.7.0"])
144
+ s.add_dependency(%q<whenever>.freeze, ["~> 1.0.0"])
144
145
  s.add_dependency(%q<bundler>.freeze, [">= 0"])
145
146
  s.add_dependency(%q<database_cleaner>.freeze, ["~> 1.7.0"])
146
- s.add_dependency(%q<factory_bot_rails>.freeze, ["~> 5.0.2"])
147
+ s.add_dependency(%q<factory_girl>.freeze, ["~> 4.9.0"])
147
148
  s.add_dependency(%q<rdoc>.freeze, ["~> 6.1.1"])
148
149
  s.add_dependency(%q<rspec>.freeze, ["~> 3.8.0"])
149
150
  s.add_dependency(%q<shoulda>.freeze, ["~> 2.11.3"])
@@ -162,9 +163,10 @@ Gem::Specification.new do |s|
162
163
  s.add_dependency(%q<rubocop>.freeze, ["~> 0.73.0"])
163
164
  s.add_dependency(%q<sqlite3>.freeze, ["~> 1.4.1"])
164
165
  s.add_dependency(%q<time_difference>.freeze, ["~> 0.7.0"])
166
+ s.add_dependency(%q<whenever>.freeze, ["~> 1.0.0"])
165
167
  s.add_dependency(%q<bundler>.freeze, [">= 0"])
166
168
  s.add_dependency(%q<database_cleaner>.freeze, ["~> 1.7.0"])
167
- s.add_dependency(%q<factory_bot_rails>.freeze, ["~> 5.0.2"])
169
+ s.add_dependency(%q<factory_girl>.freeze, ["~> 4.9.0"])
168
170
  s.add_dependency(%q<rdoc>.freeze, ["~> 6.1.1"])
169
171
  s.add_dependency(%q<rspec>.freeze, ["~> 3.8.0"])
170
172
  s.add_dependency(%q<shoulda>.freeze, ["~> 2.11.3"])
@@ -1,8 +1,6 @@
1
1
  # Begin Whenever generated tasks for: caperoma
2
2
  0 22 * * 1-5 /bin/bash -l -c 'caperoma report daily'
3
3
 
4
- 0,10,20,30,40,50 * * * * /bin/bash -l -c 'caperoma copy_airbrake_emails_to_pivotal'
5
-
6
4
  0 22 * * 3,5 /bin/bash -l -c 'caperoma report three_day'
7
5
 
8
6
  0 22 * * 5 /bin/bash -l -c 'caperoma report weekly'
@@ -1,21 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # every :weekday, at: '10pm' do
4
- # command 'caperoma daily_report'
5
- # end
6
- #
7
- # every 10.minutes do
8
- # command 'caperoma copy_airbrake_emails_to_pivotal'
9
- # end
10
- #
11
- # every :wednesday, at: '10pm' do
12
- # command 'caperoma three_day_report'
13
- # end
14
- #
15
- # every :friday, at: '10pm' do
16
- # command 'caperoma three_day_report'
17
- # end
18
- #
19
- # every :friday, at: '10pm' do
20
- # command 'caperoma retrospective_report'
21
- # end
3
+ set :job_template, nil
4
+
5
+ every :weekday, at: '5:00pm' do
6
+ command 'caperoma report daily'
7
+ end
8
+
9
+ every :wednesday, at: '5:05pm' do
10
+ command 'caperoma report three_day'
11
+ end
12
+
13
+ every :friday, at: '5:05pm' do
14
+ command 'caperoma report three_day'
15
+ end
16
+
17
+ every :friday, at: '5:10pm' do
18
+ command 'caperoma report weekly'
19
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ set :job_template, nil
Binary file
Binary file
@@ -7,15 +7,18 @@ require 'action_view'
7
7
  require 'json'
8
8
  require 'jbuilder'
9
9
  require 'time_difference'
10
- require 'pivotal-tracker'
11
10
  require 'net/smtp'
12
11
  require 'gmail'
13
12
  require 'faraday'
14
13
  require 'pp'
15
14
 
15
+ database_name = "#{ENV['HOME']}/.caperoma.sqlite3"
16
+ database_name = "#{ENV['HOME']}/.caperoma-test.sqlite3" if ENV['CAPEROMA_TEST'].present? || ENV['CAPEROMA_INTEGRATION_TEST'].present?
17
+ database_name = "#{ENV['HOME']}/.caperoma-staging.sqlite3" if ENV['CAPEROMA_STAGING'].present?
18
+
16
19
  DB_SPEC = {
17
20
  adapter: 'sqlite3',
18
- database: ENV['CAPEROMA_TEST'].present? || ENV['CAPEROMA_INTEGRATION_TEST'].present? ? "#{ENV['HOME']}/.caperoma-test.sqlite3" : "#{ENV['HOME']}/.caperoma.sqlite3"
21
+ database: database_name
19
22
  }.freeze
20
23
 
21
24
  ActiveRecord::Base.establish_connection(DB_SPEC)
@@ -37,8 +40,6 @@ require 'caperoma/models/tasks/meeting'
37
40
 
38
41
  require 'caperoma/models/report_recipient'
39
42
 
40
- require 'caperoma/models/branch'
41
-
42
43
  require 'caperoma/models/report'
43
44
  require 'caperoma/models/reports/daily_report'
44
45
  require 'caperoma/models/reports/three_day_report'
@@ -46,9 +47,6 @@ require 'caperoma/models/reports/retrospective_report'
46
47
 
47
48
  require 'caperoma/version'
48
49
 
49
- require 'caperoma/services/pivotal_fetcher'
50
- require 'caperoma/services/airbrake_email_processor'
51
-
52
50
  class Caperoma
53
51
  def self.setup
54
52
  puts 'Initializing Caperoma'
@@ -93,27 +91,21 @@ class Caperoma
93
91
  end
94
92
  add_index :projects, :jira_project_id
95
93
 
96
- create_table :branches do |t|
97
- t.column :project_id, :integer
98
- t.column :name, :string
99
-
100
- t.timestamps
101
- end
102
- add_index :branches, :project_id
103
-
104
94
  create_table :tasks do |t|
105
95
  t.column :project_id, :integer
106
- t.column :branch_id, :integer
107
96
  t.column :title, :string
108
97
  t.column :description, :text
109
98
  t.column :url, :text
110
99
  t.column :uuid, :string
100
+ t.column :pivotal_estimate, :integer, default: 0
111
101
  t.column :type, :string
112
102
  t.column :jira_id, :string
113
103
  t.column :jira_key, :string
114
104
  t.column :jira_url, :string
115
105
  t.column :parent_branch, :string
106
+ t.column :branch, :string
116
107
  t.column :pivotal_id, :string
108
+ t.column :additional_time, :integer
117
109
  t.column :started_at, :datetime
118
110
  t.column :finished_at, :datetime
119
111
  t.column :daily_report_id, :integer
@@ -123,7 +115,6 @@ class Caperoma
123
115
  t.timestamps
124
116
  end
125
117
  add_index :tasks, :project_id
126
- add_index :tasks, :branch_id
127
118
  add_index :tasks, :daily_report_id
128
119
  add_index :tasks, :three_day_report_id
129
120
  add_index :tasks, :retrospective_report_id
@@ -149,9 +140,11 @@ class Caperoma
149
140
  end
150
141
 
151
142
  def self.init
152
- if `git -C "#{project.folder_path}" rev-parse --is-inside-work-tree`.strip == 'true'
143
+ if `git rev-parse --is-inside-work-tree`.strip == 'true'
153
144
  template_path = File.join(File.dirname(__FILE__), '..', 'Capefile.template')
154
- new_path = `git rev-parse --show-toplevel`.strip + '/Capefile'
145
+ capefile_filename = ENV['CAPEROMA_TEST'].blank? && ENV['CAPEROMA_INTEGRATION_TEST'].blank? ? 'Capefile' : 'Capefile.test'
146
+
147
+ new_path = `git rev-parse --show-toplevel`.strip + '/' + capefile_filename
155
148
 
156
149
  FileUtils.cp template_path, new_path
157
150
 
@@ -162,47 +155,156 @@ class Caperoma
162
155
  end
163
156
  end
164
157
 
165
- # todo: here is project.jira_url. but it has an undefined method project.
158
+ # TODO: here is project.jira_url. but it has an undefined method project.
166
159
  # should move this method to be inside a project (get ids for this project or something).
167
160
  def self.get_jira_issue_type_ids
168
- conn = Faraday.new(url: project.jira_url) do |c|
169
- c.basic_auth(Account.jira.email, Account.jira.password)
170
- c.adapter Faraday.default_adapter
171
- end
172
-
173
- response = conn.get do |request|
174
- request.url 'rest/api/3/issuetype.json'
175
- #request.body = data
176
- request.headers['User-Agent'] = 'Caperoma'
177
- request.headers['Content-Type'] = 'application/json'
178
- end
179
-
180
- puts 'Received these issue types:'
181
-
182
- result = JSON.parse(response.body)
183
-
184
- result.each do |item|
185
- puts "ID: #{item['id']}, Name: #{item['name']}"
161
+ puts 'Getting issue ids from Jira'
162
+
163
+ if Account.jira.present?
164
+ capefile_filename = ENV['CAPEROMA_TEST'].blank? && ENV['CAPEROMA_INTEGRATION_TEST'].blank? ? 'Capefile' : 'Capefile.test'
165
+ if File.exist?(capefile_filename)
166
+ capedata = YAML.load_file(capefile_filename)
167
+ if capedata
168
+ jira_url = capedata['jira_url']
169
+ if jira_url
170
+ puts 'Receiving issue types'
171
+ conn = Faraday.new(url: jira_url) do |c|
172
+ c.basic_auth(Account.jira.email, Account.jira.password)
173
+ c.adapter Faraday.default_adapter
174
+ end
175
+
176
+ response = conn.get do |request|
177
+ request.url 'rest/api/3/issuetype.json'
178
+ request.headers['User-Agent'] = 'Caperoma'
179
+ request.headers['Content-Type'] = 'application/json'
180
+ end
181
+
182
+ case response.status
183
+ when 200, 201, 202, 204, 301, 302, 303, 304, 307
184
+ puts 'Received these issue types:'
185
+
186
+ result = JSON.parse(response.body)
187
+
188
+ result.each do |item|
189
+ puts "Name: #{item['name']}, ID: #{item['id']}"
190
+ end
191
+ when 401, 403
192
+ puts 'No access to Jira. Maybe login or api_key are incorrect.'
193
+ when 404
194
+ puts 'Resource not found. Maybe Jira ID is incorrect.'
195
+ else
196
+ puts 'Could not get data from Jira.'
197
+ puts "Error status: #{response.status}"
198
+ puts "Message from server: #{response.reason_phrase}"
199
+ end
200
+ else
201
+ puts 'Please put at least jira url into your Capefile'
202
+ end
203
+ else
204
+ puts 'Can not parse Capfile. Is it formatted properly?'
205
+ end
206
+ else
207
+ puts 'Capefile not found. Are you in the project folder? If yes, run "caperoma init" to create Capefile.'
208
+ end
209
+ else
210
+ puts 'Please set up Jira account first'
186
211
  end
212
+ rescue Faraday::ConnectionFailed
213
+ puts 'Connection failed.'
187
214
  end
188
215
 
189
216
  def self.get_jira_transition_ids
190
- conn = Faraday.new(url: project.jira_url) do |c|
191
- c.basic_auth(Account.jira.email, Account.jira.password)
192
- c.adapter Faraday.default_adapter
193
- end
194
-
195
- response = conn.post do |request|
196
- request.url 'rest/api/3/issue/{some_issue_key_or_id}/transitions.json'
197
- request.body = data
198
- request.headers['User-Agent'] = 'Caperoma'
199
- request.headers['Content-Type'] = 'application/json'
200
- end
201
-
202
- puts 'Received these transition types:'
203
- JSON.parse(response).each do |item|
204
- puts "ID: #{item.id}, Name: #{item.name}"
217
+ puts 'Getting transition ids from Jira'
218
+
219
+ if Account.jira.present?
220
+ capefile_filename = ENV['CAPEROMA_TEST'].blank? && ENV['CAPEROMA_INTEGRATION_TEST'].blank? ? 'Capefile' : 'Capefile.test'
221
+ if File.exist?(capefile_filename)
222
+ capedata = YAML.load_file(capefile_filename)
223
+ if capedata
224
+ jira_url = capedata['jira_url']
225
+ if jira_url
226
+ jira_project_id = capedata['jira_project_id']
227
+
228
+ if jira_project_id
229
+ puts 'Receiving an issue to get transition ids:'
230
+
231
+ conn = Faraday.new(url: jira_url) do |c|
232
+ c.basic_auth(Account.jira.email, Account.jira.password)
233
+ c.adapter Faraday.default_adapter
234
+ end
235
+
236
+ response = conn.get do |request|
237
+ request.url "rest/api/3/search?jql=project=%22#{jira_project_id}%22"
238
+ request.headers['User-Agent'] = 'Caperoma'
239
+ request.headers['Content-Type'] = 'application/json'
240
+ end
241
+
242
+ case response.status
243
+ when 200, 201, 202, 204, 301, 302, 303, 304, 307
244
+ issues = JSON.parse(response.body)['issues']
245
+
246
+ if !issues.empty?
247
+ first_issue = issues[0]
248
+ first_issue_key = first_issue['key']
249
+
250
+ conn2 = Faraday.new(url: jira_url) do |c|
251
+ c.basic_auth(Account.jira.email, Account.jira.password)
252
+ c.adapter Faraday.default_adapter
253
+ end
254
+
255
+ response2 = conn2.get do |request|
256
+ request.url "rest/api/3/issue/#{first_issue_key}/transitions"
257
+ request.headers['User-Agent'] = 'Caperoma'
258
+ request.headers['Content-Type'] = 'application/json'
259
+ end
260
+
261
+ case response2.status
262
+ when 200, 201, 202, 204, 301, 302, 303, 304, 307
263
+ puts 'Received these transitions:'
264
+ transitions = JSON.parse(response2.body)['transitions']
265
+
266
+ transitions.each do |transition|
267
+ pp "Name: #{transition['name']}, ID: #{transition['id']}"
268
+ end
269
+ when 401, 403
270
+ puts 'No access to Jira. Maybe login or api_key are incorrect.'
271
+ when 404
272
+ puts 'Resource not found. Maybe Jira ID is incorrect.'
273
+ else
274
+ puts 'Could not get data from Jira.'
275
+ puts "Error status: #{response2.status}"
276
+ puts "Message from server: #{response2.reason_phrase}"
277
+ end
278
+ else
279
+ puts 'Please create at least one issue in this project manually in the browser.'
280
+ end
281
+ when 401, 403
282
+ puts 'No access to Jira. Maybe login or api_key are incorrect.'
283
+ when 404
284
+ puts 'Resource not found. Maybe Jira ID is incorrect.'
285
+ else
286
+ puts 'Could not get data from Jira.'
287
+ puts "Error status: #{response.status}"
288
+ puts "Message from server: #{response.reason_phrase}"
289
+ end
290
+ else
291
+ puts 'Please put jira_project_id into your Capefile'
292
+ end
293
+
294
+ else
295
+ puts 'Please put jira_url into your Capefile'
296
+ end
297
+ else
298
+ puts 'Can not parse Capfile. Is it formatted properly?'
299
+ end
300
+ else
301
+ puts 'Capefile not found. Are you in the project folder? If yes, run "caperoma init" to create Capefile.'
302
+ end
303
+ else
304
+ puts 'Please set up Jira account first'
205
305
  end
306
+ rescue Faraday::ConnectionFailed
307
+ puts 'Connection failed.'
206
308
  end
207
309
 
208
310
  def self.drop_db
@@ -214,7 +316,7 @@ class Caperoma
214
316
 
215
317
  def self.create_task(argv)
216
318
  # test if Capefile exists
217
- capefile_filename = (ENV['CAPEROMA_TEST'].blank? && ENV['CAPEROMA_INTEGRATION_TEST'].blank?) ? 'Capefile' : 'Capefile.test'
319
+ capefile_filename = ENV['CAPEROMA_TEST'].blank? && ENV['CAPEROMA_INTEGRATION_TEST'].blank? ? 'Capefile' : 'Capefile.test'
218
320
 
219
321
  if File.exist?(capefile_filename)
220
322
  capedata = nil
@@ -237,7 +339,7 @@ class Caperoma
237
339
  create_fixes_in_pivotal_as_chores = nil
238
340
  create_meetings_in_pivotal_as_chores = nil
239
341
 
240
- capedata = YAML.load_file(capefile_filename)
342
+ capedata = YAML.load_file(capefile_filename)
241
343
  if capedata
242
344
  jira_url = capedata['jira_url']
243
345
  jira_project_id = capedata['jira_project_id']
@@ -292,43 +394,58 @@ class Caperoma
292
394
  additional_time_flag_position = argv.index('-a') || argv.index('--additional_time')
293
395
  additional_time = argv[additional_time_flag_position + 1] if additional_time_flag_position
294
396
 
295
- if title
296
- project = Project.all.select { |project| project.jira_project_id == jira_project_id || project.pivotal_tracker_project_id == pivotal_tracker_project_id || project.folder_path == folder_path || project.github_repo == github_repo }.first
297
-
298
- project ||= Project.new
299
-
300
- project.folder_path = folder_path
301
- project.jira_url = jira_url
302
- project.jira_project_id = jira_project_id
303
- project.github_repo = github_repo
304
- project.feature_jira_task_id = feature_jira_task_id
305
- project.bug_jira_task_id = bug_jira_task_id
306
- project.chore_jira_task_id = chore_jira_task_id
307
- project.fix_jira_task_id = fix_jira_task_id
308
- project.meeting_jira_task_id = meeting_jira_task_id
309
- project.jira_transition_id_todo = jira_transition_id_todo
310
- project.jira_transition_id_in_progress = jira_transition_id_in_progress
311
- project.jira_transition_id_done = jira_transition_id_done
312
- project.pivotal_tracker_project_id = pivotal_tracker_project_id
313
- project.create_features_in_pivotal = create_features_in_pivotal
314
- project.create_bugs_in_pivotal = create_bugs_in_pivotal
315
- project.create_chores_in_pivotal = create_chores_in_pivotal
316
- project.create_fixes_in_pivotal_as_chores = create_fixes_in_pivotal_as_chores
317
- project.create_meetings_in_pivotal_as_chores = create_meetings_in_pivotal_as_chores
318
- project.save
397
+ pivotal_id = pivotal_id.gsub(/#/, '') if pivotal_id.present?
398
+
399
+ project = Project.all.select { |project| project.jira_project_id == jira_project_id || project.pivotal_tracker_project_id == pivotal_tracker_project_id || project.folder_path == folder_path || project.github_repo == github_repo }.first
400
+
401
+ project ||= Project.new
402
+
403
+ project.folder_path = folder_path
404
+ project.jira_url = jira_url
405
+ project.jira_project_id = jira_project_id
406
+ project.github_repo = github_repo
407
+ project.feature_jira_task_id = feature_jira_task_id
408
+ project.bug_jira_task_id = bug_jira_task_id
409
+ project.chore_jira_task_id = chore_jira_task_id
410
+ project.fix_jira_task_id = fix_jira_task_id
411
+ project.meeting_jira_task_id = meeting_jira_task_id
412
+ project.jira_transition_id_todo = jira_transition_id_todo
413
+ project.jira_transition_id_in_progress = jira_transition_id_in_progress
414
+ project.jira_transition_id_done = jira_transition_id_done
415
+ project.pivotal_tracker_project_id = pivotal_tracker_project_id
416
+ project.create_features_in_pivotal = create_features_in_pivotal
417
+ project.create_bugs_in_pivotal = create_bugs_in_pivotal
418
+ project.create_chores_in_pivotal = create_chores_in_pivotal
419
+ project.create_fixes_in_pivotal_as_chores = create_fixes_in_pivotal_as_chores
420
+ project.create_meetings_in_pivotal_as_chores = create_meetings_in_pivotal_as_chores
421
+ project.save
422
+
423
+ pivotal_data = get_pivotal_data(pivotal_id)
424
+ title ||= pivotal_data[:title]
425
+ description ||= pivotal_data[:description]
426
+ pivotal_id = pivotal_data[:pivotal_id]
427
+ pivotal_estimate = pivotal_data[:estimate]
319
428
 
429
+ if title
430
+ record = nil
320
431
 
321
432
  case argv[0]
322
433
  when 'chore'
323
- project.chores.create(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time)
434
+ record = project.chores.new(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time, pivotal_estimate: pivotal_estimate)
324
435
  when 'bug'
325
- project.bugs.create(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time)
436
+ record = project.bugs.new(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time, pivotal_estimate: pivotal_estimate)
326
437
  when 'feature'
327
- project.features.create(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time)
438
+ record = project.features.new(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time, pivotal_estimate: pivotal_estimate)
328
439
  when 'fix'
329
- project.fixes.create(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time)
440
+ record = project.fixes.new(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time, pivotal_estimate: pivotal_estimate)
330
441
  when 'meeting'
331
- project.meetings.create(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time)
442
+ record = project.meetings.new(title: title, description: description, project_id: project_id, pivotal_id: pivotal_id, additional_time: additional_time, pivotal_estimate: pivotal_estimate)
443
+ end
444
+
445
+ if record.valid?
446
+ record.save
447
+ else
448
+ puts record.errors.details.to_s
332
449
  end
333
450
  else
334
451
  puts "Title is required. Add -t \"my #{argv[0]} title\" flag."
@@ -339,26 +456,119 @@ class Caperoma
339
456
  else
340
457
  puts 'Capefile not found. Are you in the project folder? If yes, run "caperoma init" to create Capefile.'
341
458
  end
459
+ end
342
460
 
461
+ def self.get_pivotal_data(pivotal_id)
462
+ resulting_hash = { title: nil, description: nil, pivotal_id: pivotal_id, estimate: 0 }
463
+
464
+ if ENV['CAPEROMA_INTEGRATION_TEST'].blank?
465
+ if pivotal_id.present?
466
+ if Account.pivotal.present?
467
+
468
+ if pivotal_id.match? /\d+/
469
+ conn = Faraday.new(url: 'https://www.pivotaltracker.com/') do |c|
470
+ c.adapter Faraday.default_adapter
471
+ end
472
+
473
+ response = conn.get do |request|
474
+ request.url "services/v5/stories/#{pivotal_id}"
475
+ request.headers['User-Agent'] = 'Caperoma'
476
+ request.headers['Content-Type'] = 'application/json'
477
+ request.headers['X-TrackerToken'] = Account.pivotal.password
478
+ end
479
+
480
+ case response.status
481
+ when 200, 201, 202, 204, 301, 302, 303, 304, 307
482
+ result = JSON.parse response.body
483
+
484
+ resulting_hash[:title] = result['name']
485
+ resulting_hash[:description] = result['description']
486
+ resulting_hash[:estimate] = result['estimate'].to_i
487
+ when 401, 403
488
+ puts 'No access Pivotal. Maybe login or api_key are incorrect.'
489
+ when 404
490
+ puts 'Resource not found. Maybe Pivotal ID is incorrect.'
491
+ else
492
+ puts 'Could not get data from Pivotal.'
493
+ puts "Error status: #{response.status}"
494
+ puts "Message from server: #{response.reason_phrase}"
495
+ end
496
+
497
+ resulting_hash
498
+ else
499
+ puts 'Pivotal ID needs to be copied from the task in Pivotal (in either 12345678 or #12345678 format).'
500
+ puts "Pivotal ID you entered was #{pivotal_id}, which does not match the allowed format."
501
+ puts 'Skipping usage of this ID.'
502
+ puts 'Proceeding as if Pivotal ID was not set.'
503
+ puts 'Please start/finish the needed task in Pivotal manually.'
504
+
505
+ resulting_hash[:pivotal_id] = nil
506
+ end
507
+ else
508
+ puts 'Please set up Pivotal account.'
509
+ end
510
+ end
511
+ end
512
+ resulting_hash
513
+ rescue Faraday::ConnectionFailed
514
+ puts 'Connection failed. Performing the task without requests to Pivotal.'
515
+ resulting_hash
343
516
  end
344
517
 
345
518
  def self.get_jira_project_ids
346
519
  puts 'Getting projects from Jira'
347
520
 
348
- conn = Faraday.new(url: Caperoma::Capefile::JIRA_URL) do |c|
349
- c.basic_auth(Account.jira.email, Account.jira.password)
350
- c.adapter Faraday.default_adapter
351
- end
352
-
353
- response = conn.get do |request|
354
- request.url 'rest/api/3/project.json'
355
- request.headers['User-Agent'] = 'Caperoma'
356
- request.headers['Content-Type'] = 'application/json'
357
- end
358
-
359
- JSON.parse(response.body).each_with_index do |project|
360
- pp "Name: #{project['name']}, jira_project_id: #{project['id']}"
521
+ if Account.jira.present?
522
+
523
+ capefile_filename = ENV['CAPEROMA_TEST'].blank? && ENV['CAPEROMA_INTEGRATION_TEST'].blank? ? 'Capefile' : 'Capefile.test'
524
+ if File.exist?(capefile_filename)
525
+ capedata = YAML.load_file(capefile_filename)
526
+ if capedata
527
+ jira_url = capedata['jira_url']
528
+ if jira_url
529
+ conn = Faraday.new(url: jira_url) do |c|
530
+ c.basic_auth(Account.jira.email, Account.jira.password)
531
+ c.adapter Faraday.default_adapter
532
+ end
533
+
534
+ response = conn.get do |request|
535
+ request.url 'rest/api/3/project.json'
536
+ request.headers['User-Agent'] = 'Caperoma'
537
+ request.headers['Content-Type'] = 'application/json'
538
+ end
539
+
540
+ case response.status
541
+ when 200, 201, 202, 204, 301, 302, 303, 304, 307
542
+ puts 'Received these projects'
543
+
544
+ result = JSON.parse(response.body)
545
+
546
+ result.each do |project|
547
+ puts "Name: #{project['name']}, jira_project_id: #{project['id']}"
548
+ end
549
+ when 401, 403
550
+ puts 'No access to Jira. Maybe login or api_key are incorrect.'
551
+ when 404
552
+ puts 'Resource not found. Maybe Jira ID is incorrect.'
553
+ else
554
+ puts 'Could not get data from Jira.'
555
+ puts "Error status: #{response.status}"
556
+ puts "Message from server: #{response.reason_phrase}"
557
+ end
558
+ else
559
+ puts 'Please put at least jira url into your Capefile'
560
+ end
561
+ else
562
+ puts 'Can not parse Capfile. Is it formatted properly?'
563
+ end
564
+ else
565
+ puts 'Capefile not found. Are you in the project folder? If yes, run "caperoma init" to create Capefile.'
566
+ end
567
+ else
568
+ puts 'Please set up Jira account first'
361
569
  end
570
+ rescue Faraday::ConnectionFailed
571
+ puts 'Connection failed.'
362
572
  end
363
573
 
364
574
  def self.manage_recipients(argv)
@@ -403,7 +613,7 @@ class Caperoma
403
613
  when /^(remove|delete|--remove|--delete|-d|-r)$/
404
614
  Account.where(type: argv[2]).destroy_all
405
615
  when nil
406
- Account.all.each { |x| puts "#{x.type[2..-1].capitalize}: #{x.email}" }
616
+ Account.all.each { |x| puts "#{x.type[2..-1].capitalize}: #{x.email} #{x.password} #{x.username}" }
407
617
  puts ''
408
618
  puts 'to delete run "caperoma accounts remove "--<type>"'
409
619
  puts 'to update run "... accounts --add "--<type>" again'