-
Notifications
You must be signed in to change notification settings - Fork 158
Expand file tree
/
Copy pathclient.rb
More file actions
158 lines (136 loc) · 4.67 KB
/
client.rb
File metadata and controls
158 lines (136 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# frozen_string_literal: true
require "digest"
module Jekyll
module GitHubMetadata
class Client
InvalidMethodError = Class.new(NoMethodError)
BadCredentialsError = Class.new(StandardError)
# Whitelisted API calls.
API_CALLS = Set.new(%w(
repository
organization
user
repository?
pages
contributors
releases
latest_release
list_repos
organization_public_members
))
def initialize(options = nil)
@client = build_octokit_client(options)
end
def safe_require(gem_name)
require gem_name
true
rescue LoadError
false
end
def default_octokit_options
{
:api_endpoint => Jekyll::GitHubMetadata::Pages.api_url,
:web_endpoint => Jekyll::GitHubMetadata::Pages.github_url,
:auto_paginate => true,
}
end
def build_octokit_client(options = nil)
options ||= {}
options.merge!(pluck_auth_method) unless options.key?(:access_token)
Octokit::Client.new(default_octokit_options.merge(options))
end
def accepts_client_method?(method_name)
API_CALLS.include?(method_name.to_s) && @client.respond_to?(method_name)
end
def respond_to_missing?(method_name, include_private = false)
accepts_client_method?(method_name) || super
end
def method_missing(method_name, *args, &block)
method = method_name.to_s
if accepts_client_method?(method_name)
key = cache_key(method_name, args)
GitHubMetadata.log :debug, "Calling @client.#{method}(#{args.map(&:inspect).join(", ")})"
cache[key] ||= save_from_errors { @client.public_send(method_name, *args, &block) }
elsif @client.respond_to?(method_name)
raise InvalidMethodError, "#{method_name} is not whitelisted on #{inspect}"
else
super
end
end
# NOTE: Faraday's error classes have been simplified from v1.0.0.
#
# In older versions, both `Faraday::Error::ConnectionFailed` and `Faraday::ConnectionFailed`
# were valid and equivalent to each other.
# From v1.0.0 onwards, `Faraday::Error::ConnectionFailed` no longer exists.
#
# TODO: Remove in v2.0 of this plugin.
FARADAY_FAILED_CONNECTION =
begin
Faraday::Error::ConnectionFailed
rescue NameError
Faraday::ConnectionFailed
end
deprecate_constant :FARADAY_FAILED_CONNECTION
def save_from_errors(default = false)
unless internet_connected?
GitHubMetadata.log :warn, "No internet connection. GitHub metadata may be missing or incorrect."
return default
end
yield @client
rescue Octokit::Unauthorized
raise BadCredentialsError, "The GitHub API credentials you provided aren't valid."
rescue Faraday::ConnectionFailed, Octokit::TooManyRequests => e
GitHubMetadata.log :warn, e.message
default
rescue Octokit::NotFound, Octokit::UnavailableForLegalReasons
default
end
def inspect
"#<#{self.class.name} @client=#{client_inspect} @internet_connected=#{internet_connected?}>"
end
def authenticated?
!@client.access_token.to_s.empty?
end
def internet_connected?
return @internet_connected if defined?(@internet_connected)
require "resolv"
begin
Resolv::DNS.open do |dns|
dns.timeouts = 2
dns.getaddress("api.github.com")
end
@internet_connected = true
rescue Resolv::ResolvError
@internet_connected = false
end
end
private
def client_inspect
if @client.nil?
"nil"
else
"#<#{@client.class.name} (#{"un" unless authenticated?}authenticated)>"
end
end
# rubocop:disable Metrics/CyclomaticComplexity
def pluck_auth_method
if ENV["JEKYLL_GITHUB_TOKEN"] || Octokit.access_token
{ :access_token => ENV["JEKYLL_GITHUB_TOKEN"] || Octokit.access_token }
elsif !ENV["NO_NETRC"] && File.exist?(File.join(Dir.home, ".netrc")) && safe_require("netrc")
{ :netrc => true }
else
GitHubMetadata.log :warn, "No GitHub API authentication could be found. " \
"Some fields may be missing or have incorrect data."
{}.freeze
end
end
# rubocop:enable Metrics/CyclomaticComplexity
def cache_key(method, *args)
Digest::SHA1.hexdigest(method.to_s + args.join(", "))
end
def cache
@cache ||= {}
end
end
end
end