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.
@@ -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