jiraMule 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +17 -0
- data/LICENSE +22 -0
- data/README.md +37 -0
- data/Rakefile +95 -0
- data/TODO.taskpaper +6 -0
- data/bin/jm +87 -0
- data/jiraMule.gemspec +43 -0
- data/lib/JiraMule/Tempo.rb +75 -0
- data/lib/JiraMule/commands/assign.rb +38 -0
- data/lib/JiraMule/commands/githubImport.rb +46 -0
- data/lib/JiraMule/commands/link.rb +41 -0
- data/lib/JiraMule/commands/timesheet.rb +113 -0
- data/lib/JiraMule/gb.rb +33 -0
- data/lib/JiraMule.rb +7 -0
- data/lib/jiraMule/Config.rb +224 -0
- data/lib/jiraMule/Passwords.rb +81 -0
- data/lib/jiraMule/commands/attach.rb +69 -0
- data/lib/jiraMule/commands/config.rb +68 -0
- data/lib/jiraMule/commands/goto.rb +166 -0
- data/lib/jiraMule/commands/kanban.rb +243 -0
- data/lib/jiraMule/commands/logWork.rb +39 -0
- data/lib/jiraMule/commands/next.rb +89 -0
- data/lib/jiraMule/commands/progress.rb +68 -0
- data/lib/jiraMule/commands/query.rb +80 -0
- data/lib/jiraMule/commands/release.rb +44 -0
- data/lib/jiraMule/commands/testReady.rb +68 -0
- data/lib/jiraMule/commands.rb +20 -0
- data/lib/jiraMule/gitUtils.rb +11 -0
- data/lib/jiraMule/http.rb +147 -0
- data/lib/jiraMule/jiraUtils.rb +288 -0
- data/lib/jiraMule/verbosing.rb +28 -0
- data/lib/jiraMule/version.rb +3 -0
- metadata +268 -0
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
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 :
|
data/lib/JiraMule/gb.rb
ADDED
@@ -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 :
|