newsman 0.1.14 → 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 +4 -4
- data/README.md +7 -1
- data/lib/newsman/assistant.rb +83 -96
- data/lib/newsman/github.rb +80 -0
- data/lib/newsman/html_output.rb +42 -17
- data/lib/newsman/issues.rb +92 -15
- data/lib/newsman/pull_request.rb +32 -1
- data/lib/newsman/report.rb +49 -13
- data/lib/newsman/stdout_output.rb +22 -0
- data/lib/newsman/txt_output.rb +21 -0
- data/lib/newsman.rb +64 -100
- data/test/test_assistant.rb +8 -3
- data/test/test_htmlout.rb +1 -1
- data/test/test_issue.rb +62 -0
- data/test/test_pdd_issue.rb +35 -5
- data/test/test_pull_request.rb +39 -0
- data/test/test_report.rb +32 -24
- data/test/test_week_before.rb +1 -1
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0ec4c08d224982a75fc3ae533368cdeff2c4d7cab0072441fcfbd604f194b42
|
4
|
+
data.tar.gz: 8633c4f4dc84b0f6a285e06b67b0cb9dd3f9e7a18d6dc032589237652181d36f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85df6a743456154cdfcd2999a2f3a1977347cf9b101c8f2e35bd0b13024e6e1d66e8cf699bc7a11feac586f5b7bb6a2bdc08b75936bf967b011afdc2f1963716
|
7
|
+
data.tar.gz: e4aa02defb4c4a02dee05fe334fb799f0f10b825110e194e0f3d7e5da79ce54144e5a77d1543c57acbdc56ca444fa4be625f4e16a9c83487abc917711d0e771c
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Newsman
|
2
2
|
|
3
|
+
|
4
|
+
[](LICENSE.txt)
|
5
|
+
[](https://rubygems.org/gems/newsman)
|
6
|
+
|
3
7
|
Newsman is a simple script that collects information about a developer's weekly activity on GitHub and creates a human-readable summary of the work done. To create the summary, Newsman asks ChatGPT to handle all the information about a developer's activity, including their pull requests and created issues.
|
4
8
|
|
5
9
|
## Install
|
@@ -31,7 +35,9 @@ Usage: newsman [options]
|
|
31
35
|
-n, --name NAME Reporter name. Human readable name that will be used in a report
|
32
36
|
-u, --username USERNAME GitHub username. For example, 'volodya-lombrozo'
|
33
37
|
-r, --repository REPOSITORIES Specify which repositories to include in a report. You can specify several repositories using a comma separator, for example: '-r objectionary/jeo-maven-plugin,objectionary/opeo-maven-plugin'
|
34
|
-
-p, --position
|
38
|
+
-p, --position POSITION Reporter position in a company. Default value is a 'Software Developer'.
|
39
|
+
-o, --output OUTPUT Output type. Newsman prints a report to a stdout by default. You can choose another options like '-o html', '-o txt' or even '-o html'
|
40
|
+
-t, --title TITLE Project Title. Empty by default
|
35
41
|
```
|
36
42
|
|
37
43
|
### Example
|
data/lib/newsman/assistant.rb
CHANGED
@@ -1,8 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2024 Volodya Lombrozo
|
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 NONINFINGEMENT. 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
|
+
|
1
23
|
require 'openai'
|
2
24
|
|
25
|
+
# This class mimics a robot that can analyse a developer activity.
|
26
|
+
# The assistant uses OpenAI API to analyze.
|
3
27
|
class Assistant
|
4
|
-
|
5
|
-
|
28
|
+
CONTEXT = 'You are a developer tasked'\
|
29
|
+
' with composing a concise report detailing your activities'\
|
30
|
+
' and progress for the previous week,'\
|
31
|
+
' intended for submission to your supervisor.'
|
6
32
|
|
7
33
|
def initialize(token, model: 'gpt-3.5-turbo', temperature: 0.3)
|
8
34
|
@token = token
|
@@ -12,111 +38,92 @@ class Assistant
|
|
12
38
|
end
|
13
39
|
|
14
40
|
def say_hello
|
15
|
-
|
41
|
+
<<~HELLO
|
42
|
+
I'm an assistant that can work with OpenAI client.
|
43
|
+
Please, use me, if you need any help.
|
44
|
+
I'm using #{@model}, with #{@temperature} temperature.
|
45
|
+
HELLO
|
16
46
|
end
|
17
47
|
|
48
|
+
# rubocop:disable Metrics/MethodLength
|
18
49
|
def next_plans(issues)
|
19
50
|
example = "repository-name:\n
|
20
51
|
- To publish ABC package draft [#27]\n
|
21
52
|
- To review first draft of the report [#56]\n
|
22
53
|
- To implement optimization for the class X [#125]"
|
23
|
-
|
54
|
+
prompt = <<~PROMPT
|
55
|
+
Please compile a summary of the plans for the next week using the GitHub Issues.
|
56
|
+
Each issue should be summarized in a single sentence.
|
57
|
+
Combine all the information from each Issue into a concise and fluent sentence.
|
58
|
+
Pay attention, that you didn't loose any issue.
|
59
|
+
Ensure that each sentence includes the corresponding issue number as an integer value. If an issue doesn't mention an issue number, just print [#chore].
|
60
|
+
If several issues have the same number, combine them into a single sentence.
|
61
|
+
Please strictly adhere to the example template provided: "#{example}".
|
62
|
+
List of GitHub Issues in JSON format: ```json #{issues}```.
|
63
|
+
PROMPT
|
64
|
+
send(prompt)
|
24
65
|
end
|
66
|
+
# rubocop:enable Metrics/MethodLength
|
25
67
|
|
68
|
+
# rubocop:disable Metrics/MethodLength
|
26
69
|
def prev_results(prs)
|
27
70
|
example = "repository-name:\n
|
28
71
|
- Added 100 new files to the Dataset [#168]\n
|
29
72
|
- Fixed the deployment of XYZ [#169]\n
|
30
73
|
- Refined the requirements [#177]\n"
|
31
|
-
|
74
|
+
prompt = <<~PROMPT
|
75
|
+
Please compile a summary of the work completed in the following Pull Requests (PRs).
|
76
|
+
Each PR should be summarized in a single sentence, focusing on the PR title rather than the implementation details.
|
77
|
+
Ensure no PR is omitted.
|
78
|
+
Each sentence must include the corresponding issue number as an integer value. If a PR does not mention an issue number, use [#chore].
|
79
|
+
If several PRs have the same number, combine them into a single sentence.
|
80
|
+
Combine the information from each PR into a concise and fluent sentence.
|
81
|
+
Follow the provided example template strictly: "#{example}".
|
82
|
+
List of Pull Requests in JSON format: ```json #{prs}```.
|
83
|
+
PROMPT
|
84
|
+
send(prompt)
|
32
85
|
end
|
86
|
+
# rubocop:enable Metrics/MethodLength
|
33
87
|
|
88
|
+
# rubocop:disable Metrics/MethodLength
|
34
89
|
def risks(all)
|
35
90
|
example = "repository-name:\n
|
36
91
|
- The server is weak, we may fail the delivery\n
|
37
92
|
of the dataset, report milestone will be missed [#487].\n
|
38
93
|
- The code in repository is suboptimal, we might have some problems for the future maintainability [#44].\n"
|
39
|
-
|
94
|
+
prompt = <<~PROMPT
|
95
|
+
Please compile a summary of the risks identified in the repository from the list of pull requests provided.
|
96
|
+
If no risks are identified in a pull request, just answer 'No risks identified' for that PR.
|
97
|
+
Each risk should be summarized in a concise and fluent single sentence.
|
98
|
+
Developers usually mention some risks in pull request descriptions, either as 'risk' or 'issue'.#{' '}
|
99
|
+
Ensure that each sentence includes the corresponding PR number as an integer value. If a PR doesn't mention an issue number, just print [#chore].
|
100
|
+
Please strictly adhere to the example template provided: "#{example}".
|
101
|
+
List of Pull Requests: ```json #{all}```.
|
102
|
+
PROMPT
|
103
|
+
send(prompt)
|
40
104
|
end
|
105
|
+
# rubocop:enable Metrics/MethodLength
|
41
106
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
- Refined the requirements [#177]
|
48
|
-
some-repository-name-y:
|
49
|
-
- Removed XYZ class [#57]
|
50
|
-
- Refactored http module [#69]"
|
51
|
-
response = @client.chat(
|
52
|
-
parameters: {
|
53
|
-
model: 'gpt-3.5-turbo',
|
54
|
-
messages: [
|
55
|
-
{ role: 'system',
|
56
|
-
content: 'You are a developer tasked with composing a concise report detailing your activities and progress for the previous week, intended for submission to your supervisor.' },
|
57
|
-
{ role: 'user',
|
58
|
-
content: "Please compile a summary of the work completed in the following Pull Requests (PRs). Each PR should be summarized in a single sentence, focusing more on the PR title and less on implementation details. Group the sentences by repositories, each identified by its name mentioned in the 'repository:[name]' attribute of the PR. Pay attention, that you don't lose any PR. The grouping is important an should be precise. Ensure that each sentence includes the corresponding issue number as an integer value. If a PR doesn't mention an issue number, just print [#chore]. Combine all the information from each PR into a concise and fluent sentence, as if you were a developer reporting on your work. Please strictly adhere to the example template provided. Example of a report: #{example}. List of Pull Requests: [#{prs}]" }
|
59
|
-
],
|
60
|
-
temperature: 0.3
|
61
|
-
}
|
62
|
-
)
|
63
|
-
answer = response.dig('choices', 0, 'message', 'content')
|
64
|
-
return answer
|
65
|
-
end
|
107
|
+
def format(report)
|
108
|
+
prompt = <<~PROMPT
|
109
|
+
I have a weekly report with different parts that use various formatting styles.
|
110
|
+
Please format the entire report into a single cohesive format while preserving the original text without any changes.
|
111
|
+
Ensure that the formatting is consistent throughout the document.
|
66
112
|
|
67
|
-
|
68
|
-
deprecated(__method__)
|
69
|
-
example_plans = "some-repository-name-x:
|
70
|
-
- To publish ABC package draft [#27]
|
71
|
-
- To review first draft of the report [#56]
|
72
|
-
some-repository-name-y:
|
73
|
-
- To implement optimization for the class X [#125]"
|
74
|
-
issues_response = @client.chat(
|
75
|
-
parameters: {
|
76
|
-
model: 'gpt-3.5-turbo',
|
77
|
-
messages: [
|
78
|
-
{ role: 'system',
|
79
|
-
content: 'You are a developer tasked with composing a concise report detailing your activities and progress for the previous week, intended for submission to your supervisor.' },
|
80
|
-
{ role: 'user',
|
81
|
-
content: "Please compile a summary of the plans for the next week using the following GitHub Issues descriptions. Each issue should be summarized in a single sentence, focusing more on the issue title and less on implementation details. Group the sentences by repositories, each identified by its name mentioned in the 'repository:[name]' attribute of the issue. Pat attention, that you din't loose any issue. The grouping is important an should be precise. Ensure that each sentence includes the corresponding issue number as an integer value. If an issue doesn't mention an issue number, just print [#chore]. Combine all the information from each Issue into a concise and fluent sentences, as if you were a developer reporting on your work. Please strictly adhere to the example template provided: #{example_plans}. List of GitHub issues to aggregate: [#{issues}]." }
|
82
|
-
],
|
83
|
-
temperature: 0.3
|
84
|
-
}
|
85
|
-
)
|
86
|
-
issues_full_answer = issues_response.dig('choices', 0, 'message', 'content')
|
87
|
-
return issues_full_answer
|
88
|
-
end
|
113
|
+
Here is the report:
|
89
114
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
- The server is weak, we may fail the delivery
|
94
|
-
of the dataset, report milestone will be missed [#487].
|
95
|
-
some-repository-name-y:
|
96
|
-
- The code in repository is suboptimal, we might have some problems for the future maintainability [#44]."
|
97
|
-
return @client.chat(
|
98
|
-
parameters: {
|
99
|
-
model: 'gpt-3.5-turbo',
|
100
|
-
messages: [
|
101
|
-
{ role: 'system',
|
102
|
-
content: 'You are a developer tasked with composing a concise report detailing your activities and progress for the previous week, intended for submission to your supervisor.' },
|
103
|
-
{ role: 'user',
|
104
|
-
content: "Please compile a summary of the risks identified in some repositories. If you can't find anything, just leave answer empty. Add some entries to a report only if you are sure it's a risk. Developers usually mention some risks in pull request descriptions. They either mention 'risk' or 'issue'. I will give you a list of pull requests. Each risk should be summarized in a single sentence. Ensure that each sentence includes the corresponding issue number or PR number as an integer value. If a PR or an issue doesn't mention an issue number, just print [#chore]. Combine all the information from each PR into a concise and fluent sentence, as if you were a developer reporting on your work. Please strictly adhere to the example template provided. Example of a report: #{example_risks}. List of Pull Requests: ```#{all}```.]" }
|
105
|
-
],
|
106
|
-
temperature: 0.3
|
107
|
-
}
|
108
|
-
).dig('choices', 0, 'message', 'content')
|
115
|
+
#{report}
|
116
|
+
PROMPT
|
117
|
+
send(prompt)
|
109
118
|
end
|
110
119
|
|
111
120
|
def send(request)
|
112
|
-
|
121
|
+
@client.chat(
|
113
122
|
parameters: {
|
114
123
|
model: @model,
|
115
124
|
messages: [
|
116
|
-
{ role: 'system',
|
117
|
-
|
118
|
-
{ role: 'user',
|
119
|
-
content: "#{request}" }
|
125
|
+
{ role: 'system', content: CONTEXT },
|
126
|
+
{ role: 'user', content: request.to_s }
|
120
127
|
],
|
121
128
|
temperature: @temperature
|
122
129
|
}
|
@@ -126,24 +133,4 @@ some-repository-name-y:
|
|
126
133
|
def deprecated(method)
|
127
134
|
warn "Warning! '#{method}' is deprecated and will be removed in future versions."
|
128
135
|
end
|
129
|
-
|
130
|
-
def send(request)
|
131
|
-
return @client.chat(
|
132
|
-
parameters: {
|
133
|
-
model: @model,
|
134
|
-
messages: [
|
135
|
-
{ role: 'system',
|
136
|
-
content: CONTEXT },
|
137
|
-
{ role: 'user',
|
138
|
-
content: "#{request}" }
|
139
|
-
],
|
140
|
-
temperature: @temperature
|
141
|
-
}
|
142
|
-
).dig('choices', 0, 'message', 'content')
|
143
|
-
end
|
144
|
-
|
145
|
-
def deprecated(method)
|
146
|
-
warn "Warning! '#{method}' is deprecated and will be removed in future versions."
|
147
|
-
end
|
148
|
-
|
149
136
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# Copyright (c) 2024 Volodya Lombrozo
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
12
|
+
# furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
15
|
+
# copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
|
+
# SOFTWARE.
|
24
|
+
|
25
|
+
# This class represents a useful abstraction over Github API.
|
26
|
+
class Github
|
27
|
+
def initialize(token)
|
28
|
+
@client = Octokit::Client.new(github_token: token)
|
29
|
+
end
|
30
|
+
|
31
|
+
def pull_requests(username, repositories)
|
32
|
+
query = "is:pr author:#{username} created:>=#{date_one_week_ago(Date.today)} #{repositories}"
|
33
|
+
puts "Searching pull requests for #{username}."
|
34
|
+
puts 'Newsman uses the following request to GitHub to gather the'\
|
35
|
+
" required information about user activity: '#{query}'"
|
36
|
+
@client.search_issues(query).items.map do |pull_request|
|
37
|
+
parse_pr(pull_request)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def issues(username, repositories)
|
42
|
+
one_month_ago = Date.today.prev_month.strftime('%Y-%m-%d')
|
43
|
+
query = "is:issue is:open author:#{username}"\
|
44
|
+
" author:0pdd created:>=#{one_month_ago} #{repositories}"
|
45
|
+
puts "Searching issues using the following query: '#{query}'"
|
46
|
+
@client.search_issues(query).items.map do |issue|
|
47
|
+
parse_issue(issue)
|
48
|
+
end.select(&:important?)
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_pr(pull_request)
|
52
|
+
title = pull_request.title.to_s
|
53
|
+
repository = pull_request.repository_url.split('/').last
|
54
|
+
puts "Found PR in #{repository}: #{title}"
|
55
|
+
PullRequest.new(repository, title, pull_request.body.to_s, url: pull_request.html_url)
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_issue(issue)
|
59
|
+
title, repository, number = issue_details(issue)
|
60
|
+
if issue.user.login == '0pdd'
|
61
|
+
PddIssue.new(title, issue.body.to_s, repository, number, url: issue.html_url, labels: issue.labels.map(&:name))
|
62
|
+
else
|
63
|
+
Issue.new(title, issue.body.to_s, repository, number, url: issue.html_url, labels: issue.labels.map(&:name))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def issue_details(issue)
|
68
|
+
title = issue.title.to_s
|
69
|
+
repository = issue.repository_url.split('/').last
|
70
|
+
number = issue.number.to_s
|
71
|
+
puts "Found issue in #{repository}:[##{number}] #{title}"
|
72
|
+
[title, repository, number]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def date_one_week_ago(today)
|
77
|
+
today = Date.parse(today) unless today.is_a?(Date)
|
78
|
+
one_week_ago = today - 7
|
79
|
+
one_week_ago.strftime('%Y-%m-%d')
|
80
|
+
end
|
data/lib/newsman/html_output.rb
CHANGED
@@ -1,40 +1,57 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Copyright (c) 2024 Volodya Lombrozo
|
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 NONINFINGEMENT. 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
|
+
|
3
23
|
require 'erb'
|
4
24
|
require 'redcarpet'
|
5
25
|
require 'nokogiri'
|
6
|
-
# frozen_string_literal: true
|
7
26
|
|
27
|
+
# This class represents a report output in HTML format.
|
8
28
|
class Htmlout
|
9
|
-
TEMPLATE =
|
10
|
-
<head>
|
11
|
-
|
12
|
-
</head>
|
13
|
-
<body>
|
14
|
-
|
15
|
-
|
16
|
-
</body>
|
17
|
-
|
29
|
+
TEMPLATE = <<~HTML
|
30
|
+
<head>
|
31
|
+
<title><%= title %></title>
|
32
|
+
</head>
|
33
|
+
<body>
|
34
|
+
<h1><%= title %></h1>
|
35
|
+
<%= body %>
|
36
|
+
</body>
|
37
|
+
HTML
|
18
38
|
|
19
39
|
def initialize(root = '.')
|
20
40
|
@root = root
|
21
41
|
end
|
22
42
|
|
43
|
+
# rubocop:disable Metrics/AbcSize
|
23
44
|
def print(report, reporter)
|
24
45
|
title = title(reporter)
|
25
|
-
|
26
|
-
markdown = Redcarpet::Markdown.new(renderer, autolink: true, tables: true)
|
27
|
-
body = markdown.render(report)
|
28
|
-
renderer = ERB.new(TEMPLATE)
|
29
|
-
html_content = renderer.result(binding)
|
30
|
-
html_content = Nokogiri::HTML(html_content, &:noblanks).to_xhtml(indent: 2)
|
46
|
+
body = to_html(report)
|
31
47
|
puts "Create a html file in a directory #{@root}"
|
32
48
|
file = File.new(File.join(@root, filename(reporter)), 'w')
|
33
49
|
puts "File #{file.path} was successfully created"
|
34
|
-
file.puts
|
50
|
+
file.puts Nokogiri::HTML(ERB.new(TEMPLATE).result(binding), &:noblanks).to_xhtml(indent: 2)
|
35
51
|
puts "Report was successfully printed to a #{file.path}"
|
36
52
|
file.close
|
37
53
|
end
|
54
|
+
# rubocop:enable Metrics/AbcSize
|
38
55
|
|
39
56
|
def title(reporter)
|
40
57
|
date = Time.new.strftime('%d.%m.%Y')
|
@@ -45,4 +62,12 @@ class Htmlout
|
|
45
62
|
date = Time.new.strftime('%d.%m.%Y')
|
46
63
|
"#{date}.#{reporter}.html"
|
47
64
|
end
|
65
|
+
|
66
|
+
def to_html(report)
|
67
|
+
Redcarpet::Markdown.new(
|
68
|
+
Redcarpet::Render::HTML.new(no_links: true, hard_wrap: true, prettify: true),
|
69
|
+
autolink: true,
|
70
|
+
tables: true
|
71
|
+
).render(report)
|
72
|
+
end
|
48
73
|
end
|
data/lib/newsman/issues.rb
CHANGED
@@ -1,39 +1,89 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Copyright (c) 2024 Volodya Lombrozo
|
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 NONINFINGEMENT. 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
|
+
|
3
23
|
require 'net/http'
|
4
|
-
|
24
|
+
require 'json'
|
5
25
|
|
26
|
+
# This class represents a GitHub Issue abstraction created by a user.
|
6
27
|
class Issue
|
7
28
|
attr_accessor :title, :body, :repo, :number
|
8
|
-
attr_reader :url
|
9
29
|
|
10
|
-
def initialize(title, body, repo, number,
|
30
|
+
def initialize(title, body, repo, number, **additional)
|
31
|
+
defaults = { url: 'undefined', labels: [] }
|
11
32
|
@title = title
|
12
33
|
@body = body
|
13
34
|
@repo = repo
|
14
35
|
@number = number
|
15
|
-
@
|
36
|
+
@additional = defaults.merge(additional)
|
16
37
|
end
|
17
38
|
|
18
39
|
def to_s
|
19
|
-
|
40
|
+
<<~MARKDOWN
|
41
|
+
title: ```#{@title}```,
|
42
|
+
description: ```#{@body}```,
|
43
|
+
repo: ```#{@repo}```,
|
44
|
+
issue number: \##{@number},
|
45
|
+
additional: #{@additional}
|
46
|
+
MARKDOWN
|
47
|
+
end
|
48
|
+
|
49
|
+
def detailed_title
|
50
|
+
"title: #{@title}, repo: #{@repo}, number: \##{@number}, url: #{url}, labels: #{labels}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def url
|
54
|
+
@additional[:url]
|
55
|
+
end
|
56
|
+
|
57
|
+
def labels
|
58
|
+
@additional[:labels]
|
20
59
|
end
|
21
60
|
|
22
|
-
def
|
23
|
-
|
61
|
+
def to_json(*_args)
|
62
|
+
{
|
63
|
+
number: @number,
|
64
|
+
title: @title,
|
65
|
+
description: @body,
|
66
|
+
repository: @repo,
|
67
|
+
url: url.to_s
|
68
|
+
}.to_json
|
69
|
+
end
|
70
|
+
|
71
|
+
def important?
|
72
|
+
labels.include? 'soon'
|
24
73
|
end
|
25
|
-
|
26
74
|
end
|
27
75
|
|
76
|
+
# This class represents a GitHub issue abstraction created by a 0pdd robot.
|
28
77
|
class PddIssue
|
29
78
|
attr_accessor :repo
|
30
79
|
|
31
|
-
def initialize(title, body, repo, number,
|
80
|
+
def initialize(title, body, repo, number, **additional)
|
81
|
+
defaults = { url: 'undefined', labels: [] }
|
32
82
|
@title = title
|
33
83
|
@body = body
|
34
84
|
@repo = repo
|
35
85
|
@number = number
|
36
|
-
@
|
86
|
+
@additional = defaults.merge(additional)
|
37
87
|
end
|
38
88
|
|
39
89
|
def extract_real_body
|
@@ -44,17 +94,44 @@ class PddIssue
|
|
44
94
|
end
|
45
95
|
|
46
96
|
def issue_link
|
47
|
-
@body[%r{https://github\.com/[\w\-/]+/blob/[\w\d]+/[\w/.-]+#\w+-\w+}, 0]
|
48
|
-
'
|
49
|
-
|
97
|
+
@body[%r{https://github\.com/[\w\-/]+/blob/[\w\d]+/[\w/.-]+#\w+-\w+}, 0]
|
98
|
+
.gsub('https://github.com', 'https://raw.githubusercontent.com')
|
99
|
+
.gsub('blob/', '')
|
50
100
|
end
|
51
101
|
|
52
102
|
def to_s
|
53
|
-
|
103
|
+
<<~MARKDOWN
|
104
|
+
title: ```#{@title}```,
|
105
|
+
description: ```#{extract_real_body}```,
|
106
|
+
repo: ```#{@repo}```,
|
107
|
+
issue number: \##{@number},
|
108
|
+
additional: #{@additional}
|
109
|
+
MARKDOWN
|
54
110
|
end
|
55
111
|
|
56
112
|
def detailed_title
|
57
|
-
"title: #{@title}, repo: #{@repo}, issue number: \##{@number}, url: #{
|
113
|
+
"title: #{@title}, repo: #{@repo}, issue number: \##{@number}, url: #{url}, labels: #{labels}"
|
58
114
|
end
|
59
115
|
|
116
|
+
def to_json(*_args)
|
117
|
+
{
|
118
|
+
number: @number,
|
119
|
+
title: @title,
|
120
|
+
description: @body,
|
121
|
+
repository: @repo,
|
122
|
+
url: url.to_s
|
123
|
+
}.to_json
|
124
|
+
end
|
125
|
+
|
126
|
+
def important?
|
127
|
+
labels.include? 'soon'
|
128
|
+
end
|
129
|
+
|
130
|
+
def url
|
131
|
+
@additional[:url]
|
132
|
+
end
|
133
|
+
|
134
|
+
def labels
|
135
|
+
@additional[:labels]
|
136
|
+
end
|
60
137
|
end
|
data/lib/newsman/pull_request.rb
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Copyright (c) 2024 Volodya Lombrozo
|
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 NONINFINGEMENT. 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
|
+
require 'json'
|
23
|
+
|
24
|
+
# This class represents GitHub Pull Request abstraction.
|
25
|
+
# In the future, it might be any Pull or Merge request.
|
3
26
|
class PullRequest
|
4
27
|
attr_accessor :repository, :title, :description
|
5
28
|
attr_reader :url
|
@@ -11,6 +34,15 @@ class PullRequest
|
|
11
34
|
@url = url
|
12
35
|
end
|
13
36
|
|
37
|
+
def to_json(*_args)
|
38
|
+
{
|
39
|
+
title: @title,
|
40
|
+
description: @description,
|
41
|
+
repository: @repository,
|
42
|
+
url: @url
|
43
|
+
}.to_json
|
44
|
+
end
|
45
|
+
|
14
46
|
def to_s
|
15
47
|
"title: ```#{@title}```,\ndescription: ```#{@description}```,\nrepo: ```#{@repository}```\n"
|
16
48
|
end
|
@@ -18,5 +50,4 @@ class PullRequest
|
|
18
50
|
def detailed_title
|
19
51
|
"title: #{@title}, repo: #{@repository}, url: #{@url}"
|
20
52
|
end
|
21
|
-
|
22
53
|
end
|