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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d008f2c8e0cba19fd13ccd63a83a5a7b7781fb0c
4
+ data.tar.gz: 3c9b22e555541db99d55a69d053248119ef90a28
5
+ SHA512:
6
+ metadata.gz: 031b45942d961a29fe74eb7df4ca9bd0b11a5c6c094208ee849b71267ec5146d209ee82575a224fda9ca7e8021409541326a3f8e7db8171f80f0e9768d8be602
7
+ data.tar.gz: 76e18cfc740fae51ec9554cbe4d603a230fd93dc0a86ef9f0ee43467ec8b8bb3cab3bc09c7d0fea61f6a4f8ac70df6943e6c1621ee0c6be542ddc3c4ca05948b
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ .DS_Store
2
+ .AppleDouble
3
+ .LSOverride
4
+ Icon
5
+ *.sw[a-z]
6
+ cookies
7
+ .jiraProject
8
+ .rpjProject
9
+ .jiramulerc
10
+ jiraMule-*.gem
11
+ tags
12
+
13
+ xcuserdata
14
+ Pods/
15
+
16
+ # Thumbnails
17
+ ._*
18
+
19
+ # Files that might appear on external disk
20
+ .Spotlight-V100
21
+ .Trashes
22
+
23
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'chronic_duration'
6
+ gem 'commander'
7
+ gem 'inifile', '~> 3.0'
8
+ gem 'mime-types', '~> 1.25.1'
9
+ gem 'mime-types-data', '~> 3.2016'
10
+ gem 'multipart-post'
11
+ gem 'mustache'
12
+ gem "octokit", "~> 4.0"
13
+ gem 'terminal-table'
14
+ gem 'vine'
15
+ gem 'zip'
16
+
17
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 michael conrad tadpol tilstra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # jiraMule
2
+
3
+ ## Install
4
+
5
+ ### From source
6
+ ```
7
+ > bundler install
8
+ > rake install
9
+ ```
10
+
11
+ ### By Gem
12
+ ```
13
+ > gem install JiraMule
14
+ ```
15
+
16
+ ## Setup
17
+
18
+ You need to set a few config keys before anyhting really works.
19
+
20
+ Globally:
21
+ ```
22
+ jm config net.url <URL to your Jira> --user
23
+ jm config user.name <Your account name in Jira> --user
24
+ ```
25
+
26
+ Then in each project directory:
27
+ ```
28
+ jm config jira.project <Project ID>
29
+ ```
30
+
31
+ (you could add that to your user config too if you wanted.)
32
+
33
+
34
+ #### Jira API Docs
35
+
36
+ [https://docs.atlassian.com/jira/REST/6.4.7/][]
37
+
data/Rakefile ADDED
@@ -0,0 +1,95 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ #task :default => []
4
+
5
+ tagName = "v#{Bundler::GemHelper.gemspec.version}"
6
+ gemName = "jiraMule-#{Bundler::GemHelper.gemspec.version}.gem"
7
+ builtGem = "pkg/#{gemName}"
8
+
9
+ desc "Install gem in user dir"
10
+ task :bob do
11
+ sh %{gem install --user-install #{builtGem}}
12
+ end
13
+
14
+ desc "Uninstall from user dir"
15
+ task :unbob do
16
+ sh %{gem uninstall --user-install #{builtGem}}
17
+ end
18
+
19
+ task :echo do
20
+ puts tagName
21
+ puts gemName
22
+ puts builtGem
23
+ end
24
+
25
+ namespace :git do
26
+ desc "Push only develop, master, and tags to origin"
27
+ task :origin do
28
+ sh %{git push origin develop}
29
+ sh %{git push origin master}
30
+ sh %{git push origin --tags}
31
+ end
32
+
33
+ # desc "Push only develop, master, and tags to upstream"
34
+ # task :upstream do
35
+ # sh %{git push upstream develop}
36
+ # sh %{git push upstream master}
37
+ # sh %{git push upstream --tags}
38
+ # end
39
+
40
+ desc "Push to origin and upstream"
41
+ task :all => [:origin]
42
+ end
43
+
44
+ task :gemit do
45
+ mrt=Bundler::GemHelper.gemspec.version
46
+ sh %{git checkout v#{mrt}}
47
+ Rake::Task[:build].invoke
48
+ Rake::Task[:bob].invoke
49
+ Rake::Task['push:gem'].invoke
50
+ sh %{git checkout develop}
51
+ end
52
+
53
+ namespace :push do
54
+ desc 'Push gem up to RubyGems'
55
+ task :gem do
56
+ sh %{gem push #{builtGem}}
57
+ end
58
+
59
+ namespace :github do
60
+ desc "Make a release in Github"
61
+ task :makeRelease do
62
+ # ENV['GITHUB_TOKEN'] set by CI.
63
+ # ENV['GITHUB_USER'] set by CI.
64
+ # ENV['GITHUB_REPO'] set by CI
65
+ # Create Release
66
+ sh %{github-release info --tag #{tagName}} do |ok, res|
67
+ if not ok then
68
+ sh %{github-release release --tag #{tagName}}
69
+ end
70
+ end
71
+ end
72
+
73
+ desc 'Push gem up to Github Releases'
74
+ task :gem => [:makeRelease, :build] do
75
+ # ENV['GITHUB_TOKEN'] set by CI.
76
+ # ENV['GITHUB_USER'] set by CI.
77
+ # ENV['GITHUB_REPO'] set by CI
78
+ # upload gem
79
+ sh %{github-release upload --tag #{tagName} --name #{gemName} --file #{builtGem}}
80
+ end
81
+ end
82
+ end
83
+
84
+ task :run do
85
+ sh %{ruby -Ilib bin/jm }
86
+ end
87
+
88
+ desc "Prints a cmd to test this in another directory"
89
+ task :testwith do
90
+ pwd=Dir.pwd.sub(Dir.home, '~')
91
+ puts "ruby -I#{pwd}/lib #{pwd}/bin/jm "
92
+ end
93
+
94
+
95
+ # vim: set sw=4 ts=4 :
data/TODO.taskpaper ADDED
@@ -0,0 +1,6 @@
1
+
2
+ New commands:
3
+ - 'comment' for adding a comment. If no '-m' then open $EDITOR
4
+ - 'assign' Assign to another user.
5
+
6
+
data/bin/jm ADDED
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'commander/import'
5
+ require 'JiraMule'
6
+ require 'pp'
7
+ require 'json'
8
+
9
+ Signal.trap('INT', 'EXIT') # Don't drop traces on ^C
10
+
11
+ program :version, JiraMule::VERSION
12
+ program :description, %{A collection of things that I do with jira.
13
+
14
+ Many of which are either big batch operations, or need bits of info from
15
+ the command line. All of which turn out to be better handled as a command
16
+ line app.
17
+
18
+ This very specifically does not try to be a generic jira tool; those exist
19
+ already. Rather this is specific to things I need.
20
+ }
21
+ global_option('-V', '--verbose', 'Be chatty') {
22
+ $cfg['tool.verbose'] = true
23
+ }
24
+ global_option('-n', '--dry', "Don't run actions that make changes") {
25
+ $cfg['tool.dry'] = true
26
+ $cfg['tool.verbose'] = true # dry implies verbose
27
+ }
28
+ #global_option('--username USERNAME') {|un|
29
+ # $cfg['jira.userpass'] = un
30
+ #}
31
+ #global_option('--project PROJECT', "Which project to use") {|project|
32
+ # $cfg['jira.project'] = project
33
+ #}
34
+ #global_option('--url URL', "Set jira base url") {|url|
35
+ # $cfg['jira.url'] = url
36
+ #}
37
+ global_option('-L', '--curl', 'Print out a curl command for each network call') {
38
+ $cfg['tool.curldebug'] = true
39
+ }
40
+ global_option '--skip-plugins', %{Don't load plugins. Good for when one goes bad.}
41
+
42
+ global_option('-C', '--configfile FILE', %{Load additional configuration file}) {|file|
43
+ # this is called after all of the top level code in this file.
44
+ $cfg.load_specific(file)
45
+ }
46
+ global_option('-c', '--config KEY=VALUE', %{Set a single config key}) {|param|
47
+ key, value = param.split('=', 2)
48
+ # a=b :> ["a","b"]
49
+ # a= :> ["a",""]
50
+ # a :> ["a"]
51
+ raise "Bad config '#{param}'" if key.nil?
52
+ if value.nil? then
53
+ $cfg[key] = 'true'
54
+ else
55
+ $cfg[key] = value
56
+ end
57
+ }
58
+
59
+ default_command :help
60
+
61
+ $cfg = JiraMule::Config.new
62
+ $cfg.load
63
+
64
+ # Look for plug-ins
65
+ pgds = [
66
+ Pathname.new(Dir.home) + '.jiramule' + 'plugins'
67
+ ]
68
+ # Add plugin dirs from configs
69
+ # This is run before the command line options are parsed, so need to check old way.
70
+ if not ARGV.include? '--skip-plugins' then
71
+ pgds << Pathname.new(ENV['JIRAMULE_PLUGIN_DIR']) if ENV.has_key? 'JIRAMULE_PLUGIN_DIR'
72
+ pgds.each do |path|
73
+ next unless path.exist?
74
+ path.each_child do |plugin|
75
+ next if plugin.directory?
76
+ next unless plugin.readable?
77
+ next if plugin.basename.fnmatch('.*') # don't read anything starting with .
78
+ begin
79
+ require plugin.to_s
80
+ rescue Exception => e
81
+ $stderr.puts "Failed to load plugin at #{plugin} because #{e}"
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ # vim: set sw=2 ts=2 :
data/jiraMule.gemspec ADDED
@@ -0,0 +1,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
+ require 'jiraMule/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'jiraMule'
7
+ s.version = JiraMule::VERSION
8
+ s.authors = ['Michael Conrad Tadpol Tilstra']
9
+ s.email = ['tadpol@tadpol.org']
10
+ s.license = 'MIT'
11
+ s.homepage = ''
12
+ s.summary = 'A collection of things that I do with jira'
13
+ s.description = %{A collection of things that I do with jira.
14
+
15
+ Many of which are either big batch operations, or need bits of info from
16
+ the command line. All of which turn out to be better handled as a command
17
+ line app.
18
+
19
+ This very specifically does not try to be a generic jira tool; those exist
20
+ already. Rather this is specific to things I need.
21
+ }
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
26
+ s.require_paths = ['lib']
27
+
28
+ s.add_runtime_dependency('chronic_duration', '~> 0.10.6')
29
+ s.add_runtime_dependency('commander', '~> 4.4.0')
30
+ s.add_runtime_dependency('inifile', '~> 3.0')
31
+ s.add_runtime_dependency('mime-types', '~> 1.25.1')
32
+ s.add_runtime_dependency('mime-types-data', '~> 3.2016')
33
+ s.add_runtime_dependency('multipart-post', '~> 2.0.0')
34
+ s.add_runtime_dependency('mustache', '~> 1.0')
35
+ s.add_runtime_dependency('terminal-table', '~> 1.4.5')
36
+ s.add_runtime_dependency('vine', '~> 0.2')
37
+ s.add_runtime_dependency('zip', '~> 2.0.0')
38
+
39
+ s.add_development_dependency('bundler', '~> 1.12.0')
40
+ s.add_development_dependency('rspec', '~> 3.2')
41
+ s.add_development_dependency('rake')
42
+ end
43
+
@@ -0,0 +1,75 @@
1
+ require 'date'
2
+ require 'json'
3
+ require 'pp'
4
+ require 'vine'
5
+ require 'JiraMule/Config'
6
+ require 'JiraMule/Passwords'
7
+ require 'JiraMule/http'
8
+ require 'JiraMule/verbosing'
9
+
10
+ module JiraMule
11
+ class Tempo
12
+ include Verbose
13
+ include Http
14
+
15
+ def initialize()
16
+ acc = Account.new
17
+ up = acc.loginInfo
18
+ @username = up[:email]
19
+ @password = up[:password]
20
+ end
21
+ attr_reader :username, :password
22
+
23
+ def endPoint(path='')
24
+ URI($cfg['net.url'] + '/rest/tempo-timesheets/3/' + path.to_s)
25
+ end
26
+
27
+ # Get worklogs from Tempo plugin
28
+ def workLogs(username=@username, dateFrom=nil, dateTo=nil, project=nil)
29
+ q = {:username => username}
30
+ q[:dateFrom] = DateTime.parse(dateFrom).to_date.iso8601 unless dateFrom.nil?
31
+ q[:dateTo] = DateTime.parse(dateTo).to_date.iso8601 unless dateTo.nil?
32
+ q[:projectKey] = project unless project.nil?
33
+ #q[:accountKey]
34
+ #q[:teamId]
35
+
36
+ verbose "Fetching worklogs for #{q}"
37
+ get('worklogs', q)
38
+ end
39
+
40
+ ## Submit a timesheet for approval.
41
+ def submitForApproval(period=nil, name=@username, comment='')
42
+ if period.nil? then
43
+ # First day of work week
44
+ cur = currentApprovalStatus(nil, name)
45
+ period = cur.access 'period.dateFrom'
46
+ end
47
+ verbose "Submitting timesheet for #{period}"
48
+ post('timesheet-approval/', {
49
+ :user=>{
50
+ :name=>name,
51
+ },
52
+ :period=>{
53
+ :dateFrom=>period,
54
+ },
55
+ :action=>{
56
+ :name=>:submit,
57
+ :comment=>comment,
58
+ }
59
+ }) unless $cfg['tool.dry']
60
+ end
61
+
62
+ def currentApprovalStatus(period=nil, name=@username)
63
+ verbose "Getting current approval status; #{period} #{name}"
64
+ q = {
65
+ :username => name,
66
+ }
67
+ q[:periodStartDate] = period unless period.nil?
68
+
69
+ get('timesheet-approval/current/', q)
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,38 @@
1
+ require 'JiraMule/jiraUtils'
2
+
3
+ command :assign do |c|
4
+ c.syntax = 'jm assign [options] <to user> <keys...> '
5
+ c.summary = 'Assign keys to another user'
6
+
7
+ c.action do |args, options|
8
+
9
+ jira = JiraMule::JiraUtils.new(args, options)
10
+
11
+ muser = args.shift
12
+ if muser == '-1' or muser =~ /^:de/ then
13
+ # assign to default
14
+ to = '-1'
15
+ else
16
+ to = jira.checkUser(muser)
17
+ if to.count > 1 then
18
+ say "Username '#{muser}' is ambigious."
19
+ say "Could be: #{to.join(' ')}"
20
+ exit 4
21
+ elsif to.empty? then
22
+ say "No such user: '#{muser}'"
23
+ exit 4
24
+ end
25
+ to = to.first
26
+ end
27
+
28
+ # keys can be with or without the project prefix.
29
+ keys = jira.expandKeys(args)
30
+
31
+ jira.printVars(:key=>keys, :to=>to)
32
+
33
+ jira.assignTo(keys, to)
34
+
35
+ end
36
+ end
37
+
38
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,46 @@
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 :
@@ -0,0 +1,41 @@
1
+ require 'JiraMule/jiraUtils'
2
+
3
+ command :links do |c|
4
+ c.syntax = %{jm links <keys>}
5
+ c.summary = %{Show all remote links}
6
+
7
+ c.action do |args, options|
8
+ jira = JiraMule::JiraUtils.new(args, options)
9
+ keys = jira.expandKeys(args)
10
+ keys.each do |key|
11
+ jira.remote_links(key).each do |link|
12
+ obj = link[:object]
13
+ unless obj.nil? then
14
+ say "- #{obj[:title]}"
15
+ say " #{obj[:url]}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ command :addLink do |c|
23
+ c.syntax = %{jm addLink <key> <url> <title>}
24
+ c.summary = %{Add a remote link to an issue}
25
+ c.action do |args, options|
26
+ jira = JiraMule::JiraUtils.new(args, options)
27
+ key = jira.expandKeys([args[0]]).first
28
+ url = args[1]
29
+ title = args[2]
30
+ if url.nil? then
31
+ say_error "Missing URL"
32
+ elsif title.nil? then
33
+ say_error "Missing Title"
34
+ else
35
+ jira.linkTo(key, url, title)
36
+ end
37
+ end
38
+ end
39
+ alias_command :link, :addLink
40
+
41
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,113 @@
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
+
40
+ # Get keys to get worklogs from
41
+ keys = jira.expandKeys(args)
42
+ if keys.empty? then
43
+ query = %{worklogAuthor = #{jira.username}}
44
+ query << %{ AND worklogDate >= #{dayFrom.iso8601}}
45
+
46
+ if options.project and not options.project.empty? then
47
+ query << ' AND ('
48
+ query << options.project.map{|p| %{project="#{p}"}}.join(' OR ')
49
+ query << ')'
50
+ end
51
+
52
+ keys = jira.getIssues(query, ['key']).map{|k| k[:key]}
53
+ end
54
+ jira.printVars(:keys=>keys) if $cfg['tool.verbose']
55
+
56
+ wls = tempo.workLogs(jira.username, dayFrom.iso8601, dayTo.iso8601)
57
+
58
+ # filter out entries not in keys.
59
+ selected = wls.select{|i| keys.include? i.access('issue.key')}
60
+
61
+ # build table; each row is a key. each column is hours worked in SSMTWTF
62
+ # multiple passes.
63
+ # 1: build hash by issue, each value is a hash by week day.
64
+ hrows = {}
65
+ selected.each do |isu|
66
+ k = isu.access('issue.key')
67
+ hrows[k] = {} unless hrows.has_key? k
68
+ ds = DateTime.parse(isu[:dateStarted]).to_date
69
+ dow = dows[ds.wday]
70
+ hrows[k][dow] = 0 unless hrows[k].has_key?(dow)
71
+ hrows[k][dow] += isu[:timeSpentSeconds]
72
+ end
73
+
74
+ totals = Hash[ *(workweek.map{|i| [i,0]}.flatten) ]
75
+ # 2: reshape into Array or Arrays.
76
+ rows = hrows.to_a.map do |row|
77
+ # row[0] is key, want to keep that.
78
+ # row[1] is a hash we want to sort and flatten.
79
+ row[1] = workweek.map do |d|
80
+ s = row[1][d]
81
+ if s.nil? then
82
+ nil
83
+ else
84
+ totals[d] += s
85
+ ChronicDuration.output(s, :format=>:short)
86
+ end
87
+ end
88
+ row.flatten
89
+ end
90
+
91
+ trow = workweek.map do |d|
92
+ s = totals[d]
93
+ if s.nil? then
94
+ nil
95
+ else
96
+ ChronicDuration.output(s, :format=>:short)
97
+ end
98
+ end
99
+ trow.insert(0, 'TOTALS:')
100
+
101
+ hdr = workweek.insert(0, :Key)
102
+ table = Terminal::Table.new do |t|
103
+ t.headings = hdr
104
+ t.rows = rows
105
+ t.add_separator
106
+ t.add_row trow
107
+ end
108
+ puts table
109
+ end
110
+ end
111
+ alias_command :ts, :timesheet
112
+
113
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,33 @@
1
+ require 'pp'
2
+
3
+ # You don't need this.
4
+ # To use this:
5
+ # - mkdir -p ~/.jiramule/plugins
6
+ # - ln gb.rb ~/.jiramule/plugins
7
+
8
+ command :_gb do |c|
9
+ c.syntax = %{jm _gb <class> <method> (<args>)}
10
+ c.summary = %{Call internal class methods directly.}
11
+ c.description = %{Call internal class methods directly.}
12
+
13
+ c.action do |args, options|
14
+ cls = args[0]
15
+ meth = args[1].to_sym
16
+ args.shift(2)
17
+
18
+ begin
19
+ gb = Object::const_get("JiraMule::#{cls}").new
20
+ if gb.respond_to? meth then
21
+ pp gb.__send__(meth, *args)
22
+ else
23
+ say_error "'#{cls}' doesn't '#{meth}'"
24
+ end
25
+ rescue Exception => e
26
+ say_error e.message
27
+ pp e
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ # vim: set ai et sw=2 ts=2 :