forked from
mackuba.eu/sdk.blue
A curated list of libraries & SDKs for the Bluesky API and AT Protocol
1require_relative 'npm_import'
2require_relative 'requests'
3require 'base64'
4
5class GithubImport
6 include Requests
7
8 def initialize
9 @user_cache = {}
10 end
11
12 def request_headers
13 { 'Authorization' => "Bearer " + auth_config['github_token'] }
14 end
15
16 def url_matches?(url)
17 url =~ %r{^https://github\.com/[\w\-\.]+/[\w\-\.]+}
18 end
19
20 def import_url(url)
21 url =~ %r{^https://github\.com/([\w\-\.]+)/([\w\-\.]+)}
22 user, repo = $1, $2
23
24 repo_info = get_repo_info(user, repo)
25 data = extract_repo_data(repo_info)
26
27 if release = get_latest_release(user, repo)
28 data['last_release'] = release
29 end
30
31 if tag_info = get_latest_tag(user, repo)
32 data['last_tag'] = tag_info
33 end
34
35 if ['JavaScript', 'TypeScript'].include?(repo_info['language'])
36 npm = get_npm_releases(user, repo)
37 last_update = npm.map { |n| n.last_release_time }.sort.last
38
39 if last_update && (release.nil? || last_update > release['published_at'])
40 data['last_release'] = { 'published_at' => last_update }
41 end
42 end
43
44 data['last_commit'] = get_latest_commit(user, repo)
45
46 if user_info = get_user_info(user)
47 data['user_name'] = user_info['name']
48 end
49
50 data
51 end
52
53 def get_repo_info(user, repo)
54 response = get_response("https://api.github.com/repos/#{user}/#{repo}")
55 raise FetchError.new(response) unless response.code.to_i == 200
56
57 JSON.parse(response.body)
58 end
59
60 def extract_repo_data(json)
61 data = {
62 'name' => json['name'],
63 'description' => json['description'],
64 'user_login' => json['owner']['login'],
65 'user_profile' => "https://github.com/#{json['owner']['login']}",
66 'homepage' => json['homepage'],
67 'stars' => json['stargazers_count']
68 }
69
70 if json['license'] && json['license']['spdx_id'] != 'NOASSERTION'
71 data['license'] = json['license']['spdx_id']
72 end
73
74 data
75 end
76
77 def get_latest_release(user, repo)
78 response = get_response("https://api.github.com/repos/#{user}/#{repo}/releases/latest")
79
80 if response.code.to_i == 200
81 json = JSON.parse(response.body)
82
83 {
84 'tag_name' => json['tag_name'],
85 'name' => json['name'],
86 'draft' => json['draft'],
87 'prerelease' => json['prerelease'],
88 'created_at' => Time.parse(json['created_at']),
89 'published_at' => Time.parse(json['published_at'])
90 }
91 elsif response.code.to_i == 404
92 nil
93 else
94 raise FetchError.new(response)
95 end
96 end
97
98 def get_latest_tag(user, repo)
99 response = get_response("https://api.github.com/repos/#{user}/#{repo}/tags")
100 raise FetchError.new(response) unless response.code.to_i == 200
101
102 json = JSON.parse(response.body)
103
104 if tag = json.first
105 tag_name = tag['name']
106 response = get_response(tag['commit']['url'])
107 raise FetchError.new(response) unless response.code.to_i == 200
108
109 json = JSON.parse(response.body)
110 {
111 'name' => tag_name,
112 'author_date' => Time.parse(json['commit']['author']['date']),
113 'committer_date' => Time.parse(json['commit']['committer']['date'])
114 }
115 else
116 nil
117 end
118 end
119
120 def get_latest_commit(user, repo)
121 response = get_response("https://api.github.com/repos/#{user}/#{repo}/commits")
122 raise FetchError.new(response) unless response.code.to_i == 200
123
124 json = JSON.parse(response.body)
125
126 if commit = json.first
127 {
128 'author_date' => Time.parse(commit['commit']['author']['date']),
129 'committer_date' => Time.parse(commit['commit']['committer']['date'])
130 }
131 else
132 raise FetchError.new(response)
133 end
134 end
135
136 def get_user_info(user)
137 @user_cache[user] ||= begin
138 response = get_response("https://api.github.com/users/#{user}")
139 raise FetchError.new(response) unless response.code.to_i == 200
140
141 JSON.parse(response.body)
142 end
143 end
144
145 def get_npm_releases(user, repo)
146 sleep 5
147
148 search_url = URI("https://api.github.com/search/code")
149 search_url.query = URI.encode_www_form(q: "repo:#{user}/#{repo} filename:package.json", per_page: 100)
150 response = get_response(search_url)
151 raise FetchError.new(response) unless response.code.to_i == 200
152
153 json = JSON.parse(response.body)
154 releases = []
155
156 json['items'].each do |file|
157 response = get_response(file['url'])
158 raise FetchError.new(response) unless response.code.to_i == 200
159
160 details = JSON.parse(response.body)
161 contents = Base64.decode64(details['content'])
162 package = NPMImport::LocalPackage.new(JSON.parse(contents))
163
164 next if package.version.nil? || package.private?
165
166 if npm = NPMImport.new.get_package_info(package.name)
167 if npm.repository_url =~ %r{://github\.com/#{Regexp.escape(user)}/#{Regexp.escape(repo)}(\.git)?$}
168 releases << npm
169 end
170 end
171 end
172
173 releases
174 end
175end