bas 1.4.0 → 1.4.2
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/CHANGELOG.md +6 -0
- data/README.md +2 -136
- data/examples/serverless_example.md +132 -0
- data/lib/bas/bot/create_work_item.rb +7 -6
- data/lib/bas/bot/fetch_billing_from_digital_ocean.rb +16 -4
- data/lib/bas/bot/fetch_github_issues.rb +27 -5
- data/lib/bas/bot/format_do_bill_alert.rb +16 -11
- data/lib/bas/bot/update_work_item.rb +54 -5
- data/lib/bas/bot/verify_issue_existance_in_notion.rb +4 -3
- data/lib/bas/utils/notion/fetch_database_record.rb +46 -0
- data/lib/bas/utils/notion/types.rb +0 -4
- data/lib/bas/utils/notion/update_db_page.rb +44 -0
- data/lib/bas/version.rb +1 -1
- metadata +5 -3
- data/lib/bas/bot/write_github_issue_requests.rb +0 -96
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6956cdda4a4735a5eb0a3d4413d41a972ac8190bb8d7da920e298a71bbe41516
|
4
|
+
data.tar.gz: 27c071aa1a681fb0f657af8e21c46057e3eb11cb467b5dd715f28c2f691d6dda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb89f398a03c6c8bae97798d069772790f2bd80a3ef7db4956b86751c4ef5a2b04420184e76ed138685f45dee3b1a9cdb1994517ca585663d9998a40bcb07f83
|
7
|
+
data.tar.gz: 9a586528f93844ad4e68d34a938bb2cff62eec5cd58fd952d1b431c5641c7af9ba5933ed8803b7fda42086b258b167c3826d2b492546887155b47e563c080b1f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
# 1.4.2 (28.08.2024)
|
4
|
+
- [Adjust digital ocean billing bots](https://github.com/kommitters/bas/issues/97)
|
5
|
+
|
6
|
+
# 1.4.1 (12.08.2024)
|
7
|
+
- [Add github issues assignees to work items](https://github.com/kommitters/bas/issues/92)
|
8
|
+
|
3
9
|
# 1.4.0 (26.07.2024)
|
4
10
|
- [Add bots to synchronize issues with notion work items](https://github.com/kommitters/bas/issues/87)
|
5
11
|
- [Update fetch pto from notion bot](https://github.com/kommitters/bas/issues/75)
|
data/README.md
CHANGED
@@ -102,142 +102,8 @@ bot.execute
|
|
102
102
|
|
103
103
|
```
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
#### Configuring environment variables
|
109
|
-
Create the environment variables configuration file.
|
110
|
-
|
111
|
-
```bash
|
112
|
-
cp env.yml.example env.yml
|
113
|
-
```
|
114
|
-
|
115
|
-
And put the following env variables
|
116
|
-
```
|
117
|
-
dev:
|
118
|
-
BIRTHDAY_NOTION_DATABASE_ID: "BIRTHDAY_NOTION_DATABASE_ID"
|
119
|
-
BIRTHDAY_NOTION_SECRET: "BIRTHDAY_NOTION_SECRET"
|
120
|
-
prod:
|
121
|
-
BIRTHDAY_NOTION_DATABASE_ID: "BIRTHDAY_NOTION_DATABASE_ID"
|
122
|
-
BIRTHDAY_NOTION_SECRET: "BIRTHDAY_NOTION_SECRET"
|
123
|
-
|
124
|
-
```
|
125
|
-
|
126
|
-
The variables should be defined either in the custom settings section within the `serverless.yml` file to ensure accessibility by all lambdas, or in the environment configuration option for each lambda respectively. For example:
|
127
|
-
|
128
|
-
```bash
|
129
|
-
# Accessible by all the lambdas
|
130
|
-
custom:
|
131
|
-
settings:
|
132
|
-
api:
|
133
|
-
NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.NOTION_DATABASE_ID}
|
134
|
-
NOTION_SECRET: ${file(./env.yml):${env:STAGE}.NOTION_SECRET}}
|
135
|
-
|
136
|
-
# Accessible by the lambda
|
137
|
-
functions:
|
138
|
-
lambdaName:
|
139
|
-
environment:
|
140
|
-
NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.NOTION_DATABASE_ID}
|
141
|
-
NOTION_SECRET: ${file(./env.yml):${env:STAGE}.NOTION_SECRET}}
|
142
|
-
```
|
143
|
-
|
144
|
-
#### Schedule
|
145
|
-
the schedule is configured using an environment variable containing the cron configuration. For example:
|
146
|
-
```bash
|
147
|
-
# env.yml file
|
148
|
-
SCHEDULER: cron(0 13 ? * MON-FRI *)
|
149
|
-
|
150
|
-
# serverless.yml
|
151
|
-
functions:
|
152
|
-
lambdaName:
|
153
|
-
events:
|
154
|
-
- schedule:
|
155
|
-
rate: ${file(./env.yml):${env:STAGE}.SCHEDULER}
|
156
|
-
```
|
157
|
-
|
158
|
-
To learn how to modify the cron configuration follow this guide: [Schedule expressions using rate or cron](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents-expressions.html)
|
159
|
-
|
160
|
-
#### Building your lambda
|
161
|
-
On your serverless configuration, create your lambda function, on your serverless `/src` folder.
|
162
|
-
|
163
|
-
```ruby
|
164
|
-
# frozen_string_literal: true
|
165
|
-
|
166
|
-
require 'bas/bot/fetch_birthdays_from_notion'
|
167
|
-
|
168
|
-
# Initialize the environment variables
|
169
|
-
NOTION_DATABASE_ID = ENV.fetch('NOTION_DATABASE_ID')
|
170
|
-
NOTION_SECRET = ENV.fetch('NOTION_SECRET')
|
171
|
-
|
172
|
-
module Notifier
|
173
|
-
# Service description
|
174
|
-
class UseCaseName
|
175
|
-
def self.notify(*)
|
176
|
-
options = { process_options: , write_options: }
|
177
|
-
|
178
|
-
begin
|
179
|
-
use_case = Bot::FetchBirthdaysFromNotion.new(options)
|
180
|
-
|
181
|
-
use_case.execute
|
182
|
-
rescue StandardError => e
|
183
|
-
{ body: { message: e.message } }
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def self.process_options
|
188
|
-
{
|
189
|
-
database_id: NOTION_DATABASE_ID,
|
190
|
-
secret: NOTION_SECRET
|
191
|
-
}
|
192
|
-
end
|
193
|
-
|
194
|
-
def self.write_options
|
195
|
-
{
|
196
|
-
connection: {
|
197
|
-
host: "host",
|
198
|
-
port: 5432,
|
199
|
-
dbname: "bas",
|
200
|
-
user: "postgres",
|
201
|
-
password: "postgres"
|
202
|
-
},
|
203
|
-
db_table: "use_cases",
|
204
|
-
bot_name: "FetchBirthdaysFromNotion"
|
205
|
-
}
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
```
|
210
|
-
|
211
|
-
#### Configure the lambda
|
212
|
-
In the `serverless.yml` file, add a new instance in the `functions` block with this structure:
|
213
|
-
|
214
|
-
```bash
|
215
|
-
functions:
|
216
|
-
fetchBirthdayFromNotion:
|
217
|
-
handler: src/lambdas/birthday_fetch.Bot::Birthday.fetch
|
218
|
-
environment:
|
219
|
-
BIRTHDAY_NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.BIRTHDAY_NOTION_DATABASE_ID}
|
220
|
-
BIRTHDAY_NOTION_SECRET: ${file(./env.yml):${env:STAGE}.BIRTHDAY_NOTION_SECRET}
|
221
|
-
events:
|
222
|
-
- schedule:
|
223
|
-
name: birthday-fetch
|
224
|
-
description: "Fetch every 24 hours at 8:30 a.m (UTC-5) from monday to friday"
|
225
|
-
rate: cron(${file(./env.yml):${env:STAGE}.BIRTHDAY_FETCH_SCHEDULER})
|
226
|
-
enabled: true
|
227
|
-
```
|
228
|
-
|
229
|
-
#### Deploying
|
230
|
-
|
231
|
-
Configure the AWS keys:
|
232
|
-
|
233
|
-
```bash
|
234
|
-
serverless config credentials --provider aws --key YOUR_KEY --secret YOUR_SECRET
|
235
|
-
```
|
236
|
-
|
237
|
-
Deploy the project:
|
238
|
-
```bash
|
239
|
-
STAGE=prod sls deploy --verbose
|
240
|
-
```
|
105
|
+
## Real case usage
|
106
|
+
For implementation details, please refer to the examples folder in the repository. You can find an example of how to configure a Lambda function with a bot there.
|
241
107
|
|
242
108
|
## Development
|
243
109
|
|
@@ -0,0 +1,132 @@
|
|
1
|
+
### Serverless
|
2
|
+
We'll explain how to configure and deploy a bot with serverless.
|
3
|
+
|
4
|
+
#### Configuring environment variables
|
5
|
+
Create the environment variables configuration file (`env.yml`)
|
6
|
+
|
7
|
+
And put the following env variables
|
8
|
+
```
|
9
|
+
dev:
|
10
|
+
BIRTHDAY_NOTION_DATABASE_ID: "BIRTHDAY_NOTION_DATABASE_ID"
|
11
|
+
BIRTHDAY_NOTION_SECRET: "BIRTHDAY_NOTION_SECRET"
|
12
|
+
prod:
|
13
|
+
BIRTHDAY_NOTION_DATABASE_ID: "BIRTHDAY_NOTION_DATABASE_ID"
|
14
|
+
BIRTHDAY_NOTION_SECRET: "BIRTHDAY_NOTION_SECRET"
|
15
|
+
|
16
|
+
```
|
17
|
+
|
18
|
+
The variables should be defined either in the custom settings section within the `serverless.yml` file to ensure accessibility by all lambdas, or in the environment configuration option for each lambda respectively. For example:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
# Accessible by all the lambdas
|
22
|
+
custom:
|
23
|
+
settings:
|
24
|
+
api:
|
25
|
+
NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.NOTION_DATABASE_ID}
|
26
|
+
NOTION_SECRET: ${file(./env.yml):${env:STAGE}.NOTION_SECRET}}
|
27
|
+
|
28
|
+
# Accessible by the lambda
|
29
|
+
functions:
|
30
|
+
lambdaName:
|
31
|
+
environment:
|
32
|
+
NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.NOTION_DATABASE_ID}
|
33
|
+
NOTION_SECRET: ${file(./env.yml):${env:STAGE}.NOTION_SECRET}}
|
34
|
+
```
|
35
|
+
|
36
|
+
#### Schedule
|
37
|
+
the schedule is configured using an environment variable containing the cron configuration. For example:
|
38
|
+
```bash
|
39
|
+
# env.yml file
|
40
|
+
SCHEDULER: cron(0 13 ? * MON-FRI *)
|
41
|
+
|
42
|
+
# serverless.yml
|
43
|
+
functions:
|
44
|
+
lambdaName:
|
45
|
+
events:
|
46
|
+
- schedule:
|
47
|
+
rate: ${file(./env.yml):${env:STAGE}.SCHEDULER}
|
48
|
+
```
|
49
|
+
|
50
|
+
To learn how to modify the cron configuration follow this guide: [Schedule expressions using rate or cron](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents-expressions.html)
|
51
|
+
|
52
|
+
#### Building your lambda
|
53
|
+
On your serverless configuration, create your lambda function, on your serverless `/src` folder.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# frozen_string_literal: true
|
57
|
+
|
58
|
+
require 'bas/bot/fetch_birthdays_from_notion'
|
59
|
+
|
60
|
+
# Initialize the environment variables
|
61
|
+
NOTION_DATABASE_ID = ENV.fetch('NOTION_DATABASE_ID')
|
62
|
+
NOTION_SECRET = ENV.fetch('NOTION_SECRET')
|
63
|
+
|
64
|
+
module Notifier
|
65
|
+
# Service description
|
66
|
+
class UseCaseName
|
67
|
+
def self.notify(*)
|
68
|
+
options = { process_options: , write_options: }
|
69
|
+
|
70
|
+
begin
|
71
|
+
use_case = Bot::FetchBirthdaysFromNotion.new(options)
|
72
|
+
|
73
|
+
use_case.execute
|
74
|
+
rescue StandardError => e
|
75
|
+
{ body: { message: e.message } }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.process_options
|
80
|
+
{
|
81
|
+
database_id: NOTION_DATABASE_ID,
|
82
|
+
secret: NOTION_SECRET
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.write_options
|
87
|
+
{
|
88
|
+
connection: {
|
89
|
+
host: "host",
|
90
|
+
port: 5432,
|
91
|
+
dbname: "bas",
|
92
|
+
user: "postgres",
|
93
|
+
password: "postgres"
|
94
|
+
},
|
95
|
+
db_table: "use_cases",
|
96
|
+
bot_name: "FetchBirthdaysFromNotion"
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
#### Configure the lambda
|
104
|
+
In the `serverless.yml` file, add a new instance in the `functions` block with this structure:
|
105
|
+
|
106
|
+
```bash
|
107
|
+
functions:
|
108
|
+
fetchBirthdayFromNotion:
|
109
|
+
handler: src/lambdas/birthday_fetch.Bot::Birthday.fetch
|
110
|
+
environment:
|
111
|
+
BIRTHDAY_NOTION_DATABASE_ID: ${file(./env.yml):${env:STAGE}.BIRTHDAY_NOTION_DATABASE_ID}
|
112
|
+
BIRTHDAY_NOTION_SECRET: ${file(./env.yml):${env:STAGE}.BIRTHDAY_NOTION_SECRET}
|
113
|
+
events:
|
114
|
+
- schedule:
|
115
|
+
name: birthday-fetch
|
116
|
+
description: "Fetch every 24 hours at 8:30 a.m (UTC-5) from monday to friday"
|
117
|
+
rate: cron(${file(./env.yml):${env:STAGE}.BIRTHDAY_FETCH_SCHEDULER})
|
118
|
+
enabled: true
|
119
|
+
```
|
120
|
+
|
121
|
+
#### Deploying
|
122
|
+
|
123
|
+
Configure the AWS keys:
|
124
|
+
|
125
|
+
```bash
|
126
|
+
serverless config credentials --provider aws --key YOUR_KEY --secret YOUR_SECRET
|
127
|
+
```
|
128
|
+
|
129
|
+
Deploy the project:
|
130
|
+
```bash
|
131
|
+
STAGE=prod sls deploy --verbose
|
132
|
+
```
|
@@ -56,6 +56,7 @@ module Bot
|
|
56
56
|
include Utils::Notion::Types
|
57
57
|
|
58
58
|
UPDATE_REQUEST = "UpdateWorkItemRequest"
|
59
|
+
STATUS = "Backlog"
|
59
60
|
|
60
61
|
# read function to execute the PostgresDB Read component
|
61
62
|
#
|
@@ -117,17 +118,17 @@ module Bot
|
|
117
118
|
|
118
119
|
def properties # rubocop:disable Metrics/AbcSize
|
119
120
|
{
|
120
|
-
"Responsible domain": select(
|
121
|
-
"Github Issue
|
122
|
-
"Status": status(
|
121
|
+
"Responsible domain": select(read_response.data["domain"]),
|
122
|
+
"Github Issue Id": rich_text(read_response.data["issue"]["id"].to_s),
|
123
|
+
"Status": status(STATUS),
|
123
124
|
"Detail": title(read_response.data["issue"]["title"])
|
124
125
|
}.merge(work_item_type)
|
125
126
|
end
|
126
127
|
|
127
128
|
def work_item_type
|
128
|
-
case
|
129
|
-
when "activity" then { "Activity": relation(
|
130
|
-
when "project" then { "Project": relation(
|
129
|
+
case read_response.data["work_item_type"]
|
130
|
+
when "activity" then { "Activity": relation(read_response.data["type_id"]) }
|
131
|
+
when "project" then { "Project": relation(read_response.data["type_id"]) }
|
131
132
|
else {}
|
132
133
|
end
|
133
134
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "./base"
|
4
|
-
require_relative "../read/
|
4
|
+
require_relative "../read/postgres"
|
5
5
|
require_relative "../utils/digital_ocean/request"
|
6
6
|
require_relative "../write/postgres"
|
7
7
|
|
@@ -37,7 +37,7 @@ module Bot
|
|
37
37
|
# Read function to execute the default Read component
|
38
38
|
#
|
39
39
|
def read
|
40
|
-
reader = Read::
|
40
|
+
reader = Read::Postgres.new(read_options.merge(conditions))
|
41
41
|
|
42
42
|
reader.execute
|
43
43
|
end
|
@@ -48,8 +48,7 @@ module Bot
|
|
48
48
|
response = Utils::DigitalOcean::Request.execute(params)
|
49
49
|
|
50
50
|
if response.code == 200
|
51
|
-
|
52
|
-
{ success: { billing: response.parsed_response } }
|
51
|
+
{ success: { billing: response.parsed_response, last_billing: } }
|
53
52
|
else
|
54
53
|
{ error: { message: response.parsed_response, status_code: response.code } }
|
55
54
|
end
|
@@ -65,6 +64,13 @@ module Bot
|
|
65
64
|
|
66
65
|
private
|
67
66
|
|
67
|
+
def conditions
|
68
|
+
{
|
69
|
+
where: "archived=$1 AND tag=$2 ORDER BY inserted_at DESC",
|
70
|
+
params: [false, read_options[:tag]]
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
68
74
|
def params
|
69
75
|
{
|
70
76
|
endpoint: "customers/my/balance",
|
@@ -73,5 +79,11 @@ module Bot
|
|
73
79
|
body: {}
|
74
80
|
}
|
75
81
|
end
|
82
|
+
|
83
|
+
def last_billing
|
84
|
+
return read_response.data["billing"] unless read_response.data.nil?
|
85
|
+
|
86
|
+
{ month_to_date_balance: 0 }
|
87
|
+
end
|
76
88
|
end
|
77
89
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "./base"
|
4
|
-
require_relative "../read/
|
4
|
+
require_relative "../read/postgres"
|
5
5
|
require_relative "../utils/github/octokit_client"
|
6
6
|
require_relative "../write/postgres"
|
7
7
|
|
@@ -32,6 +32,15 @@ module Bot
|
|
32
32
|
# repo: "repository name",
|
33
33
|
# filters: "hash with filters",
|
34
34
|
# organization: "GitHub organization name"
|
35
|
+
# connection: {
|
36
|
+
# host: "localhost",
|
37
|
+
# port: 5432,
|
38
|
+
# dbname: "bas",
|
39
|
+
# user: "postgres",
|
40
|
+
# password: "postgres"
|
41
|
+
# },
|
42
|
+
# db_table: "github_issues",
|
43
|
+
# tag: "GithubIssueRequest"
|
35
44
|
# },
|
36
45
|
# write_options: {
|
37
46
|
# connection: {
|
@@ -50,7 +59,7 @@ module Bot
|
|
50
59
|
# bot.execute
|
51
60
|
#
|
52
61
|
class FetchGithubIssues < Bot::Base
|
53
|
-
ISSUE_PARAMS = %i[id html_url title body labels state created_at updated_at].freeze
|
62
|
+
ISSUE_PARAMS = %i[id html_url title body labels state created_at updated_at state].freeze
|
54
63
|
PER_PAGE = 100
|
55
64
|
|
56
65
|
# read function to execute the PostgresDB Read component
|
@@ -69,9 +78,9 @@ module Bot
|
|
69
78
|
if octokit[:client]
|
70
79
|
repo_issues = octokit[:client].issues(@process_options[:repo], filters)
|
71
80
|
|
72
|
-
|
81
|
+
normalize_response(repo_issues).each { |issue| create_request(issue) }
|
73
82
|
|
74
|
-
{ success: {
|
83
|
+
{ success: { created: true } }
|
75
84
|
else
|
76
85
|
{ error: octokit[:error] }
|
77
86
|
end
|
@@ -107,7 +116,7 @@ module Bot
|
|
107
116
|
def filters
|
108
117
|
default_filter = { per_page: PER_PAGE }
|
109
118
|
|
110
|
-
filters =
|
119
|
+
filters = process_options[:filters]
|
111
120
|
filters = filters.merge({ since: read_response.inserted_at }) unless read_response.nil?
|
112
121
|
|
113
122
|
filters.is_a?(Hash) ? default_filter.merge(filters) : default_filter
|
@@ -121,5 +130,18 @@ module Bot
|
|
121
130
|
end
|
122
131
|
end
|
123
132
|
end
|
133
|
+
|
134
|
+
def create_request(issue)
|
135
|
+
write_data = {
|
136
|
+
success: {
|
137
|
+
issue:,
|
138
|
+
work_item_type: process_options[:work_item_type],
|
139
|
+
type_id: process_options[:type_id],
|
140
|
+
domain: process_options[:domain]
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
Write::Postgres.new(process_options, write_data).execute
|
145
|
+
end
|
124
146
|
end
|
125
147
|
end
|
@@ -79,25 +79,30 @@ module Bot
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def threshold_exceeded
|
82
|
-
|
82
|
+
return false if billing.zero?
|
83
|
+
|
84
|
+
usage > process_options[:threshold]
|
85
|
+
end
|
86
|
+
|
87
|
+
def usage
|
88
|
+
billing - last_billing
|
83
89
|
end
|
84
90
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
91
|
+
def billing
|
92
|
+
read_response.data["billing"]["month_to_date_balance"].to_f
|
93
|
+
end
|
88
94
|
|
89
|
-
|
95
|
+
def last_billing
|
96
|
+
read_response.data["last_billing"]["month_to_date_balance"].to_f
|
90
97
|
end
|
91
98
|
|
92
99
|
def message
|
93
|
-
balance =
|
100
|
+
balance = billing
|
94
101
|
threshold = process_options[:threshold]
|
95
102
|
|
96
|
-
"
|
97
|
-
Current balance: #{balance}
|
98
|
-
|
99
|
-
Current daily usage: #{daily_usage.round(3)}
|
100
|
-
"""
|
103
|
+
":warning: The **DigitalOcean** daily usage was exceeded. \
|
104
|
+
Current balance: #{balance}, Threshold: #{threshold}, \
|
105
|
+
Current daily usage: #{usage.round(3)}"
|
101
106
|
end
|
102
107
|
end
|
103
108
|
end
|
@@ -8,6 +8,8 @@ require_relative "../read/postgres"
|
|
8
8
|
require_relative "../utils/notion/request"
|
9
9
|
require_relative "../utils/notion/types"
|
10
10
|
require_relative "../utils/notion/delete_page_blocks"
|
11
|
+
require_relative "../utils/notion/fetch_database_record"
|
12
|
+
require_relative "../utils/notion/update_db_page"
|
11
13
|
require_relative "../write/postgres"
|
12
14
|
|
13
15
|
module Bot
|
@@ -53,6 +55,7 @@ module Bot
|
|
53
55
|
include Utils::Notion::Types
|
54
56
|
|
55
57
|
DESCRIPTION = "Issue Description"
|
58
|
+
GITHUB_COLUMN = "Username"
|
56
59
|
|
57
60
|
# read function to execute the PostgresDB Read component
|
58
61
|
#
|
@@ -67,11 +70,11 @@ module Bot
|
|
67
70
|
def process
|
68
71
|
return { success: { updated: nil } } if unprocessable_response
|
69
72
|
|
70
|
-
|
71
|
-
|
72
|
-
response = Utils::Notion::Request.execute(params)
|
73
|
+
response = process_wi
|
73
74
|
|
74
75
|
if response.code == 200
|
76
|
+
update_assigness
|
77
|
+
|
75
78
|
{ success: { issue: read_response.data["issue"] } }
|
76
79
|
else
|
77
80
|
{ error: { message: response.parsed_response, status_code: response.code } }
|
@@ -95,6 +98,12 @@ module Bot
|
|
95
98
|
}
|
96
99
|
end
|
97
100
|
|
101
|
+
def process_wi
|
102
|
+
delete_wi
|
103
|
+
|
104
|
+
Utils::Notion::Request.execute(params)
|
105
|
+
end
|
106
|
+
|
98
107
|
def params
|
99
108
|
{
|
100
109
|
endpoint: "blocks/#{read_response.data["notion_wi"]}/children",
|
@@ -121,12 +130,52 @@ module Bot
|
|
121
130
|
end
|
122
131
|
|
123
132
|
def delete_wi
|
124
|
-
|
133
|
+
options = {
|
125
134
|
page_id: read_response.data["notion_wi"],
|
126
135
|
secret: process_options[:secret]
|
127
136
|
}
|
128
137
|
|
129
|
-
Utils::Notion::DeletePageBlocks.new(
|
138
|
+
Utils::Notion::DeletePageBlocks.new(options).execute
|
139
|
+
end
|
140
|
+
|
141
|
+
def update_assigness
|
142
|
+
relation = users.map { |user| user_id(user) }
|
143
|
+
|
144
|
+
options = {
|
145
|
+
page_id: read_response.data["notion_wi"],
|
146
|
+
secret: process_options[:secret],
|
147
|
+
body: { properties: { People: { relation: } }.merge(status) }
|
148
|
+
}
|
149
|
+
|
150
|
+
Utils::Notion::UpdateDatabasePage.new(options).execute
|
151
|
+
end
|
152
|
+
|
153
|
+
def users
|
154
|
+
options = {
|
155
|
+
database_id: process_options[:users_database_id],
|
156
|
+
secret: process_options[:secret],
|
157
|
+
body: { filter: { or: github_usernames } }
|
158
|
+
}
|
159
|
+
|
160
|
+
Utils::Notion::FetchDatabaseRecord.new(options).execute
|
161
|
+
end
|
162
|
+
|
163
|
+
def github_usernames
|
164
|
+
read_response.data["issue"]["assignees"].map do |username|
|
165
|
+
{ property: GITHUB_COLUMN, rich_text: { equals: username } }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def user_id(user)
|
170
|
+
relation = user.dig("properties", "People", "relation")
|
171
|
+
|
172
|
+
relation.nil? ? {} : relation.first
|
173
|
+
end
|
174
|
+
|
175
|
+
def status
|
176
|
+
return {} unless read_response.data["issue"]["state"] == "closed"
|
177
|
+
|
178
|
+
{ Status: { status: { name: "Done" } } }
|
130
179
|
end
|
131
180
|
end
|
132
181
|
end
|
@@ -50,6 +50,7 @@ module Bot
|
|
50
50
|
#
|
51
51
|
class VerifyIssueExistanceInNotion < Bot::Base
|
52
52
|
NOT_FOUND = "not found"
|
53
|
+
NOTION_PROPERTY = "Github Issue Id"
|
53
54
|
|
54
55
|
# read function to execute the PostgresDB Read component
|
55
56
|
#
|
@@ -70,7 +71,7 @@ module Bot
|
|
70
71
|
if response.code == 200
|
71
72
|
result = response.parsed_response["results"].first
|
72
73
|
|
73
|
-
{ success:
|
74
|
+
{ success: read_response.data.merge({ notion_wi: notion_wi_id(result) }) }
|
74
75
|
else
|
75
76
|
{ error: { message: response.parsed_response, status_code: response.code } }
|
76
77
|
end
|
@@ -107,8 +108,8 @@ module Bot
|
|
107
108
|
def body
|
108
109
|
{
|
109
110
|
filter: {
|
110
|
-
property:
|
111
|
-
rich_text: { equals: read_response.data["
|
111
|
+
property: NOTION_PROPERTY,
|
112
|
+
rich_text: { equals: read_response.data["issue"]["id"].to_s }
|
112
113
|
}
|
113
114
|
}
|
114
115
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httparty"
|
4
|
+
require_relative "request"
|
5
|
+
|
6
|
+
module Utils
|
7
|
+
module Notion
|
8
|
+
##
|
9
|
+
# This module is a Notion utility for fetching record from a database.
|
10
|
+
#
|
11
|
+
class FetchDatabaseRecord
|
12
|
+
# Implements the fetch page process logic to Notion.
|
13
|
+
#
|
14
|
+
# <br>
|
15
|
+
# <b>Params:</b>
|
16
|
+
# * <tt>database_id</tt> Id of the notion database.
|
17
|
+
# * <tt>secret</tt> Notion secret.
|
18
|
+
# * <tt>body</tt> Body with the filters.
|
19
|
+
#
|
20
|
+
# <br>
|
21
|
+
# <b>returns</b> <tt>HTTParty::Response</tt>
|
22
|
+
#
|
23
|
+
#
|
24
|
+
def initialize(options)
|
25
|
+
@options = options
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute
|
29
|
+
records = Utils::Notion::Request.execute(params)
|
30
|
+
|
31
|
+
records.parsed_response["results"] || []
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def params
|
37
|
+
{
|
38
|
+
endpoint: "databases/#{@options[:database_id]}/query",
|
39
|
+
secret: @options[:secret],
|
40
|
+
method: "post",
|
41
|
+
body: @options[:body]
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httparty"
|
4
|
+
require_relative "request"
|
5
|
+
|
6
|
+
module Utils
|
7
|
+
module Notion
|
8
|
+
##
|
9
|
+
# This module is a Notion utility for updating database properties.
|
10
|
+
#
|
11
|
+
class UpdateDatabasePage
|
12
|
+
# Implements the update database properties process logic to Notion.
|
13
|
+
#
|
14
|
+
# <br>
|
15
|
+
# <b>Params:</b>
|
16
|
+
# * <tt>page_id</tt> Id of the notion page.
|
17
|
+
# * <tt>secret</tt> Notion secret.
|
18
|
+
# * <tt>body</tt> Request body with the properties to be updated.
|
19
|
+
#
|
20
|
+
# <br>
|
21
|
+
# <b>returns</b> <tt>HTTParty::Response</tt>
|
22
|
+
#
|
23
|
+
#
|
24
|
+
def initialize(options)
|
25
|
+
@options = options
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute
|
29
|
+
Utils::Notion::Request.execute(params)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def params
|
35
|
+
{
|
36
|
+
endpoint: "pages/#{@options[:page_id]}",
|
37
|
+
secret: @options[:secret],
|
38
|
+
method: "patch",
|
39
|
+
body: @options[:body]
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/bas/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bas
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kommitters Open Source
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gmail_xoauth
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- README.md
|
185
185
|
- Rakefile
|
186
186
|
- SECURITY.md
|
187
|
+
- examples/serverless_example.md
|
187
188
|
- lib/bas.rb
|
188
189
|
- lib/bas/bot/base.rb
|
189
190
|
- lib/bas/bot/compare_wip_limit_count.rb
|
@@ -213,7 +214,6 @@ files:
|
|
213
214
|
- lib/bas/bot/update_work_item.rb
|
214
215
|
- lib/bas/bot/verify_issue_existance_in_notion.rb
|
215
216
|
- lib/bas/bot/write_domain_review_requests.rb
|
216
|
-
- lib/bas/bot/write_github_issue_requests.rb
|
217
217
|
- lib/bas/bot/write_media_review_in_notion.rb
|
218
218
|
- lib/bas/bot/write_media_review_requests.rb
|
219
219
|
- lib/bas/read/base.rb
|
@@ -228,8 +228,10 @@ files:
|
|
228
228
|
- lib/bas/utils/google/send_email.rb
|
229
229
|
- lib/bas/utils/imap/request.rb
|
230
230
|
- lib/bas/utils/notion/delete_page_blocks.rb
|
231
|
+
- lib/bas/utils/notion/fetch_database_record.rb
|
231
232
|
- lib/bas/utils/notion/request.rb
|
232
233
|
- lib/bas/utils/notion/types.rb
|
234
|
+
- lib/bas/utils/notion/update_db_page.rb
|
233
235
|
- lib/bas/utils/notion/update_db_state.rb
|
234
236
|
- lib/bas/utils/openai/run_assistant.rb
|
235
237
|
- lib/bas/utils/postgres/request.rb
|
@@ -1,96 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "./base"
|
4
|
-
require_relative "../read/postgres"
|
5
|
-
require_relative "../write/postgres"
|
6
|
-
|
7
|
-
module Bot
|
8
|
-
##
|
9
|
-
# The Bot::WriteGithubIssueRequests class serves as a bot implementation to write GitHub issues
|
10
|
-
# request to be sent individually.
|
11
|
-
#
|
12
|
-
# <br>
|
13
|
-
# <b>Example</b>
|
14
|
-
#
|
15
|
-
# options = {
|
16
|
-
# read_options: {
|
17
|
-
# connection: {
|
18
|
-
# host: "localhost",
|
19
|
-
# port: 5432,
|
20
|
-
# dbname: "bas",
|
21
|
-
# user: "postgres",
|
22
|
-
# password: "postgres"
|
23
|
-
# },
|
24
|
-
# db_table: "github_issues",
|
25
|
-
# tag: "FetchGithubIssues"
|
26
|
-
# },
|
27
|
-
# process_options: {
|
28
|
-
# connection: {
|
29
|
-
# host: "localhost",
|
30
|
-
# port: 5432,
|
31
|
-
# dbname: "bas",
|
32
|
-
# user: "postgres",
|
33
|
-
# password: "postgres"
|
34
|
-
# },
|
35
|
-
# db_table: "github_issues",
|
36
|
-
# tag: "GithubIssueRequest"
|
37
|
-
# },
|
38
|
-
# write_options: {
|
39
|
-
# connection: {
|
40
|
-
# host: "localhost",
|
41
|
-
# port: 5432,
|
42
|
-
# dbname: "bas",
|
43
|
-
# user: "postgres",
|
44
|
-
# password: "postgres"
|
45
|
-
# },
|
46
|
-
# db_table: "github_issues",
|
47
|
-
# tag: "WriteGithubIssueRequests"
|
48
|
-
# }
|
49
|
-
# }
|
50
|
-
#
|
51
|
-
# bot = Bot::WriteGithubIssueRequests.new(options)
|
52
|
-
# bot.execute
|
53
|
-
#
|
54
|
-
class WriteGithubIssueRequests < Bot::Base
|
55
|
-
# read function to execute the PostgresDB Read component
|
56
|
-
#
|
57
|
-
def read
|
58
|
-
reader = Read::Postgres.new(read_options.merge(conditions))
|
59
|
-
|
60
|
-
reader.execute
|
61
|
-
end
|
62
|
-
|
63
|
-
# Process function to write GitHub issues requests.
|
64
|
-
#
|
65
|
-
def process
|
66
|
-
return { success: { created: nil } } if unprocessable_response
|
67
|
-
|
68
|
-
read_response.data["issues"].each { |request| create_request(request) }
|
69
|
-
|
70
|
-
{ success: { created: true } }
|
71
|
-
end
|
72
|
-
|
73
|
-
# Write function to execute the PostgresDB write component
|
74
|
-
#
|
75
|
-
def write
|
76
|
-
write = Write::Postgres.new(write_options, process_response)
|
77
|
-
|
78
|
-
write.execute
|
79
|
-
end
|
80
|
-
|
81
|
-
private
|
82
|
-
|
83
|
-
def conditions
|
84
|
-
{
|
85
|
-
where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
|
86
|
-
params: [false, read_options[:tag], "unprocessed"]
|
87
|
-
}
|
88
|
-
end
|
89
|
-
|
90
|
-
def create_request(request)
|
91
|
-
write_data = { success: { request: } }
|
92
|
-
|
93
|
-
Write::Postgres.new(process_options, write_data).execute
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|