jiraMule 0.1.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.
@@ -0,0 +1,243 @@
1
+ require 'terminal-table'
2
+ require 'mustache'
3
+ require 'yaml'
4
+ require 'JiraMule/jiraUtils'
5
+
6
+ command :kanban do |c|
7
+ extra_columns = []
8
+ c.syntax = 'jm query [options] kanban'
9
+ c.summary = 'Show a kanban table'
10
+ c.description = %{
11
+ Display issues grouped by a query. Each group is a column in a table or a section in a list.
12
+
13
+ Original intent was to build kanban tables, hence the name. However, the output is quite
14
+ configurable can can be used for many other styles.
15
+
16
+ Use the --dump option to see how things have been styled.
17
+
18
+ Formatting is done with Mustash.
19
+ }
20
+ c.example 'Show a kanban table', 'jm kanban'
21
+ c.example 'Show a status list', 'jm status'
22
+ c.example 'Another way to show a status list', 'jm --style status'
23
+ c.example 'Show a list to use with Taskpaper', 'jm --style taskpaper'
24
+ c.example 'Show status list, with differnt styling', %{jm --style status --header '# {{column}}' --item '** {{key}} {{summary}}'}
25
+ c.example 'Showoff', %{jm kanban --style empty --heading '<h1>{{column}}</h1>' \\
26
+ --column 'Working=status="In Progress"' \\
27
+ --column 'Done=status="Pending Release"' \\
28
+ --fields key,summary,assignee \\
29
+ --item '<h2>{{key}}</h2><b>Who:{{assignee.name}}</b><p>{{summary}}</p>'}
30
+
31
+ c.option '--[no-]raw', 'Do not prefix queries with project and assignee'
32
+ c.option '-w', '--width WIDTH', Integer, 'Width of the terminal'
33
+ c.option '-s', '--style STYLE', String, 'Which style to use'
34
+ c.option '--heading STYLE', String, 'Format for heading'
35
+ c.option '--item STYLE', String, 'Format for items'
36
+ c.option('-c', '--column NAME=QUERY', '') {|ec| extra_columns << ec}
37
+ c.option '-f', '--fields FIELDS', Array, 'Which fields to return'
38
+ c.option '-d', '--dump', 'Dump the style to STDOUT as yaml'
39
+ c.option '--file FILE', String, %{Style definition file to load}
40
+
41
+ c.action do |args, options|
42
+ options.default :width=>HighLine::SystemExtensions.terminal_size[0],
43
+ :style => 'kanban'
44
+
45
+ # Table of Styles. Appendable via config file. ??and command line??
46
+ allOfThem = {
47
+ :empty => {
48
+ :fields => [:key, :summary],
49
+ :format => {
50
+ :heading => "{{column}}",
51
+ :item => "{{key}} {{summary}}",
52
+ },
53
+ :columns => {}
54
+ },
55
+ :status => {
56
+ :fields => [:key, :summary],
57
+ :format => {
58
+ :heading => "#### {{column}}",
59
+ :item => "- {{key}} {{summary}}",
60
+ :order => [:Done, :Testing, :InProgress, :Todo],
61
+ },
62
+ :columns => {
63
+ :Done => [%{status = 'Pending Release'}],
64
+ :Testing => [%{status = Testing}],
65
+ :InProgress => [%{status = "In Progress"}],
66
+ :Todo => [%{(status = Open OR},
67
+ %{status = Reopened OR},
68
+ %{status = "On Deck" OR},
69
+ %{status = "Waiting Estimation Approval" OR},
70
+ %{status = "Reopened" OR},
71
+ %{status = "Testing (Signoff)" OR},
72
+ %{status = "Testing (Review)" OR},
73
+ %{status = "Testing - Bug Found")}],
74
+ },
75
+
76
+ },
77
+ :kanban => {
78
+ :fields => [:key, :summary],
79
+ :format => {
80
+ :heading => "{{column}}",
81
+ :item => "{{key}}\n {{summary}}",
82
+ :order => [:Todo, :InProgress, :Done],
83
+ :usetable => true
84
+ },
85
+ :columns => {
86
+ :Done => [%{(status = Released OR status = "Not Needed - Closed")}],
87
+ :InProgress => [%{(status = "In Progress" OR},
88
+ %{status = "In Dev" OR},
89
+ %{status = "Pending Release" OR},
90
+ %{status = "In QA" OR},
91
+ %{status = "Integration QA" OR},
92
+ %{status = "In Design")},
93
+ ],
94
+ :Todo => [%{(status = Open OR},
95
+ %{status = Reopened OR},
96
+ %{status = "On Deck" OR},
97
+ %{status = "Waiting Estimation Approval" OR},
98
+ %{status = "Reopened" OR},
99
+ %{status = "Testing (Signoff)" OR},
100
+ %{status = "Testing (Review)" OR},
101
+ %{status = "Testing - Bug Found" OR},
102
+ %{status = "Backlog" OR},
103
+ %{status = "Ready For Dev" OR},
104
+ %{status = "Ready For QA" OR},
105
+ %{status = "To Do" OR},
106
+ %{status = "Release Package")},
107
+ ],
108
+ },
109
+ },
110
+ :taskpaper => {
111
+ :fields => [:key, :summary, :duedate],
112
+ :format => {
113
+ :heading => "{{column}}:",
114
+ :item => "- {{summary}} @jira({{key}}) {{#duedate}}@due({{duedate}}){{/duedate}}",
115
+ },
116
+ :columns => {
117
+ :InProgress => %{status = "In Progress"},
118
+ :Todo => [%{(status = Open OR},
119
+ %{status = "Testing - Bug Found")}],
120
+ }
121
+ },
122
+ }
123
+ # TODO: Load styles from project dir
124
+
125
+ if options.file.nil? then
126
+ theStyle = allOfThem[options.style.to_sym]
127
+ else
128
+ theStyle = allOfThem[:empty]
129
+ File.open(options.file) {|io|
130
+ theStyle = YAML.load(io)
131
+ # make sure the required keys are symbols.
132
+ %w{fields format columns}.each do |key|
133
+ if theStyle.has_key? key then
134
+ theStyle[key.to_sym] = theStyle[key]
135
+ theStyle.delete(key)
136
+ end
137
+ end
138
+ %w{heading item}.each do |key|
139
+ if theStyle[:format].has_key? key then
140
+ theStyle[:format][key.to_sym] = theStyle[:format][key]
141
+ theStyle[:format].delete(key)
142
+ end
143
+ end
144
+ }
145
+ end
146
+
147
+ #### look for command line overrides
148
+ extra_columns.each do |cm|
149
+ name, query = cm.split(/=/, 2)
150
+ theStyle[:columns][name.to_sym] = [query]
151
+ end
152
+
153
+ theStyle[:fields] = options.fields if options.fields
154
+ theStyle[:format][:heading] = options.heading if options.heading
155
+ theStyle[:format][:item] = options.item if options.item
156
+
157
+
158
+ # All loading and computing of the style is complete, now fetch and print
159
+
160
+ if options.dump then
161
+ puts theStyle.to_yaml
162
+ else
163
+
164
+ ### Fetch the issues for each column
165
+ columns = theStyle[:columns]
166
+
167
+ jira = JiraMule::JiraUtils.new(args, options)
168
+
169
+ #### Fetch these fields
170
+ fields = theStyle[:fields]
171
+
172
+ #### Now fetch
173
+ qBase = []
174
+ qBase.unshift("assignee = #{jira.username} AND") unless options.raw
175
+ qBase.unshift("project = #{jira.project} AND") unless options.raw
176
+ qBase.unshift('(' + args.join(' ') + ') AND') unless args.empty?
177
+
178
+ results = {}
179
+ columns.each_pair do |name, query|
180
+ query = [query] unless query.is_a? Array
181
+ q = qBase + query + [%{ORDER BY Rank}]
182
+ issues = jira.getIssues(q.join(' '), fields)
183
+ results[name] = issues
184
+ end
185
+
186
+ ### Now format the output
187
+ format = theStyle[:format]
188
+
189
+ #### Setup ordering
190
+ format[:order] = columns.keys.sort unless format.has_key? :order
191
+
192
+ #### setup column widths
193
+ cW = options.width.to_i
194
+ cW = -1 if cW == 0
195
+ cWR = cW
196
+ if format[:usetable] and cW > 0 then
197
+ borders = 4 + (columns.count * 3); # 2 on left, 2 on right, 3 for each internal
198
+ cW = (cW - borders) / columns.count
199
+ cWR = cW + ((cW - borders) % columns.count)
200
+ end
201
+
202
+ #### Format Items
203
+ formatted={}
204
+ results.each_pair do |name, issues|
205
+ formatted[name] = issues.map do |issue|
206
+ line = Mustache.render(format[:item], issue.merge(issue[:fields]))
207
+ #### Trim length?
208
+ if format[:order].last == name
209
+ line[0..cWR]
210
+ else
211
+ line[0..cW]
212
+ end
213
+ end
214
+ end
215
+
216
+ #### Print
217
+ if format.has_key?(:usetable) and format[:usetable] then
218
+ # Table type
219
+ #### Pad
220
+ longest = formatted.values.map{|l| l.length}.max
221
+ formatted.each_pair do |name, issues|
222
+ if issues.length <= longest then
223
+ issues.fill(' ', issues.length .. longest)
224
+ end
225
+ end
226
+
227
+ #### Transpose
228
+ rows = format[:order].map{|n| formatted[n]}.transpose
229
+ puts Terminal::Table.new :headings => format[:order], :rows=>rows
230
+
231
+ else
232
+ # List type
233
+ format[:order].each do |columnName|
234
+ puts Mustache.render(format[:heading], :column => columnName.to_s)
235
+ formatted[columnName].each {|issue| puts issue}
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+ alias_command :status, :kanban, '--style', 'status'
242
+
243
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,39 @@
1
+ require 'chronic_duration'
2
+ require 'date'
3
+ require 'JiraMule/jiraUtils'
4
+
5
+ command :logwork do |c|
6
+ c.syntax = 'jm logwork [options] <key> <time spent...>'
7
+ c.summary = 'Log work spent'
8
+ c.description = %{Log time spent on a issue}
9
+ c.option '-m', '--message MSG', String, 'Message to add to work log'
10
+ c.option '--date DATE', String, 'When this work was done'
11
+ c.example 'Log some work done on an issue', %{jm logwork BUG-42 1h 12m}
12
+
13
+ c.action do |args, options|
14
+ options.default :message => ''
15
+ jira = JiraMule::JiraUtils.new(args, options)
16
+
17
+ key = jira.expandKeys(args).shift
18
+ ts = ChronicDuration.parse(args.join(' '))
19
+
20
+ unless options.date.nil? then
21
+ options.date = DateTime.parse(options.date)
22
+ if options.date.day_fraction.numerator == 0 then
23
+ # No time component. Need to add timezone...
24
+ offset = -(Time.now.gmt_offset/3600)
25
+ options.date += Rational(offset,24)
26
+ end
27
+ end
28
+
29
+ begin
30
+ jira.logWork(key, ts, options.message, options.date)
31
+ rescue JiraUtilsException => e
32
+ pp e.response.body
33
+ end
34
+
35
+ end
36
+ end
37
+ alias_command :lw, :logwork
38
+
39
+ # vim: set et sw=2 ts=2 :
@@ -0,0 +1,89 @@
1
+ require 'vine'
2
+ require 'pp'
3
+ require 'JiraMule/jiraUtils'
4
+
5
+ command :next do |c|
6
+ c.syntax = 'jm next [options] [keys]'
7
+ c.summary = 'Move issue to the next state'
8
+ c.description = %{
9
+ Move to the next state. For states with multiple exits, use the 'preferred' one.
10
+ }
11
+ c.example 'Move BUG-4 into the next state.', %{jm next BUG-4}
12
+ c.option '--[no-]save-next', %{Save transition as preferred}
13
+ c.option '--force-choice', %{Always show menu of transitions (if more than one)}
14
+
15
+ c.action do |args, options|
16
+ jira = JiraMule::JiraUtils.new(args, options)
17
+
18
+ # keys can be with or without the project prefix.
19
+ keys = jira.expandKeys(args)
20
+ jira.printVars(:keys=>keys)
21
+ return if keys.empty?
22
+
23
+ keys.each do |key|
24
+ # First see if there is a single exit. If so, just do that.
25
+ trans = jira.transitionsFor(key)
26
+ if trans.length == 1 then
27
+ id = trans.first[:id]
28
+ jira.verbose "Taking single exit: '#{trans.first[:name]}'"
29
+ jira.transition(key, id)
30
+
31
+ else
32
+ # If more than one:
33
+
34
+ # Need to know the name of the state we are currently in
35
+ #query = "assignee = #{jira.username} AND project = #{jira.project} AND "
36
+ query = "key = #{key}"
37
+ issues = jira.getIssues(query, ["status"])
38
+ raise "Cannot find #{key}" if issues.empty?
39
+ at = issues.first.access('fields.status.name')
40
+
41
+ unless options.force_choice then
42
+ # If a preferred transition is set, use that
43
+ nxt = $cfg["next-preferred.#{at}"]
44
+ unless nxt.nil? then
45
+ direct = trans.select {|item| jira.fuzzyMatchStatus(item, nxt) }
46
+ unless direct.empty? then
47
+ id = direct.first[:id]
48
+ jira.verbose "Taking preferred exit #{key} to #{direct.first['name']} (#{id})"
49
+ jira.transition(key, id)
50
+ exit
51
+ end
52
+ end
53
+
54
+ # Filter ignored transitions; If only one left, goto it.
55
+ skiplist = $cfg['next.ignore'] || []
56
+ check = trans.reject{|t| skiplist.include? t[:name] }
57
+ if check.length == 1 then
58
+ id = check.first[:id]
59
+ jira.verbose "Taking filtered single exit: '#{check.first[:name]}'"
60
+ jira.transition(key, id)
61
+ exit
62
+ end
63
+ end
64
+
65
+ # Otherwise, ask which transition to use.
66
+ # - save that as preferred
67
+ # - goto it.
68
+ choose do |menu|
69
+ menu.prompt = "Follow which transition?"
70
+ trans.each do |tr|
71
+ menu.choice(tr[:name]) do
72
+ if options.save_next then
73
+ $cfg.set("next-preferred.#{at}", tr[:name], :project)
74
+ end
75
+ jira.verbose "Transitioning #{key} to #{tr[:name]} (#{tr[:id]})"
76
+ jira.transition(key, tr[:id])
77
+ end
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ end #keys.each
84
+ end
85
+ end
86
+
87
+
88
+ # vim: set sw=2 ts=2 :
89
+
@@ -0,0 +1,68 @@
1
+ require 'date'
2
+ require 'terminal-table'
3
+ require 'vine'
4
+ require 'JiraMule/jiraUtils'
5
+
6
+ command :progress do |c|
7
+ c.syntax = 'jm progress [options] [<key>]'
8
+ c.summary = 'Show progress on issues'
9
+ c.description = %{}
10
+ # Show only overdue (today > duedate)
11
+ # Show only unstarted (timespent == 0)
12
+ # Show only Started (timespent > 0)
13
+ c.option '-s', '--status STATUSES', Array, %{Which status to limit to. (default is "In Progress")}
14
+
15
+ c.example 'Show how current project is going', %{jm progress}
16
+ c.example 'Show how work on task 5 is going', %{jm progress 5}
17
+
18
+ c.action do |args, options|
19
+ options.default :status=>[]
20
+
21
+ jira = JiraMule::JiraUtils.new(args, options)
22
+ keys = jira.expandKeys(args)
23
+ if keys.empty? and options.status.empty? then
24
+ options.status << 'In Progress'
25
+ end
26
+
27
+ query = []
28
+ query << %{assignee = #{jira.username}}
29
+ query << %{project = #{jira.project}} if keys.empty?
30
+ unless keys.empty? then
31
+ query << '(' + keys.map{|k| "key=#{k}"}.join(' OR ') + ')'
32
+ end
33
+ unless options.status.empty? then
34
+ query << '(' + options.status.map{|s| %{status="#{s}"}}.join(' OR ') + ')'
35
+ end
36
+ query = query.join(' AND ')
37
+
38
+ #jira.printVars(:q=>query)
39
+ progresses = jira.getIssues(query, ['key', 'workratio', 'aggregatetimespent',
40
+ 'duedate', 'aggregatetimeoriginalestimate'])
41
+
42
+ rows = progresses.map do |issue|
43
+ estimate = (issue.access('fields.aggregatetimeoriginalestimate') or 0)/3600.0
44
+ progress = (issue.access('fields.aggregatetimespent') or 0)/3600.0
45
+ due = issue.access('fields.duedate')
46
+ percent = issue.access('fields.workratio')
47
+ if percent < 0 then
48
+ estimate = progress if estimate == 0
49
+ percent = (progress / estimate * 100).floor
50
+ end
51
+ ret = [ issue[:key], "%.2f"%[estimate], "%.2f"%[progress],
52
+ %{#{"%.1f"%[percent]}%}, due ]
53
+ if progress > estimate or (not due.nil? and Date.new >= Date.parse(due)) then
54
+ ret.map!{|v| HighLine.color((v or ''), :bold)}
55
+ end
56
+ ret
57
+ end.sort{|a,b| a[0].sub(/^\D+(\d+)$/,'\1').to_i <=> b[0].sub(/^\D+(\d+)$/,'\1').to_i }
58
+
59
+ tbl = Terminal::Table.new :headings=>[:key, :estimated, :progress, :percent, :due], :rows=>rows
60
+ tbl.align_column(1, :right)
61
+ tbl.align_column(2, :right)
62
+ tbl.align_column(3, :right)
63
+ puts tbl
64
+
65
+ end
66
+ end
67
+
68
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,80 @@
1
+ require 'terminal-table'
2
+ require 'mustache'
3
+
4
+ command :query do |c|
5
+ c.syntax = 'jm query [options] query'
6
+ c.summary = 'Get the keys from a jira query'
7
+ c.description = 'Run a query. '
8
+ c.example 'Get Open issues and dump everything', %{jm query status=Open --fields "" --json}
9
+ c.option '--[no-]raw', 'Do not prefix query with project and assignee'
10
+ c.option '--[no-]json', 'Output json reply instead of summary'
11
+ c.option '--fields FIELDS', Array, 'Which fields to return.'
12
+ c.option '--all_fields', 'Return all fields'
13
+ c.option '--format STYLE', String, 'Format for keys'
14
+ c.option '--style STYLE', String, 'Which style to use'
15
+
16
+ c.action do |args, options|
17
+ options.default :json => false, :all_fields => false, :style => 'basic'
18
+
19
+ allOfThem = {
20
+ :basic => {
21
+ :fields => [:key, :summary],
22
+ :format => %{{{key}} {{summary}}},
23
+ },
24
+ :info => {
25
+ :fields => [:key, :description, :assignee, :reporter, :priority, :issuetype,
26
+ :status, :resolution, :votes, :watches],
27
+ :format => %{{{key}}
28
+ Reporter: {{reporter.displayName}}
29
+ Assignee: {{assignee.displayName}}
30
+ Type: {{issuetype.name}} ({{priority.name}})
31
+ Status: {{status.name}} (Resolution: {{resolution.name}})
32
+ Watches: {{watches.watchCount}} Votes: {{votes.votes}}
33
+ Description: {{description}}
34
+ }
35
+ },
36
+ }
37
+
38
+ theStyle = allOfThem[options.style.to_sym]
39
+ theStyle[:fields] = options.fields if options.fields
40
+
41
+ jira = JiraMule::JiraUtils.new(args, options)
42
+ args.unshift("assignee = #{jira.username} AND") unless options.raw
43
+ args.unshift("project = #{jira.project} AND") unless options.raw
44
+ q = args.join(' ')
45
+ if options.all_fields then
46
+ issues = jira.getIssues(q, [])
47
+ else
48
+ issues = jira.getIssues(q, theStyle[:fields])
49
+ end
50
+ if options.json then
51
+ puts JSON.dump(issues)
52
+ else
53
+
54
+ format = theStyle[:format]
55
+ keys = issues.map do |issue|
56
+ Mustache.render(format, issue.merge(issue[:fields]))
57
+ end
58
+ keys.each {|k| puts k}
59
+
60
+
61
+
62
+
63
+ # headers = [:key]
64
+ # rows = issues.map do |item|
65
+ # rw = [item[:key]]
66
+ # item[:fields].each_pair do |fname, fvalue|
67
+ # headers << fname unless headers.include? fname
68
+ # rw << fvalue
69
+ # end
70
+ # rw
71
+ # end
72
+ #
73
+ # puts Terminal::Table.new :headings => headers, :rows=>rows
74
+
75
+ end
76
+ end
77
+ end
78
+ alias_command :q, :query
79
+
80
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,44 @@
1
+
2
+ command :release do |c|
3
+ c.syntax = 'jm release [options]'
4
+ c.summary = 'Little tool for releasing a version in Jira'
5
+ c.description = ''
6
+ c.example 'description', 'command example'
7
+ c.option '--some-switch', 'Some switch that does something'
8
+ c.action do |args, options|
9
+ # Do something or c.when_called Jira::Commands::Release
10
+
11
+ version = GitUtils.getVersion
12
+ newver = ask("\033[1m=?\033[0m Enter the version you want to release (#{version}) ")
13
+ version = newver unless newver == ''
14
+
15
+ project = $cfg['jira.project']
16
+ jira = JiraUtils.new(args, options)
17
+
18
+ jira.createVersion(project, version)
19
+
20
+ ### Find all unreleased issues
21
+ query ="assignee = #{jira.username} AND project = #{project} AND (status = Resolved OR status = Closed) AND fixVersion = EMPTY"
22
+ keys = jira.getIssues(query).map {|item| item['key'] }
23
+ printVars({:keys=>keys})
24
+
25
+ ### Mark issues as fixed by version
26
+ updt = { 'fixVersions'=>[{'add'=>{'name'=>version}}] }
27
+ jira.updateKeys(keys, updt)
28
+
29
+ ### This is old process residue. So should consider removing
30
+ if $cfg['jira.alsoClose'] == true
31
+ puts "Also closing." if options.verbose
32
+ query = "assignee = #{jira.username} AND project = #{project} AND status = Resolved AND fixVersion != EMPTY"
33
+ keys = jira.getIssues(query).map {|item| item['key'] }
34
+ printVars({:Rkeys=>keys})
35
+
36
+ if !keys.empty?
37
+ jira.transition(keys, 'Closed')
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+
44
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,68 @@
1
+
2
+ def printErr(msg)
3
+ $stdout.print("\033[1m=!\033[0m ")
4
+ $stdout.print(msg)
5
+ $stdout.print("\n")
6
+ end
7
+
8
+ command :testReady do |c|
9
+ c.syntax = 'jm testReady [options] [version]'
10
+ c.summary = 'Little tool for setting the fix version on testable issues'
11
+ c.description = %{On all issues in the Testing state, set the fix version and optionally reassign.
12
+ }
13
+ c.example 'Set the release version to the latest git tag', %{jm testReady}
14
+ c.example 'Set the release version to "v2.0"', %{jm testReady v2.0}
15
+ c.example 'Also reassign to the default', %{jm testReady -r v2.0}
16
+ c.example 'Also reassign to BOB', %{jm testReady v2.0 --assign BOB}
17
+ c.option '-r', '--[no-]reassign', 'Also reassign to Default'
18
+ c.option '-a', '--assign USER', 'Assign to USER'
19
+ c.action do |args, options|
20
+ options.default :reassign => false
21
+
22
+ if args[0].nil? then
23
+ version = GitUtils.getVersion
24
+ newver = ask("\033[1m=?\033[0m Enter the version you want to release (#{version}) ")
25
+ version = newver unless newver == ''
26
+ else
27
+ version = args[0]
28
+ end
29
+
30
+ jira = JiraUtils.new(args, options)
31
+ project = jira.project
32
+
33
+ if !options.assign.nil? then
34
+ users = jira.checkUser(options.assign)
35
+ if users.length > 1 then
36
+ printErr "User name '#{options.assign}' is ambigious."
37
+ printVars('Could be'=>users)
38
+ exit 4
39
+ end
40
+ if users.length <= 0 then
41
+ printErr "No users match #{options.assign}"
42
+ exit 4
43
+ end
44
+ options.assign = users[0]
45
+ printVars(:assign=>options.assign)
46
+ end
47
+
48
+ jira.createVersion(project, version)
49
+
50
+ ### Find all unreleased issues
51
+ query ="assignee = #{jira.username} AND project = #{project} AND status = Testing"
52
+ keys = jira.getIssues(query).map {|item| item['key'] }
53
+ printVars({:keys=>keys})
54
+
55
+ ### Mark issues as fixed by version
56
+ updt = { 'fixVersions'=>[{'add'=>{'name'=>version}}] }
57
+ ## assign to '-1' to have Jira automatically assign it
58
+ updt['assignee'] = [{'set'=>{'name'=>'-1'}}] if options.reassign
59
+ updt['assignee'] = [{'set'=>{'name'=>options.assign}}] if options.assign
60
+
61
+ printVars(:update=>updt) if options.verbose
62
+
63
+ jira.updateKeys(keys, updt)
64
+
65
+ end
66
+ end
67
+
68
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,20 @@
1
+ require 'JiraMule/commands/assign'
2
+ require 'JiraMule/commands/attach'
3
+ require 'JiraMule/commands/config'
4
+ require 'JiraMule/commands/githubImport'
5
+ require 'JiraMule/commands/goto'
6
+ require 'JiraMule/commands/kanban'
7
+ require 'JiraMule/commands/link'
8
+ require 'JiraMule/commands/logWork'
9
+ require 'JiraMule/commands/next'
10
+ require 'JiraMule/commands/progress'
11
+ require 'JiraMule/commands/query'
12
+ require 'JiraMule/commands/timesheet'
13
+
14
+ #require 'JiraMule/commands/release'
15
+ #require 'JiraMule/commands/testReady'
16
+ # difference between testReady and release is two things:
17
+ # 1. testReady also assigns
18
+ # 2. release also transitions
19
+ #
20
+ # So, merge all that into one command and have the parts be --options; maybe
@@ -0,0 +1,11 @@
1
+
2
+
3
+ class GitUtils
4
+
5
+ def self.getVersion
6
+ tag = `git for-each-ref --sort=taggerdate --format '%(refname)' refs/tags | head -1`.chomp
7
+ return tag.split('/').last
8
+ end
9
+ end
10
+
11
+ # vim: set sw=4 ts=4 :