Class: Entitlements::Service::GitHub

Inherits:
Object
  • Object
show all
Includes:
Contracts::Core
Defined in:
lib/entitlements/service/github.rb

Constant Summary collapse

C =
::Contracts
MAX_GRAPHQL_RESULTS =

This is a limitation of the GitHub API

100
MAX_GRAPHQL_RETRIES =

Retries to smooth over transient network blips

3
WAIT_BETWEEN_GRAPHQL_RETRIES =
1

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(addr: nil, org:, token:, ou:, ignore_not_found: false) ⇒ GitHub

Returns a new instance of GitHub.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/entitlements/service/github.rb', line 40

def initialize(addr: nil, org:, token:, ou:, ignore_not_found: false)
  # init the retry module
  Retry.setup!

  # Save some parameters for the connection but don't actually connect yet.
  @addr = addr
  @org = org
  @token = token
  @ou = ou
  @ignore_not_found = ignore_not_found

  # This is a global cache across all invocations of this object. GitHub membership
  # need to be obtained only one time per organization, but might be used multiple times.
  Entitlements.cache[:github_pending_members] ||= {}
  Entitlements.cache[:github_org_members] ||= {}
end

Instance Attribute Details

#addrObject (readonly)

Returns the value of attribute addr.



22
23
24
# File 'lib/entitlements/service/github.rb', line 22

def addr
  @addr
end

#ignore_not_foundObject (readonly)

Returns the value of attribute ignore_not_found.



22
23
24
# File 'lib/entitlements/service/github.rb', line 22

def ignore_not_found
  @ignore_not_found
end

#orgObject (readonly)

Returns the value of attribute org.



22
23
24
# File 'lib/entitlements/service/github.rb', line 22

def org
  @org
end

#ouObject (readonly)

Returns the value of attribute ou.



22
23
24
# File 'lib/entitlements/service/github.rb', line 22

def ou
  @ou
end

#tokenObject (readonly)

Returns the value of attribute token.



22
23
24
# File 'lib/entitlements/service/github.rb', line 22

def token
  @token
end

Instance Method Details

#enterprise?Boolean

Returns:

  • (Boolean)


101
102
103
104
105
106
107
# File 'lib/entitlements/service/github.rb', line 101

def enterprise?
  meta = Retryable.with_context(:default) do
    octokit.github_meta
  end

  meta.key? :installed_version
end

#identifierObject



63
64
65
66
67
68
69
70
71
72
# File 'lib/entitlements/service/github.rb', line 63

def identifier
  @identifier ||= begin
    if addr.nil?
      "github.com"
    else
      u = URI(addr)
      u.host
    end
  end
end

#invalidate_org_members_predictive_cacheObject



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/entitlements/service/github.rb', line 145

def invalidate_org_members_predictive_cache
  # If the entry was not from the predictive cache in the first place, just return.
  # This really should not get called if that's the case, but regardless, we don't
  # want to pointlessly hit the API twice.
  return unless org_members_from_predictive_cache?

  # The entry did come from the predictive cache. Invalidate the entry, clear local
  # caches, and re-read the data from the API.
  Entitlements.logger.debug "Invalidating cache entries for cn=(admin|member),#{ou}"
  Entitlements::Data::Groups::Cached.invalidate("cn=admin,#{ou}")
  Entitlements::Data::Groups::Cached.invalidate("cn=member,#{ou}")
  Entitlements.cache[:github_org_members].delete(org_signature)
  org_members
  nil
end

#org_membersObject



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/entitlements/service/github.rb', line 82

def org_members
  Entitlements.cache[:github_org_members][org_signature] ||= begin
    roles = Entitlements::Backend::GitHubOrg::ORGANIZATION_ROLES.invert

    # Some basic stats are helpful for debugging
    data, cache = members_and_roles_from_graphql_or_cache
    result = data.map { |username, role| [username, roles.fetch(role)] }.to_h
    admin_count = result.count { |_, role| role == "admin" }
    member_count = result.count { |_, role| role == "member" }
    Entitlements.logger.debug "Currently #{org} has #{admin_count} admin(s) and #{member_count} member(s)"

    { cache:, value: result }
  end

  Entitlements.cache[:github_org_members][org_signature][:value]
end

#org_members_from_predictive_cache?Boolean

Returns:

  • (Boolean)


133
134
135
136
# File 'lib/entitlements/service/github.rb', line 133

def org_members_from_predictive_cache?
  org_members # Force this to be read if for some reason it has not been yet.
  Entitlements.cache[:github_org_members][org_signature][:cache] || false
end

#pending_membersObject



116
117
118
119
120
121
122
123
124
# File 'lib/entitlements/service/github.rb', line 116

def pending_members
  Entitlements.cache[:github_pending_members][org_signature] ||= begin
    # ghes does not support org invites
    return Set.new if enterprise?
    pm = pending_members_from_graphql
    Entitlements.logger.debug "Currently #{org} has #{pm.size} pending member(s)"
    pm
  end
end