firespring_dev_commands 2.2.1.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 (52) 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/cloudformation.rb +3 -10
  5. data/lib/firespring_dev_commands/common.rb +4 -24
  6. data/lib/firespring_dev_commands/docker/status.rb +0 -20
  7. data/lib/firespring_dev_commands/docker.rb +16 -86
  8. data/lib/firespring_dev_commands/eol/aws.rb +2 -10
  9. data/lib/firespring_dev_commands/eol.rb +2 -22
  10. data/lib/firespring_dev_commands/git.rb +23 -19
  11. data/lib/firespring_dev_commands/jira/issue.rb +1 -3
  12. data/lib/firespring_dev_commands/node.rb +1 -1
  13. data/lib/firespring_dev_commands/php.rb +12 -28
  14. data/lib/firespring_dev_commands/platform.rb +31 -38
  15. data/lib/firespring_dev_commands/ruby.rb +3 -6
  16. data/lib/firespring_dev_commands/target_process/query.rb +4 -30
  17. data/lib/firespring_dev_commands/target_process/release.rb +1 -1
  18. data/lib/firespring_dev_commands/target_process/team_assignment.rb +1 -1
  19. data/lib/firespring_dev_commands/target_process/user.rb +1 -13
  20. data/lib/firespring_dev_commands/target_process/user_story.rb +1 -1
  21. data/lib/firespring_dev_commands/target_process/user_story_history.rb +1 -1
  22. data/lib/firespring_dev_commands/target_process.rb +7 -24
  23. data/lib/firespring_dev_commands/templates/aws.rb +6 -17
  24. data/lib/firespring_dev_commands/templates/base_interface.rb +2 -2
  25. data/lib/firespring_dev_commands/templates/docker/application.rb +2 -2
  26. data/lib/firespring_dev_commands/templates/docker/node/application.rb +5 -55
  27. data/lib/firespring_dev_commands/templates/docker/php/application.rb +16 -58
  28. data/lib/firespring_dev_commands/templates/docker/ruby/application.rb +5 -54
  29. data/lib/firespring_dev_commands/templates/eol.rb +2 -9
  30. data/lib/firespring_dev_commands/templates/git.rb +0 -17
  31. data/lib/firespring_dev_commands/version.rb +1 -1
  32. data/lib/firespring_dev_commands.rb +1 -1
  33. metadata +35 -68
  34. data/lib/firespring_dev_commands/aws/route53.rb +0 -107
  35. data/lib/firespring_dev_commands/bloom_growth/rock.rb +0 -34
  36. data/lib/firespring_dev_commands/bloom_growth/seat.rb +0 -16
  37. data/lib/firespring_dev_commands/bloom_growth/user.rb +0 -43
  38. data/lib/firespring_dev_commands/bloom_growth.rb +0 -132
  39. data/lib/firespring_dev_commands/certificate.rb +0 -59
  40. data/lib/firespring_dev_commands/coverage/base.rb +0 -16
  41. data/lib/firespring_dev_commands/coverage/cobertura.rb +0 -86
  42. data/lib/firespring_dev_commands/coverage/none.rb +0 -21
  43. data/lib/firespring_dev_commands/docker/desktop.rb +0 -59
  44. data/lib/firespring_dev_commands/eol/node.rb +0 -37
  45. data/lib/firespring_dev_commands/eol/php.rb +0 -45
  46. data/lib/firespring_dev_commands/eol/ruby.rb +0 -37
  47. data/lib/firespring_dev_commands/jira/parent.rb +0 -19
  48. data/lib/firespring_dev_commands/os.rb +0 -35
  49. data/lib/firespring_dev_commands/port.rb +0 -24
  50. data/lib/firespring_dev_commands/target_process/time.rb +0 -32
  51. data/lib/firespring_dev_commands/templates/aws/services/route53.rb +0 -106
  52. data/lib/firespring_dev_commands/templates/certificate.rb +0 -41
@@ -1,43 +0,0 @@
1
- module Dev
2
- class BloomGrowth
3
- # Class containing user information
4
- class User
5
- attr_accessor :data, :id, :type, :name, :rocks, :direct_reports, :seats
6
-
7
- def initialize(data)
8
- @data = data
9
- @id = data['Id']
10
- @type = data['Type']
11
- @name = data['Name'].to_s.strip
12
- @rocks = nil
13
- @direct_reports = nil
14
- @seats = nil
15
- end
16
-
17
- def rocks
18
- @rocks ||= [].tap do |ary|
19
- Dev::BloomGrowth.new.get("/api/v1/rocks/user/#{id}") do |data|
20
- ary << Rock.new(data)
21
- end
22
- end
23
- end
24
-
25
- def direct_reports
26
- @direct_reports ||= [].tap do |ary|
27
- Dev::BloomGrowth.new.get("/api/v1/users/#{id}/directreports") do |data|
28
- ary << User.new(data)
29
- end
30
- end
31
- end
32
-
33
- def seats
34
- @seats ||= [].tap do |ary|
35
- Dev::BloomGrowth.new.get("/api/v1/users/#{id}/seats") do |data|
36
- ary << Seat.new(data)
37
- puts ary.last.inspect
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -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,59 +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
- # If a user based socket has been defined, default to that
50
- ::Docker.url = if File.exist?("/#{Dir.home}/.docker/run/docker.sock")
51
- "unix://#{Dir.home}/.docker/run/docker.sock"
52
- elsif File.exist?("/#{Dir.home}/.docker/desktop/docker.sock")
53
- "unix://#{Dir.home}/.docker/desktop/docker.sock"
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,37 +0,0 @@
1
- module Dev
2
- class EndOfLife
3
- class Node
4
- attr_reader :node, :lockfile
5
-
6
- def initialize(node = Dev::Node.new)
7
- @node = node
8
- @lockfile = File.join(node.local_path, "#{node.package_file.reverse.split('.')[-1].reverse}-lock.json")
9
- end
10
-
11
- def default_products
12
- npm_products
13
- end
14
-
15
- def npm_products
16
- eol = Dev::EndOfLife.new
17
- major_version_only_products = %w(ckeditor vue jquery)
18
-
19
- [].tap do |ary|
20
- packages = JSON.parse(File.read(lockfile))&.fetch('packages', [])
21
- packages.each do |key, info|
22
- name = key.split('node_modules/').last
23
- product = name
24
-
25
- # Make sure what we found is supported by the EOL library
26
- next unless eol.product?(product)
27
-
28
- version = info['version'].reverse.split('.')[-2..].join('.').reverse.tr('v', '')
29
- version = version.split('.').first if major_version_only_products.include?(product)
30
- version.chop! if version.end_with?('.00')
31
- ary << Dev::EndOfLife::ProductVersion.new(product, version, name)
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,45 +0,0 @@
1
- module Dev
2
- class EndOfLife
3
- class Php
4
- attr_reader :php, :lockfile
5
-
6
- def initialize(php = Dev::Php.new)
7
- @php = php
8
- @lockfile = File.join(php.local_path, "#{php.package_file.reverse.split('.')[-1].reverse}.lock")
9
- end
10
-
11
- def default_products
12
- composer_products
13
- end
14
-
15
- def composer_products
16
- eol = Dev::EndOfLife.new
17
- major_version_only_products = ['laravel']
18
- laravel_products = ['laravel/framework']
19
- symfony_products = ['symfony/http-client', 'symfony/mailer', 'symfony/mailchimp-mailer']
20
-
21
- [].tap do |ary|
22
- packages = JSON.parse(File.read(lockfile))&.fetch('packages', [])
23
- packages&.each do |package|
24
- name = package['name']
25
- product = if laravel_products.include?(name)
26
- 'laravel'
27
- elsif symfony_products.include?(name)
28
- 'symfony'
29
- else
30
- name
31
- end
32
-
33
- # Make sure what we found is supported by the EOL library
34
- next unless eol.product?(product)
35
-
36
- version = package['version'].reverse.split('.')[-2..].join('.').reverse.tr('v', '')
37
- version = version.split('.').first if major_version_only_products.include?(product)
38
- version.chop! if version.end_with?('.00')
39
- ary << Dev::EndOfLife::ProductVersion.new(product, version, name)
40
- end
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,37 +0,0 @@
1
- module Dev
2
- class EndOfLife
3
- class Ruby
4
- attr_reader :ruby, :lockfile
5
-
6
- def initialize(ruby = Dev::Ruby.new)
7
- @ruby = ruby
8
- @lockfile = File.join(ruby.local_path, "#{ruby.package_file.reverse.split('.')[-1].reverse}.lock")
9
- end
10
-
11
- def default_products
12
- composer_products
13
- end
14
-
15
- def composer_products
16
- eol = Dev::EndOfLife.new
17
- major_version_only_products = []
18
-
19
- [].tap do |ary|
20
- packages = Bundler::LockfileParser.new(Bundler.read_file(lockfile)).specs
21
- packages.each do |package|
22
- name = package.name
23
- product = name
24
-
25
- # Make sure what we found is supported by the EOL library
26
- next unless eol.product?(product)
27
-
28
- version = package.version.to_s.reverse.split('.')[-2..].join('.').reverse.tr('v', '')
29
- version = version.split('.').first if major_version_only_products.include?(product)
30
- version.chop! if version.end_with?('.00')
31
- ary << Dev::EndOfLife::ProductVersion.new(product, version, name)
32
- end
33
- end
34
- end
35
- end
36
- end
37
- 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
@@ -1,24 +0,0 @@
1
- module Dev
2
- # Class containing methods for actions to be taken on ports
3
- class Port
4
- attr_accessor :ip_address, :port
5
-
6
- def initialize(ip_address, port)
7
- @ip_address = ip_address
8
- @port = port
9
- end
10
-
11
- # Returns true if the port is open
12
- # Returns false otherwise
13
- def open?(timeout = 1)
14
- Timeout.timeout(timeout) do
15
- TCPSocket.new(ip_address, port).close
16
- return true
17
- end
18
-
19
- false
20
- rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
21
- false
22
- end
23
- end
24
- end
@@ -1,32 +0,0 @@
1
- module Dev
2
- class TargetProcess
3
- # The class to query time information from Target Process
4
- class Time
5
- # The resource type for the api endpoint
6
- RESOURCE_TYPE = 'Time'.freeze
7
-
8
- # The api path for time requests
9
- PATH = '/Time'.freeze
10
-
11
- attr_accessor :data, :id, :type, :description, :hours, :date, :story, :user
12
-
13
- def initialize(data)
14
- @data = data
15
- @id = data['Id']
16
- @type = data['ResourceType']
17
- @description = data['Description']
18
- @hours = data['Spent']
19
- @date = parse_time(data['Date'])
20
- @story = UserStory.new(data['Assignable']) if data['Assignable']
21
- @user = User.new(data['User']) if data['User']
22
- end
23
-
24
- # Parse the dot net time representation into something that ruby can use
25
- def parse_time(string)
26
- return nil unless string && !string.empty?
27
-
28
- ::Time.at(string.slice(6, 10).to_i)
29
- end
30
- end
31
- end
32
- end