getv-rs 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1a0f9f67eef721617d91a03f548a9a24488d8e1f74d071b479d4df874fc57578
4
+ data.tar.gz: c92fc90d57b1b25a4bc6dc1d20400022f7fbfacc52bf300735e1f154b00ba004
5
+ SHA512:
6
+ metadata.gz: 0df35d693cd27977bf421e154d8be695fd22f85d6cf0945186cd0992221d28bb303451e385e5ed5b5e0c740ef7557184d13fd0b617984284cc6526d076b4c7b5
7
+ data.tar.gz: fe427c825af69ed7e0b33e2bce52c7e10ceb7c398fc3739ecca315416cb535f907533580af652a59abf461dbb058485f25b92325121f450b0328dcc55997b101
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Richard Grainger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # getv
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/getv.svg)](https://rubygems.org/gems/getv)
4
+
5
+ The goal of `getv` is to make it easy and quick to pull software package version numbers from various sources on the web. The application is packaged as a [gem](https://rubygems.org/gems/getv) and provides both a Ruby library and an executable command line tool, `getv`.
6
+
7
+ ## Installation
8
+
9
+ Install `getv` with:
10
+
11
+ ```
12
+ gem install getv
13
+ ```
14
+
15
+ Or add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'getv'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ ```sh
24
+ bundle install
25
+ ```
26
+
27
+ ## CLI
28
+
29
+ An executable command tool, `getv` is bundled with this gem:
30
+
31
+ ```console
32
+ $ getv
33
+ NAME
34
+ getv - Get package version numbers from the web in various ways
35
+
36
+
37
+ SYNOPSIS
38
+ getv [global options] command [command options] [arguments...]
39
+
40
+
41
+ VERSION
42
+ 2.1.4
43
+
44
+
45
+
46
+ GLOBAL OPTIONS
47
+ --help - Show this message
48
+ -j, --json - Output in json
49
+ -l, --latest - Latest version
50
+ -p, --proxy=arg - Web proxy (default: none)
51
+ --version - Display the program version
52
+
53
+
54
+
55
+ COMMANDS
56
+ docker - Get package versions from a Docker or OCI container image registry
57
+ gem - Get package versions from RubyGems.org
58
+ github_commit - Get package versions from GitHub commits
59
+ github_release - Get package versions from GitHub releases
60
+ github_tag - Get package versions from GitHub tags
61
+ helm - Get package versions from a Helm chart repository
62
+ help - Shows a list of commands or help for one command
63
+ npm - Get package versions from npm at registry.npmjs.org
64
+ pypi - Get package versions from the Python Package Index at pypi.org
65
+ text - Get package versions from text file URL
66
+ xml - Get package versions from XML file URL
67
+ ```
68
+
69
+ ### CLI examples
70
+
71
+ Show the latest available version of the `getv` gem:
72
+
73
+ ```console
74
+ $ getv --latest gem getv
75
+ 2.1.4
76
+ ```
77
+
78
+ Show all `dep` GitHub release versions in JSON:
79
+
80
+ ```console
81
+ $ getv --json github_release golang/dep
82
+ {"name":"golang/dep","versions":["0.2.0","0.2.1","0.3.0","0.3.1","0.3.2","0.4.0","0.4.1","0.5.0","0.5.1","0.5.2","0.5.3","0.5.4"]}
83
+ ```
84
+
85
+ Show all AtomicParsley Github release versions:
86
+
87
+ ```console
88
+ $ getv github_release --invalid_versions wez/atomicparsley
89
+ 20200701.154658.b0d6223
90
+ 20201231.092811.cbecfb1
91
+ 20210114.184825.1dbe1be
92
+ 20210124.204813.840499f
93
+ 20210617.200601.1ac7c08
94
+ 20210715.151551.e7ad03a
95
+ ```
96
+
97
+ Show the latest stable version of Kubernetes using the release text file URL:
98
+
99
+ ```console
100
+ $ getv -l text --url=https://storage.googleapis.com/kubernetes-release/release/stable.txt kubernetes
101
+ 1.23.2
102
+ ```
103
+
104
+ Show selected semantic versions of the `apache/superset` Docker image in JSON:
105
+
106
+ ```console
107
+ $ getv --json docker --reject '-' --semantic_select '~>1.3.0,!=1.3.1' apache/superset
108
+ {"name":"apache/superset","versions":["1.3.0","1.3.2"]}
109
+ ```
110
+
111
+ Show all versions of `libnetfilter_acct` using selected link values (`<a>` HTML elements) on an indexed web page:
112
+
113
+ ```console
114
+ $ getv xml --url=https://netfilter.org/projects/libnetfilter_acct/files --xpath '//a' --select_search='^.*libnetfilter_acct-([\d\.]*)\.tar\.bz2$' libnetfilter_acct
115
+ 1.0.0
116
+ 1.0.1
117
+ 1.0.2
118
+ 1.0.3
119
+ ```
120
+
121
+ Show the latest GitHub commit to the `main` branch of the `getv` project in a useful versioning format:
122
+
123
+ ```console
124
+ # By default the \2 capture group contains the date and \5 contains the short commit hash
125
+ $ getv -l github_commit --select_replace '\2git\5' --branch main liger1978/getv
126
+ 20220123git9ed86f0
127
+ ```
128
+
129
+ ## Ruby library
130
+
131
+ Example:
132
+
133
+ ```ruby
134
+ require 'getv'
135
+
136
+ superset = Getv::Package::Docker.new 'apache/superset', reject: '-'
137
+ puts superset.versions
138
+ puts superset.latest_version
139
+
140
+ # You can also use the flexible "create" factory method
141
+ Getv::Package.create 'apache/superset', type: 'docker', reject: '-'
142
+ Getv::Package.create 'golang/dep', type: 'github release'
143
+ Getv::Package.create 'golang/dep', type: 'github_release'
144
+ Getv::Package.create 'golang/dep', type: 'GitHub::Release'
145
+ Getv::Package.create 'rubygem-getv'
146
+ ```
147
+
148
+ ## Development
149
+
150
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. Run `bundle exec rubocop` to run the linter. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
151
+
152
+ Note that by default, Bundler will attempt to install gems to the system, e.g. `/usr/bin`, `/usr/share`, which requires elevated access and can interfere with files that are managed by the system's package manager. This behaviour can be overridden by creating the file `.bundle/config` and adding the following line:
153
+ ```
154
+ BUNDLE_PATH: "./.bundle"
155
+ ```
156
+ When you run `bin/setup` or `bundle install`, all gems will be installed inside the .bundle directory of this project.
157
+
158
+ To make this behaviour a default for all gem projects, the above line can be added to the user's bundle config file in their home directory (`~/.bundle/config`)
159
+
160
+ ## Contributing
161
+
162
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/liger1978/getv).
163
+
164
+ ## License
165
+
166
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/exe/getv ADDED
@@ -0,0 +1,324 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'getv'
5
+ require 'gli'
6
+
7
+ module Getv
8
+ # cli class
9
+ class Cli
10
+ def self.output(package, latest: false, json: false)
11
+ key = latest ? 'latest_version' : 'versions'
12
+ result = package.send(key)
13
+
14
+ if json
15
+ require 'json'
16
+ result = { 'name' => package.name, key => result }.to_json
17
+ end
18
+
19
+ puts result
20
+ end
21
+ end
22
+ end
23
+
24
+ # app class
25
+ class App # rubocop:disable Metrics/ClassLength
26
+ extend GLI::App
27
+
28
+ program_desc 'Get package version numbers from the web in various ways'
29
+
30
+ version Getv::VERSION
31
+
32
+ subcommand_option_handling :normal
33
+ arguments :strict
34
+
35
+ switch %i[l latest], desc: 'Latest version', negatable: false
36
+ switch %i[j json], desc: 'Output in json', negatable: false
37
+ flag %i[p proxy], desc: 'Web proxy', default_value: nil
38
+
39
+ desc 'Get package versions from a Docker or OCI container image registry'
40
+ arg_name 'package_name'
41
+ command :docker do |c| # rubocop:disable Metrics/BlockLength
42
+ defaults = (Getv::Package::Docker.new 'name').opts
43
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
44
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
45
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
46
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
47
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
48
+ default_value: defaults[:semantic_select]
49
+ c.flag %i[owner], desc: 'Repository owner',
50
+ default_value: "'<owner>' if package_name is in format '<registry>/<owner>/<repo>' or '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
51
+ c.flag %i[repo], desc: 'Repository name',
52
+ default_value: "'<repo>' if package_name is in format '<registry>/<owner>/<repo>' or <owner>/<repo>, otherwise just package_name" # rubocop:disable Layout/LineLength
53
+ c.flag %i[url], desc: 'URL',
54
+ default_value: "'https://<registry>' if package_name is in format '<registry>/<owner>/<repo>', otherwise #{defaults[:url]}" # rubocop:disable Layout/LineLength
55
+ c.flag %i[user], desc: 'Username', default_value: defaults[:user]
56
+ c.flag %i[password], desc: 'Password', default_value: defaults[:password]
57
+ c.action do |global_options, options, args|
58
+ help_now! unless args.size == 1
59
+
60
+ opts = global_options.merge(options)
61
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :owner, :repo,
62
+ :url, :user, :password, :proxy
63
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
64
+ opts[:semantic_only] = !options[:invalid_versions]
65
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
66
+ package = Getv::Package::Docker.new args[0], opts
67
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
68
+ end
69
+ end
70
+
71
+ desc 'Get package versions from RubyGems.org'
72
+ arg_name 'package_name'
73
+ command :gem do |c|
74
+ defaults = (Getv::Package::Gem.new 'name').opts
75
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
76
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
77
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
78
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
79
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
80
+ default_value: defaults[:semantic_select]
81
+ c.action do |global_options, options, args|
82
+ help_now! unless args.size == 1
83
+
84
+ opts = global_options.merge(options)
85
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :proxy
86
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
87
+ opts[:semantic_only] = !options[:invalid_versions]
88
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
89
+ package = Getv::Package::Gem.new args[0], opts
90
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
91
+ end
92
+ end
93
+
94
+ desc 'Get package versions from text file URL'
95
+ arg_name 'package_name'
96
+ command :text do |c|
97
+ defaults = (Getv::Package::Text.new 'name').opts
98
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
99
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
100
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
101
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
102
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
103
+ default_value: defaults[:semantic_select]
104
+ c.flag %i[url], desc: 'URL', default_value: defaults[:url]
105
+ c.action do |global_options, options, args|
106
+ help_now! unless args.size == 1
107
+
108
+ opts = global_options.merge(options)
109
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :url, :proxy
110
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
111
+ opts[:semantic_only] = !options[:invalid_versions]
112
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
113
+ package = Getv::Package::Text.new args[0], opts
114
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
115
+ end
116
+ end
117
+
118
+ desc 'Get package versions from GitHub commits'
119
+ arg_name 'package_name'
120
+ command :github_commit do |c|
121
+ defaults = (Getv::Package::GitHub::Commit.new 'name').opts
122
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
123
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
124
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
125
+ c.flag %i[owner], desc: 'Repository owner',
126
+ default_value: "'<owner>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
127
+ c.flag %i[repo], desc: 'Repository name',
128
+ default_value: "'<repo>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
129
+ c.flag %i[branch], desc: 'Repository branch', default_value: defaults[:branch]
130
+ c.flag %i[token], desc: 'Token', default_value: defaults[:token]
131
+ c.action do |global_options, options, args|
132
+ help_now! unless args.size == 1
133
+
134
+ opts = global_options.merge(options)
135
+ opts = opts.slice :select_search, :select_replace, :reject, :owner, :repo, :branch, :token, :proxy
136
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
137
+ package = Getv::Package::GitHub::Commit.new args[0], opts
138
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
139
+ end
140
+ end
141
+
142
+ desc 'Get package versions from GitHub releases'
143
+ arg_name 'package_name'
144
+ command :github_release do |c|
145
+ defaults = (Getv::Package::GitHub::Release.new 'name').opts
146
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
147
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
148
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
149
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
150
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
151
+ default_value: defaults[:semantic_select]
152
+ c.flag %i[owner], desc: 'Repository owner',
153
+ default_value: "'<owner>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
154
+ c.flag %i[repo], desc: 'Repository name',
155
+ default_value: "'<repo>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
156
+ c.flag %i[token], desc: 'Token', default_value: defaults[:token]
157
+ c.action do |global_options, options, args|
158
+ help_now! unless args.size == 1
159
+
160
+ opts = global_options.merge(options)
161
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :owner, :repo,
162
+ :token, :proxy
163
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
164
+ opts[:semantic_only] = !options[:invalid_versions]
165
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
166
+ package = Getv::Package::GitHub::Release.new args[0], opts
167
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
168
+ end
169
+ end
170
+
171
+ desc 'Get package versions from GitHub tags'
172
+ arg_name 'package_name'
173
+ command :github_tag do |c|
174
+ defaults = (Getv::Package::GitHub::Tag.new 'name').opts
175
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
176
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
177
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
178
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
179
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
180
+ default_value: defaults[:semantic_select]
181
+ c.flag %i[owner], desc: 'Repository owner',
182
+ default_value: "'<owner>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
183
+ c.flag %i[repo], desc: 'Repository name',
184
+ default_value: "'<repo>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
185
+ c.flag %i[token], desc: 'Token', default_value: defaults[:token]
186
+ c.action do |global_options, options, args|
187
+ help_now! unless args.size == 1
188
+
189
+ opts = global_options.merge(options)
190
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :owner, :repo,
191
+ :token, :proxy
192
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
193
+ opts[:semantic_only] = !options[:invalid_versions]
194
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
195
+ package = Getv::Package::GitHub::Tag.new args[0], opts
196
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
197
+ end
198
+ end
199
+
200
+ desc 'Get package versions from a Helm chart repository'
201
+ arg_name 'package_name'
202
+ command :helm do |c|
203
+ defaults = (Getv::Package::Helm.new 'name').opts
204
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
205
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
206
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
207
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
208
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
209
+ default_value: defaults[:semantic_select]
210
+ c.flag %i[chart], desc: 'Chart name', default_value: 'package_name'
211
+ c.flag %i[url], desc: 'URL', default_value: defaults[:url]
212
+ c.flag %i[user], desc: 'Username', default_value: defaults[:user]
213
+ c.flag %i[password], desc: 'Password', default_value: defaults[:password]
214
+ c.action do |global_options, options, args|
215
+ help_now! unless args.size == 1
216
+
217
+ opts = global_options.merge(options)
218
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :chart, :url,
219
+ :user, :password, :proxy
220
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
221
+ opts[:semantic_only] = !options[:invalid_versions]
222
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
223
+ package = Getv::Package::Helm.new args[0], opts
224
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
225
+ end
226
+ end
227
+
228
+ desc 'Get package versions from XML file URL'
229
+ arg_name 'package_name'
230
+ command :xml do |c|
231
+ defaults = (Getv::Package::Xml.new 'name').opts
232
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
233
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
234
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
235
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
236
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
237
+ default_value: defaults[:semantic_select]
238
+ c.flag %i[url], desc: 'URL', default_value: defaults[:url]
239
+ c.flag %i[xpath], desc: 'XPath', default_value: defaults[:xpath]
240
+ c.switch %i[link_value], desc: 'Use the value (target) of links rather than the content (display text)',
241
+ negatable: false, default_value: false
242
+ c.action do |global_options, options, args|
243
+ help_now! unless args.size == 1
244
+
245
+ opts = global_options.merge(options)
246
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :url, :proxy
247
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
248
+ opts[:link] == 'value' if options[:link_value]
249
+ opts[:semantic_only] = !options[:invalid_versions]
250
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
251
+ package = Getv::Package::Xml.new args[0], opts
252
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
253
+ end
254
+ end
255
+
256
+ desc 'Get package versions from npm at registry.npmjs.org'
257
+ arg_name 'package_name'
258
+ command :npm do |c|
259
+ defaults = (Getv::Package::Npm.new 'name').opts
260
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
261
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
262
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
263
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
264
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
265
+ default_value: defaults[:semantic_select]
266
+ c.action do |global_options, options, args|
267
+ help_now! unless args.size == 1
268
+
269
+ opts = global_options.merge(options)
270
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :proxy
271
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
272
+ opts[:semantic_only] = !options[:invalid_versions]
273
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
274
+ package = Getv::Package::Npm.new args[0], opts
275
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
276
+ end
277
+ end
278
+
279
+ desc 'Get package versions from the Python Package Index at pypi.org'
280
+ arg_name 'package_name'
281
+ command :pypi do |c|
282
+ defaults = (Getv::Package::Pypi.new 'name').opts
283
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
284
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
285
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
286
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
287
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
288
+ default_value: defaults[:semantic_select]
289
+ c.action do |global_options, options, args|
290
+ help_now! unless args.size == 1
291
+
292
+ opts = global_options.merge(options)
293
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :proxy
294
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
295
+ opts[:semantic_only] = !options[:invalid_versions]
296
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
297
+ package = Getv::Package::Pypi.new args[0], opts
298
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
299
+ end
300
+ end
301
+
302
+ pre do |_global, _command, _options, _args|
303
+ # Pre logic here
304
+ # Return true to proceed; false to abort and not call the
305
+ # chosen command
306
+ # Use skips_pre before a command to skip this block
307
+ # on that command only
308
+ true
309
+ end
310
+
311
+ post do |global, command, options, args|
312
+ # Post logic here
313
+ # Use skips_post before a command to skip this
314
+ # block on that command only
315
+ end
316
+
317
+ on_error do |_exception|
318
+ # Error logic here
319
+ # return false to skip default error handling
320
+ true
321
+ end
322
+ end
323
+
324
+ exit App.run(ARGV)
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Docker class
6
+ class Docker < Package
7
+ def initialize(name, opts = {}, no_owner_domains = [])
8
+ @no_owner_domains = no_owner_domains
9
+ opts = defaults.merge(opts)
10
+ opts = { user: nil, password: nil, auto_paginate: true }.merge(opts)
11
+ opts = docker_defaults(name).merge(opts)
12
+ super name, opts
13
+ end
14
+
15
+ private
16
+
17
+ def docker_defaults(name)
18
+ case name.count('/')
19
+ when 0
20
+ { owner: 'library', repo: name, url: 'https://registry.hub.docker.com' }
21
+ when 1
22
+ if @no_owner_domains.include?(name.split('/')[0])
23
+ { owner: '', repo: name.split('/')[1],
24
+ url: "https://#{name.split('/')[0]}" }
25
+ else
26
+ { owner: name.split('/')[0], repo: name.split('/')[1],
27
+ url: 'https://registry.hub.docker.com' }
28
+ end
29
+ else
30
+ { owner: name.split('/')[1], repo: name.split('/')[2..].join('/'),
31
+ url: "https://#{name.split('/')[0]}" }
32
+ end
33
+ end
34
+
35
+ def docker_opts
36
+ d_opts = {}
37
+ d_opts[:http_options] = { proxy: opts[:proxy] } unless opts[:proxy].nil?
38
+ if opts[:user] && opts[:password]
39
+ d_opts[:user] = opts[:user]
40
+ d_opts[:password] = opts[:password]
41
+ end
42
+ d_opts
43
+ end
44
+
45
+ def retrieve_versions # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
46
+ require 'docker_registry2'
47
+ retries ||= 0
48
+ docker = DockerRegistry2.connect(opts[:url], docker_opts)
49
+ full_name = if opts[:owner].empty?
50
+ opts[:repo]
51
+ else
52
+ "#{opts[:owner]}/#{opts[:repo]}"
53
+ end
54
+ docker.tags(full_name, auto_paginate: opts[:auto_paginate])['tags'] || []
55
+ rescue DockerRegistry2::NotFound
56
+ []
57
+ rescue StandardError => e
58
+ if (retries += 1) < 4
59
+ retry
60
+ else
61
+ puts "Error fetching tags for docker image #{opts[:url]}/#{opts[:owner]}/#{opts[:repo]}:"
62
+ puts e.message
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Gem class
6
+ class Gem < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { gem: name[/ruby(gem)?-(.*)/, 2] || name }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ require 'json'
17
+ retries ||= 0
18
+ JSON.parse(get("https://rubygems.org/api/v1/versions/#{opts[:gem]}.json")).map do |v|
19
+ v['number']
20
+ end
21
+ rescue StandardError
22
+ retry if (retries += 1) < 4
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ class GitHub
6
+ # Getv::Package::GitHub::Commit class
7
+ class Commit < Package::GitHub
8
+ def initialize(name, opts = {})
9
+ opts = {
10
+ branch: 'master',
11
+ select_search: '^((\d{8})(\d{6}),(([a-z\d]{7})(.*)))$',
12
+ semantic_only: false
13
+ }.merge(opts)
14
+ opts = defaults.merge(opts)
15
+ opts = github_defaults(name).merge(opts)
16
+ super name, opts
17
+ end
18
+
19
+ private
20
+
21
+ def retrieve_versions # rubocop:disable Metrics/AbcSize
22
+ retries ||= 0
23
+ github.commits("#{opts[:owner]}/#{opts[:repo]}", opts[:branch]).map do |c|
24
+ "#{DateTime.parse(c[:commit][:author][:date].to_s).strftime('%Y%m%d%H%M%S')},#{c[:sha]}"
25
+ end
26
+ rescue StandardError
27
+ retry if (retries += 1) < 4
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ class GitHub
6
+ # Getv::Package::GitHub::Release class
7
+ class Release < Package::GitHub
8
+ def initialize(name, opts = {})
9
+ opts = defaults.merge(opts)
10
+ opts = github_defaults(name).merge(opts)
11
+ super name, opts
12
+ end
13
+
14
+ private
15
+
16
+ def retrieve_versions
17
+ retries ||= 0
18
+ github.releases("#{opts[:owner]}/#{opts[:repo]}").map(&:tag_name)
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ class GitHub
6
+ # Getv::Package::GitHub::Tag class
7
+ class Tag < Package::GitHub
8
+ def initialize(name, opts = {})
9
+ opts = defaults.merge(opts)
10
+ opts = github_defaults(name).merge(opts)
11
+ super name, opts
12
+ end
13
+
14
+ private
15
+
16
+ def retrieve_versions
17
+ retries ||= 0
18
+ github.tags("#{opts[:owner]}/#{opts[:repo]}").map { |t| t[:name] }
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::GitHub class
6
+ class GitHub < Package
7
+ def initialize(name, opts = {})
8
+ super name, opts
9
+ end
10
+
11
+ private
12
+
13
+ def github_defaults(name)
14
+ case name.count('/')
15
+ when 1
16
+ { owner: name.split('/')[0], repo: name.split('/')[1], token: nil }
17
+ else
18
+ { owner: name, repo: name, token: nil }
19
+ end
20
+ end
21
+
22
+ def github # rubocop:disable Metrics/MethodLength
23
+ require 'octokit'
24
+ if opts[:token]
25
+ github = Octokit::Client.new(access_token: opts[:token])
26
+ user = github.user
27
+ user.login
28
+ else
29
+ github = Octokit::Client.new
30
+ end
31
+ github.auto_paginate = true
32
+ github.proxy = opts[:proxy]
33
+ github
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Helm class
6
+ class Helm < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { chart: name, url: nil, user: nil, password: nil }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ require 'yaml'
17
+ retries ||= 0
18
+ YAML.safe_load(get("#{opts[:url]}/index.yaml")).fetch('entries', {}).fetch(opts[:chart], []).map do |e|
19
+ e['version']
20
+ end
21
+ rescue StandardError
22
+ retry if (retries += 1) < 4
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Npm class
6
+ class Npm < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { npm: name[/node(js)?-(.*)/, 2] || name }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ require 'json'
17
+ retries ||= 0
18
+ JSON.parse(get("https://registry.npmjs.org/#{opts[:npm]}"))['versions'].keys
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Pypi class
6
+ class Pypi < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { pypi: name[/python.*-(.*)/, 1] || name }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ require 'json'
17
+ retries ||= 0
18
+ JSON.parse(get("https://pypi.org/pypi/#{opts[:pypi]}/json"))['releases'].keys
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Text class
6
+ class Text < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { url: nil, user: nil, password: nil }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ retries ||= 0
17
+ get(opts[:url]).split("\n")
18
+ rescue StandardError
19
+ retry if (retries += 1) < 4
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Xml class
6
+ class Xml < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { url: nil, user: nil, password: nil, xpath: '//a/@href' }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ retries ||= 0
17
+ require 'nokogiri'
18
+ Nokogiri::XML(get(opts[:url])).xpath(opts[:xpath]).map(&:text)
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ # Getv::Package class
5
+ class Package
6
+ attr_accessor :name, :opts
7
+
8
+ def self.create(name, opts = {})
9
+ if opts.fetch(:type, nil).nil?
10
+ opts.delete(:type)
11
+ create_using_name(name, opts)
12
+ else
13
+ type = opts[:type]
14
+ opts.delete(:type)
15
+ type_to_class(type).new name, opts
16
+ end
17
+ end
18
+
19
+ private_class_method def self.create_using_name(name, opts)
20
+ case name
21
+ when /ruby(gem)?-.*/
22
+ Getv::Package::Gem.new name, opts
23
+ when /node(js)?-.*/
24
+ Getv::Package::Npm.new name, opts
25
+ when /python.*-.*/
26
+ Getv::Package::Pypi.new name, opts
27
+ else
28
+ Getv::Package::GitHub::Release.new name, opts
29
+ end
30
+ end
31
+
32
+ private_class_method def self.type_to_class(type)
33
+ sections = type.split(/_|::| |-|:/)
34
+ sections.each(&:capitalize!)
35
+ sections.each { |section| section.sub! 'Github', 'GitHub' }
36
+ type = sections.join '::'
37
+ Object.const_get("Getv::Package::#{type}")
38
+ end
39
+
40
+ def initialize(name, opts = {})
41
+ @name = name
42
+ @opts = opts
43
+ end
44
+
45
+ def defaults # rubocop:disable Metrics/MethodLength
46
+ {
47
+ select_search: '^\s*v?(.*)\s*$',
48
+ select_replace: '\1',
49
+ reject: nil,
50
+ semantic_only: true,
51
+ semantic_prefix: nil,
52
+ semantic_select: ['*'],
53
+ proxy: nil,
54
+ versions: nil,
55
+ latest_version: nil
56
+ }
57
+ end
58
+
59
+ def latest_version
60
+ update_versions if opts[:latest_version].nil?
61
+ opts[:latest_version]
62
+ end
63
+
64
+ def versions
65
+ update_versions if opts[:versions].nil?
66
+ opts[:versions]
67
+ end
68
+
69
+ def update_versions # rubocop:disable Metrics/PerceivedComplexity,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/AbcSize
70
+ versions = retrieve_versions || []
71
+ versions.sort! if instance_of?(Getv::Package::GitHub::Commit)
72
+ select_pattern = Regexp.new(opts[:select_search])
73
+ versions.select! { |v| v =~ select_pattern }
74
+ versions.map! { |v| v.sub(select_pattern, opts[:select_replace]) }
75
+ versions.reject! { |v| v =~ Regexp.new(opts[:reject]) } unless opts[:reject].nil?
76
+
77
+ if opts[:semantic_only]
78
+ require 'semantic'
79
+ require 'semantic/core_ext'
80
+
81
+ # remove non semantic version tags
82
+ versions.select! do |v|
83
+ v.sub(/^#{opts[:semantic_prefix]}/, '').is_version? && v.start_with?(opts[:semantic_prefix].to_s)
84
+ end
85
+
86
+ opts[:semantic_select].each do |comparator|
87
+ versions.select! do |v|
88
+ Semantic::Version.new(v.sub(/^#{opts[:semantic_prefix]}/, '')).satisfies?(comparator)
89
+ end
90
+ end
91
+ versions.sort_by! { |v| Semantic::Version.new(v.sub(/^#{opts[:semantic_prefix]}/, '')) }
92
+ else
93
+ versions.sort! unless instance_of?(Getv::Package::GitHub::Commit)
94
+ end
95
+ opts[:versions] = versions.uniq
96
+ opts[:latest_version] = opts[:versions][-1] unless opts[:versions].empty?
97
+ end
98
+
99
+ private
100
+
101
+ def get(url) # rubocop:disable Metrics/AbcSize
102
+ require 'rest-client'
103
+ if opts[:user] && opts[:password]
104
+ RestClient::Request.execute(method: :get, url: url, proxy: opts[:proxy], user: opts[:user],
105
+ password: opts[:password]).body
106
+ else
107
+ RestClient::Request.execute(method: :get, url: url, proxy: opts[:proxy]).body
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ VERSION = '2.3.0'
5
+ end
data/lib/getv.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'getv/version'
4
+ require 'getv/package'
5
+ require 'getv/package/docker'
6
+ require 'getv/package/gem'
7
+ require 'getv/package/github'
8
+ require 'getv/package/github/commit'
9
+ require 'getv/package/github/release'
10
+ require 'getv/package/github/tag'
11
+ require 'getv/package/helm'
12
+ require 'getv/package/npm'
13
+ require 'getv/package/pypi'
14
+ require 'getv/package/text'
15
+ require 'getv/package/xml'
16
+
17
+ module Getv
18
+ class Error < StandardError; end
19
+ # Your code goes here...
20
+ end
metadata ADDED
@@ -0,0 +1,184 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: getv-rs
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.3.0
5
+ platform: ruby
6
+ authors:
7
+ - ryan-scheinberg
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-09-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.20.1
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 2.20.1
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 3.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: docker_registry2
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 1.10.1
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: 2.0.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.10.1
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: 2.0.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: nokogiri
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 1.0.0
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: 2.0.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 1.0.0
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: 2.0.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: octokit
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 3.0.0
80
+ - - "<"
81
+ - !ruby/object:Gem::Version
82
+ version: 5.0.0
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.0
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: 5.0.0
93
+ - !ruby/object:Gem::Dependency
94
+ name: rest-client
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 2.1.0
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: 3.0.0
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: 2.1.0
110
+ - - "<"
111
+ - !ruby/object:Gem::Version
112
+ version: 3.0.0
113
+ - !ruby/object:Gem::Dependency
114
+ name: semantic
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: 1.0.0
120
+ - - "<"
121
+ - !ruby/object:Gem::Version
122
+ version: 2.0.0
123
+ type: :runtime
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: 1.0.0
130
+ - - "<"
131
+ - !ruby/object:Gem::Version
132
+ version: 2.0.0
133
+ description: Pull package version numbers from the web in various ways.
134
+ email:
135
+ - ryan.scheinberg@gmail.com
136
+ executables:
137
+ - getv
138
+ extensions: []
139
+ extra_rdoc_files: []
140
+ files:
141
+ - LICENSE.txt
142
+ - README.md
143
+ - exe/getv
144
+ - lib/getv.rb
145
+ - lib/getv/package.rb
146
+ - lib/getv/package/docker.rb
147
+ - lib/getv/package/gem.rb
148
+ - lib/getv/package/github.rb
149
+ - lib/getv/package/github/commit.rb
150
+ - lib/getv/package/github/release.rb
151
+ - lib/getv/package/github/tag.rb
152
+ - lib/getv/package/helm.rb
153
+ - lib/getv/package/npm.rb
154
+ - lib/getv/package/pypi.rb
155
+ - lib/getv/package/text.rb
156
+ - lib/getv/package/xml.rb
157
+ - lib/getv/version.rb
158
+ homepage: https://github.com/ryan-scheinberg/getv
159
+ licenses:
160
+ - MIT
161
+ metadata:
162
+ homepage_uri: https://github.com/ryan-scheinberg/getv
163
+ source_code_uri: https://github.com/ryan-scheinberg/getv
164
+ changelog_uri: https://github.com/ryan-scheinberg/getv
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubygems_version: 3.0.3.1
181
+ signing_key:
182
+ specification_version: 4
183
+ summary: Pull package version numbers from the web in various ways.
184
+ test_files: []