Module: Fbe

Defined in:
lib/fbe.rb

Overview

The main and only module of this gem.

Author

Yegor Bugayenko (yegor256@gmail.com)

Copyright

Copyright © 2024-2025 Zerocracy

License

MIT

Defined Under Namespace

Modules: Middleware Classes: Award, Conclude, FakeOctokit, Graph, Iterate

Constant Summary collapse

VERSION =

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

'0.2.0'

Class Method Summary collapse

Class Method Details

.bylaws(anger: 2, love: 2, paranoia: 2) ⇒ Hash<String, String>

Generates policies/bylaws.

Using the templates stored in the assets/bylaws directory, this function creates a hash, where keys are names and values are formulas of bylaws.

Parameters:

  • anger (Integer) (defaults to: 2)

    How strict must be the bylaws, giving punishments

  • love (Integer) (defaults to: 2)

    How big should be the volume of rewards

  • paranoia (Integer) (defaults to: 2)

    How much should be required to reward love

Returns:

  • (Hash<String, String>)

    Names of bylaws and their formulas



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/fbe/bylaws.rb', line 18

def Fbe.bylaws(anger: 2, love: 2, paranoia: 2)
  raise "The 'anger' must be in the [0..4] interval: #{anger.inspect}" unless !anger.negative? && anger < 5
  raise "The 'love' must be in the [0..4] interval: #{love.inspect}" unless !love.negative? && love < 5
  raise "The 'paranoia' must be in the [1..4] interval: #{paranoia.inspect}" unless paranoia.positive? && paranoia < 5
  home = File.join(__dir__, '../../assets/bylaws')
  raise "The directory with templates is absent #{home.inspect}" unless File.exist?(home)
  Dir[File.join(home, '*.liquid')].to_h do |f|
    formula = Liquid::Template.parse(File.read(f)).render(
      'anger' => anger, 'love' => love, 'paranoia' => paranoia
    )
    [File.basename(f).gsub(/\.liquid$/, ''), formula]
  end
end

.conclude(fb: Fbe.fb, judge: $judge, loog: $loog, options: $options, global: $global) {|Factbase::Fact| ... } ⇒ Object

Creates an instance of Conclude and evals it with the block provided.

Parameters:

  • fb (Factbase) (defaults to: Fbe.fb)

    The factbase

  • judge (String) (defaults to: $judge)

    The name of the judge, from the judges tool

  • global (Hash) (defaults to: $global)

    The hash for global caching

  • options (Judges::Options) (defaults to: $options)

    The options coming from the judges tool

  • loog (Loog) (defaults to: $loog)

    The logging facility

Yields:

  • (Factbase::Fact)

    The fact



19
20
21
22
# File 'lib/fbe/conclude.rb', line 19

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

.copy(source, target, except: []) ⇒ Integer

Makes a copy of a fact, moving all properties to a new fact.

All properties from the source will be copied to the target, except those listed in the except.

Parameters:

  • source (Factbase::Fact)

    The source

  • target (Factbase::Fact)

    The targer

  • except (Array<String>) (defaults to: [])

    List of properties to NOT copy

Returns:

  • (Integer)

    How many properties were copied



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/fbe/copy.rb', line 18

def Fbe.copy(source, target, except: [])
  raise 'The source is nil' if source.nil?
  raise 'The target is nil' if target.nil?
  raise 'The except is nil' if except.nil?
  copied = 0
  source.all_properties.each do |k|
    next unless target[k].nil?
    next if except.include?(k)
    source[k].each do |v|
      target.send(:"#{k}=", v)
      copied += 1
    end
  end
  copied
end

.enter(badge, why, options: $options, loog: $loog) ⇒ String

Enter a new valve.

Parameters:

  • badge (String)

    Unique badge of the valve

  • why (String)

    The reason

  • options (Judges::Options) (defaults to: $options)

    The options coming from the judges tool

  • loog (Loog) (defaults to: $loog)

    The logging facility

Returns:

  • (String)

    Full name of the user



16
17
18
19
20
# File 'lib/fbe/enter.rb', line 16

def Fbe.enter(badge, why, options: $options, loog: $loog, &)
  return yield unless options.testing.nil?
  baza = BazaRb.new('api.zerocracy.com', 443, options.zerocracy_token, loog:)
  baza.enter(options.job_name, badge, why, options.job_id.to_i, &)
end

.fb(fb: $fb, global: $global, options: $options, loog: $loog) ⇒ Factbase

Returns an instance of Factbase (cached).

Instead of using $fb directly, it is recommended to use this utility method. It will not only return the global factbase, but will also make sure it’s properly decorated and cached.

Parameters:

  • fb (Factbase) (defaults to: $fb)

    The global factbase provided by the judges tool

  • global (Hash) (defaults to: $global)

    The hash for global caching

  • options (Judges::Options) (defaults to: $options)

    The options coming from the judges tool

  • loog (Loog) (defaults to: $loog)

    The logging facility

Returns:

  • (Factbase)

    The global factbase



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/fbe/fb.rb', line 25

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, fbt|
          max = fbt.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.action_version}"
          f._job = options.job_id unless options.job_id.nil?
        end
      Factbase::Logged.new(fbe, loog)
    end
end

.github_graph(options: $options, global: $global, loog: $loog) ⇒ Fbe::Graph

Creates an instance of Graph.

Parameters:

  • options (Judges::Options) (defaults to: $options)

    The options available globally

  • global (Hash) (defaults to: $global)

    Hash of global options

  • loog (Loog) (defaults to: $loog)

    Logging facility

Returns:



16
17
18
19
20
21
22
23
24
# File 'lib/fbe/github_graph.rb', line 16

def Fbe.github_graph(options: $options, global: $global, loog: $loog)
  global[:github_graph] ||=
    if options.testing.nil?
      Fbe::Graph.new(token: options.github_token || ENV.fetch('GITHUB_TOKEN', nil))
    else
      loog.debug('The connection to GitHub GraphQL API is mocked')
      Fbe::Graph::Fake.new
    end
end

.if_absent(fb: Fbe.fb) {|Factbase::Fact| ... } ⇒ nil|Factbase::Fact

Injects a fact if it’s absent in the factbase, otherwise (it is already there) returns NIL.

Here is what you do when you want to add a fact to the factbase, but don’t want to make a duplicate of an existing one:

require 'fbe/if_absent'
n =
 Fbe.if_absent do |f|
   f.what = 'something'
   f.details = 'important'
 end
return if n.nil?
n.when = Time.now

This code will definitely create one fact with what equals to something and details equals to important, while the when will be equal to the time of its first creation.

Parameters:

  • fb (Factbase) (defaults to: Fbe.fb)

    The global factbase

Yields:

  • (Factbase::Fact)

    The fact just created

Returns:

  • (nil|Factbase::Fact)

    Either nil if it’s already there or a new fact



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

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})"
  before = fb.query(q).each.to_a.first
  return nil if before
  n = fb.insert
  attrs.each { |k, v| n.send(:"#{k}=", v) }
  n
end

.issue(fact, options: $options, global: $global, loog: $loog) ⇒ String

Converts an ID of GitHub issue into a nicely formatting string.

The function takes the repository property of the provided fact, goes to the GitHub API in order to find the full name of the repository, and then creates a string with the full name of repository + issue, for example “zerocracy/fbe#42”.

Parameters:

  • fact (Factbase::Fact)

    The fact, where to get the ID of GitHub issue

  • options (Judges::Options) (defaults to: $options)

    The options coming from the judges tool

  • global (Hash) (defaults to: $global)

    The hash for global caching

  • loog (Loog) (defaults to: $loog)

    The logging facility

Returns:

  • (String)

    Textual representation of GitHub issue number



21
22
23
24
25
26
27
28
29
# File 'lib/fbe/issue.rb', line 21

def Fbe.issue(fact, options: $options, global: $global, loog: $loog)
  rid = fact['repository']
  raise "There is no 'repository' property" if rid.nil?
  rid = rid.first.to_i
  issue = fact['issue']
  raise "There is no 'issue' property" if issue.nil?
  issue = issue.first.to_i
  "#{Fbe.octo(global:, options:, loog:).repo_name_by_id(rid)}##{issue}"
end

.iterate(fb: Fbe.fb, loog: $loog, options: $options, global: $global) {|Factbase::Fact| ... } ⇒ Object

Creates an instance of Iterate and evals it with the block provided.

Parameters:

  • fb (Factbase) (defaults to: Fbe.fb)

    The global factbase provided by the judges tool

  • options (Judges::Options) (defaults to: $options)

    The options coming from the judges tool

  • global (Hash) (defaults to: $global)

    The hash for global caching

  • loog (Loog) (defaults to: $loog)

    The logging facility

Yields:

  • (Factbase::Fact)

    The fact



20
21
22
23
# File 'lib/fbe/iterate.rb', line 20

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) {|Factbase::Fact| ... } ⇒ Factbase::Fact

Injects a fact if it’s absent in the factbase, otherwise (it is already there) returns the existing one.

require 'fbe/just_one'
n =
 Fbe.just_one do |f|
   f.what = 'something'
   f.details = 'important'
 end

This code will guarantee that only one fact with what equals to something and details equals to important may exist.

Parameters:

  • fb (Factbase) (defaults to: Fbe.fb)

    The global factbase

Yields:

  • (Factbase::Fact)

    The fact that was either created or found

Returns:

  • (Factbase::Fact)

    The fact found



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/fbe/just_one.rb', line 27

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) ⇒ Regex

Converts mask to repository name.

This function takes something like “zerocracy/*” as an input and returns a regular expression that may match repositories defined by this mask, which is /zerocracy/.* in this particular case.

Parameters:

  • mask (String)

    The mask

Returns:

  • (Regex)

    Regular expression



17
18
19
20
21
# File 'lib/fbe/unmask_repos.rb', line 17

def Fbe.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) ⇒ Hash

Makes a call to the GitHub API.

It is supposed to be used instead of Octokit::Client, because it is pre-configured and enables additional features, such as retrying, logging, and caching.

Parameters:

  • options (Judges::Options) (defaults to: $options)

    The options available globally

  • global (Hash) (defaults to: $global)

    Hash of global options

  • loog (Loog) (defaults to: $loog)

    Logging facility

Returns:

  • (Hash)

    Usually returns a JSON, as it comes from the GitHub API



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

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..].inspect})")
        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, loog:, pause: options.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, formatter: Fbe::Middleware::Formatter)
            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("Too 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.inspect} 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) ⇒ Factbase::Fact

Overwrites 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 re-set (the entire fact will be destroyed, new fact created, and property set with the new value).

It is important that the fact has the _id property. If it doesn’t, an exception will be raised.

Parameters:

  • fact (Factbase::Fact)

    The fact to modify

  • property (String)

    The name of the property to set

  • value (Any)

    The value to set

Returns:

  • (Factbase::Fact)

    Returns new fact or previous one



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/fbe/overwrite.rb', line 22

def Fbe.overwrite(fact, property, value, fb: Fbe.fb)
  raise 'The fact is nil' if fact.nil?
  raise "The property is not a String but #{property.class} (#{property})" unless property.is_a?(String)
  return fact if !fact[property].nil? && fact[property].size == 1 && fact[property].first == value
  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
  n
end

.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog) ⇒ String|Integer

Takes configuration parameter from the “PMP” fact.

The factbase may have a few facts with the what set to pmp (stands for “project management plan”). These facts contain information that configure the project. It is expected that every fact with the what set to pmp also contains the area property, which is set to one of nine values: scope, time, cost, etc. (by nine process areas in the PMBOK).

Parameters:

  • fb (Factbase) (defaults to: Fbe.fb)

    The factbase

  • global (Hash) (defaults to: $global)

    The hash for global caching

  • options (Judges::Options) (defaults to: $options)

    The options coming from the judges tool

  • loog (Loog) (defaults to: $loog)

    The logging facility

Returns:

  • (String|Integer)

    The value of the property found



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/fbe/pmp.rb', line 23

def Fbe.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog)
  others do |*args1|
    area = args1.first
    unless %w[cost scope hr time procurement risk integration quality communication].include?(area.to_s)
      raise "Invalid area #{area.inspect} (not part of PMBOK)"
    end
    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.inspect}" if f.nil?
      r = f[param]
      raise "Unknown property #{param.inspect} in the #{area.inspect} 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| ... } ⇒ nil

Run the block provided every X days.

Parameters:

  • area (String)

    The name of the PMP area

  • p_every_days (Integer)

    How frequently to run, every X days

  • p_since_days (Integer) (defaults to: nil)

    Since when to collect stats, X days

  • fb (Factbase) (defaults to: Fbe.fb)

    The factbase

  • judge (String) (defaults to: $judge)

    The name of the judge, from the judges tool

  • loog (Loog) (defaults to: $loog)

    The logging facility

Yields:

  • (f)

Returns:

  • (nil)

    Nothing



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/fbe/regularly.rb', line 18

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

.repeatedly(area, p_every_hours, fb: Fbe.fb, judge: $judge, loog: $loog) {|fb.query("(and (eq what '#{judge}'))").each.to_a.first| ... } ⇒ nil

Run the block provided every X hours.

Parameters:

  • area (String)

    The name of the PMP area

  • p_every_hours (Integer)

    How frequently to run, every X hours

  • fb (Factbase) (defaults to: Fbe.fb)

    The factbase

  • judge (String) (defaults to: $judge)

    The name of the judge, from the judges tool

  • loog (Loog) (defaults to: $loog)

    The logging facility

Yields:

  • (fb.query("(and (eq what '#{judge}'))").each.to_a.first)

Returns:

  • (nil)

    Nothing



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/fbe/repeatedly.rb', line 18

def Fbe.repeatedly(area, p_every_hours, fb: Fbe.fb, judge: $judge, loog: $loog, &)
  pmp = fb.query("(and (eq what 'pmp') (eq area '#{area}') (exists #{p_every_hours}))").each.to_a.first
  hours = pmp.nil? ? 24 : pmp[p_every_hours].first
  unless fb.query(
    "(and
      (eq what '#{judge}')
      (gt when (minus (to_time (env 'TODAY' '#{Time.now.utc.iso8601}')) '#{hours} hours')))"
  ).each.to_a.empty?
    loog.debug("#{$judge} have recently been executed, skipping now")
    return
  end
  f = fb.query("(and (eq what '#{judge}'))").each.to_a.first
  if f.nil?
    f = fb.insert
    f.what = judge
  end
  Fbe.overwrite(f, 'when', Time.now)
  yield fb.query("(and (eq what '#{judge}'))").each.to_a.first
  nil
end

.sec(fact, prop = :seconds) ⇒ String

Converts number of seconds into text.

THe number of seconds is taken from the fact provided, usually stored there in the seconds property. The seconds are formatted to hours, days, or weeks.

Parameters:

  • fact (Factbase::Fact)

    The fact, where to get the number of seconds

  • prop (String) (defaults to: :seconds)

    The property in the fact, with the seconds

Returns:

  • (String)

    Time interval as a text



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/fbe/sec.rb', line 17

def Fbe.sec(fact, prop = :seconds)
  s = fact[prop.to_s]
  raise "There is no #{prop.inspect} property" if s.nil?
  s = s.first.to_i
  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))
  elsif s < 7 * 60 * 60 * 24
    format('%d days', s / (60 * 60 * 24))
  else
    format('%d weeks', s / (7 * 60 * 60 * 24))
  end
end

.unmask_repos(options: $options, global: $global, loog: $loog) ⇒ Array<String>

Builds a list of repositories required by the repositories option.

The repositories option defined in the $options must contain something like “zerocracy/fbe,zerocracy/ab*” (comma-separated list of masks). This function will go to the GitHub API and fetch all available repositories by these masks.

Parameters:

  • options (Judges::Options) (defaults to: $options)

    The options coming from the judges tool

  • global (Hash) (defaults to: $global)

    The hash for global caching

  • loog (Loog) (defaults to: $loog)

    The logging facility

Returns:

  • (Array<String>)

    List of repository full names



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/fbe/unmask_repos.rb', line 34

def Fbe.unmask_repos(options: $options, global: $global, loog: $loog)
  repos = []
  octo = Fbe.octo(loog:, global:, options:)
  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)
    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: #{options.repositories}" if repos.empty?
  repos.shuffle!
  loog.debug("Scanning #{repos.size} repositories: #{repos.join(', ')}...")
  repos
end

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

Converts an ID of GitHub user into a nicely formatting string with his name.

The ID of the user (integer) is expected to be stored in the who property of the provided fact. This function makes a live request to GitHub API in order to find out what is the name of the user. For example, the ID 526301 will be converted to the “@yegor256” string.

Parameters:

  • fact (Factbase::Fact)

    The fact, where to get the ID of GitHub user

  • prop (String) (defaults to: :who)

    The property in the fact, with the ID

  • options (Judges::Options) (defaults to: $options)

    The options coming from the judges tool

  • global (Hash) (defaults to: $global)

    The hash for global caching

  • loog (Loog) (defaults to: $loog)

    The logging facility

Returns:

  • (String)

    Full name of the user



22
23
24
25
26
27
# File 'lib/fbe/who.rb', line 22

def Fbe.who(fact, prop = :who, options: $options, global: $global, loog: $loog)
  id = fact[prop.to_s]
  raise "There is no #{prop.inspect} property" if id.nil?
  id = id.first.to_i
  "@#{Fbe.octo(options:, global:, loog:).user_name_by_id(id)}"
end