roko 0.2.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/.gitignore +11 -0
- data/.reek.yml +3 -0
- data/.rspec +3 -0
- data/.solargraph.yml +15 -0
- data/.travis.yml +6 -0
- data/.vscode/settings.json +17 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +210 -0
- data/README.md +94 -0
- data/bin/console +10 -0
- data/bin/roko +5 -0
- data/bin/setup +8 -0
- data/lib/roko.rb +6 -0
- data/lib/roko/cli.rb +69 -0
- data/lib/roko/report_event.rb +37 -0
- data/lib/roko/source/base/report_events.rb +41 -0
- data/lib/roko/source/configurable.rb +38 -0
- data/lib/roko/source/confluence/event_adapter.rb +31 -0
- data/lib/roko/source/confluence/events.rb +27 -0
- data/lib/roko/source/confluence/report_events.rb +32 -0
- data/lib/roko/source/events.rb +45 -0
- data/lib/roko/source/github/event_adapter.rb +73 -0
- data/lib/roko/source/github/report_events.rb +31 -0
- data/lib/roko/source/google_calendar/client.rb +60 -0
- data/lib/roko/source/google_calendar/event_adapter.rb +35 -0
- data/lib/roko/source/google_calendar/report_events.rb +32 -0
- data/lib/roko/source/jira/event_adapter.rb +33 -0
- data/lib/roko/source/jira/report_events.rb +48 -0
- data/lib/roko/source/slack/event_adapter.rb +44 -0
- data/lib/roko/source/slack/events.rb +65 -0
- data/lib/roko/source/slack/report_events.rb +34 -0
- data/lib/roko/version.rb +3 -0
- data/roko.gemspec +28 -0
- metadata +77 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Roko
|
|
4
|
+
DEFAULT_ONELINE_TEMPLATE = '%{Y}/%{m}/%{d} %{H}:%{M} %{event_type} [%{summary}](%{url})'
|
|
5
|
+
|
|
6
|
+
# ReportEvent defines event format that should be reported.
|
|
7
|
+
class ReportEvent
|
|
8
|
+
attr_reader :source, :event_type, :created_at, :url, :summary, :detail
|
|
9
|
+
|
|
10
|
+
# @param source [String] Event source name
|
|
11
|
+
# @param event_type [String]
|
|
12
|
+
# @param create_at [Time]
|
|
13
|
+
# @param url [String]
|
|
14
|
+
# @param summary [String] summary for the url
|
|
15
|
+
# @param detail [String] detail for the url
|
|
16
|
+
def initialize(source, event_type, created_at, url, summary, detail)
|
|
17
|
+
@source = source
|
|
18
|
+
@event_type = event_type
|
|
19
|
+
@created_at = created_at
|
|
20
|
+
@url = url
|
|
21
|
+
@summary = summary
|
|
22
|
+
@detail = detail
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def oneline_template
|
|
26
|
+
env_template = ENV.fetch('ROKO_ONELINE_TEMPLATE', '')
|
|
27
|
+
return env_template unless env_template.nil? || env_template.empty?
|
|
28
|
+
|
|
29
|
+
DEFAULT_ONELINE_TEMPLATE
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def oneline
|
|
33
|
+
oneline_summary = @summary.gsub("\n", ' ')
|
|
34
|
+
format(oneline_template, Y: @created_at.year, m: @created_at.strftime('%m'), d: @created_at.strftime('%d'), H: @created_at.hour, M: @created_at.min, event_type: @event_type, summary: oneline_summary, url: @url, detail: @detail)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'roko/source/configurable'
|
|
4
|
+
|
|
5
|
+
module Roko
|
|
6
|
+
module Source
|
|
7
|
+
# base module for event sources
|
|
8
|
+
module Base
|
|
9
|
+
# report event
|
|
10
|
+
class ReportEvents
|
|
11
|
+
include Roko::Source::Configurable
|
|
12
|
+
|
|
13
|
+
def initialize(configurable = nil)
|
|
14
|
+
configure_with(configurable) unless configurable.nil?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def fetch
|
|
18
|
+
fetch_service_event(client)
|
|
19
|
+
.map! { |event| to_report_event(event) }
|
|
20
|
+
.compact
|
|
21
|
+
.filter { |e| e.created_at.between?(@start, @end) }
|
|
22
|
+
.sort_by(&:created_at)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def client
|
|
28
|
+
raise NotImplementedError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def fetch_service_event(_client)
|
|
32
|
+
raise NotImplementedError
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_report_event(_event)
|
|
36
|
+
raise NotImplementedError
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'date'
|
|
4
|
+
require 'time'
|
|
5
|
+
|
|
6
|
+
module Roko
|
|
7
|
+
module Source
|
|
8
|
+
# @!attribute start
|
|
9
|
+
# @return [Time] start time of this report
|
|
10
|
+
# @!attribute end
|
|
11
|
+
# @return [Time] end time of this report
|
|
12
|
+
module Configurable
|
|
13
|
+
attr_accessor :start, :end
|
|
14
|
+
|
|
15
|
+
def setup(options)
|
|
16
|
+
today = Date.today
|
|
17
|
+
@start = parse_time_or_nil(options[:from]) || today.to_time
|
|
18
|
+
@end = parse_time_or_nil(options[:to]) || today.next.to_time
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param configurable [Roko::Source::Configurable]
|
|
22
|
+
def configure_with(configurable)
|
|
23
|
+
@start = configurable.start
|
|
24
|
+
@end = configurable.end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def parse_time_or_nil(str)
|
|
30
|
+
Time.parse(str)
|
|
31
|
+
rescue ArgumentError
|
|
32
|
+
nil
|
|
33
|
+
rescue TypeError
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'roko/report_event'
|
|
4
|
+
require 'time'
|
|
5
|
+
|
|
6
|
+
module Roko
|
|
7
|
+
module Source
|
|
8
|
+
module Confluence
|
|
9
|
+
# convert from Confluence event to [Roko::ReportEvent]
|
|
10
|
+
module EventAdapter
|
|
11
|
+
class << self
|
|
12
|
+
# @param event [Hash]
|
|
13
|
+
# @return [Roko::ReportEvent] or nil
|
|
14
|
+
def to_report_event(event)
|
|
15
|
+
created_at = Time.parse(event.metadata.currentuser.lastmodified.version.when)
|
|
16
|
+
url = "#{ENV['CONFLUENCE_URL']}#{event._links.webui}"
|
|
17
|
+
|
|
18
|
+
Roko::ReportEvent.new(
|
|
19
|
+
'confluence',
|
|
20
|
+
'document',
|
|
21
|
+
created_at,
|
|
22
|
+
url,
|
|
23
|
+
event.title,
|
|
24
|
+
''
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Roko
|
|
4
|
+
module Source
|
|
5
|
+
module Confluence
|
|
6
|
+
# access Confluence events
|
|
7
|
+
#
|
|
8
|
+
# @!attribute [Faraday::Connection] client
|
|
9
|
+
class Events
|
|
10
|
+
# @param client [Faraday::Connection]
|
|
11
|
+
def initialize(client)
|
|
12
|
+
@client = client
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def fetch
|
|
16
|
+
response = @client.get(
|
|
17
|
+
ENV['CONFLUENCE_URL'] + '/rest/api/content/search', {
|
|
18
|
+
expand: 'container,metadata.currentuser.lastmodified',
|
|
19
|
+
cql: 'type in (page,blogpost) and id in recentlyModifiedPagesAndBlogPostsByUser(currentUser(), 0, 20)'
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
response.body.results
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'faraday'
|
|
4
|
+
|
|
5
|
+
require_relative 'events'
|
|
6
|
+
require_relative 'event_adapter'
|
|
7
|
+
require 'roko/source/base/report_events'
|
|
8
|
+
|
|
9
|
+
module Roko
|
|
10
|
+
module Source
|
|
11
|
+
# event from confluence
|
|
12
|
+
module Confluence
|
|
13
|
+
# report events from confluence
|
|
14
|
+
class ReportEvents < Roko::Source::Base::ReportEvents
|
|
15
|
+
def client
|
|
16
|
+
Faraday.new(url: ENV['CONFLUENCE_URL']) do |conn|
|
|
17
|
+
conn.basic_auth(ENV['CONFLUENCE_USER'], ENV['CONFLUENCE_PASSWORD'])
|
|
18
|
+
conn.response :json, parser_options: { object_class: OpenStruct }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def fetch_service_event(client)
|
|
23
|
+
Events.new(client).fetch
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_report_event(event)
|
|
27
|
+
EventAdapter.to_report_event(event)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'time'
|
|
4
|
+
require 'pry'
|
|
5
|
+
require 'roko/source/github/report_events'
|
|
6
|
+
require 'roko/source/google_calendar/report_events'
|
|
7
|
+
require 'roko/source/slack/report_events'
|
|
8
|
+
require 'roko/source/jira/report_events'
|
|
9
|
+
require 'roko/source/confluence/report_events'
|
|
10
|
+
require_relative 'configurable'
|
|
11
|
+
|
|
12
|
+
module Roko
|
|
13
|
+
module Source
|
|
14
|
+
# daily report events from several sources
|
|
15
|
+
module Events
|
|
16
|
+
extend Configurable
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def github
|
|
20
|
+
Github::ReportEvents.new(self).fetch
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def google_calendar
|
|
24
|
+
GoogleCalendar::ReportEvents.new(self).fetch
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def jira
|
|
28
|
+
Jira::ReportEvents.new(self).fetch
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def slack
|
|
32
|
+
Slack::ReportEvents.new(self).fetch
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def confluence
|
|
36
|
+
Confluence::ReportEvents.new(self).fetch
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def all
|
|
40
|
+
(github + google_calendar + slack + confluence + jira).sort_by(&:created_at)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'roko/report_event'
|
|
4
|
+
require 'time'
|
|
5
|
+
|
|
6
|
+
module Roko
|
|
7
|
+
module Source
|
|
8
|
+
module Github
|
|
9
|
+
# convert from Github event [Sawyer::Resource] to [Roko::ReportEvent]
|
|
10
|
+
module EventAdapter
|
|
11
|
+
class << self
|
|
12
|
+
# @param event [Sawyer::Resource]
|
|
13
|
+
# @return [Roko::ReportEvent] or nil
|
|
14
|
+
def to_report_event(event)
|
|
15
|
+
created_at = extract_created_at(event)
|
|
16
|
+
payload = extract_from_payload(event.type, event.payload)
|
|
17
|
+
return nil if payload.nil? || created_at.nil?
|
|
18
|
+
|
|
19
|
+
Roko::ReportEvent.new(
|
|
20
|
+
'github',
|
|
21
|
+
payload[:event_type],
|
|
22
|
+
created_at,
|
|
23
|
+
payload[:url],
|
|
24
|
+
payload[:summary],
|
|
25
|
+
payload[:detail]
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @param [Sawyer::Resource]
|
|
30
|
+
# @return [Time] or nil if created_at is not present
|
|
31
|
+
def extract_created_at(event)
|
|
32
|
+
created_at = event.created_at
|
|
33
|
+
if created_at.instance_of? Time
|
|
34
|
+
created_at
|
|
35
|
+
elsif created_at.instance_of? String
|
|
36
|
+
Time.parse(created_at)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @param event_type [String] github event type name
|
|
41
|
+
# @param payload [Hash] github event payload
|
|
42
|
+
# @return [String, String, String, String]
|
|
43
|
+
def extract_from_payload(event_type, payload)
|
|
44
|
+
case event_type
|
|
45
|
+
when 'PullRequestReviewCommentEvent' then
|
|
46
|
+
{ event_type: 'PR review',
|
|
47
|
+
url: payload.comment.html_url,
|
|
48
|
+
summary: payload.pull_request.title.to_s,
|
|
49
|
+
detail: payload.comment.body }
|
|
50
|
+
when 'PullRequestEvent' then
|
|
51
|
+
{ event_type: "PR #{payload.action}",
|
|
52
|
+
url: payload.pull_request.html_url,
|
|
53
|
+
summary: payload.pull_request.title.to_s,
|
|
54
|
+
detail: payload.pull_request.body }
|
|
55
|
+
when 'CreateEvent' then
|
|
56
|
+
{ event_type: 'create',
|
|
57
|
+
url: '',
|
|
58
|
+
summary: "#{payload.ref_type} #{payload.ref}",
|
|
59
|
+
detail: '' }
|
|
60
|
+
when 'DeleteEvent' then
|
|
61
|
+
{ event_type: 'delete',
|
|
62
|
+
url: '',
|
|
63
|
+
summary: "#{payload.ref_type} #{payload.ref}",
|
|
64
|
+
detail: '' }
|
|
65
|
+
when 'PushEvent'
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'octokit'
|
|
4
|
+
|
|
5
|
+
require_relative 'event_adapter'
|
|
6
|
+
require 'roko/source/base/report_events'
|
|
7
|
+
|
|
8
|
+
module Roko
|
|
9
|
+
module Source
|
|
10
|
+
module Github
|
|
11
|
+
# report events from github
|
|
12
|
+
class ReportEvents < Roko::Source::Base::ReportEvents
|
|
13
|
+
def client
|
|
14
|
+
Octokit.configure do |c|
|
|
15
|
+
c.netrc_file = ENV['NETRC_FILE_PATH'] || '~/.netrc'
|
|
16
|
+
c.auto_paginate = true
|
|
17
|
+
end
|
|
18
|
+
Octokit::Client.new(netrc: true)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def fetch_service_event(client)
|
|
22
|
+
client.user_events(client.login)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_report_event(event)
|
|
26
|
+
EventAdapter.to_report_event(event)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# https://github.com/gsuitedevs/ruby-samples/blob/master/calendar/quickstart/quickstart.rb
|
|
4
|
+
|
|
5
|
+
require 'google/apis/calendar_v3'
|
|
6
|
+
require 'googleauth'
|
|
7
|
+
require 'googleauth/stores/file_token_store'
|
|
8
|
+
require 'date'
|
|
9
|
+
require 'fileutils'
|
|
10
|
+
|
|
11
|
+
module Roko
|
|
12
|
+
module Source
|
|
13
|
+
module GoogleCalendar
|
|
14
|
+
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
|
|
15
|
+
APPLICATION_NAME = 'hmiyado/roko'
|
|
16
|
+
CREDENTIALS_PATH = ENV['GOOGLE_API_CREDENTIALS_PATH'] || '~/credentials.json'
|
|
17
|
+
# The file token.yaml stores the user's access and refresh tokens, and is
|
|
18
|
+
# created automatically when the authorization flow completes for the first
|
|
19
|
+
# time.
|
|
20
|
+
TOKEN_PATH = 'tmp/token.yaml'
|
|
21
|
+
SCOPE = Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY
|
|
22
|
+
USER_ID = 'default'
|
|
23
|
+
|
|
24
|
+
# client for google calendar
|
|
25
|
+
module Client
|
|
26
|
+
def self.new_client
|
|
27
|
+
service = Google::Apis::CalendarV3::CalendarService.new
|
|
28
|
+
service.client_options.application_name = APPLICATION_NAME
|
|
29
|
+
service.authorization = authorize
|
|
30
|
+
service
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.authorize
|
|
34
|
+
Dir.mkdir('tmp') unless Dir.exist?('tmp')
|
|
35
|
+
authorizer = create_authorizer
|
|
36
|
+
credentials = authorizer.get_credentials USER_ID
|
|
37
|
+
return credentials unless credentials.nil?
|
|
38
|
+
|
|
39
|
+
url = authorizer.get_authorization_url base_url: OOB_URI
|
|
40
|
+
puts request_authorization_message(url)
|
|
41
|
+
code = STDIN.gets
|
|
42
|
+
authorizer.get_and_store_credentials_from_code(
|
|
43
|
+
user_id: USER_ID, code: code, base_url: OOB_URI
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.create_authorizer
|
|
48
|
+
client_id = Google::Auth::ClientId.from_file File.expand_path(CREDENTIALS_PATH)
|
|
49
|
+
token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH
|
|
50
|
+
Google::Auth::UserAuthorizer.new client_id, SCOPE, token_store
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.request_authorization_message(url)
|
|
54
|
+
'Open the following URL in the browser and enter the ' \
|
|
55
|
+
"resulting code after authorization:\n" + url
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'roko/report_event'
|
|
4
|
+
require 'time'
|
|
5
|
+
|
|
6
|
+
module Roko
|
|
7
|
+
module Source
|
|
8
|
+
module GoogleCalendar
|
|
9
|
+
module EventAdapter
|
|
10
|
+
class << self
|
|
11
|
+
# @param event [Google::Apis::CalendarV3::Event]
|
|
12
|
+
# @return [Roko::ReportEvent]
|
|
13
|
+
def to_report_event(event)
|
|
14
|
+
source = 'google calendar'
|
|
15
|
+
event_type = 'MTG'
|
|
16
|
+
# [Google::Apis::CalendarV3::EventDateTime]
|
|
17
|
+
start = event.start
|
|
18
|
+
return nil if start.nil?
|
|
19
|
+
|
|
20
|
+
created_at = if start.date_time.nil?
|
|
21
|
+
Time.parse(start.date.to_s)
|
|
22
|
+
else
|
|
23
|
+
Time.parse(start.date_time.to_s)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
url = event.html_link
|
|
27
|
+
summary = event.summary
|
|
28
|
+
detail = event.description
|
|
29
|
+
Roko::ReportEvent.new(source, event_type, created_at, url, summary, detail)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|