Module: Fbe
- Defined in:
- lib/fbe.rb,
lib/fbe/pmp.rb,
lib/fbe/unmask_repos.rb
Overview
Unmask.
- Author
-
Yegor Bugayenko (yegor256@gmail.com)
- Copyright
-
Copyright © 2024 Zerocracy
- License
-
MIT
Defined Under Namespace
Modules: Middleware Classes: Award, Conclude, FakeOctokit, Iterate
Constant Summary collapse
- VERSION =
Current version of the gem (changed by .rultor.yml on every release)
'0.0.44'
Class Method Summary collapse
-
.conclude(fb: Fbe.fb, judge: $judge, loog: $loog, options: $options, global: $global) ⇒ Object
Create a conclude code block.
- .fb(fb: $fb, global: $global, options: $options, loog: $loog) ⇒ Object
-
.if_absent(fb: Fbe.fb) {|f| ... } ⇒ Object
Injects a fact if it’s absent in the factbase, otherwise (it is already there) returns NIL.
- .issue(fact, options: $options, global: $global, loog: $loog) ⇒ Object
-
.iterate(fb: Fbe.fb, loog: $loog, options: $options, global: $global) ⇒ Object
Create a conclude code block.
-
.just_one(fb: Fbe.fb) {|f| ... } ⇒ Object
Injects a fact if it’s absent in the factbase, otherwise (it is already there) returns the existing one.
- .mask_to_regex(mask) ⇒ Object
-
.octo(options: $options, global: $global, loog: $loog) ⇒ Object
Interface to GitHub API.
-
.overwrite(fact, property, value, fb: Fbe.fb) ⇒ Object
Overwrite a property in the fact.
- .pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog) ⇒ Object
- .regularly(area, p_every_days, p_since_days = nil, fb: Fbe.fb, judge: $judge, loog: $loog) {|f| ... } ⇒ Object
- .sec(fact, prop = :seconds) ⇒ Object
- .unmask_repos(options: $options, global: $global, loog: $loog) ⇒ Object
- .who(fact, prop = :who, options: $options, global: $global, loog: $loog) ⇒ Object
Class Method Details
.conclude(fb: Fbe.fb, judge: $judge, loog: $loog, options: $options, global: $global) ⇒ Object
Create a conclude code block.
31 32 33 34 |
# File 'lib/fbe/conclude.rb', line 31 def Fbe.conclude(fb: Fbe.fb, judge: $judge, loog: $loog, options: $options, global: $global, &) c = Fbe::Conclude.new(fb:, judge:, loog:, options:, global:) c.instance_eval(&) end |
.fb(fb: $fb, global: $global, options: $options, loog: $loog) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/fbe/fb.rb', line 33 def Fbe.fb(fb: $fb, global: $global, options: $options, loog: $loog) global[:fb] ||= begin rules = Dir.glob(File.join('rules', '*.fe')).map { |f| File.read(f) } fbe = Factbase::Rules.new( fb, "(and \n#{rules.join("\n")}\n)", uid: '_id' ) fbe = Factbase::Pre.new(fbe) do |f| max = fb.query('(eq _id (max _id))').each.to_a.first f._id = (max.nil? ? 0 : max._id) + 1 f._time = Time.now f._version = "#{Factbase::VERSION}/#{Judges::VERSION}/#{.judges_action_version}" end Factbase::Looged.new(fbe, loog) end end |
.if_absent(fb: Fbe.fb) {|f| ... } ⇒ Object
Injects a fact if it’s absent in the factbase, otherwise (it is already there) returns NIL.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/fbe/if_absent.rb', line 32 def Fbe.if_absent(fb: Fbe.fb) attrs = {} f = others(map: attrs) do |*args| k = args[0] if k.end_with?('=') @map[k[0..-2].to_sym] = args[1] else @map[k.to_sym] end end yield f q = attrs.except('_id', '_time', '_version').map do |k, v| vv = v.to_s if v.is_a?(String) vv = "'#{vv.gsub('"', '\\\\"').gsub("'", "\\\\'")}'" elsif v.is_a?(Time) vv = v.utc.iso8601 end "(eq #{k} #{vv})" end.join(' ') q = "(and #{q})" return nil unless fb.query(q).each.to_a.empty? n = fb.insert attrs.each { |k, v| n.send("#{k}=", v) } n end |
.issue(fact, options: $options, global: $global, loog: $loog) ⇒ Object
27 28 29 |
# File 'lib/fbe/issue.rb', line 27 def Fbe.issue(fact, options: $options, global: $global, loog: $loog) "#{Fbe.octo(global:, options:, loog:).repo_name_by_id(fact.repository)}##{fact.issue}" end |
.iterate(fb: Fbe.fb, loog: $loog, options: $options, global: $global) ⇒ Object
Create a conclude code block.
31 32 33 34 |
# File 'lib/fbe/iterate.rb', line 31 def Fbe.iterate(fb: Fbe.fb, loog: $loog, options: $options, global: $global, &) c = Fbe::Iterate.new(fb:, loog:, options:, global:) c.instance_eval(&) end |
.just_one(fb: Fbe.fb) {|f| ... } ⇒ Object
Injects a fact if it’s absent in the factbase, otherwise (it is already there) returns the existing one.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/fbe/just_one.rb', line 32 def Fbe.just_one(fb: Fbe.fb) attrs = {} f = others(map: attrs) do |*args| k = args[0] if k.end_with?('=') @map[k[0..-2].to_sym] = args[1] else @map[k.to_sym] end end yield f q = attrs.except('_id', '_time', '_version').map do |k, v| vv = v.to_s if v.is_a?(String) vv = "'#{vv.gsub('"', '\\\\"').gsub("'", "\\\\'")}'" elsif v.is_a?(Time) vv = v.utc.iso8601 end "(eq #{k} #{vv})" end.join(' ') q = "(and #{q})" before = fb.query(q).each.to_a.first return before unless before.nil? n = fb.insert attrs.each { |k, v| n.send("#{k}=", v) } n end |
.mask_to_regex(mask) ⇒ Object
32 33 34 35 36 |
# File 'lib/fbe/unmask_repos.rb', line 32 def self.mask_to_regex(mask) org, repo = mask.split('/') raise "Org '#{org}' can't have an asterisk" if org.include?('*') Regexp.compile("#{org}/#{repo.gsub('*', '.*')}") end |
.octo(options: $options, global: $global, loog: $loog) ⇒ Object
Interface to GitHub API.
It is supposed to be used instead of Octokit client, because it is pre-configured and enables additional fearues, such as retrying, logging, and caching.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/fbe/octo.rb', line 45 def Fbe.octo(options: $options, global: $global, loog: $loog) raise 'The $global is not set' if global.nil? global[:octo] ||= begin if .testing.nil? o = Octokit::Client.new token = .github_token if token.nil? loog.debug("The 'github_token' option is not provided") token = ENV.fetch('GITHUB_TOKEN', nil) if token.nil? loog.debug("The 'GITHUB_TOKEN' environment variable is not set") else loog.debug("The 'GITHUB_TOKEN' environment was provided") end else loog.debug("The 'github_token' option was provided") end if token.nil? loog.warn('Accessing GitHub API without a token!') elsif token.empty? loog.warn('The GitHub API token is an empty string, won\'t use it') else o = Octokit::Client.new(access_token: token) loog.info("Accessing GitHub API with a token (#{token.length} chars, ending by #{token[-4..]})") end o.auto_paginate = true o.per_page = 100 o. = { request: { open_timeout: 15, timeout: 15 } } stack = Faraday::RackBuilder.new do |builder| builder.use( Faraday::Retry::Middleware, exceptions: Faraday::Retry::Middleware::DEFAULT_EXCEPTIONS + [ Octokit::TooManyRequests, Octokit::ServiceUnavailable ], max: 4, interval: ENV['RACK_ENV'] == 'test' ? 0.01 : 4, methods: [:get], backoff_factor: 2 ) builder.use(Fbe::Middleware::Quota, loog:, pause: .github_api_pause || 60) builder.use(Faraday::HttpCache, serializer: Marshal, shared_cache: false, logger: Loog::NULL) builder.use(Octokit::Response::RaiseError) builder.use(Faraday::Response::Logger, Loog::NULL) builder.adapter(Faraday.default_adapter) end o.middleware = stack o = Verbose.new(o, log: loog) else loog.debug('The connection to GitHub API is mocked') o = Fbe::FakeOctokit.new end decoor(o, loog:) do def off_quota left = @origin.rate_limit.remaining if left < 5 @loog.info("To much GitHub API quota consumed already (remaining=#{left}), stopping") true else false end end def user_name_by_id(id) json = @origin.user(id) name = json[:login] @loog.debug("GitHub user ##{id} has a name: @#{name}") name end def repo_id_by_name(name) json = @origin.repository(name) id = json[:id] @loog.debug("GitHub repository #{name} has an ID: ##{id}") id end def repo_name_by_id(id) json = @origin.repository(id) name = json[:full_name] @loog.debug("GitHub repository ##{id} has a name: #{name}") name end end end end |
.overwrite(fact, property, value, fb: Fbe.fb) ⇒ Object
Overwrite a property in the fact.
If the property doesn’t exist in the fact, it will be added. If it does exist, it will be removed (the entire fact will be destroyed, new fact created, and property set).
It is important that the fact has _id
property. If it doesn’t, an exception will be raised.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/fbe/overwrite.rb', line 40 def Fbe.overwrite(fact, property, value, fb: Fbe.fb) raise 'The fact is nil' if fact.nil? before = {} fact.all_properties.each do |prop| before[prop.to_s] = fact[prop] end id = fact['_id']&.first raise 'There is no _id in the fact, cannot use Fbe.overwrite' if id.nil? raise "No facts by _id = #{id}" if fb.query("(eq _id #{id})").delete!.zero? n = fb.insert before[property.to_s] = [value] before.each do |k, vv| next unless n[k].nil? vv.each do |v| n.send("#{k}=", v) end end end |
.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/fbe/pmp.rb', line 31 def Fbe.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog) others do |*args1| area = args1.first others do |*args2| param = args2.first f = Fbe.fb(global:, fb:, options:, loog:).query("(and (eq what 'pmp') (eq area '#{area}'))").each.to_a.first raise "Unknown area '#{area}'" if f.nil? r = f[param] raise "Unknown property '#{param}' in the '#{area}' area" if r.nil? r.first end end end |
.regularly(area, p_every_days, p_since_days = nil, fb: Fbe.fb, judge: $judge, loog: $loog) {|f| ... } ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/fbe/regularly.rb', line 28 def Fbe.regularly(area, p_every_days, p_since_days = nil, fb: Fbe.fb, judge: $judge, loog: $loog, &) pmp = fb.query("(and (eq what 'pmp') (eq area '#{area}') (exists #{p_every_days}))").each.to_a.first interval = pmp.nil? ? 7 : pmp[p_every_days].first unless fb.query( "(and (eq what '#{judge}') (gt when (minus (to_time (env 'TODAY' '#{Time.now.utc.iso8601}')) '#{interval} days')))" ).each.to_a.empty? loog.debug("#{$judge} statistics have recently been collected, skipping now") return end f = fb.insert f.what = judge f.when = Time.now unless p_since_days.nil? days = pmp.nil? ? 28 : pmp[p_since_days].first since = Time.now - (days * 24 * 60 * 60) f.since = since end yield f end |
.sec(fact, prop = :seconds) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/fbe/sec.rb', line 27 def Fbe.sec(fact, prop = :seconds) s = fact.send(prop.to_s) if s < 60 format('%d seconds', s) elsif s < 60 * 60 format('%d minutes', s / 60) elsif s < 60 * 60 * 24 format('%d hours', s / (60 * 60)) else format('%d days', s / (60 * 60 * 24)) end end |
.unmask_repos(options: $options, global: $global, loog: $loog) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/fbe/unmask_repos.rb', line 38 def self.unmask_repos(options: $options, global: $global, loog: $loog) repos = [] octo = Fbe.octo(loog:, global:, options:) masks = (.repositories || '').split(',') masks.reject { |m| m.start_with?('-') }.each do |mask| unless mask.include?('*') repos << mask next end re = Fbe.mask_to_regex(mask) octo.repositories(mask.split('/')[0]).each do |r| repos << r[:full_name] if re.match?(r[:full_name]) end end masks.select { |m| m.start_with?('-') }.each do |mask| re = Fbe.mask_to_regex(mask[1..]) repos.reject! { |r| re.match?(r) } end repos.reject! { |repo| octo.repository(repo)[:archived] } raise "No repos found matching: #{.repositories}" if repos.empty? loog.debug("Scanning #{repos.size} repositories: #{repos.join(', ')}...") repos end |