forked from edgarjs/alfred-github-repos
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgithub
executable file
·158 lines (136 loc) · 4.68 KB
/
github
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
#!/usr/bin/env ruby
require 'json'
require 'net/http'
require 'cgi'
require 'open3'
class AlfredGithubError < StandardError; end
class AuthenticationError < AlfredGithubError; end
class APIError < AlfredGithubError; end
class Github
KEYCHAIN_ENTRY = "alfred-github-workflow".freeze
BASE_URI = "https://api.github.com"
USER_CACHE_FILE = ".user-cache"
def store_token(token)
_, err, st = Open3.capture3("security add-generic-password -a $USER -s #{KEYCHAIN_ENTRY} -w #{token} -U")
raise AuthenticationError.new("Failed to store token in keychain") unless st.success?
File.delete(USER_CACHE_FILE) if File.exist?(USER_CACHE_FILE)
end
def search_repo(query)
load_token!
search_user_repos(query)
end
def refresh_users
File.delete(USER_CACHE_FILE) if File.exist?(USER_CACHE_FILE)
load_token!
cache_user_and_orgs
end
private
def load_token!
token, err, st = Open3.capture3("security find-generic-password -a $USER -s #{KEYCHAIN_ENTRY} -w")
@token = strip_non_printable_characters(token)
if !st.success?
raise AuthenticationError.new("Keychain entry not found. Use gh-auth to fix this.")
elsif !@token || @token.empty?
raise AuthenticationError.new("Invalid token retrieved from keychain. Use gh-auth to fix this.")
end
end
def search_user_repos(keyword)
return [] if !keyword || keyword.empty?
user_params = user_and_orgs.each_with_object("") { |u, params| params << " user:#{u}" }
results = get "/search/repositories", { "q" => "#{keyword}#{user_params} in:name sort:updated" }
results['items'].map do |repo|
{ 'name' => repo['full_name'], 'url' => repo['html_url'] }
end
end
def user_and_orgs
@user_and_orgs ||= []
return @user_and_orgs unless @user_and_orgs.empty?
if File.exist?(USER_CACHE_FILE)
@user_and_orgs = File.read(USER_CACHE_FILE).split("\n")
end
return @user_and_orgs unless @user_and_orgs.empty?
@user_and_orgs = cache_user_and_orgs
end
def cache_user_and_orgs
org_results = get "/user/orgs"
found = org_results.each_with_object([]) do |org, orgs|
orgs << org["login"]
end
user_result = get "/user"
found << user_result["login"]
File.write(USER_CACHE_FILE, found.join("\n"))
found
end
def get(path, params = {})
params['per_page'] = 15 # slightly more than shown by default
qs = params.map {|k, v| "#{CGI.escape k.to_s}=#{CGI.escape v.to_s}"}.join("&")
uri = URI("#{BASE_URI}#{path}?#{qs}")
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
req = Net::HTTP::Get.new(uri)
req['Accept'] = "application/vnd.github.v3+json"
req['Authorization'] = "token #{@token}"
http.request(req)
end
response_code = response.code.to_i
if response_code == 401
raise AuthenticationError.new("Github auth error (#{response_code}). Add a valid token using gh-auth to fix this.")
elsif response_code == 403
raise AuthenticationError.new("Github auth error (#{response_code}). Github token must have 'repo' and 'public_repo' permissions.")
elsif response_code > 399
raise APIError.new("Error communicating with Github. Details: GET #{path} #{response_code}")
end
JSON.parse(response.body)
end
def strip_non_printable_characters(string)
string.gsub(/[^[:print:]]/i, '').strip
end
end
case ARGV[0]
when '--auth'
begin
Github.new.store_token(ARGV[1])
puts "Successfully stored auth token in keychain"
rescue AlfredGithubError => e
puts e.message
end
when '--refresh'
begin
Github.new.refresh_users
puts "Successfully refreshed user cache"
rescue AlfredGithubError => e
puts e.message
end
when '--search'
begin
results = Github.new.search_repo(ARGV[1] || '')
alfred_results = results.map do |repo|
{
"uid" => repo['name'],
"title" => repo['name'],
"subtitle" => repo['url'],
"arg" => repo['url'],
"autocomplete" => repo['name'],
"quicklookurl" => repo['url']
}
end
alfred_results = { "items" => alfred_results }.to_json
puts alfred_results
rescue AuthenticationError => e
main_message, secondary_message = e.message.split(".", 2)
alfred_results = [{
"title" => main_message,
"subtitle" => "Hit enter to use gh-auth to add a valid token.",
"arg" => 'gh-auth'
}]
alfred_results = { "items" => alfred_results }.to_json
puts alfred_results
rescue APIError => e
main_message, secondary_message = e.message.split(".", 2)
alfred_results = [{
"title" => main_message,
"subtitle" => secondary_message
}]
alfred_results = { "items" => alfred_results }.to_json
puts alfred_results
end
end