github_bot 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/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- data/.github/ISSUE_TEMPLATE/config.yml +6 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +30 -0
- data/.github/pull_request_template.md +32 -0
- data/.github/workflows/cd.yml +53 -0
- data/.github/workflows/ci.yml +39 -0
- data/.gitignore +23 -0
- data/.rspec +4 -0
- data/.rubocop.yml +927 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +2 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +40 -0
- data/CONTRIBUTORS.md +3 -0
- data/Gemfile +22 -0
- data/LICENSE +205 -0
- data/NOTICE +13 -0
- data/README.md +66 -0
- data/Rakefile +8 -0
- data/app/controllers/github_bot/application_controller.rb +40 -0
- data/app/controllers/github_bot/concerns/response.rb +25 -0
- data/app/controllers/github_bot/webhooks/github_controller.rb +36 -0
- data/app/helpers/github_bot/github_request_helper.rb +123 -0
- data/bin/bundle-audit +29 -0
- data/bin/bundler-audit +29 -0
- data/bin/rails +26 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/config/routes.rb +13 -0
- data/github_bot.gemspec +36 -0
- data/lib/github_bot.rb +10 -0
- data/lib/github_bot/engine.rb +9 -0
- data/lib/github_bot/github/check_run.rb +56 -0
- data/lib/github_bot/github/client.rb +203 -0
- data/lib/github_bot/github/payload.rb +225 -0
- data/lib/github_bot/rails/railtie.rb +15 -0
- data/lib/github_bot/tasks/base.rb +42 -0
- data/lib/github_bot/validator/base.rb +232 -0
- data/lib/github_bot/version.rb +11 -0
- metadata +154 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Only include in the context of a rails application
|
4
|
+
return unless defined?(Rails)
|
5
|
+
|
6
|
+
require 'octokit'
|
7
|
+
|
8
|
+
module GithubBot
|
9
|
+
# Public: Railtie for injecting configuration of Octokit in a Rails environment
|
10
|
+
class Railtie < ::Rails::Railtie
|
11
|
+
config.after_initialize do
|
12
|
+
Octokit.configure { |c| c.api_endpoint = "https://#{ENV['GITHUB_HOST']}/api/v3/" } if ENV['GITHUB_HOST'].present?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GithubBot
|
4
|
+
module Tasks
|
5
|
+
# Public: Base class for establishing tasks to be executed via a validator
|
6
|
+
class Base
|
7
|
+
# Public: Returns the validator associated to the task execution
|
8
|
+
attr_reader :validator
|
9
|
+
|
10
|
+
# Public: Initialize the task from a specific validator
|
11
|
+
#
|
12
|
+
# @param validator [GithubBot::Validator::Base] An instance of the validator that is asking for the task
|
13
|
+
def initialize(validator)
|
14
|
+
@validator = validator
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# because tasks are executed by a validator, some methods are relayed across
|
20
|
+
# from the task back to the validator. this override checks for that existence
|
21
|
+
def method_missing(method, *args, &block)
|
22
|
+
return super unless respond_to_missing?(method)
|
23
|
+
|
24
|
+
@validator.send(method, *args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# because tasks are executed by a validator, some methods are relayed across
|
28
|
+
# from the task back to the validator. this override checks for that existence
|
29
|
+
def respond_to_missing?(method, *args)
|
30
|
+
@validator.respond_to?(method, *args)
|
31
|
+
end
|
32
|
+
|
33
|
+
# returns the github client api established either by the task or the validator
|
34
|
+
def client_api
|
35
|
+
# evaluate if the validator has defined the api and delegate accordingly
|
36
|
+
return validator.client_api if validator.respond_to?(:client_api)
|
37
|
+
|
38
|
+
::GithubBot::Github::Client.instance
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GithubBot
|
4
|
+
module Validator
|
5
|
+
# Public: Base class for validators to extend to provide helpful
|
6
|
+
# methods for interactions with GitHub
|
7
|
+
class Base
|
8
|
+
class << self
|
9
|
+
# Public: Validation method that every consumer will need to override
|
10
|
+
def validate; end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Public: Initializes an instance of the validator
|
14
|
+
def initialize
|
15
|
+
@feedback = []
|
16
|
+
@check = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# Public: Provide feedback to be generated upon completion of the check run
|
20
|
+
# see https://docs.github.com/en/rest/reference/checks#create-a-check-run for additional
|
21
|
+
# details on available parameters for the 'annotations' item
|
22
|
+
def feedback(path:, start_line: 0, end_line: 0, annotation_level:, message:, **opts)
|
23
|
+
@feedback << {
|
24
|
+
path: path,
|
25
|
+
start_line: start_line,
|
26
|
+
end_line: end_line,
|
27
|
+
annotation_level: annotation_level,
|
28
|
+
message: message,
|
29
|
+
**opts
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Public: Moves the check run into the in progress status
|
34
|
+
def in_progress(**opts)
|
35
|
+
raise StandardError, 'check run has not been established' unless @check
|
36
|
+
|
37
|
+
defaults = {
|
38
|
+
output: {
|
39
|
+
title: "#{@check.name} validation is in progress...",
|
40
|
+
summary: 'We\'re currently validating this request. Please stand by.'
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
@check.in_progress!(defaults.deep_merge(opts))
|
45
|
+
end
|
46
|
+
|
47
|
+
# Public: Block for execution logic that is the be evaluated and finalized
|
48
|
+
# within the GitHub check run content
|
49
|
+
def check_run(name:, **_opts)
|
50
|
+
# queue request for processing
|
51
|
+
@check = client_api.create_check_run(
|
52
|
+
name: name,
|
53
|
+
output: {
|
54
|
+
title: "#{name} validation has been queued...",
|
55
|
+
summary: "We're awaiting processing."
|
56
|
+
}
|
57
|
+
)
|
58
|
+
|
59
|
+
yield if block_given?
|
60
|
+
|
61
|
+
if @feedback.empty?
|
62
|
+
@check.complete!(
|
63
|
+
output: {
|
64
|
+
title: "#{name} validation is complete...",
|
65
|
+
summary: "#{name} validation passed!"
|
66
|
+
}
|
67
|
+
)
|
68
|
+
|
69
|
+
else
|
70
|
+
# because limitation of 50 checks per API call execution, break up annotations
|
71
|
+
# https://developer.github.com/v3/checks/runs/
|
72
|
+
@feedback.each_slice(50).to_a.each do |annotations|
|
73
|
+
@check.action_required!(
|
74
|
+
output: {
|
75
|
+
title: "#{name} validation is complete...",
|
76
|
+
summary: "#{name} validation determined there are changes that need attention.",
|
77
|
+
annotations: annotations
|
78
|
+
}
|
79
|
+
)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
rescue StandardError => e
|
83
|
+
Rails.logger.error message: 'Error occurred during check run', exception: e
|
84
|
+
@check.action_required!(
|
85
|
+
output: {
|
86
|
+
title: "#{name} validation failed...",
|
87
|
+
summary: "# Message\n```\n#{e.message}\n```\n# Exception\n```\n#{e.backtrace.join("\n")}\n```"
|
88
|
+
}
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Public: Return all files from request.
|
93
|
+
def files
|
94
|
+
client_api.files
|
95
|
+
end
|
96
|
+
|
97
|
+
# Public: Return the modified files from request.
|
98
|
+
def modified_files
|
99
|
+
client_api.modified_files
|
100
|
+
end
|
101
|
+
|
102
|
+
# Public: Validates the file extension for the provided file
|
103
|
+
#
|
104
|
+
# @param file [Sawyer::Resource] The file to evaluate
|
105
|
+
# @param extension [String] The extension type to evaluate
|
106
|
+
def validate_file_extension(file, extension)
|
107
|
+
return if File.extname(file.filename) == ".#{extension}"
|
108
|
+
|
109
|
+
feedback(
|
110
|
+
path: file.filename,
|
111
|
+
annotation_level: 'failure',
|
112
|
+
message: "File suffix is incorrect, please use '.#{extension}'"
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Public: Loads the yaml of the file provided
|
117
|
+
#
|
118
|
+
# @param file [Sawyer::Resource] The file to load
|
119
|
+
def load_yaml(file)
|
120
|
+
YAML.safe_load(client_api.file_content(file)).with_indifferent_access
|
121
|
+
rescue StandardError => e
|
122
|
+
feedback(
|
123
|
+
path: file.filename,
|
124
|
+
annotation_level: 'failure',
|
125
|
+
message: 'Malformed yaml content'\
|
126
|
+
"exception: #{e.message}"
|
127
|
+
)
|
128
|
+
|
129
|
+
{}
|
130
|
+
end
|
131
|
+
|
132
|
+
# Public: Validates for the provided file at a given hash point that the
|
133
|
+
# required and allowed fields are met
|
134
|
+
#
|
135
|
+
# @param file [Sawyer::Resource] The file for reference that is being evaluated
|
136
|
+
# @param ident [String/Symbol] The text identifier for the hash being evaluated
|
137
|
+
# @param hash [Hash] The hash to review keys
|
138
|
+
# @param required_fields [Array] An array of required elements
|
139
|
+
# @param allowed_fields [Array] An array of allowed fields
|
140
|
+
def validate_fields(file:, ident:, hash:, required_fields:, allowed_fields:, **opts)
|
141
|
+
unless hash
|
142
|
+
feedback(
|
143
|
+
path: file.filename,
|
144
|
+
annotation_level: 'failure',
|
145
|
+
message: 'Element is empty or nil'
|
146
|
+
)
|
147
|
+
|
148
|
+
return
|
149
|
+
end
|
150
|
+
|
151
|
+
validate_required_fields(
|
152
|
+
file: file,
|
153
|
+
ident: ident,
|
154
|
+
hash: hash,
|
155
|
+
required_fields: required_fields,
|
156
|
+
**opts
|
157
|
+
)
|
158
|
+
validate_allowed_fields(
|
159
|
+
file: file,
|
160
|
+
ident: ident,
|
161
|
+
hash: hash,
|
162
|
+
allowed_fields: allowed_fields,
|
163
|
+
**opts
|
164
|
+
)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Public: Validates for the provided file at a given hash point that the
|
168
|
+
# required fields are met
|
169
|
+
#
|
170
|
+
# @param file [Sawyer::Resource] The file for reference that is being evaluated
|
171
|
+
# @param ident [String/Symbol] The text identifier for the hash being evaluated
|
172
|
+
# @param hash [Hash] The hash to review keys
|
173
|
+
# @param required_fields [Array] An array of required elements
|
174
|
+
def validate_required_fields(file:, ident:, hash:, required_fields:, **_opts)
|
175
|
+
unless hash
|
176
|
+
feedback(
|
177
|
+
path: file.filename,
|
178
|
+
annotation_level: 'failure',
|
179
|
+
message: "#{ident}: Element is empty or nil"
|
180
|
+
)
|
181
|
+
|
182
|
+
return
|
183
|
+
end
|
184
|
+
|
185
|
+
required_fields.each do |key|
|
186
|
+
next unless hash[key].nil?
|
187
|
+
|
188
|
+
feedback(
|
189
|
+
path: file.filename,
|
190
|
+
annotation_level: 'failure',
|
191
|
+
message: "#{ident}: Missing required element '#{key}'"
|
192
|
+
)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Public: Validates for the provided file at a given hash point that the
|
197
|
+
# allowed fields are met
|
198
|
+
#
|
199
|
+
# @param file [Sawyer::Resource] The file for reference that is being evaluated
|
200
|
+
# @param ident [String/Symbol] The text identifier for the hash being evaluated
|
201
|
+
# @param hash [Hash] The hash to review keys
|
202
|
+
# @param allowed_fields [Array] An array of allowed fields
|
203
|
+
def validate_allowed_fields(file:, ident:, hash:, allowed_fields:, **_opts)
|
204
|
+
unless hash
|
205
|
+
feedback(
|
206
|
+
path: file.filename,
|
207
|
+
annotation_level: 'failure',
|
208
|
+
message: "#{ident}: Element is empty or nil"
|
209
|
+
)
|
210
|
+
|
211
|
+
return
|
212
|
+
end
|
213
|
+
|
214
|
+
hash.keys&.each do |key|
|
215
|
+
unless allowed_fields.include?(key)
|
216
|
+
feedback(
|
217
|
+
path: file.filename,
|
218
|
+
annotation_level: 'failure',
|
219
|
+
message: "#{ident}: Key '#{key}' not in the allowed fields [#{allowed_fields.join(', ')}]"
|
220
|
+
)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
def client_api
|
228
|
+
::GithubBot::Github::Client.instance
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: github_bot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Greg Howdeshell
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-06-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: git
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jwt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: octokit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.18'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.18'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.0.0.1
|
62
|
+
- - "<"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: 7.0.0
|
65
|
+
type: :runtime
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 5.0.0.1
|
72
|
+
- - "<"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 7.0.0
|
75
|
+
description: 'A rubygem designed to assist in the creation of GitHub bot applications.
|
76
|
+
|
77
|
+
'
|
78
|
+
email:
|
79
|
+
- greg.howdeshell@gmail.com
|
80
|
+
executables:
|
81
|
+
- bundle-audit
|
82
|
+
- bundler-audit
|
83
|
+
- rails
|
84
|
+
- rake
|
85
|
+
- rspec
|
86
|
+
- rubocop
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
91
|
+
- ".github/ISSUE_TEMPLATE/config.yml"
|
92
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
93
|
+
- ".github/pull_request_template.md"
|
94
|
+
- ".github/workflows/cd.yml"
|
95
|
+
- ".github/workflows/ci.yml"
|
96
|
+
- ".gitignore"
|
97
|
+
- ".rspec"
|
98
|
+
- ".rubocop.yml"
|
99
|
+
- ".ruby-gemset"
|
100
|
+
- ".ruby-version"
|
101
|
+
- CHANGELOG.md
|
102
|
+
- CODE_OF_CONDUCT.md
|
103
|
+
- CONTRIBUTING.md
|
104
|
+
- CONTRIBUTORS.md
|
105
|
+
- Gemfile
|
106
|
+
- LICENSE
|
107
|
+
- NOTICE
|
108
|
+
- README.md
|
109
|
+
- Rakefile
|
110
|
+
- app/controllers/github_bot/application_controller.rb
|
111
|
+
- app/controllers/github_bot/concerns/response.rb
|
112
|
+
- app/controllers/github_bot/webhooks/github_controller.rb
|
113
|
+
- app/helpers/github_bot/github_request_helper.rb
|
114
|
+
- bin/bundle-audit
|
115
|
+
- bin/bundler-audit
|
116
|
+
- bin/rails
|
117
|
+
- bin/rake
|
118
|
+
- bin/rspec
|
119
|
+
- bin/rubocop
|
120
|
+
- config/routes.rb
|
121
|
+
- github_bot.gemspec
|
122
|
+
- lib/github_bot.rb
|
123
|
+
- lib/github_bot/engine.rb
|
124
|
+
- lib/github_bot/github/check_run.rb
|
125
|
+
- lib/github_bot/github/client.rb
|
126
|
+
- lib/github_bot/github/payload.rb
|
127
|
+
- lib/github_bot/rails/railtie.rb
|
128
|
+
- lib/github_bot/tasks/base.rb
|
129
|
+
- lib/github_bot/validator/base.rb
|
130
|
+
- lib/github_bot/version.rb
|
131
|
+
homepage: https://github.com/cerner/github_bot-ruby
|
132
|
+
licenses:
|
133
|
+
- Apache-2.0
|
134
|
+
metadata: {}
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: 2.6.2
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
requirements: []
|
150
|
+
rubygems_version: 3.0.3.1
|
151
|
+
signing_key:
|
152
|
+
specification_version: 4
|
153
|
+
summary: A rubygem designed to assist in the creation of GitHub bot applications.
|
154
|
+
test_files: []
|