jiraMule 0.1.2 → 0.3.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/Gemfile +2 -1
- data/README.md +2 -2
- data/Rakefile +20 -3
- data/TODO.taskpaper +0 -1
- data/jiraMule.gemspec +4 -2
- data/lib/JiraMule.rb +4 -2
- data/lib/JiraMule/StyleLoader.rb +323 -0
- data/lib/JiraMule/commands.rb +11 -0
- data/lib/{jiraMule → JiraMule}/commands/kanban.rb +30 -40
- data/lib/JiraMule/commands/open.rb +27 -0
- data/lib/JiraMule/commands/query.rb +74 -0
- data/lib/JiraMule/commands/statuses.rb +30 -0
- data/lib/{jiraMule → JiraMule}/jiraUtils.rb +19 -10
- data/lib/JiraMule/renderMagic.rb +30 -0
- data/lib/jiraMule/commands/goto.rb +0 -55
- data/lib/jiraMule/commands/logWork.rb +12 -8
- data/lib/jiraMule/http.rb +1 -1
- data/lib/jiraMule/version.rb +1 -1
- metadata +72 -46
- data/lib/JiraMule/Tempo.rb +0 -75
- data/lib/JiraMule/commands/githubImport.rb +0 -46
- data/lib/JiraMule/commands/timesheet.rb +0 -116
- data/lib/jiraMule/commands.rb +0 -20
- data/lib/jiraMule/commands/progress.rb +0 -68
- data/lib/jiraMule/commands/query.rb +0 -80
- data/lib/jiraMule/commands/release.rb +0 -44
- data/lib/jiraMule/commands/testReady.rb +0 -68
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'octokit'
|
2
|
-
|
3
|
-
command 'github import' do |c|
|
4
|
-
c.syntax = %{jm github import <issue id>}
|
5
|
-
c.summary = %{Import a Github issue into Jira}
|
6
|
-
|
7
|
-
c.action do |args, options|
|
8
|
-
|
9
|
-
iid = args.shift
|
10
|
-
|
11
|
-
okey = $cfg['github.token']
|
12
|
-
if okey.nil? then
|
13
|
-
say_error "Missing github token!"
|
14
|
-
exit 2
|
15
|
-
end
|
16
|
-
|
17
|
-
oc = Octokit::Client.new(:access_token => okey)
|
18
|
-
if oc.nil? then
|
19
|
-
exit 3
|
20
|
-
end
|
21
|
-
oc.login
|
22
|
-
|
23
|
-
repo = oc.repo $cfg['github.project']
|
24
|
-
rel = repo.rels[:issues]
|
25
|
-
gissue = rel.get(:uri=>{:number=>iid})
|
26
|
-
if gissue.status != 200 then
|
27
|
-
say_error "Failed to get issue: #{gissue}"
|
28
|
-
exit 2
|
29
|
-
end
|
30
|
-
gissue = gissue.data
|
31
|
-
|
32
|
-
jira = JiraMule::JiraUtils.new(args, options)
|
33
|
-
# Create Issue
|
34
|
-
it = jira.checkIssueType
|
35
|
-
|
36
|
-
jissue = jira.createIssue(it.first[:name], gissue[:title], gissue[:body])
|
37
|
-
jira.verbose "Created #{jissue[:key]}"
|
38
|
-
|
39
|
-
# Link
|
40
|
-
jira.linkTo(jissue[:key], gissue[:html_url], gissue[:title])
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|
44
|
-
alias_command :ghi, 'github import'
|
45
|
-
|
46
|
-
# vim: set ai et sw=2 ts=2 :
|
@@ -1,116 +0,0 @@
|
|
1
|
-
require 'chronic_duration'
|
2
|
-
require 'date'
|
3
|
-
require 'terminal-table'
|
4
|
-
require 'vine'
|
5
|
-
require 'JiraMule/jiraUtils'
|
6
|
-
require 'JiraMule/Tempo'
|
7
|
-
|
8
|
-
command :timesheet do |c|
|
9
|
-
c.syntax = 'jm timesheet [options]'
|
10
|
-
c.summary = 'Show work done this week'
|
11
|
-
c.description = %{Show the work done this week
|
12
|
-
}
|
13
|
-
c.example 'Show work done this week', 'jm timesheet'
|
14
|
-
c.example 'Show work done for project', 'jm timesheet --project DEV'
|
15
|
-
c.example 'Show work done for projects', 'jm timesheet --project DEV,PROD'
|
16
|
-
c.example 'Show work done for keys', 'jm timesheet 12 PROD-15 99 STG-6'
|
17
|
-
|
18
|
-
c.option '--project PROJECTS', Array, 'Limit results to specific projects'
|
19
|
-
|
20
|
-
#c.option '--prev COUNT', Integer, 'Look at previous weeks'
|
21
|
-
c.option '--starts_on DAY', String, 'Which day does the week start on'
|
22
|
-
|
23
|
-
c.action do |args, options|
|
24
|
-
options.default :starts_on => 'Mon'
|
25
|
-
|
26
|
-
jira = JiraMule::JiraUtils.new
|
27
|
-
tempo = JiraMule::Tempo.new
|
28
|
-
|
29
|
-
#Days Of Week
|
30
|
-
dows = [:Sun,:Mon,:Tue,:Wed,:Thu,:Fri,:Sat]
|
31
|
-
dayShift = dows.index{|i| options.starts_on.downcase.start_with? i.to_s.downcase}
|
32
|
-
workweek = dows.rotate dayShift
|
33
|
-
|
34
|
-
dayTo = Date.today
|
35
|
-
dayFrom = dayTo
|
36
|
-
while not dayFrom.wday == dayShift do
|
37
|
-
dayFrom = dayFrom.prev_day
|
38
|
-
end
|
39
|
-
while not dayTo.wday == (7-dayShift) do
|
40
|
-
dayTo = dayTo.next_day
|
41
|
-
end
|
42
|
-
|
43
|
-
# Get keys to get worklogs from
|
44
|
-
keys = jira.expandKeys(args)
|
45
|
-
if keys.empty? then
|
46
|
-
query = %{worklogAuthor = #{jira.username}}
|
47
|
-
query << %{ AND worklogDate >= #{dayFrom.iso8601}}
|
48
|
-
|
49
|
-
if options.project and not options.project.empty? then
|
50
|
-
query << ' AND ('
|
51
|
-
query << options.project.map{|p| %{project="#{p}"}}.join(' OR ')
|
52
|
-
query << ')'
|
53
|
-
end
|
54
|
-
|
55
|
-
keys = jira.getIssues(query, ['key']).map{|k| k[:key]}
|
56
|
-
end
|
57
|
-
jira.printVars(:keys=>keys) if $cfg['tool.verbose']
|
58
|
-
|
59
|
-
wls = tempo.workLogs(jira.username, dayFrom.iso8601, dayTo.iso8601)
|
60
|
-
|
61
|
-
# filter out entries not in keys.
|
62
|
-
selected = wls.select{|i| keys.include? i.access('issue.key')}
|
63
|
-
|
64
|
-
# build table; each row is a key. each column is hours worked in SSMTWTF
|
65
|
-
# multiple passes.
|
66
|
-
# 1: build hash by issue, each value is a hash by week day.
|
67
|
-
hrows = {}
|
68
|
-
selected.each do |isu|
|
69
|
-
k = isu.access('issue.key')
|
70
|
-
hrows[k] = {} unless hrows.has_key? k
|
71
|
-
ds = DateTime.parse(isu[:dateStarted]).to_date
|
72
|
-
dow = dows[ds.wday]
|
73
|
-
hrows[k][dow] = 0 unless hrows[k].has_key?(dow)
|
74
|
-
hrows[k][dow] += isu[:timeSpentSeconds]
|
75
|
-
end
|
76
|
-
|
77
|
-
totals = Hash[ *(workweek.map{|i| [i,0]}.flatten) ]
|
78
|
-
# 2: reshape into Array or Arrays.
|
79
|
-
rows = hrows.to_a.map do |row|
|
80
|
-
# row[0] is key, want to keep that.
|
81
|
-
# row[1] is a hash we want to sort and flatten.
|
82
|
-
row[1] = workweek.map do |d|
|
83
|
-
s = row[1][d]
|
84
|
-
if s.nil? then
|
85
|
-
nil
|
86
|
-
else
|
87
|
-
totals[d] += s
|
88
|
-
ChronicDuration.output(s, :format=>:short)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
row.flatten
|
92
|
-
end
|
93
|
-
|
94
|
-
trow = workweek.map do |d|
|
95
|
-
s = totals[d]
|
96
|
-
if s.nil? then
|
97
|
-
nil
|
98
|
-
else
|
99
|
-
ChronicDuration.output(s, :format=>:short)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
trow.insert(0, 'TOTALS:')
|
103
|
-
|
104
|
-
hdr = workweek.insert(0, :Key)
|
105
|
-
table = Terminal::Table.new do |t|
|
106
|
-
t.headings = hdr
|
107
|
-
t.rows = rows
|
108
|
-
t.add_separator
|
109
|
-
t.add_row trow
|
110
|
-
end
|
111
|
-
puts table
|
112
|
-
end
|
113
|
-
end
|
114
|
-
alias_command :ts, :timesheet
|
115
|
-
|
116
|
-
# vim: set sw=2 ts=2 :
|
data/lib/jiraMule/commands.rb
DELETED
@@ -1,20 +0,0 @@
|
|
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
|
@@ -1,68 +0,0 @@
|
|
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 :
|
@@ -1,80 +0,0 @@
|
|
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 :
|
@@ -1,44 +0,0 @@
|
|
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 :
|
@@ -1,68 +0,0 @@
|
|
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 :
|