class RepositoryReport

Constants

ADMIN
FAIL
MAIN_BRANCH
PASS

Attributes

exceptions[R]
organization[R]
repo_name[R]
team[R]

Public Class Methods

new(params) click to toggle source
Calls superclass method GithubGraphQlClient::new
# File lib/repository_report.rb, line 9
def initialize(params)
  @organization = params.fetch(:organization)
  @exceptions = params.fetch(:exceptions) # repos which are allowed to break the rules
  @repo_name = params.fetch(:repo_name)
  @team = params.fetch(:team)
  super(params)
end

Public Instance Methods

report() click to toggle source

TODO: additional checks

* has issues enabled
* deleteBranchOnMerge
* mergeCommitAllowed (do we want this on or off?)
* squashMergeAllowed (do we want this on or off?)
# File lib/repository_report.rb, line 23
def report
  {
    organization: organization,
    name: repo_name,
    default_branch: default_branch,
    url: repo_url,
    status: status,
    report: all_checks_result
  }
end

Private Instance Methods

all_checks_result() click to toggle source
# File lib/repository_report.rb, line 52
def all_checks_result
  @all_checks_result ||= {
    default_branch_main: default_branch_main?,
    has_main_branch_protection: has_main_branch_protection?,
    requires_approving_reviews: has_branch_protection_property?("requiresApprovingReviews"),
    requires_code_owner_reviews: has_branch_protection_property?("requiresCodeOwnerReviews"),
    administrators_require_review: has_branch_protection_property?("isAdminEnforced"),
    dismisses_stale_reviews: has_branch_protection_property?("dismissesStaleReviews"),
    team_is_admin: is_team_admin?,
  }
end
branch_protection_rules() click to toggle source
# File lib/repository_report.rb, line 125
def branch_protection_rules
  @rules ||= repo_data.dig("data", "repository", "branchProtectionRules", "edges")
end
default_branch() click to toggle source
# File lib/repository_report.rb, line 110
def default_branch
  repo_data.dig("data", "repository", "defaultBranchRef", "name")
end
default_branch_main?() click to toggle source
# File lib/repository_report.rb, line 129
def default_branch_main?
  default_branch == MAIN_BRANCH
end
fetch_repo_data() click to toggle source
# File lib/repository_report.rb, line 64
def fetch_repo_data
  body = repo_settings_query(
    organization: organization,
    repo_name: repo_name,
  )

  json = run_query(
    body: body,
    token: github_token
  )

  JSON.parse(json)
end
has_branch_protection_property?(property) click to toggle source
# File lib/repository_report.rb, line 142
def has_branch_protection_property?(property)
  requiring_branch_protection_rules do |rules|
    rules
      .map { |edge| edge.dig("node", property) }
      .all?
  end
end
has_main_branch_protection?() click to toggle source
# File lib/repository_report.rb, line 133
def has_main_branch_protection?
  requiring_branch_protection_rules do |rules|

    rules
      .select { |edge| edge.dig("node", "pattern") == MAIN_BRANCH }
      .any?
  end
end
is_team_admin?() click to toggle source
# File lib/repository_report.rb, line 114
def is_team_admin?
  client = Octokit::Client.new(access_token: github_token)

  client.repo_teams([organization, repo_name].join("/")).select do |t|
    t[:name] == team && t[:permission] == ADMIN
  end.any?
rescue Octokit::NotFound
  # This happens if our token does not have permission to view repo settings
  false
end
repo_data() click to toggle source
# File lib/repository_report.rb, line 36
def repo_data
  @repo_data ||= fetch_repo_data
end
repo_settings_query(params) click to toggle source
# File lib/repository_report.rb, line 78
def repo_settings_query(params)
  owner = params.fetch(:organization)
  repo_name = params.fetch(:repo_name)

  %[
    {
      repository(owner: "#{owner}", name: "#{repo_name}") {
        name
        url
        owner {
          login
        }
        defaultBranchRef {
          name
        }
        branchProtectionRules(first: 50) {
          edges {
            node {
              pattern
              requiresApprovingReviews
              requiresCodeOwnerReviews
              isAdminEnforced
              dismissesStaleReviews
              requiresStrictStatusChecks
            }
          }
        }
      }
    }
  ]
end
repo_url() click to toggle source
# File lib/repository_report.rb, line 40
def repo_url
  @url ||= repo_data.dig("data", "repository", "url")
end
requiring_branch_protection_rules() { |rules| ... } click to toggle source
# File lib/repository_report.rb, line 150
def requiring_branch_protection_rules
  rules = branch_protection_rules
  return false unless rules.any?

  yield rules
end
status() click to toggle source
# File lib/repository_report.rb, line 44
def status
  if exceptions.include?(repo_name)
    PASS
  else
    all_checks_result.values.all? ? PASS : FAIL
  end
end