Module: Fbe

Defined in:
lib/fbe.rb,
lib/fbe/unmask_repos.rb
more...

Overview

Unmask.

Author

Yegor Bugayenko (yegor256@gmail.com)

Copyright

Copyright © 2024 Zerocracy

License

MIT

Defined Under Namespace

Classes: Award, Conclude, FakeOctokit, Iterate

Constant Summary collapse

VERSION =

Current version of the gem (changed by .rultor.yml on every release)

'0.0.24'

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.

[View source]

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

[View source]

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)
[View source]

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

[View source]

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.

[View source]

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

[View source]

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

[View source]

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

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
      loog.debug("The 'github_token' option is not provided") if token.nil?
      token = ENV.fetch('GITHUB_TOKEN', nil) if token.nil?
      loog.debug("The 'GITHUB_TOKEN' environment variable is not set") if token.nil?
      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)")
      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],
          max: 5, interval: 1
        )
        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

[View source]

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

[View source]

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

[View source]

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