Module: Fbe

Defined in:
lib/fbe.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.35'

Class Method Summary collapse

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
# 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}/#{options.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.

Yields:

  • (f)


31
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
# File 'lib/fbe/if_absent.rb', line 31

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

.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



36
37
38
39
40
41
42
43
44
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
# File 'lib/fbe/octo.rb', line 36

def Fbe.octo(options: $options, global: $global, loog: $loog)
  raise 'The $global is not set' if global.nil?
  global[:octo] ||= begin
    if options.testing.nil?
      o = Octokit::Client.new
      token = options.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.connection_options = {
        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,
          logger: loog,
          pause: options.github_api_pause
        )
        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

.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
# File 'lib/fbe/unmask_repos.rb', line 38

def self.unmask_repos(options: $options, global: $global, loog: $loog)
  repos = []
  masks = (options.repositories || '').split(',')
  masks.reject { |m| m.start_with?('-') }.each do |mask|
    unless mask.include?('*')
      repos << mask
      next
    end
    re = Fbe.mask_to_regex(mask)
    Fbe.octo(loog:, global:, options:).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
  raise "No repos found matching: #{options.repositories}" if repos.empty?
  loog.debug("Scanning #{repos.size} repositories: #{repos.join(', ')}...")
  repos
end

.who(fact, prop = :who, options: $options, global: $global, loog: $loog) ⇒ Object



27
28
29
# File 'lib/fbe/who.rb', line 27

def Fbe.who(fact, prop = :who, options: $options, global: $global, loog: $loog)
  "@#{Fbe.octo(options:, global:, loog:).user_name_by_id(fact.send(prop.to_s))}"
end