firespring_dev_commands 2.1.8 → 2.1.10.pre.alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56b724b0a6f7c0ab20b780894cc5c312fe545efb7a0460801bdde3fd25ea5d0c
4
- data.tar.gz: 940ff9bff43521dbc47be595adb02cc369ec7e0e1f70c0ea1361ecf0f32a796f
3
+ metadata.gz: c75f83066598edad92a8d34dd12d898d9f5229cf80bd8eeba166cd7e5451296e
4
+ data.tar.gz: 832006c6ec28b9b8a288e3a0d510f628f3c468b3c0cb8614d1eae5927f25184a
5
5
  SHA512:
6
- metadata.gz: 3faa331db0c214a38e4d17c352f86c4978e2813985111b59b1e43fc7a775907e7bf1fe178ccfbd2df275933345a16fe4882c99ac6a9779e8dee877a66143b0e5
7
- data.tar.gz: 0e5da5e49aa2664c7fb678cd4cd11c37d85a4787c3aa91210022f1d20f1084109815cb3e875729c81932eb074a1f81b3372eb9e5f21c41a3ddeb2caae921669e
6
+ metadata.gz: f3ea07c7f9be119c8ec47914c213560069ee1c17b6a0e8dcbe43b41cb246febd258079b12843d2819cdd4b1cc7aa180e3515fd8edeaca8fea9a5866758614a33
7
+ data.tar.gz: b395757808d58b999546d5df762ef46caf59ebf670599ec77d0b1c91098381c9f6da96e102141050f1a638ea83972c2757d795016e90cff1bb0474d0865b5db0
@@ -203,6 +203,7 @@ module Dev
203
203
 
204
204
  # Checks out the given branch in the given repo
205
205
  # Defaults to the current directory
206
+ # optionally raise errors
206
207
  def checkout(branch, dir: default_project_dir, raise_errors: false)
207
208
  raise 'branch is required' if branch.to_s.strip.empty?
208
209
  return unless File.exist?(dir)
@@ -231,6 +232,8 @@ module Dev
231
232
  end
232
233
 
233
234
  # Create the given branch in the given repo
235
+ # Defaults to the current directory
236
+ # optionally raise errors
234
237
  def create_branch(branch, dir: default_project_dir, raise_errors: false)
235
238
  raise 'branch is required' if branch.to_s.strip.empty?
236
239
  raise "refusing to create protected branch '#{branch}'" if %w(master develop).any?(branch.to_s.strip)
@@ -259,6 +262,9 @@ module Dev
259
262
  false
260
263
  end
261
264
 
265
+ # Add the given paths to git
266
+ # Defaults to the current directory
267
+ # optionally raise errors
262
268
  def add(*paths, dir: default_project_dir, raise_errors: false)
263
269
  g = ::Git.open(dir)
264
270
  indent g.add(paths)
@@ -292,6 +298,8 @@ module Dev
292
298
  end
293
299
 
294
300
  # Merge the given branch into the given repo
301
+ # Defaults to the current directory
302
+ # optionally raise errors
295
303
  def merge(branch, dir: default_project_dir, raise_errors: false)
296
304
  raise 'branch is required' if branch.to_s.strip.empty?
297
305
  return unless File.exist?(dir)
@@ -337,6 +345,8 @@ module Dev
337
345
  end
338
346
 
339
347
  # Pull the given repo
348
+ # Defaults to the current directory
349
+ # optionally raise errors
340
350
  def pull(dir: default_project_dir, raise_errors: false)
341
351
  return unless File.exist?(dir)
342
352
 
@@ -374,6 +384,8 @@ module Dev
374
384
  end
375
385
 
376
386
  # Push the given repo
387
+ # Defaults to the current directory
388
+ # optionally raise errors
377
389
  def push(dir: default_project_dir, raise_errors: false)
378
390
  return unless File.exist?(dir)
379
391
 
@@ -1,6 +1,8 @@
1
1
  module Dev
2
2
  class Jira
3
+ # Class which provides a helper method for converting the changelog data to history objects
3
4
  class Histories
5
+ # If changelog is present in the given data, return an array of history objects for each changelog entry
4
6
  def self.populate(data)
5
7
  return nil unless data.attrs.key?('changelog')
6
8
 
@@ -2,6 +2,7 @@ require 'date'
2
2
 
3
3
  module Dev
4
4
  class Jira
5
+ # Class contains history data for jira objects
5
6
  class History
6
7
  attr_accessor :date, :id, :author, :created, :items
7
8
 
@@ -21,21 +21,25 @@ module Dev
21
21
  @last_closed_history = nil
22
22
  end
23
23
 
24
+ # Returns the cycle time of the issue (time between in progress and closed states)
24
25
  def cycle_time
25
26
  # Calculate the difference and convert to days
26
27
  ((last_closed_history.created - last_in_progress_history.created) / 60 / 60 / 24).round(2)
27
28
  end
28
29
 
30
+ # Returns the time the issue was in progress (time between in progress and in review states)
29
31
  def in_progress_cycle_time
30
32
  # Calculate the difference and convert to days
31
33
  ((first_in_review_history.created - last_in_progress_history.created) / 60 / 60 / 24).round(2)
32
34
  end
33
35
 
36
+ # Returns the time the issue was in review (time between in review and closed states)
34
37
  def in_review_cycle_time
35
38
  # Calculate the difference and convert to days
36
39
  ((last_closed_history.created - first_in_review_history.created) / 60 / 60 / 24).round(2)
37
40
  end
38
41
 
42
+ # Loop through the issue history and find the most recent state change from Open to In Progress
39
43
  private def last_in_progress_history
40
44
  raise 'you must expand the changelog field to calculate cycle time' if histories.nil?
41
45
 
@@ -50,6 +54,7 @@ module Dev
50
54
  @last_in_progress_history
51
55
  end
52
56
 
57
+ # Loop through the issue history and find the oldest state change to In Review
53
58
  private def first_in_review_history
54
59
  raise 'you must expand the changelog field to calculate cycle time' if histories.nil?
55
60
 
@@ -64,6 +69,7 @@ module Dev
64
69
  @first_in_review_history
65
70
  end
66
71
 
72
+ # Loop through the issue history and find the most recent state change to closed
67
73
  private def last_closed_history
68
74
  raise 'you must expand the changelog field to calculate cycle time' if histories.nil?
69
75
 
@@ -1,8 +1,11 @@
1
1
  module Dev
2
2
  class Common
3
+ # Class which returns information about the current platform
3
4
  class Platform
5
+ # Constant containing all supported architectures
4
6
  ALLOWED_ARCHITECTURES = %w(arm64 amd64).freeze
5
7
 
8
+ # Normalize the ruby platform to return a docker platform architecture format
6
9
  def determine_compute_architecture
7
10
  case RUBY_PLATFORM
8
11
  when /x86_64|amd64/
@@ -14,6 +17,9 @@ module Dev
14
17
  end
15
18
  end
16
19
 
20
+ # Determine the platform architecture
21
+ # If one was specified in the DOCKER_ARCHITECTURE variable, use it
22
+ # Otherwise, use the RUBY_PLATFORM built-in to auto-detect and architecture
17
23
  def architecture
18
24
  docker_architecture = ENV['DOCKER_ARCHITECTURE'].to_s.strip.downcase
19
25
  if docker_architecture.empty?
@@ -22,13 +28,11 @@ module Dev
22
28
  raise "Missing 'linux/' prefix in DOCKER_ARCHITECTURE: #{docker_architecture}" unless docker_architecture.start_with?('linux/')
23
29
 
24
30
  architecture_name = docker_architecture.split('/')[1]
25
-
26
31
  unless ALLOWED_ARCHITECTURES.include?(architecture_name)
27
32
  raise "Invalid DOCKER_ARCHITECTURE: #{architecture_name}. Allowed architectures are #{ALLOWED_ARCHITECTURES.join(', ')}"
28
33
  end
29
34
 
30
35
  docker_architecture
31
-
32
36
  end
33
37
  end
34
38
  end
@@ -0,0 +1,14 @@
1
+ module Dev
2
+ class TargetProcess
3
+ # Class containing project information
4
+ class Project
5
+ attr_accessor :id, :type, :name
6
+
7
+ def initialize(data)
8
+ @id = data['Id']
9
+ @type = data['ResourceType']
10
+ @name = data['Name']
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,82 @@
1
+ module Dev
2
+ class TargetProcess
3
+ # Class for writing target process query statements
4
+ class Query
5
+ attr_accessor :where, :incl, :take
6
+
7
+ def initialize
8
+ @where = []
9
+ @incl = []
10
+ @take = 250
11
+ end
12
+
13
+ # Add a new query clause
14
+ def <<(item)
15
+ where << item
16
+ end
17
+
18
+ # Add the item to the where clause
19
+ def where=(item)
20
+ if item.is_a?(Array)
21
+ where.concat(item)
22
+ else
23
+ where << item
24
+ end
25
+ end
26
+
27
+ # Add the item to the include clause
28
+ def include=(item)
29
+ if item.is_a?(Array)
30
+ incl.concat(item)
31
+ else
32
+ incl << item
33
+ end
34
+ end
35
+
36
+ # Generate the string representation for this query
37
+ def generate
38
+ {}.tap do |clause|
39
+ clause[:where] = where.join(' and ') unless where.nil? || where.empty?
40
+ clause[:include] = "[#{incl.join(',')}]" unless incl.nil? || incl.empty?
41
+ clause[:take] = take if take.to_i.positive?
42
+ end
43
+ end
44
+
45
+ # Generate the string representation for this query
46
+ def to_s
47
+ generate
48
+ end
49
+
50
+ # Add a filter that looks for stories whose id is contained in the list of ids given
51
+ def filter_by_user_story_ids(user_story_ids)
52
+ self << "(Id in ('#{user_story_ids.join("', '")}'))"
53
+ end
54
+
55
+ # Add a filter that looks for stories whose project id is contained in the list of ids given
56
+ def filter_by_project(projects)
57
+ self << "(Project.Name in ('#{projects.join("', '")}'))"
58
+ end
59
+
60
+ # Add a filter that looks for stories whose state is contained in the list of states given
61
+ def filter_by_states(states)
62
+ self << "(EntityState.Name in ('#{states.join("', '")}'))" unless states.nil? || states.empty?
63
+ end
64
+
65
+ # Add a filter that looks for stories whose state is set to final
66
+ def filter_by_final
67
+ self << "(EntityState.IsFinal eq 'true')"
68
+ end
69
+
70
+ # Add a filter that looks for stories whose end date is between the given dates
71
+ def filter_by_end_dates(start_date, end_date)
72
+ self << "(EndDate gt '#{start_date}')" if start_date
73
+ self << "(EndDate lt '#{end_date}')" if end_date
74
+ end
75
+
76
+ # Add a filter that looks for stories which do not have a linked test plan
77
+ def filter_by_missing_tests
78
+ self << '(LinkedTestPlan is nil)'
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,14 @@
1
+ module Dev
2
+ class TargetProcess
3
+ # Class containing release information
4
+ class Release
5
+ attr_accessor :id, :type, :name
6
+
7
+ def initialize(data)
8
+ @id = data['Id']
9
+ @type = data['ResourceType']
10
+ @name = data['Name']
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Dev
2
+ class TargetProcess
3
+ # Class containing team information
4
+ class Team
5
+ attr_accessor :id, :type, :name
6
+
7
+ def initialize(data)
8
+ @id = data['Id']
9
+ @type = data['ResourceType']
10
+ @name = data['Name']
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ module Dev
2
+ class TargetProcess
3
+ # Class containing user information
4
+ class User
5
+ attr_accessor :id, :type, :name, :login
6
+
7
+ def initialize(data)
8
+ @id = data['Id']
9
+ @type = data['ResourceType']
10
+ @name = data['FullName']
11
+ @login = data['Login']
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,48 @@
1
+ module Dev
2
+ class TargetProcess
3
+ # Class containing user story information
4
+ class UserStory
5
+ # The api path for user story requests
6
+ PATH = '/UserStories'.freeze
7
+
8
+ attr_accessor :type, :id, :name, :description, :start_date, :end_date, :create_date, :modify_date, :tags, :effort, :time_spent, :last_state_change_date, :project,
9
+ :owner, :creator, :release, :team, :priority, :state, :original_data
10
+
11
+ def initialize(data)
12
+ @id = data['Id']
13
+ @type = data['ResourceType']
14
+ @name = data['Name']
15
+ @description = data['Description']
16
+ @state = data['EntityState']['Name']
17
+ @project = Project.new(data['Project']) if data['Project']
18
+ @owner = User.new(data['Owner']) if data['Owner']
19
+ @creator = User.new(data['Creator']) if data['Creator']
20
+ @release = Release.new(data['Release']) if data['Release']
21
+ @team = Team.new(data['Team']) if data['Team']
22
+ @start_date = parse_time(data['StartDate'])
23
+ @end_date = parse_time(data['EndDate'])
24
+ @create_date = parse_time(data['CreateDate'])
25
+ @modify_date = parse_time(data['ModifyDate'])
26
+ @tags = data['Tags']
27
+ @effort = data['Effort']
28
+ @time_spent = data['TimeSpent']
29
+ @last_state_change_date = parse_time(data['LastStateChangeDate'])
30
+ @original_data = original_data
31
+ end
32
+
33
+ # Parse the dot net time representation into something that ruby can use
34
+ def parse_time(string)
35
+ return nil unless string && !string.empty?
36
+
37
+ Time.at(string.slice(6, 10).to_i)
38
+ end
39
+
40
+ # Calculate the cycle time as the amount of time the story was open
41
+ def cycle_time
42
+ return 1.0 unless start_date && end_date
43
+
44
+ (end_date - start_date).to_f
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,105 @@
1
+ require 'net/http'
2
+
3
+ module Dev
4
+ # Class for querying target process data from their api
5
+ class TargetProcess
6
+ # The config file to try to load credentials from
7
+ CONFIG_FILE = "#{Dir.home}/.env.tp".freeze
8
+
9
+ # The text of the username variable key
10
+ TP_USERNAME = 'TP_USERNAME'.freeze
11
+
12
+ # The text of the password variable key
13
+ TP_PASSWORD = 'TP_PASSWORD'.freeze
14
+
15
+ # The text of the url variable key
16
+ TP_URL = 'TP_URL'.freeze
17
+
18
+ # Config object for setting top level jira config options
19
+ Config = Struct.new(:username, :password, :url, :http_debug) do
20
+ def initialize
21
+ Dotenv.load(CONFIG_FILE) if File.exist?(CONFIG_FILE)
22
+
23
+ self.username = ENV.fetch(TP_USERNAME, nil)
24
+ self.password = ENV.fetch(TP_PASSWORD, nil)
25
+ self.url = ENV.fetch(TP_URL, nil)
26
+ self.http_debug = false
27
+ end
28
+ end
29
+
30
+ class << self
31
+ # Instantiates a new top level config object if one hasn't already been created
32
+ # Yields that config object to any given block
33
+ # Returns the resulting config object
34
+ def config
35
+ @config ||= Config.new
36
+ yield(@config) if block_given?
37
+ @config
38
+ end
39
+
40
+ # Alias the config method to configure for a slightly clearer access syntax
41
+ alias_method :configure, :config
42
+ end
43
+
44
+ attr_accessor :username, :password, :url, :auth, :client, :headers
45
+
46
+ # Initialize a new target process client using the given inputs
47
+ def initialize(username: self.class.config.username, password: self.class.config.password, url: self.class.config.url)
48
+ @username = username
49
+ @password = password
50
+ @auth = Base64.strict_encode64("#{@username}:#{@password}")
51
+ @url = url
52
+ uri = URI.parse(@url)
53
+ @client = Net::HTTP.new(uri.host, uri.port)
54
+ @client.use_ssl = true
55
+ @client.verify_mode = OpenSSL::SSL::VERIFY_PEER
56
+ @client.set_debug_output(LOG) if self.class.config.http_debug
57
+ @headers = {
58
+ 'authorization' => "Basic #{auth}",
59
+ 'content-type' => 'application/json',
60
+ 'accept' => 'application/json'
61
+ }
62
+ end
63
+
64
+ # Perform a query to the user story api path
65
+ # Call the given block (if present) with each user story
66
+ # Return all user stories
67
+ def user_stories(query, &)
68
+ [].tap do |ary|
69
+ get(UserStory::PATH, query) do |result|
70
+ ary << UserStory.new(result)
71
+ end
72
+ ary.each(&)
73
+ end
74
+ end
75
+
76
+ # Perform a get request to the given path using the given query
77
+ # Call the given block (if present) with each piece of data
78
+ # Return all pieces of data
79
+ def get(path, query, &)
80
+ query_string = query.generate
81
+ url = "/api/v1/#{path}"
82
+ url << "?#{URI.encode_www_form(query_string)}" unless query_string.empty?
83
+
84
+ response = client.request_get(url, headers)
85
+ raise "Error querying #{url} [#{query_string}]: #{response.inspect}" unless response.response.is_a?(Net::HTTPSuccess)
86
+
87
+ parsed_response = JSON.parse(response.body)
88
+ return parsed_response unless parsed_response.key?('Items')
89
+
90
+ parsed_response['Items'].each(&)
91
+
92
+ while parsed_response['Next']
93
+ response = client.request_get(parsed_response['Next'], headers)
94
+ raise "Error querying #{parsed_response['Next']} [#{query_string}]: #{response.inspect}" unless response.response.is_a?(Net::HTTPSuccess)
95
+
96
+ parsed_response = JSON.parse(response.body)
97
+ return parsed_response unless parsed_response.key?('Items')
98
+
99
+ parsed_response['Items'].each(&)
100
+ end
101
+
102
+ nil
103
+ end
104
+ end
105
+ end
@@ -6,6 +6,6 @@ module Dev
6
6
  # Use 'v.v.v.pre.alpha.v' for pre-release vesions
7
7
  # Use 'v.v.v.beta.v for beta versions
8
8
  # Use semantic versioning for any releases (https://semver.org/)
9
- VERSION = '2.1.8'.freeze
9
+ VERSION = '2.1.10.pre.alpha.2'.freeze
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firespring_dev_commands
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.8
4
+ version: 2.1.10.pre.alpha.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Firespring
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-07 00:00:00.000000000 Z
11
+ date: 2023-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 7.0.6
19
+ version: 7.1.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 7.0.6
26
+ version: 7.1.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: aws-sdk-cloudformation
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -305,6 +305,13 @@ files:
305
305
  - lib/firespring_dev_commands/tar.rb
306
306
  - lib/firespring_dev_commands/tar/pax_header.rb
307
307
  - lib/firespring_dev_commands/tar/type_flag.rb
308
+ - lib/firespring_dev_commands/target_process.rb
309
+ - lib/firespring_dev_commands/target_process/project.rb
310
+ - lib/firespring_dev_commands/target_process/query.rb
311
+ - lib/firespring_dev_commands/target_process/release.rb
312
+ - lib/firespring_dev_commands/target_process/team.rb
313
+ - lib/firespring_dev_commands/target_process/user.rb
314
+ - lib/firespring_dev_commands/target_process/user_story.rb
308
315
  - lib/firespring_dev_commands/templates/aws.rb
309
316
  - lib/firespring_dev_commands/templates/base_interface.rb
310
317
  - lib/firespring_dev_commands/templates/ci.rb
@@ -333,9 +340,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
333
340
  version: '3.1'
334
341
  required_rubygems_version: !ruby/object:Gem::Requirement
335
342
  requirements:
336
- - - ">="
343
+ - - ">"
337
344
  - !ruby/object:Gem::Version
338
- version: '0'
345
+ version: 1.3.1
339
346
  requirements: []
340
347
  rubygems_version: 3.4.10
341
348
  signing_key: