bundler-alive 0.1.5 → 0.1.6

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: dd88b794101cf7f456811a805f287ec314d9ecf202294f5ec13e5e339db5834d
4
- data.tar.gz: e0db2f2731c7dd50324900a5564365ff14abf82bc7169d30d9ad7444504dffec
3
+ metadata.gz: c3e48b8f0f5a030f9b537e4150f6b10e5bdf3ed709cde30162d2030b3292cbc6
4
+ data.tar.gz: dff1d8579c996eeb24c599e2a40ba48b778d2939af8e80f3da94ed133a4ac0b5
5
5
  SHA512:
6
- metadata.gz: 89fec08047da08d6178bae7e2760f22139005dc33cd38201a6c7782a589ab173a7b5b72ee934bb301216fe4a5e1e5814dd69b773a9c937ab7ca2f7c7b61f0d3a
7
- data.tar.gz: 0f1930be94cf0401d807ec1e63714dea3243c5bedbe226ff7cd4ff957e9d6d5f043d731f4903ca3dac35aa0403d1269cbc85e153a304894fad63848401ddec07
6
+ metadata.gz: 94d793718656beddd079aaa083fe501b2775a8b658d361b19d5c56906abba39551dd6f84628904c98235db7bc381028fb3ce261bb09178d00154ea3f682e2757
7
+ data.tar.gz: 4e4977e62794f2f9cd403187c4d60063788f8589ddef358beb2ba49827b65b7b3be6c64d563489b0c90938fe94f02b98af88fdf6bc93f29ea12bdc29ffc399a5
@@ -27,4 +27,30 @@ gems:
27
27
  fog-sakuracloud:
28
28
  url: https://github.com/fog/fog-sakuracloud
29
29
  ovirt-engine-sdk:
30
- url: https://github.com/oVirt/ovirt-engine-sdk-ruby
30
+ url: https://github.com/oVirt/ovirt-engine-sdk-ruby
31
+ declarative_policy:
32
+ url: https://gitlab.com/gitlab-org/ruby/gems/declarative-policy
33
+ spamcheck:
34
+ url: https://gitlab.com/gitlab-com/gl-security/engineering-and-research/automation-team/spam/spamcheck
35
+ tanuki_emoji:
36
+ url: https://gitlab.com/gitlab-org/ruby/gems/tanuki_emoji
37
+ cbor:
38
+ url: https://github.com/cabo/cbor-ruby
39
+ expression_parser:
40
+ url: https://github.com/nricciar/expression_parser
41
+ extended-markdown-filter:
42
+ url: https://github.com/gjtorikian/extended-markdown-filter
43
+ gettext:
44
+ url: https://github.com/ruby-gettext/gettext
45
+ png_quantizator:
46
+ url: https://github.com/rogercampos/png_quantizator
47
+ redis-actionpack:
48
+ url: https://github.com/redis-store/redis-actionpack
49
+ redis-rack:
50
+ url: https://github.com/redis-store/redis-rack
51
+ sixarm_ruby_unaccent:
52
+ url: https://github.com/SixArm/sixarm_ruby_unaccent
53
+ thrift:
54
+ url: https://github.com/szechyjs/thrift-gem
55
+ vmstat:
56
+ url: https://github.com/threez/ruby-vmstat
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  `bunder-alive` checks if gems in a RubyGem's `Gemfile.lock` are active.
9
9
 
10
- Currently only GitHub is supported as a source code repository. If the source code repository is archived, then reports as not alive.
10
+ Currently GitHub.com and GitLab.com are supported as a source code repository. If the source code repository is archived, then reports as not alive.
11
11
 
12
12
  ## Installation
13
13
 
@@ -41,6 +41,10 @@ Default `Gemfile.lock` location is in your current directory. You can specify it
41
41
  $ bundle-alive -G /path/to/Gemfile.lock
42
42
  ```
43
43
 
44
+ ## GitLab Access Token
45
+
46
+ When gems are in GitLab.com repository, you MUST set environment variable `BUNDLER_ALIVE_GITLAB_TOKEN`. See the document [Personal access tokens](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html).
47
+
44
48
  ## Exceeding rate limit
45
49
 
46
50
  In some cases, the following error may be output.
data/gemspec.yml CHANGED
@@ -19,6 +19,7 @@ dependencies:
19
19
  octokit:
20
20
  rake:
21
21
  thor:
22
+ gitlab:
22
23
 
23
24
  development_dependencies:
24
25
  rspec:
@@ -38,13 +38,20 @@ module Bundler
38
38
  private
39
39
 
40
40
  def check_by_doctor
41
- doctor = begin
42
- Doctor.new(options[:gemfile_lock], options[:config], options[:ignore])
43
- rescue Bundler::GemfileLockNotFound
41
+ doctor = initialize_doctor
42
+
43
+ begin
44
+ doctor.diagnose
45
+ rescue Bundler::Alive::Client::GitlabApi::AccessTokenNotFoundError => e
46
+ say "\n#{e.message}", :yellow
44
47
  exit 1
45
48
  end
49
+ end
46
50
 
47
- doctor.diagnose
51
+ def initialize_doctor
52
+ Doctor.new(options[:gemfile_lock], options[:config], options[:ignore])
53
+ rescue Bundler::GemfileLockNotFound
54
+ exit 1
48
55
  end
49
56
  end
50
57
  end
@@ -111,16 +111,23 @@ module Bundler
111
111
 
112
112
  def source_code_url(body:, gem_name:)
113
113
  url = body["source_code_uri"]
114
- return url if SourceCodeRepositoryUrl.support_url?(url)
114
+ return url_via_redirect(url) if SourceCodeRepositoryUrl.support_url?(url)
115
115
 
116
116
  url = body["homepage_uri"]
117
- return url if SourceCodeRepositoryUrl.support_url?(url)
117
+ return url_via_redirect(url) if SourceCodeRepositoryUrl.support_url?(url)
118
118
 
119
119
  message = "[#{gem_name}] Source code repository is not found in RubyGems.org,"\
120
120
  " or not supported. URL: https://rubygems.org/gems/#{gem_name}"
121
121
  raise NotFound, message
122
122
  end
123
123
 
124
+ def url_via_redirect(url)
125
+ response = connection.head(url)
126
+ return response.headers["location"] if response.status == 301
127
+
128
+ url
129
+ end
130
+
124
131
  def get_repository_urls(gem_names)
125
132
  result = gem_names.map do |gem_name|
126
133
  $stdout.write "."
@@ -11,7 +11,7 @@ module Bundler
11
11
  #
12
12
  # @see https://docs.github.com/en/rest/search#search-repositories
13
13
  #
14
- module GitHubApi
14
+ module GithubApi
15
15
  # Environment variable name of GitHub Access Token
16
16
  ACCESS_TOKEN_ENV_NAME = "BUNDLER_ALIVE_GITHUB_TOKEN"
17
17
 
@@ -44,6 +44,7 @@ module Bundler
44
44
  base.instance_eval do
45
45
  @rate_limit_exceeded = false
46
46
  @retries_on_too_many_requests = 0
47
+ @name_with_archived = {}
47
48
  end
48
49
  end
49
50
 
@@ -63,15 +64,12 @@ module Bundler
63
64
  #
64
65
  # @return [StatusResult]
65
66
  #
66
- # rubocop:disable Metrics/MethodLength
67
67
  def query(urls:)
68
68
  collection = StatusCollection.new
69
- name_with_archived = get_name_with_statuses(urls)
69
+ @name_with_archived = get_name_with_statuses(urls)
70
70
  urls.each do |url|
71
- $stdout.write "."
72
-
73
71
  gem_name = url.gem_name
74
- alive = !name_with_archived[gem_name]
72
+ alive = alive?(gem_name)
75
73
  status = Status.new(name: gem_name, repository_url: url, alive: alive, checked_at: Time.now)
76
74
  collection = collection.add(gem_name, status)
77
75
  end
@@ -79,10 +77,16 @@ module Bundler
79
77
  StatusResult.new(collection: collection, error_messages: @error_messages,
80
78
  rate_limit_exceeded: @rate_limit_exceeded)
81
79
  end
82
- # rubocop:enable Metrics/MethodLength
83
80
 
84
81
  private
85
82
 
83
+ def alive?(gem_name)
84
+ return false unless @name_with_archived.key?(gem_name)
85
+
86
+ value = @name_with_archived[gem_name]
87
+ value == Status::ALIVE_UNKNOWN ? Status::ALIVE_UNKNOWN : !value
88
+ end
89
+
86
90
  #
87
91
  # Search status of repositories
88
92
  #
@@ -93,23 +97,39 @@ module Bundler
93
97
  #
94
98
  # rubocop:disable Metrics/MethodLength
95
99
  def get_name_with_statuses(urls)
96
- raise ArgumentError unless urls.instance_of?(Array)
97
-
98
100
  name_with_status = {}
99
101
  urls.each_slice(QUERY_MAX_OPERATORS_AT_ONCE) do |sliced_urls|
102
+ $stdout.print "." * sliced_urls.size
103
+
100
104
  q = search_query(sliced_urls)
101
105
  repositories = search_repositories_with_retry(q)
102
106
  next if repositories.nil?
103
107
 
104
- repositories.each do |repository|
105
- name = repository["name"]
106
- name_with_status[name] = repository["archived"]
108
+ sliced_urls.each do |url|
109
+ repository = find_repository_from_repositories(url: url,
110
+ repositories: repositories)
111
+ alive_status = if repository.nil?
112
+ Status::ALIVE_UNKNOWN
113
+ else
114
+ repository["archived"]
115
+ end
116
+ name_with_status[url.gem_name] = alive_status
107
117
  end
108
118
  end
109
119
  name_with_status
110
120
  end
111
121
  # rubocop:enable Metrics/MethodLength
112
122
 
123
+ # @param [SourceCodeRepositoryUrl] :url
124
+ # @param [Array<Sawyer::Resource>] :repositories
125
+ #
126
+ # @return [Sawyer::Resource|nil]
127
+ def find_repository_from_repositories(url:, repositories:)
128
+ repositories.find do |repository|
129
+ slug(url.url) == repository["full_name"]
130
+ end
131
+ end
132
+
113
133
  #
114
134
  # Search query of repositories
115
135
  #
@@ -172,7 +192,7 @@ module Bundler
172
192
  # @return [String]
173
193
  #
174
194
  def slug(repository_url)
175
- Octokit::Repository.from_url(repository_url).slug
195
+ Octokit::Repository.from_url(repository_url).slug.gsub(/\.git/, "")
176
196
  end
177
197
  end
178
198
  end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gitlab"
4
+ require "json"
5
+
6
+ module Bundler
7
+ module Alive
8
+ module Client
9
+ #
10
+ # API Client for GitLab API
11
+ #
12
+ # @see https://docs.gitlab.com/ee/api/projects.html#get-single-project
13
+ #
14
+ module GitlabApi
15
+ #
16
+ # Access token isn't set error
17
+ #
18
+ # @see https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html
19
+ #
20
+ class AccessTokenNotFoundError < StandardError
21
+ def initialize(_message = nil)
22
+ message = "Environment variable #{ACCESS_TOKEN_ENV_NAME} is not set."\
23
+ " Need to set GitLab Personal Access Token to be authenticated at gitlab.com API."\
24
+ " See: https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html"
25
+ super(message)
26
+ end
27
+ end
28
+
29
+ # Environment variable name of GitLab Access Token
30
+ #
31
+ # @see https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html
32
+ #
33
+ ACCESS_TOKEN_ENV_NAME = "BUNDLER_ALIVE_GITLAB_TOKEN"
34
+
35
+ # Endpoint of GitLab API
36
+ ENDPOINT = "https://gitlab.com/api/v4"
37
+
38
+ def self.extended(base)
39
+ base.instance_eval do
40
+ @rate_limit_exceeded = false
41
+ @retries_on_too_many_requests = 0
42
+ end
43
+ end
44
+
45
+ #
46
+ # Creates a GitLab client
47
+ #
48
+ # @return [Octokit::Client]
49
+ #
50
+ def create_client
51
+ access_token = ENV.fetch(ACCESS_TOKEN_ENV_NAME, nil)
52
+ raise AccessTokenNotFoundError if access_token.nil?
53
+
54
+ Gitlab.client(
55
+ endpoint: ENDPOINT,
56
+ private_token: access_token
57
+ )
58
+ end
59
+
60
+ #
61
+ # Query repository statuses
62
+ #
63
+ # @param [Array<RepositoryUrl>] :urls
64
+ #
65
+ # @return [StatusResult]
66
+ #
67
+ def query(urls:)
68
+ collection = StatusCollection.new
69
+ name_with_archived = get_name_with_statuses(urls)
70
+ urls.each do |url|
71
+ gem_name = url.gem_name
72
+ alive = name_with_archived.key?(gem_name) && !name_with_archived[gem_name]
73
+ status = Status.new(name: gem_name, repository_url: url, alive: alive, checked_at: Time.now)
74
+ collection = collection.add(gem_name, status)
75
+ end
76
+
77
+ StatusResult.new(collection: collection, error_messages: @error_messages,
78
+ rate_limit_exceeded: @rate_limit_exceeded)
79
+ end
80
+
81
+ private
82
+
83
+ #
84
+ # Search status of repositories
85
+ #
86
+ # @param [Array<RepositoryUrl>] urls
87
+ #
88
+ # @return [Hash<String, Boolean>]
89
+ # gem name with archived or not
90
+ #
91
+ def get_name_with_statuses(urls)
92
+ name_with_status = {}
93
+ urls.each do |url|
94
+ $stdout.write "."
95
+ project = search_repositories_with_retry(url)
96
+ next if project.nil? || project.empty?
97
+
98
+ name = url.gem_name
99
+ name_with_status[name] = project["archived"]
100
+ end
101
+ name_with_status
102
+ end
103
+
104
+ def project_path_from_url(url)
105
+ uri = URI.parse(url.url)
106
+ uri.path.split("/")[1..].join("/")
107
+ end
108
+
109
+ def search_repositories_with_retry(url)
110
+ project_path = project_path_from_url(url)
111
+
112
+ # Must be converted to hash due to warnings
113
+ @client.project(project_path).to_h
114
+ rescue StandardError => e
115
+ @error_messages << e.message
116
+ []
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -16,7 +16,8 @@ module Bundler
16
16
  end
17
17
 
18
18
  SERVICE_WITH_STRATEGIES = {
19
- SourceCodeRepository::Service::GITHUB => GitHubApi
19
+ SourceCodeRepository::Service::GITHUB => GithubApi,
20
+ SourceCodeRepository::Service::GITLAB => GitlabApi
20
21
  }.freeze
21
22
 
22
23
  private_constant :SERVICE_WITH_STRATEGIES
@@ -21,8 +21,11 @@ module Bundler
21
21
  error_messages = report.error_messages
22
22
  print_error(error_messages)
23
23
 
24
- gems = result.archived_gems
25
- print_archived_gems(gems) if gems.size.positive?
24
+ unknown_gems = result.unknown_gems
25
+ print_archived_gems(unknown_gems, header: "Unknown gems:") if unknown_gems.size.positive?
26
+
27
+ archived_gems = result.archived_gems
28
+ print_archived_gems(archived_gems, header: "Archived gems:") if archived_gems.size.positive?
26
29
 
27
30
  print_summary(result)
28
31
  print_message(result, report.rate_limit_exceeded)
@@ -31,15 +34,15 @@ module Bundler
31
34
  private
32
35
 
33
36
  # soo messy
34
- def print_archived_gems(gems)
37
+ def print_archived_gems(gems, header:)
35
38
  $stdout.puts
36
- $stdout.puts "Archived gems:"
37
- archived_gems = gems.map do |_name, gem|
39
+ $stdout.puts header
40
+ gems_to_report = gems.map do |_name, gem|
38
41
  gem.report.split("\n").each_with_object([]) do |line, gem_str|
39
42
  gem_str << " #{line}"
40
43
  end.join("\n")
41
44
  end
42
- $stdout.puts archived_gems.join("\n\n")
45
+ $stdout.puts gems_to_report.join("\n\n")
43
46
  end
44
47
 
45
48
  def print_error(error_messages)
@@ -56,7 +59,7 @@ module Bundler
56
59
  def print_summary(result)
57
60
  $stdout.puts <<~RESULT
58
61
 
59
- Total: #{result.total_size} (Archived: #{result.archived_size}, Alive: #{result.alive_size}, Unknown: #{result.unknown_size})
62
+ Total: #{result.total_size} (Archived: #{result.archived_size}, Unknown: #{result.unknown_size}, Alive: #{result.alive_size})
60
63
  RESULT
61
64
  end
62
65
 
@@ -6,6 +6,7 @@ module Bundler
6
6
  class SourceCodeRepository
7
7
  module Service
8
8
  GITHUB = :github
9
+ GITLAB = :gitlab
9
10
  end
10
11
 
11
12
  #
@@ -7,7 +7,8 @@ module Bundler
7
7
  # service domain with service
8
8
  DOMAIN_WITH_SERVICES = {
9
9
  "github.com" => SourceCodeRepository::Service::GITHUB,
10
- "www.github.com" => SourceCodeRepository::Service::GITHUB
10
+ "www.github.com" => SourceCodeRepository::Service::GITHUB,
11
+ "gitlab.com" => SourceCodeRepository::Service::GITLAB
11
12
  }.freeze
12
13
 
13
14
  private_constant :DOMAIN_WITH_SERVICES
@@ -89,6 +89,10 @@ module Bundler
89
89
  collection.find_all { |_name, gem| !!!gem.alive }
90
90
  end
91
91
 
92
+ def unknown_gems
93
+ collection.find_all { |_name, gem| gem.unknown? }
94
+ end
95
+
92
96
  #
93
97
  # All of statuses are alive nor not
94
98
  #
@@ -17,7 +17,7 @@ module Bundler
17
17
  #
18
18
  # @return [StatusResult]
19
19
  #
20
- def initialize(collection: nil, error_messages: nil, rate_limit_exceeded: nil)
20
+ def initialize(collection: StatusCollection.new, error_messages: [], rate_limit_exceeded: false)
21
21
  @collection = collection
22
22
  @error_messages = error_messages
23
23
  @rate_limit_exceeded = rate_limit_exceeded
@@ -33,9 +33,12 @@ module Bundler
33
33
  # @return [StatusResult]
34
34
  #
35
35
  def merge(result)
36
- self.class.new(collection: result.collection,
37
- error_messages: result.error_messages,
38
- rate_limit_exceeded: result.rate_limit_exceeded)
36
+ merged_collection = collection.merge(result.collection)
37
+ merged_error_messages = error_messages + result.error_messages
38
+ merged_rate_limit_exceeded = rate_limit_exceeded || result.rate_limit_exceeded
39
+ self.class.new(collection: merged_collection,
40
+ error_messages: merged_error_messages,
41
+ rate_limit_exceeded: merged_rate_limit_exceeded)
39
42
  end
40
43
  end
41
44
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bundler
4
4
  module Alive
5
- VERSION = "0.1.5"
5
+ VERSION = "0.1.6"
6
6
  end
7
7
  end
data/lib/bundler/alive.rb CHANGED
@@ -10,6 +10,7 @@ require_relative "alive/status_collection"
10
10
  require_relative "alive/report"
11
11
  require_relative "alive/client/gems_api_client"
12
12
  require_relative "alive/client/gems_api_response"
13
- require_relative "alive/client/git_hub_api"
13
+ require_relative "alive/client/github_api"
14
+ require_relative "alive/client/gitlab_api"
14
15
  require_relative "alive/client/source_code_client"
15
16
  require_relative "alive/reportable"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-alive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katsuhiko YOSHIDA
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-21 00:00:00.000000000 Z
11
+ date: 2022-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: gitlab
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -194,7 +208,8 @@ files:
194
208
  - lib/bundler/alive/cli.rb
195
209
  - lib/bundler/alive/client/gems_api_client.rb
196
210
  - lib/bundler/alive/client/gems_api_response.rb
197
- - lib/bundler/alive/client/git_hub_api.rb
211
+ - lib/bundler/alive/client/github_api.rb
212
+ - lib/bundler/alive/client/gitlab_api.rb
198
213
  - lib/bundler/alive/client/source_code_client.rb
199
214
  - lib/bundler/alive/doctor.rb
200
215
  - lib/bundler/alive/report.rb