obituary 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f4cdf9f9835202c98cc63e88ad67118e118452dcbc685377300db5f931758ba
4
- data.tar.gz: 381d5992bc0e4450700095fef0a967f951adbceee8328e6f8a3d7f504d81657d
3
+ metadata.gz: bdf0d0d04ff7d5747998cdf8e2cd5f09795dfc209cd3fb57695d29a5ebca266a
4
+ data.tar.gz: 400a554517085b8e4ab28e1e22d4d05197f0c72678af732a07f460d8b4ed4bed
5
5
  SHA512:
6
- metadata.gz: 865223eb644a0a2cd994d885b521d747d051b04c20c177898278f8cd80e920d22fe1ef55705617289468b3e03ac3b14ecde25d948855e8030ce909ac701afa12
7
- data.tar.gz: 0dfe545e0847c6233217c133f563204b4bf866be060c9e04a8194ed6d6ab8c306353b58d06b8e2d9a4b2f1f6d7858e2f9ff1b01f4ea03db07c1055cc81d08c04
6
+ metadata.gz: a6e96a0ee5518b3957e82d68293893161b828b68900cfb83433931ea2a1ef982dc96a5fdf70a4be711253bac9f276a3b6cad05878a9620f92e95a826ace35bff
7
+ data.tar.gz: fe2236c892f0ab526c6fc228b8a96ebdeb72f702c69f265b2c4ed069b95d6fb23902e765280092911da1cf0528b7861784586cc19944cf7e6f9f7e31942475cc
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Obituary
1
+ # Obituary [![Gem Version](https://badge.fury.io/rb/obituary.svg)](https://badge.fury.io/rb/obituary) [![Ruby](https://github.com/ydah/obituary/actions/workflows/main.yml/badge.svg)](https://github.com/ydah/obituary/actions/workflows/main.yml)
2
2
 
3
3
  Obituary detects archived GitHub repositories for your RubyGem dependencies. It can be used as a CLI command in CI or as an RSpec matcher to keep dependency health visible.
4
4
 
@@ -8,6 +8,7 @@ module Obituary
8
8
  class ArchiveChecker
9
9
  API_ENDPOINT = 'https://api.github.com/repos'
10
10
  WARNING_THRESHOLD = 100
11
+ MAX_REDIRECTS = 5
11
12
 
12
13
  def initialize(github_token:)
13
14
  @github_token = github_token
@@ -15,19 +16,14 @@ module Obituary
15
16
 
16
17
  def archived?(owner_repo)
17
18
  url = URI.join("#{API_ENDPOINT}/", owner_repo)
18
- request = Net::HTTP::Get.new(url)
19
- request['Authorization'] = "Bearer #{@github_token}"
20
- request['Accept'] = 'application/vnd.github.v3+json'
21
-
22
- response = Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |http|
23
- http.request(request)
24
- end
19
+ response, moved_to = fetch_response_following_redirects(url)
25
20
 
26
21
  warn_if_rate_limit_low(response)
27
22
 
28
23
  case response
29
24
  when Net::HTTPSuccess
30
25
  data = JSON.parse(response.body)
26
+ warn_if_repository_moved(owner_repo, data, moved_to)
31
27
  data.fetch('archived', nil)
32
28
  when Net::HTTPNotFound
33
29
  warn("Repository not found for #{owner_repo}")
@@ -36,6 +32,13 @@ module Obituary
36
32
  raise Obituary::Error, 'GitHub token unauthorized'
37
33
  when Net::HTTPForbidden
38
34
  raise Obituary::Error, 'GitHub API rate limit exceeded'
35
+ when Net::HTTPRedirection
36
+ if moved_to
37
+ warn("Repository moved for #{owner_repo} -> #{moved_to}")
38
+ else
39
+ warn("GitHub API error for #{owner_repo}: #{response.code}")
40
+ end
41
+ nil
39
42
  else
40
43
  warn("GitHub API error for #{owner_repo}: #{response.code}")
41
44
  nil
@@ -47,6 +50,52 @@ module Obituary
47
50
 
48
51
  private
49
52
 
53
+ def fetch_response_following_redirects(initial_url)
54
+ url = initial_url
55
+ moved_to = nil
56
+ response = nil
57
+
58
+ MAX_REDIRECTS.times do
59
+ response = request(url)
60
+ return [response, moved_to] unless response.is_a?(Net::HTTPRedirection)
61
+
62
+ location = response['Location']
63
+ return [response, moved_to] if location.nil? || location.empty?
64
+
65
+ moved_to ||= extract_owner_repo_from_location(location)
66
+ url = URI.join(url.to_s, location)
67
+ end
68
+
69
+ [response, moved_to]
70
+ end
71
+
72
+ def request(url)
73
+ request = Net::HTTP::Get.new(url)
74
+ request['Authorization'] = "Bearer #{@github_token}"
75
+ request['Accept'] = 'application/vnd.github.v3+json'
76
+
77
+ Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |http|
78
+ http.request(request)
79
+ end
80
+ end
81
+
82
+ def warn_if_repository_moved(original_owner_repo, data, moved_to)
83
+ resolved_owner_repo = data['full_name'] || moved_to
84
+ return if resolved_owner_repo.nil? || resolved_owner_repo == original_owner_repo
85
+
86
+ warn("Repository moved for #{original_owner_repo} -> #{resolved_owner_repo}")
87
+ end
88
+
89
+ def extract_owner_repo_from_location(location)
90
+ uri = URI.parse(location)
91
+ match = uri.path.match(%r{\A/repos/([^/]+)/([^/]+)\z})
92
+ return nil unless match
93
+
94
+ "#{match[1]}/#{match[2]}"
95
+ rescue URI::InvalidURIError
96
+ nil
97
+ end
98
+
50
99
  def warn_if_rate_limit_low(response)
51
100
  remaining = response['X-RateLimit-Remaining']
52
101
  return unless remaining
@@ -8,6 +8,14 @@ module Obituary
8
8
  class RepositoryFinder
9
9
  RUBYGEMS_API = 'https://rubygems.org/api/v1/gems'
10
10
  GITHUB_REGEX = %r{github\.com[/:]([^/]+)/([^/.]+)}
11
+ REPOSITORY_URL_KEYS = %w[
12
+ source_code_uri
13
+ homepage_uri
14
+ bug_tracker_uri
15
+ changelog_uri
16
+ documentation_uri
17
+ wiki_uri
18
+ ].freeze
11
19
 
12
20
  def initialize(config: Obituary.configuration)
13
21
  @config = config
@@ -25,8 +33,7 @@ module Obituary
25
33
 
26
34
  data = fetch_rubygems(gem_name)
27
35
  if data
28
- repo = parse_github_repo(data['source_code_uri']) ||
29
- parse_github_repo(data['homepage_uri'])
36
+ repo = find_repo_from_rubygems_data(data)
30
37
  return @cache[gem_name] = repo
31
38
  end
32
39
 
@@ -68,6 +75,15 @@ module Obituary
68
75
  nil
69
76
  end
70
77
 
78
+ def find_repo_from_rubygems_data(data)
79
+ REPOSITORY_URL_KEYS.each do |key|
80
+ repo = parse_github_repo(data[key])
81
+ return repo if repo
82
+ end
83
+
84
+ nil
85
+ end
86
+
71
87
  def parse_github_repo(url)
72
88
  return nil if url.nil? || url.strip.empty?
73
89
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Obituary
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: obituary
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada