firespring_dev_commands 2.2.8.pre.alpha.1 → 2.5.0.pre.alpha.1

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/firespring_dev_commands/audit/report.rb +2 -9
  4. data/lib/firespring_dev_commands/aws/account.rb +1 -1
  5. data/lib/firespring_dev_commands/aws/cloudformation.rb +3 -10
  6. data/lib/firespring_dev_commands/aws/login.rb +1 -1
  7. data/lib/firespring_dev_commands/common.rb +2 -22
  8. data/lib/firespring_dev_commands/docker/status.rb +0 -20
  9. data/lib/firespring_dev_commands/docker.rb +16 -86
  10. data/lib/firespring_dev_commands/eol/aws.rb +2 -10
  11. data/lib/firespring_dev_commands/eol.rb +2 -22
  12. data/lib/firespring_dev_commands/git.rb +24 -37
  13. data/lib/firespring_dev_commands/jira/issue.rb +1 -3
  14. data/lib/firespring_dev_commands/node.rb +1 -1
  15. data/lib/firespring_dev_commands/php/audit.rb +0 -4
  16. data/lib/firespring_dev_commands/php.rb +12 -28
  17. data/lib/firespring_dev_commands/platform.rb +31 -38
  18. data/lib/firespring_dev_commands/ruby.rb +3 -6
  19. data/lib/firespring_dev_commands/target_process/query.rb +4 -30
  20. data/lib/firespring_dev_commands/target_process/release.rb +1 -1
  21. data/lib/firespring_dev_commands/target_process/team_assignment.rb +1 -1
  22. data/lib/firespring_dev_commands/target_process/user.rb +1 -13
  23. data/lib/firespring_dev_commands/target_process/user_story.rb +1 -1
  24. data/lib/firespring_dev_commands/target_process/user_story_history.rb +1 -1
  25. data/lib/firespring_dev_commands/target_process.rb +7 -24
  26. data/lib/firespring_dev_commands/templates/aws.rb +6 -33
  27. data/lib/firespring_dev_commands/templates/base_interface.rb +2 -2
  28. data/lib/firespring_dev_commands/templates/ci.rb +11 -16
  29. data/lib/firespring_dev_commands/templates/docker/application.rb +2 -2
  30. data/lib/firespring_dev_commands/templates/docker/node/application.rb +5 -55
  31. data/lib/firespring_dev_commands/templates/docker/php/application.rb +16 -58
  32. data/lib/firespring_dev_commands/templates/docker/ruby/application.rb +5 -54
  33. data/lib/firespring_dev_commands/templates/eol.rb +2 -9
  34. data/lib/firespring_dev_commands/templates/git.rb +0 -165
  35. data/lib/firespring_dev_commands/version.rb +1 -1
  36. data/lib/firespring_dev_commands.rb +1 -1
  37. metadata +35 -125
  38. data/lib/firespring_dev_commands/aws/route53.rb +0 -177
  39. data/lib/firespring_dev_commands/bloom_growth/rock.rb +0 -34
  40. data/lib/firespring_dev_commands/bloom_growth/seat.rb +0 -16
  41. data/lib/firespring_dev_commands/bloom_growth/user.rb +0 -43
  42. data/lib/firespring_dev_commands/bloom_growth.rb +0 -132
  43. data/lib/firespring_dev_commands/certificate.rb +0 -59
  44. data/lib/firespring_dev_commands/coverage/base.rb +0 -16
  45. data/lib/firespring_dev_commands/coverage/cobertura.rb +0 -86
  46. data/lib/firespring_dev_commands/coverage/none.rb +0 -21
  47. data/lib/firespring_dev_commands/dns/resource.rb +0 -93
  48. data/lib/firespring_dev_commands/docker/desktop.rb +0 -61
  49. data/lib/firespring_dev_commands/eol/node.rb +0 -42
  50. data/lib/firespring_dev_commands/eol/php.rb +0 -50
  51. data/lib/firespring_dev_commands/eol/ruby.rb +0 -42
  52. data/lib/firespring_dev_commands/jira/parent.rb +0 -19
  53. data/lib/firespring_dev_commands/os.rb +0 -35
  54. data/lib/firespring_dev_commands/port.rb +0 -24
  55. data/lib/firespring_dev_commands/target_process/time.rb +0 -32
  56. data/lib/firespring_dev_commands/templates/aws/services/route53.rb +0 -130
  57. data/lib/firespring_dev_commands/templates/certificate.rb +0 -41
@@ -1,132 +0,0 @@
1
- require 'net/http'
2
-
3
- module Dev
4
- # Class for interacting with the Bloom Growth api
5
- class BloomGrowth
6
- # The config file to try to load credentials from
7
- CONFIG_FILE = "#{Dir.home}/.env.bloom".freeze
8
-
9
- # The text of the username variable key
10
- BLOOM_USERNAME = 'BLOOM_USERNAME'.freeze
11
-
12
- # The text of the password variable key
13
- BLOOM_PASSWORD = 'BLOOM_PASSWORD'.freeze
14
-
15
- # The text of the token variable key
16
- BLOOM_TOKEN = 'BLOOM_TOKEN'.freeze
17
-
18
- # The text of the url variable key
19
- BLOOM_URL = 'BLOOM_URL'.freeze
20
-
21
- # Config object for setting top level bloom growth config options
22
- Config = Struct.new(:username, :password, :url, :http_debug) do
23
- def initialize
24
- Dotenv.load(CONFIG_FILE) if File.exist?(CONFIG_FILE)
25
-
26
- self.username = ENV.fetch(BLOOM_USERNAME, nil)
27
- self.password = ENV.fetch(BLOOM_PASSWORD, nil)
28
- self.url = ENV.fetch(BLOOM_URL, 'https://app.bloomgrowth.com')
29
- self.http_debug = false
30
- end
31
- end
32
-
33
- class << self
34
- # Instantiates a new top level config object if one hasn't already been created
35
- # Yields that config object to any given block
36
- # Returns the resulting config object
37
- def config
38
- @config ||= Config.new
39
- yield(@config) if block_given?
40
- @config
41
- end
42
-
43
- # Alias the config method to configure for a slightly clearer access syntax
44
- alias_method :configure, :config
45
- end
46
-
47
- attr_accessor :username, :password, :url, :token, :client, :default_headers
48
-
49
- # Initialize a new target process client using the given inputs
50
- def initialize(username: self.class.config.username, password: self.class.config.password, url: self.class.config.url)
51
- raise 'username is required' if username.to_s.strip.empty?
52
- raise 'password is required' if password.to_s.strip.empty?
53
- raise 'url is required' if url.to_s.strip.empty?
54
-
55
- @username = username
56
- @password = password
57
- @url = url
58
- uri = URI.parse(@url)
59
- @client = Net::HTTP.new(uri.host, uri.port)
60
- @client.use_ssl = true
61
- @client.verify_mode = OpenSSL::SSL::VERIFY_PEER
62
- @client.set_debug_output(LOG) if self.class.config.http_debug
63
- @default_headers = {
64
- 'authorization' => "Bearer #{token}",
65
- 'content-type' => 'application/json',
66
- 'accept' => 'application/json'
67
- }
68
- end
69
-
70
- # Method for getting a bearer token for the bloom growth api. There are a couple of possible logic paths
71
- # - If a token has already been defined, use it
72
- # - If a token is found in the ENV, use it
73
- # - Otherwise, use the username and passowrd that has been configured to request a new token from bloom
74
- def token
75
- @token ||= ENV.fetch(BLOOM_TOKEN, nil)
76
-
77
- unless @token
78
- response = post(
79
- '/Token',
80
- {
81
- grant_type: 'password',
82
- userName: username,
83
- password:
84
- },
85
- headers: {
86
- 'content-type' => 'application/json',
87
- 'accept' => 'application/json'
88
- }
89
- )
90
- # TODO: Should we look at https://github.com/DannyBen/lightly for caching the token?
91
- @token = ENV[BLOOM_TOKEN] = response['access_token']
92
- LOG.info("Retrieved BloomGrowth token. Expires on #{Time.now + response['expires_in']}")
93
- end
94
-
95
- @token
96
- end
97
-
98
- # Return all user objects visible to the logged in user
99
- def visible_users(&)
100
- [].tap do |ary|
101
- get('/api/v1/users/mineviewable') do |user_data|
102
- ary << User.new(user_data)
103
- end
104
- ary.each(&)
105
- end
106
- end
107
-
108
- # Perform a get request to the given path using the given query
109
- # Call the given block (if present) with each piece of data
110
- # Return all pieces of data
111
- def get(path, query_string: nil, headers: default_headers, &)
112
- url = path
113
- url << "?#{URI.encode_www_form(query_string)}" unless query_string.to_s.strip.empty?
114
-
115
- response = client.request_get(url, headers)
116
- raise "Error querying #{url} [#{query_string}]: #{response.inspect}" unless response.response.is_a?(Net::HTTPSuccess)
117
-
118
- JSON.parse(response.body).each(&)
119
- nil
120
- end
121
-
122
- # Perform a post request to the given path using the gien data
123
- # Return the parsed json body
124
- def post(path, data, headers: default_headers)
125
- data = data.to_json unless data.is_a?(String)
126
- response = client.request_post(path, data, headers)
127
- raise "Error querying #{url}/#{path}: #{response.inspect}" unless response.response.is_a?(Net::HTTPSuccess)
128
-
129
- JSON.parse(response.body)
130
- end
131
- end
132
- end
@@ -1,59 +0,0 @@
1
- module Dev
2
- # Class contains methods for requesting a certificate from route53.
3
- # You must have a hosted zone defined for the desired domain
4
- class Certificate
5
- attr_accessor :domains, :email
6
-
7
- def initialize(domains, email)
8
- @domains = Array(domains)
9
- @email = email
10
- raise 'No certificate domains specified' if domains.empty?
11
- end
12
-
13
- # Request the certificate using the route53 docker image
14
- # Certificate is stored in /etc/letsencrypt
15
- def request
16
- puts
17
- puts 'Getting SSL Certs For:'
18
- puts domains.join("\n")
19
- puts
20
- puts 'This process can take up to 10 minutes'
21
- puts
22
- puts Time.now
23
-
24
- # TODO: Really should use the docker api for this
25
- cmd = %w(docker run -it --rm --name certbot)
26
- cmd << '-e' << 'AWS_ACCESS_KEY_ID'
27
- cmd << '-e' << 'AWS_SECRET_ACCESS_KEY'
28
- cmd << '-e' << 'AWS_SESSION_TOKEN'
29
- cmd << '-v' << '/etc/letsencrypt:/etc/letsencrypt'
30
- cmd << 'certbot/dns-route53:latest'
31
- cmd << 'certonly'
32
- cmd << '-n'
33
- cmd << '--agree-tos'
34
- cmd << '--dns-route53'
35
- cmd << '-d' << domains.join(',')
36
- cmd << '--email' << email
37
- cmd << '--server' << 'https://acme-v02.api.letsencrypt.org/directory'
38
- puts cmd.join(' ')
39
- Dev::Common.new.run_command(cmd)
40
- end
41
-
42
- # Saves the latest version of the certificate into the given dest_dir
43
- def save(dest_dir)
44
- raise "directory #{dest_dir} must be an existing directory" unless File.directory?(dest_dir)
45
-
46
- domain = domains.first.sub(/^\*\./, '') # Need to strip off the '*.' if this is a wildcard cert
47
- directories = Dir.glob("/etc/letsencrypt/live/#{domain}*/")
48
- no_suffix = directories.delete("/etc/letsencrypt/live/#{domain}/")
49
- biggest_suffix = directories.max
50
- source_dir = biggest_suffix || no_suffix
51
- raise "unable to determine certificate directory for #{domain}" unless source_dir
52
-
53
- FileUtils.cp("#{source_dir}privkey.pem", dest_dir, verbose: true)
54
- FileUtils.cp("#{source_dir}cert.pem", dest_dir, verbose: true)
55
- FileUtils.cp("#{source_dir}chain.pem", dest_dir, verbose: true)
56
- FileUtils.cp("#{source_dir}fullchain.pem", dest_dir, verbose: true)
57
- end
58
- end
59
- end
@@ -1,16 +0,0 @@
1
- module Dev
2
- module Coverage
3
- # Class which defines the methods which must be implemented to function as a coverage class
4
- class Base
5
- # Raises not implemented
6
- def php_options
7
- raise 'not implemented'
8
- end
9
-
10
- # Raises not implemented
11
- def check(*)
12
- raise 'not implemented'
13
- end
14
- end
15
- end
16
- end
@@ -1,86 +0,0 @@
1
- module Dev
2
- # Module containing different classes for interfacing with coverage files
3
- module Coverage
4
- # Class for checking code coverage using cobertura
5
- class Cobertura < Base
6
- attr_reader :local_filename, :container_filename, :filename, :threshold, :exclude
7
-
8
- def initialize(filename: File.join('coverage', 'cobertura.xml'), threshold: nil, container_path: nil, local_path: nil, exclude: nil)
9
- super()
10
-
11
- @filename = filename
12
- @local_filename = File.join(local_path || '.', @filename)
13
- @container_filename = File.join(container_path || '.', @filename)
14
- @threshold = threshold
15
- @exclude = (exclude || []).map do |it|
16
- next it if it.is_a?(Regex)
17
-
18
- Regex.new(it)
19
- end
20
- end
21
-
22
- # Remove any previous versions of the local file that will be output
23
- # return the phpunit options needed to regenerate the cobertura xml file
24
- def php_options
25
- # Remove any previous coverage info
26
- FileUtils.rm_f(local_filename, verbose: true)
27
-
28
- # Return the needed php commands to generate the cobertura report
29
- %W(--coverage-cobertura #{container_filename})
30
- end
31
-
32
- # Parse the cobertura file and check the lines missed against the desired threshold
33
- def check(application: nil)
34
- # If an application has been specified and the file does not exist locally, attempt to copy it back from the docker container
35
- if application && !File.exist?(local_filename)
36
- container = Dev::Docker::Compose.new.container_by_name(application)
37
- Dev::Docker.new.copy_from_container(container, container_filename, local_filename, required: true)
38
- end
39
-
40
- report = Ox.load(File.read(local_filename))
41
- total_missed = report.coverage.locate('packages/package').sum { |package| parse_package_missed(package) }
42
- puts "Lines missing coverage was #{total_missed}"
43
- puts "Configured threshold was #{threshold}" if threshold
44
- raise 'Code coverage not met' if threshold && total_missed > threshold
45
- end
46
-
47
- # Go through the package and add up all of the lines that were missed
48
- # Ignore if the file was in the exlude list
49
- private def parse_package_missed(package)
50
- filename = package.attributes[:name]
51
- return if exclude.any? { |it| it.match(filename) }
52
-
53
- missed = 0
54
- lines_processed = Set.new
55
- package.locate('classes/class/lines/line').each do |line|
56
- # Don't count lines multiple times
57
- line_number = line.attributes[:number]
58
- next if lines_processed.include?(line_number)
59
-
60
- lines_processed << line_number
61
- missed += 1 unless line.attributes[:hits].to_i.positive?
62
- end
63
- total = lines_processed.length
64
-
65
- sanity_check_coverage_against_cobertura_values(package, missed, total)
66
- missed
67
- end
68
-
69
- # Calculate the coverage percent based off the numbers we got and compare to the
70
- # value cobertura reported. This is meant as a sanity check that we are reading the data correctly
71
- # TODO: This should be removed after the above logic has been vetted
72
- private def sanity_check_coverage_against_cobertura_values(package, missed, total)
73
- line_rate = package.attributes[:'line-rate']
74
- cobertura_reported_coverage = line_rate.to_f
75
- cobertura_reported_precision = line_rate.split('.').last.length
76
-
77
- file_coverage = 0.0
78
- file_coverage = ((total - missed).to_f / total).round(cobertura_reported_precision) if total.positive?
79
- return if file_coverage == cobertura_reported_coverage
80
-
81
- filename = package.attributes[:name]
82
- puts "WARNINNG: #{filename} coverage (#{file_coverage}) differed from what cobertura reported (#{cobertura_reported_coverage})"
83
- end
84
- end
85
- end
86
- end
@@ -1,21 +0,0 @@
1
- module Dev
2
- # Module with a variety of coverage methods for different languages
3
- module Coverage
4
- # Class which provides methods to effectvely skip coverage
5
- class None < Base
6
- def initialize(*)
7
- super()
8
- end
9
-
10
- # Returns the php options for generating code coverage file
11
- def php_options
12
- []
13
- end
14
-
15
- # Checks the code coverage against the defined threshold
16
- def check(*)
17
- puts 'Coverage not configured'
18
- end
19
- end
20
- end
21
- end
@@ -1,93 +0,0 @@
1
- require 'whois'
2
-
3
- module Dev
4
- class Dns
5
- class Resource
6
- attr_reader :domain
7
-
8
- def initialize(domain)
9
- @domain = domain
10
- end
11
-
12
- # Returns whether or not the given value is a valid IPv4 or IPv6 address
13
- def self.ip?(value)
14
- ipv4?(value) || ipv6?(value)
15
- end
16
-
17
- # Returns whether or not the given value is a valid IPv4 address
18
- def self.ipv4?(value)
19
- value.match?(Resolv::IPv4::Regex)
20
- end
21
-
22
- # Returns whether or not the given value is a valid IPv6 address
23
- def self.ipv6?(value)
24
- value.match?(Resolv::IPv6::Regex)
25
- end
26
-
27
- # Determines the registrar(s) of the given name. Not perfect and can be rate limited.
28
- def registrar_lookup(name = domain)
29
- Whois.whois(name.chomp('.')).parts.map(&:host)
30
- rescue Whois::Error
31
- sleep(0.75)
32
- retry
33
- end
34
-
35
- # Recursively determine the correct nameservers for the given domain.
36
- # If nameservers are not found, strip subdomains off until we've reached the TLD
37
- def recursive_nameserver_lookup(name = domain)
38
- records = lookup(name, type: Resolv::DNS::Resource::IN::NS)
39
-
40
- # Strip the subdomain and try again if we didn't find any nameservers (this can happen with wildcards)
41
- return recursive_nameserver_lookup(name.split('.', 2).last) if records.empty?
42
-
43
- # Look up the IPs for the nameservers
44
- records
45
- end
46
-
47
- # Recursively attempt to find an A record for the given domain.
48
- # If one isn't found, also check for CNAMEs continually until we have either found an IP or run out of things to check
49
- def recursive_a_lookup(name = domain)
50
- # Try looking up an A record first. If we find one, we are done.
51
- records = lookup(name, type: Resolv::DNS::Resource::IN::A)
52
- return records unless records.empty?
53
-
54
- # Try looking up a CNAME record
55
- records = lookup(name, type: Resolv::DNS::Resource::IN::CNAME)
56
-
57
- # If we didn't find an A record _or_ a CNAME, just return empty
58
- return records if records.empty?
59
-
60
- # If we found more than one CNAME that is a DNS error
61
- raise "Found more than one CNAME entry for #{name}. This is not allowed by DNS" if records.length > 1
62
-
63
- recursive_a_lookup(records.first)
64
- end
65
-
66
- # Lookup the given name using the record type provided.
67
- def lookup(name = domain, type: Resolv::DNS::Resource::IN::A)
68
- # Validate the type
69
- raise 'lookup type must be a Resolv::DNS::Resource' unless type.ancestors.include?(Resolv::DNS::Resource)
70
-
71
- # If we were given a tld, return empty
72
- return [] unless name.include?('.')
73
-
74
- # Look up NS records for the given host
75
- records = Resolv::DNS.new.getresources(name, type)
76
-
77
- # Return the record names
78
- records.map do |record|
79
- if record.respond_to?(:address)
80
- record.address.to_s
81
- elsif record.respond_to?(:name)
82
- record.name.to_s
83
- else
84
- ''
85
- end
86
- end
87
- rescue
88
- sleep(1)
89
- retry
90
- end
91
- end
92
- end
93
- end
@@ -1,61 +0,0 @@
1
- module Dev
2
- class Docker
3
- # Class for configuring docker desktop
4
- # This is mostly around configuring the docker URL correctly
5
- class Desktop
6
- # A snippet of a docker compose file which forwards a socket to a local port so that we can read it in the docker library
7
- WIN_TCP_COMPOSE_CONTENT = "
8
- ---
9
- version: '3.8'
10
- services:
11
- windows_tcp:
12
- image: alpine/socat
13
- network_mode: bridge
14
- ports:
15
- - 127.0.0.1:23750:2375
16
- volumes:
17
- - /var/run/docker.sock:/var/run/docker.sock
18
- command: tcp-listen:2375,reuseaddr,fork unix-connect:/var/run/docker.sock
19
- restart: always".freeze
20
-
21
- # Set up the local ports/sockets correctly based off of the os type
22
- def configure
23
- if Dev::Os.new.windows?
24
- # Start up a small proxy container if running Docker Desktop on windows
25
- # This is needed because the docker api library cannot connect to the windows socket
26
- unless Dev::Port.new('127.0.0.1', 23_750).open?
27
- LOG.info('Starting local proxy port for docker')
28
-
29
- # Write the compose data to a tmp file
30
- tmp_compose_file = Tempfile.new('windows_tcp')
31
- tmp_compose_file.write(WIN_TCP_COMPOSE_CONTENT)
32
- tmp_compose_file.close
33
-
34
- # Start up the container
35
- Dev::Docker::Compose.new(
36
- compose_files: tmp_compose_file.path,
37
- options: ['--detach'],
38
- project_name: 'proxy'
39
- ).up
40
-
41
- # Wait 1 second before we continue
42
- sleep 1
43
- end
44
-
45
- # Configure the docker url to use 23750 on windows
46
- ::Docker.url = 'tcp://127.0.0.1:23750'
47
-
48
- else
49
- context = Dev::Common.new.run_command(
50
- "docker context inspect --format '{{.Endpoints.docker.Host}}'",
51
- capture: true
52
- ).to_s.strip
53
- raise 'context is empty' unless context
54
-
55
- # If a user based socket has been defined, default to that
56
- ::Docker.url = context
57
- end
58
- end
59
- end
60
- end
61
- end
@@ -1,42 +0,0 @@
1
- module Dev
2
- class EndOfLife
3
- # Class which checks for eol packges referenced by the node package manager
4
- class Node
5
- attr_reader :node, :lockfile
6
-
7
- def initialize(node = Dev::Node.new)
8
- @node = node
9
- @lockfile = File.join(node.local_path, "#{node.package_file.reverse.split('.')[-1].reverse}-lock.json")
10
- end
11
-
12
- # Default to NPM products
13
- def default_products
14
- npm_products
15
- end
16
-
17
- # 1.) Parse the npm lock file
18
- # 2.) Do some package name and version manipulation
19
- # 3.) Return the product if it looks like something that the EOL library tracks
20
- def npm_products
21
- eol = Dev::EndOfLife.new
22
- major_version_only_products = %w(ckeditor jquery)
23
-
24
- [].tap do |ary|
25
- packages = JSON.parse(File.read(lockfile))&.fetch('packages', [])
26
- packages.each do |key, info|
27
- name = key.split('node_modules/').last
28
- product = name
29
-
30
- # Make sure what we found is supported by the EOL library
31
- next unless eol.product?(product)
32
-
33
- version = info['version'].reverse.split('.')[-2..].join('.').reverse.tr('v', '')
34
- version = version.split('.').first if major_version_only_products.include?(product)
35
- version.chop! if version.end_with?('.00')
36
- ary << Dev::EndOfLife::ProductVersion.new(product, version, name)
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,50 +0,0 @@
1
- module Dev
2
- class EndOfLife
3
- # Class which checks for eol packges referenced by the php package manager
4
- class Php
5
- attr_reader :php, :lockfile
6
-
7
- def initialize(php = Dev::Php.new)
8
- @php = php
9
- @lockfile = File.join(php.local_path, "#{php.package_file.reverse.split('.')[-1].reverse}.lock")
10
- end
11
-
12
- # Default to Composer products
13
- def default_products
14
- composer_products
15
- end
16
-
17
- # 1.) Parse the composer lock file
18
- # 2.) Do some package name and version manipulation
19
- # 3.) Return the product if it looks like something that the EOL library tracks
20
- def composer_products
21
- eol = Dev::EndOfLife.new
22
- major_version_only_products = ['laravel']
23
- laravel_products = ['laravel/framework']
24
- symfony_products = ['symfony/http-client', 'symfony/mailer', 'symfony/mailchimp-mailer']
25
-
26
- [].tap do |ary|
27
- packages = JSON.parse(File.read(lockfile))&.fetch('packages', [])
28
- packages&.each do |package|
29
- name = package['name']
30
- product = if laravel_products.include?(name)
31
- 'laravel'
32
- elsif symfony_products.include?(name)
33
- 'symfony'
34
- else
35
- name
36
- end
37
-
38
- # Make sure what we found is supported by the EOL library
39
- next unless eol.product?(product)
40
-
41
- version = package['version'].reverse.split('.')[-2..].join('.').reverse.tr('v', '')
42
- version = version.split('.').first if major_version_only_products.include?(product)
43
- version.chop! if version.end_with?('.00')
44
- ary << Dev::EndOfLife::ProductVersion.new(product, version, name)
45
- end
46
- end
47
- end
48
- end
49
- end
50
- end
@@ -1,42 +0,0 @@
1
- module Dev
2
- class EndOfLife
3
- # Class which checks for eol packges referenced by the ruby package manager
4
- class Ruby
5
- attr_reader :ruby, :lockfile
6
-
7
- def initialize(ruby = Dev::Ruby.new)
8
- @ruby = ruby
9
- @lockfile = File.join(ruby.local_path, "#{ruby.package_file.reverse.split('.')[-1].reverse}.lock")
10
- end
11
-
12
- # Default to Rubygems products
13
- def default_products
14
- rubygems_products
15
- end
16
-
17
- # 1.) Parse the rubygems lock file
18
- # 2.) Do some package name and version manipulation
19
- # 3.) Return the product if it looks like something that the EOL library tracks
20
- def rubygems_products
21
- eol = Dev::EndOfLife.new
22
- major_version_only_products = []
23
-
24
- [].tap do |ary|
25
- packages = Bundler::LockfileParser.new(Bundler.read_file(lockfile)).specs
26
- packages.each do |package|
27
- name = package.name
28
- product = name
29
-
30
- # Make sure what we found is supported by the EOL library
31
- next unless eol.product?(product)
32
-
33
- version = package.version.to_s.reverse.split('.')[-2..].join('.').reverse.tr('v', '')
34
- version = version.split('.').first if major_version_only_products.include?(product)
35
- version.chop! if version.end_with?('.00')
36
- ary << Dev::EndOfLife::ProductVersion.new(product, version, name)
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,19 +0,0 @@
1
- module Dev
2
- class Jira
3
- # Contains information on the Jira parent issue
4
- class Parent
5
- attr_accessor :data, :id, :title
6
-
7
- def initialize(data)
8
- @data = data.parent
9
- @id = data.parent['key']
10
- @title = data.parent['fields']['summary']
11
- end
12
-
13
- # Converts the jira parent object to a string representation
14
- def to_s
15
- "[#{id}] #{title}"
16
- end
17
- end
18
- end
19
- end
@@ -1,35 +0,0 @@
1
- module Dev
2
- # Class containing methods for determining operating system information
3
- class Os
4
- attr_accessor :os
5
-
6
- def initialize
7
- @os = ::RbConfig::CONFIG['host_os']
8
- end
9
-
10
- # Returns true if the host_os contains windowsy text
11
- def windows?
12
- os.match?(/(mingw|mswin|windows)/i)
13
- end
14
-
15
- # Returns true if the host_os contains darwinsy text
16
- def darwin?
17
- os.match?(/(darwin|mac os)/i)
18
- end
19
-
20
- # Returns true if the host_os contains macsy text
21
- def mac?
22
- darwin?
23
- end
24
-
25
- # Returns true if the host_os contains nixy text
26
- def nix?
27
- os.match?(/(linux|bsd|aix|solaris)/i)
28
- end
29
-
30
- # Returns true if the host_os contains cygwiny text
31
- def cygwin?
32
- os.match?(/(cygwin)/i)
33
- end
34
- end
35
- end