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.
- checksums.yaml +4 -4
- data/Capefile +6 -6
- data/Capefile.template +4 -1
- data/Gemfile +1 -5
- data/Gemfile.lock +3 -45
- data/HELP +84 -13
- data/README.md +165 -29
- data/Rakefile +25 -22
- data/VERSION +1 -1
- data/bin/caperoma +6 -9
- data/caperoma.gemspec +15 -13
- data/config/crontab +0 -2
- data/config/schedule.rb +17 -19
- data/config/unschedule.rb +3 -0
- data/images/circle.png +0 -0
- data/images/report.png +0 -0
- data/lib/caperoma.rb +308 -98
- data/lib/caperoma/models/account.rb +1 -1
- data/lib/caperoma/models/project.rb +1 -2
- data/lib/caperoma/models/report.rb +15 -15
- data/lib/caperoma/models/task.rb +203 -46
- data/lib/caperoma/models/tasks/chore.rb +2 -0
- data/lib/caperoma/models/tasks/feature.rb +1 -0
- data/lib/caperoma/models/tasks/fix.rb +2 -0
- data/lib/caperoma/models/tasks/meeting.rb +2 -0
- data/lib/caperoma/models/tasks/modules/git.rb +94 -15
- data/lib/caperoma/models/tasks/task_with_commit.rb +8 -5
- data/lib/caperoma/models/tasks/task_with_separate_branch.rb +6 -4
- data/spec/caperoma_spec.rb +558 -2
- data/spec/factories/accounts.rb +1 -1
- data/spec/factories/projects.rb +1 -1
- data/spec/factories/report_recipients.rb +1 -1
- data/spec/factories/reports.rb +1 -1
- data/spec/factories/tasks.rb +1 -2
- data/spec/features/command_unknown_spec.rb +0 -1
- data/spec/features/feature_spec.rb +64 -44
- data/spec/features/init_spec.rb +20 -0
- data/spec/features/status_spec.rb +12 -11
- data/spec/models/project_spec.rb +0 -1
- data/spec/models/task_spec.rb +811 -27
- data/spec/models/task_with_commit_spec.rb +0 -4
- data/spec/models/task_with_separate_branch_spec.rb +4 -4
- data/spec/models/three_day_report_spec.rb +2 -3
- data/spec/spec_helper.rb +2 -0
- data/spec/support/capefile_generator.rb +35 -27
- data/spec/support/stubs.rb +7 -74
- metadata +47 -24
- data/lib/caperoma/models/branch.rb +0 -6
- data/lib/caperoma/services/airbrake_email_processor.rb +0 -47
- data/lib/caperoma/services/pivotal_fetcher.rb +0 -108
- data/spec/factories/branches.rb +0 -9
- 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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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 '
|
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 << '
|
70
|
-
gem.requirements << '
|
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
|
-
|
1
|
+
5.0.0
|
data/bin/caperoma
CHANGED
@@ -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
|
data/caperoma.gemspec
CHANGED
@@ -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
|
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 = "
|
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-
|
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
|
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 = ["
|
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<
|
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<
|
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<
|
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"])
|
data/config/crontab
CHANGED
@@ -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'
|
data/config/schedule.rb
CHANGED
@@ -1,21 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
data/images/circle.png
ADDED
Binary file
|
data/images/report.png
ADDED
Binary file
|
data/lib/caperoma.rb
CHANGED
@@ -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:
|
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
|
143
|
+
if `git rev-parse --is-inside-work-tree`.strip == 'true'
|
153
144
|
template_path = File.join(File.dirname(__FILE__), '..', 'Capefile.template')
|
154
|
-
|
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
|
-
#
|
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
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
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
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
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 =
|
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
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
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'
|