xfel-timew-jira 0.1.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 +7 -0
- data/lib/xfel/timew/jira.rb +87 -0
- data/lib/xfel/timew/report.rb +68 -0
- data/lib/xfel/timew/table.rb +57 -0
- data/lib/xfel/timew/version.rb +5 -0
- data/lib/xfel_timew_jira.rb +5 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b33fb2e86a1142e590c4031f4be634c61a4fdd08cd4fd938b8cf8082247a288b
|
4
|
+
data.tar.gz: bb36a9c53779cc2795ee732b7871532d4368caf5650b91bea105bae76e28fc83
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c7a3c2af52b6a0fdc66821a6b93f6543bdf3b0a6a599ec913d4427b2378704ad6cedc070c0c159303a443c42a8871f0478e42d4ccb3c65e1cfcd04f671987411
|
7
|
+
data.tar.gz: deba1336520f3fbc02951a1d0303140e6e72086c47e569fa3f7d500b37045dfd6bc0cca5bf046cfd290dbf01789d44aee77e630c3784d7cf482db8c2f3db79bc
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
module Xfel
|
6
|
+
module Timew
|
7
|
+
# Class for REST interaction with Jira servers.
|
8
|
+
class Jira
|
9
|
+
@worklogs = {}
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_reader :worklogs
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(worklog)
|
16
|
+
@start = worklog[:start]
|
17
|
+
@duration = worklog[:duration]
|
18
|
+
@key = worklog[:key]
|
19
|
+
return unless ENV['XFEL_JIRA_SYNC']
|
20
|
+
|
21
|
+
if ENV['JIRA_HOST'] && ENV['JIRA_USER'] && ENV['JIRA_PASS']
|
22
|
+
@uri = "#{ENV['JIRA_HOST']}/rest/api/2/issue/#{@key}/worklog"
|
23
|
+
sync
|
24
|
+
else
|
25
|
+
log 'Missing required env vars: JIRA_HOST, JIRA_USER, JIRA_PASS'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def log(msg)
|
30
|
+
puts "#{@key} | #{msg}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def vars
|
34
|
+
'notifyUsers=false&adjustEstimate=leave&overrideEditableFlag=true'
|
35
|
+
end
|
36
|
+
|
37
|
+
def sync
|
38
|
+
log "#{@start} sync..."
|
39
|
+
if worklogs.any? { |w| duplicated?(w) }
|
40
|
+
log "#{@start} already present, skipping it."
|
41
|
+
else
|
42
|
+
res = req_for_sync
|
43
|
+
log "#{@start} error: #{res.code}. #{res.body}" unless req_success?(res)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def req_success?(response)
|
48
|
+
code_int = response.code.to_i
|
49
|
+
code_int > 199 && code_int < 300
|
50
|
+
end
|
51
|
+
|
52
|
+
def req_for_sync
|
53
|
+
uri = URI("#{@uri}?#{vars}")
|
54
|
+
req = Net::HTTP::Post.new(uri)
|
55
|
+
req['Content-Type'] = 'application/json'
|
56
|
+
req.body = {
|
57
|
+
comment: '', started: @start, timeSpentSeconds: @duration
|
58
|
+
}.to_json
|
59
|
+
execute(req, uri)
|
60
|
+
end
|
61
|
+
|
62
|
+
def duplicated?(worklog)
|
63
|
+
@start == worklog['started']
|
64
|
+
end
|
65
|
+
|
66
|
+
def execute(req, uri)
|
67
|
+
req.basic_auth ENV['JIRA_USER'], ENV['JIRA_PASS']
|
68
|
+
Net::HTTP.start(uri.hostname, uri.port, { use_ssl: true }) { |http| http.request(req) }
|
69
|
+
end
|
70
|
+
|
71
|
+
def fetch_worklogs
|
72
|
+
uri = URI(@uri)
|
73
|
+
res = execute(Net::HTTP::Get.new(uri), uri)
|
74
|
+
unless req_success?(res)
|
75
|
+
log "Error getting worklogs. #{res.code}: #{res.msg}"
|
76
|
+
exit
|
77
|
+
end
|
78
|
+
self.class.worklogs[@key] = JSON.parse(res.body)['worklogs']
|
79
|
+
end
|
80
|
+
|
81
|
+
def worklogs
|
82
|
+
fetch_worklogs unless self.class.worklogs[@key]
|
83
|
+
self.class.worklogs[@key]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'json'
|
5
|
+
require_relative 'jira'
|
6
|
+
require_relative 'table'
|
7
|
+
|
8
|
+
module Xfel
|
9
|
+
module Timew
|
10
|
+
# Main entry point for TimeWarrior report
|
11
|
+
class Report
|
12
|
+
def initialize
|
13
|
+
table = Table.new
|
14
|
+
read.each do |x|
|
15
|
+
worklog = convert(x)
|
16
|
+
next if worklog.nil?
|
17
|
+
|
18
|
+
Jira.new(worklog)
|
19
|
+
table.add(worklog)
|
20
|
+
end
|
21
|
+
table.render
|
22
|
+
end
|
23
|
+
|
24
|
+
def task_rc
|
25
|
+
'rc.report.list.columns="description" rc.report.list.labels="Notes" rc.verbose=label'
|
26
|
+
end
|
27
|
+
|
28
|
+
def read
|
29
|
+
header_finished = false
|
30
|
+
json_str = ''
|
31
|
+
while (line = gets)
|
32
|
+
if !header_finished
|
33
|
+
header_finished = line.length == 1
|
34
|
+
else
|
35
|
+
json_str += line
|
36
|
+
end
|
37
|
+
end
|
38
|
+
JSON.parse(json_str)
|
39
|
+
end
|
40
|
+
|
41
|
+
def key_from_tags(tags)
|
42
|
+
return unless tags
|
43
|
+
|
44
|
+
tags.each do |x|
|
45
|
+
return x unless (x =~ /^[A-Z]+-[0-9]+$/).nil?
|
46
|
+
end
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def project_from_key(key)
|
51
|
+
key.split('-')[0]
|
52
|
+
end
|
53
|
+
|
54
|
+
def convert(item)
|
55
|
+
key = key_from_tags(item['tags'])
|
56
|
+
return unless key && item['end']
|
57
|
+
|
58
|
+
start = DateTime.parse(item['start'])
|
59
|
+
st = start.strftime('%Y-%m-%dT%H:%M:%S.%L%z')
|
60
|
+
finish = DateTime.parse(item['end'])
|
61
|
+
duration = finish.to_time.to_i - start.to_time.to_i
|
62
|
+
project = project_from_key(key)
|
63
|
+
|
64
|
+
{ project: project, key: key, start: st, duration: duration }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'terminal-table'
|
4
|
+
|
5
|
+
module Xfel
|
6
|
+
module Timew
|
7
|
+
# Report's terminal output.
|
8
|
+
class Table
|
9
|
+
def initialize
|
10
|
+
@data = {}
|
11
|
+
@table = Terminal::Table.new({ headings: %w[Project Hours Total] })
|
12
|
+
end
|
13
|
+
|
14
|
+
def time_str(seconds)
|
15
|
+
hours = seconds / 3600
|
16
|
+
minutes = seconds / 60 % 60
|
17
|
+
format("#{hours}h %02dm", minutes)
|
18
|
+
end
|
19
|
+
|
20
|
+
def project_to_table(project, tickets)
|
21
|
+
@table.add_row([project, '', ''])
|
22
|
+
project_total = 0
|
23
|
+
tickets.each do |key, duration|
|
24
|
+
project_total += duration
|
25
|
+
@table.add_row(["└── #{key}", time_str(duration), ''])
|
26
|
+
end
|
27
|
+
@table.add_row(['', '', time_str(project_total)])
|
28
|
+
project_total
|
29
|
+
end
|
30
|
+
|
31
|
+
def data_to_table
|
32
|
+
total = 0
|
33
|
+
@data.each do |project, tickets|
|
34
|
+
total += project_to_table(project, tickets)
|
35
|
+
@table.add_separator
|
36
|
+
end
|
37
|
+
@table.add_row(['', '', time_str(total)])
|
38
|
+
end
|
39
|
+
|
40
|
+
def render
|
41
|
+
data_to_table
|
42
|
+
@table.align_column(1, :right)
|
43
|
+
@table.align_column(2, :right)
|
44
|
+
puts @table
|
45
|
+
end
|
46
|
+
|
47
|
+
def add(worklog)
|
48
|
+
project = worklog[:project]
|
49
|
+
ticket = worklog[:key]
|
50
|
+
|
51
|
+
@data[project] = {} unless @data.key?(project)
|
52
|
+
@data[project][ticket] = 0 unless @data[project].key?(ticket)
|
53
|
+
@data[project][ticket] += worklog[:duration]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xfel-timew-jira
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Fernando Jascovich
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-10-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.1.4
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.1.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.19.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.19.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: terminal-table
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.8.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.8.0
|
83
|
+
description: " This gem generates a Jira ticket oriented summary and it syncs TimeWarrior
|
84
|
+
entries with Jira ticket's worklog.\n"
|
85
|
+
email:
|
86
|
+
- fernando.ej@gmail.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- lib/xfel/timew/jira.rb
|
92
|
+
- lib/xfel/timew/report.rb
|
93
|
+
- lib/xfel/timew/table.rb
|
94
|
+
- lib/xfel/timew/version.rb
|
95
|
+
- lib/xfel_timew_jira.rb
|
96
|
+
homepage: https://github.com/fernando-jascovich/xfel-timew-jira
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '2.6'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubygems_version: 3.0.3
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Jira sync and report for TimeWarrior
|
119
|
+
test_files: []
|