apadmi_grout 0.0.5 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16022940fafd296f9f52d02c001b1a78906bfe59e1d9a0c3f9c27968ca1d1386
4
- data.tar.gz: efc3cc64e75a693b32307c1b58e85a5a23d155e450187a1ecd4612d1b017d838
3
+ metadata.gz: 9a8f0b024bb98a0372b85755e14bc753370328418273d6e0d07aba74f664bb9a
4
+ data.tar.gz: '04286d3e985378d78f1dec57c220f1a4a5ec35d90ccf4a407d3dde66f75f9a6d'
5
5
  SHA512:
6
- metadata.gz: 2191857e5bfdfcf6fbca7c1b2fbb889f38ec1e198d4d149c51fa696d63eba6991ae948bd95bf057764c3d2a1528d01038d77b95a241ebf9154fb21d0f11253a6
7
- data.tar.gz: 5dcb577071f78db6e03bc5c06da0a873493f2ac9bbd3c1ecc8ec6586ba50003558d5e843d676b548cf369b330b2197b2d27029032ac9b0eece90904316a03e52
6
+ metadata.gz: 2c9d6d5fce5da1ffaa1ab71a7f54e4bba85a3f4fda470b0613049a2169ca9466d180b655c3129561e9046fe3d0a4041b85c2cf25d70dfd8ac7f521b70a6d5113
7
+ data.tar.gz: 13b59090e27577e87f7a52ef9dbcc085db1af1b0575a20e98642669155b0652e0e91976a4943f027e33c25d325fe0aa205afa481d761b7a944f5aebf3bf4138a
data/CHANGELOG.md CHANGED
@@ -1,7 +1,16 @@
1
- # Fastlane Plugin Changelog
1
+ # Core Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [1.2.0] - 2022-05-17
4
+ * Filter out issues missing from git changelogs when finding tickets to move.
4
5
 
5
- ## [0.1.0] - 2022-01-23
6
+ ## [1.1.0] - 2022-05-12
7
+ * Support allowing tickets that aren't assigned to a sprint to be moved.
8
+ * Created utilities for getting the git root and number of commits
6
9
 
7
- - Initial release
10
+ ## [1.0.0] - 2022-05-09 - Initial release
11
+
12
+ * Various JIRA utilities to simplify JIRA interactions
13
+ * Action for searching JIRA tickets
14
+ * Action for transitioning JIRA tickets
15
+ * Action for generating release notes
16
+ * Action for extracting ticket keys from Git changelog
@@ -4,7 +4,7 @@ module Apadmi
4
4
  module Grout
5
5
  # Convenience class for initializing and accessing the various actions
6
6
  class DependencyInjector
7
- attr_reader :move_jira_tickets_action, :find_tickets_to_move_action, :generate_release_notes_action, :issues_from_changelog_action
7
+ attr_reader :jira_wrapper, :move_jira_tickets_action, :find_tickets_to_move_action, :generate_release_notes_action, :issues_from_changelog_action
8
8
 
9
9
  # @param [String] username
10
10
  # @param [String] token
@@ -15,10 +15,11 @@ module Apadmi
15
15
  def initialize(username, token, base_url, context_path, project, logger)
16
16
  @jira_wrapper = Apadmi::Grout::JiraWrapper.new(username, token, base_url, context_path, project)
17
17
 
18
+ git_utils = Apadmi::Grout::GitUtils
18
19
  @move_jira_tickets_action = Apadmi::Grout::MoveJiraTicketsAction.new(@jira_wrapper, logger)
19
- @find_tickets_to_move_action = Apadmi::Grout::FindTicketsToMoveAction.new(@jira_wrapper, logger)
20
- @generate_release_notes_action = Apadmi::Grout::GenerateReleaseNotesAction.new(base_url)
21
20
  @issues_from_changelog_action = Apadmi::Grout::IssuesFromChangelogAction.new(@jira_wrapper, logger)
21
+ @find_tickets_to_move_action = Apadmi::Grout::FindTicketsToMoveAction.new(@jira_wrapper, git_utils, issues_from_changelog_action, logger)
22
+ @generate_release_notes_action = Apadmi::Grout::GenerateReleaseNotesAction.new(base_url)
22
23
  end
23
24
  end
24
25
  end
@@ -2,74 +2,113 @@
2
2
 
3
3
  module Apadmi
4
4
  module Grout
5
+ module PrStatus
6
+ MERGED = 1
7
+ UNMERGED_BUT_INCLUDED = 2
8
+ UN_INCLUDED = 3
9
+ end
10
+
11
+ # ATTENTION: Any changes to the logic here should be reflected in the docs (find-tickets.md)
12
+
5
13
  # Finds and returns a list of all the issues that are ready to be moved
6
14
  # Any tickets found that have the given status but *don't* appear ready to be moved will
7
15
  # be flagged.
8
16
  class FindTicketsToMoveAction
9
17
  # @param [Apadmi::Grout::JiraWrapper]
18
+ # @param [Apadmi::Grout::GitUtils]
19
+ # @param [Apadmi::Grout::IssuesFromChangelogAction]
10
20
  # @param [Apadmi::Grout::DefaultLogger] // or your own logger!
11
- def initialize(jira_wrapper, logger)
21
+ def initialize(jira_wrapper, git_utils, issues_from_chnglg, logger)
12
22
  @jira_wrapper = jira_wrapper
23
+ @git_utils = git_utils
24
+ @issues_from_changelog_action = issues_from_chnglg
13
25
  @logger = logger
14
26
  end
15
27
 
16
28
  # @param component [String] Only include tickets tagged with this component
17
29
  # @param status [String] The status of tickets to be moved (Usually "Awaiting QA Release")
18
30
  # @param excluded_ticket_keys [Array<String>] ticket keys to be excluded from consideration
19
- # @param custom_flag_messages [FlagMessages]
31
+ # @param custom_flag_messages [Apadmi::Grout::FlagMessages]
32
+ # @param options [Apadmi::Grout::FindTicketsOptions]
20
33
  # @return [Array<JIRA::Resource::Issue>] the issues ready to move
21
34
  def run(
22
35
  component,
23
36
  status,
24
37
  excluded_ticket_keys,
25
- custom_flag_messages = FlagMessages.new(
26
- "REASON FOR FLAG: Check this ticket - it was put in #{status} but has no PRs connected to it. CI still moved it",
27
- "REASON FOR FLAG: Check this ticket - it was put in #{status} but has no MERGED PRs and at least one OPEN PR",
28
- "REASON FOR FLAG: Check this ticket - it was put in #{status} but has only DECLINED PRs",
29
- "REASON FOR FLAG: Check this ticket - it was put in #{status} but has no MERGED PRs"
30
- )
38
+ custom_flag_messages = nil,
39
+ options = nil
31
40
  )
32
- issues = @jira_wrapper.search_unblocked_issues(component, status).reject do |issue|
33
- puts issue.key
41
+ custom_flag_messages ||= Apadmi::Grout::FlagMessages.default(status)
42
+ options ||= Apadmi::Grout::FindTicketsOptions.new(include_no_sprint_tickets: false)
43
+
44
+ issues = @jira_wrapper.search_unblocked_issues(
45
+ component, status, [],
46
+ allow_no_sprint: options.include_no_sprint_tickets
47
+ ).reject do |issue|
34
48
  excluded_ticket_keys.include? issue.key
35
49
  end
36
50
 
37
- @logger.message("Found issues to consider #{issues.map(&:key).join(", ")}")
51
+ issue_keys = issues.map(&:key)
52
+ @logger.message("Found issues to consider #{issue_keys.join(", ")}")
53
+
54
+ # Get the issues in the git changelog, filtered for the issues being considered
55
+ changelog_ids = @issues_from_changelog_action.issue_ids_from_changelog(
56
+ @git_utils.merge_changelog(issue_keys)
57
+ )
58
+
38
59
  final_list = issues.filter do |issue|
39
60
  # Decide whether to include this ticket based on PRs
40
- process_prs(issue, custom_flag_messages)
61
+ status = process_prs(issue, custom_flag_messages)
62
+ decide_should_include(issue, status, changelog_ids)
41
63
  end
64
+
42
65
  @logger.message("Final list: #{final_list.map(&:key).join(", ")}")
43
66
  final_list
44
67
  end
45
68
 
46
69
  private
47
70
 
71
+ # @param issue [JIRA::Resource::Issue]
72
+ # @param pr_status [Int] status of whether or not we can move
73
+ # @param changelog_ids [Array<String>] the ticket ids pulled from git
74
+ def decide_should_include(issue, pr_status, changelog_ids)
75
+ # For merged PRs, check if the ticket appears in the changelog.
76
+ # If it doesn't then it's likely it was merged AFTER this release build was triggered and shouldn't be moved
77
+ # by this build
78
+ if pr_status == PrStatus::MERGED
79
+ is_in_changelog = changelog_ids.include?(issue.key)
80
+ @logger.message("NOTE: Not including #{issue.key} since it's not in the git changelog.") unless is_in_changelog
81
+ return is_in_changelog
82
+ end
83
+
84
+ pr_status != PrStatus::UN_INCLUDED
85
+ end
86
+
48
87
  # @param issue [JIRA::Resource::Issue]
49
88
  # @param custom_flag_messages [FlagMessages]
50
- # @return [Boolean] whether or not this ticket can be moved
89
+ # @return [Int] status of whether or not we can move
51
90
  def process_prs(issue, custom_flag_messages)
52
91
  prs = @jira_wrapper.get_ticket_prs(issue)
53
92
 
54
93
  if prs.empty?
55
94
  @logger.message("#{issue.key} has no PRs. Flagging it: STILL MOVABLE")
56
95
  @jira_wrapper.flag_ticket(issue.key, custom_flag_messages.no_prs_flag_msg)
57
- return true
96
+ return PrStatus::UNMERGED_BUT_INCLUDED
58
97
  elsif prs.all?(&:open)
59
98
  @logger.message("#{issue.key} has only open PRs. Flagging it: NOT MOVABLE")
60
99
  @jira_wrapper.flag_ticket(issue.key, custom_flag_messages.open_prs_flag_msg)
61
- return false
100
+ return PrStatus::UN_INCLUDED
62
101
  elsif prs.all?(&:declined)
63
102
  @logger.message("#{issue.key} has only declined PRs. Flagging it: NOT MOVABLE")
64
103
  @jira_wrapper.flag_ticket(issue.key, custom_flag_messages.declined_prs_flag_msg)
65
- return false
104
+ return PrStatus::UN_INCLUDED
66
105
  elsif prs.none?(&:merged)
67
106
  @logger.message("#{issue.key} has no merged PRs. Flagging it: NOT MOVABLE")
68
107
  @jira_wrapper.flag_ticket(issue.key, custom_flag_messages.no_merged_prs_flag_msg)
69
- return false
108
+ return PrStatus::UN_INCLUDED
70
109
  end
71
110
 
72
- true # At least one merged PR, so it's included
111
+ PrStatus::MERGED # At least one merged PR
73
112
  end
74
113
  end
75
114
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apadmi
4
+ module Grout
5
+ FindTicketsOptions = Struct.new(
6
+ :include_no_sprint_tickets,
7
+ keyword_init: true
8
+ )
9
+ end
10
+ end
@@ -1,8 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- FlagMessages = Struct.new(
4
- :no_prs_flag_msg,
5
- :open_prs_flag_msg,
6
- :declined_prs_flag_msg,
7
- :no_merged_prs_flag_msg
8
- )
3
+ module Apadmi
4
+ module Grout
5
+ FlagMessages = Struct.new(
6
+ :no_prs_flag_msg,
7
+ :open_prs_flag_msg,
8
+ :declined_prs_flag_msg,
9
+ :no_merged_prs_flag_msg
10
+ ) do
11
+ # Get default flag messages
12
+ # @param status [String] status ticket will be moving to
13
+ # @return [Apadmi::Grout::FlagMessages]
14
+ def self.default(status)
15
+ FlagMessages.new(
16
+ "REASON FOR FLAG: Check this ticket - it was put in #{status} but has no PRs connected to it. CI still moved it. " \
17
+ "(WARNING: this may cause the `fix_versions` to be incorrect)",
18
+ "REASON FOR FLAG: Check this ticket - it was put in #{status} but has no MERGED PRs and at least one OPEN PR",
19
+ "REASON FOR FLAG: Check this ticket - it was put in #{status} but has only DECLINED PRs",
20
+ "REASON FOR FLAG: Check this ticket - it was put in #{status} but has no MERGED PRs"
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
@@ -46,16 +46,19 @@ module Apadmi
46
46
  # @param [String] component
47
47
  # @param [String] status
48
48
  # @param [String[]] ticket_types
49
+ # @param [Boolean] allow_no_sprint
49
50
  # @return [Array<JIRA::Resource::Issue>]
50
- def search_unblocked_issues(component, status, ticket_types = [])
51
+ def search_unblocked_issues(component, status, ticket_types = [], allow_no_sprint: false)
51
52
  component_filter = (" AND component = '#{component}' " unless component.empty?) || ""
52
53
  status_filter = (" AND status = '#{status}' " unless status.empty?) || ""
53
54
  type_filter = ("AND (#{ticket_types.map { |type| "type = #{type}" }.join("OR ")})" unless ticket_types.empty?) || ""
55
+ empty_sprint_condition = ("OR sprint is EMPTY" if allow_no_sprint) || ""
54
56
 
55
57
  jql_search = %{
56
58
  project = '#{@project}'
57
59
  #{status_filter} #{component_filter} #{type_filter}
58
- AND sprint in openSprints() AND (labels not in(Blocked) or labels is EMPTY) AND Flagged is EMPTY
60
+ AND (sprint in openSprints() #{empty_sprint_condition}) AND (labels not in(Blocked) or labels is EMPTY)
61
+ AND Flagged is EMPTY
59
62
  }
60
63
 
61
64
  @jira_client.Issue.jql(jql_search, { max_results: 1000 }).uniq
@@ -20,8 +20,6 @@ module Apadmi
20
20
  @jira_wrapper.find_issues_by_keys(ids)
21
21
  end
22
22
 
23
- private
24
-
25
23
  # @param changelog [String] raw git changelog
26
24
  # @return [Array<String>] list of issue ids from changelog
27
25
  def issue_ids_from_changelog(changelog)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apadmi
4
+ module Grout
5
+ # Generic Filename Utils
6
+ class FilenameUtils
7
+ # Constructs a standard Apadmi filename for a build output binary
8
+ # @param [Hash] options the options to create a filename with
9
+ # @option options [String] :client_name The client name
10
+ # @option options [String] :product_name The product name
11
+ # @option options [String] :platform The product's platform
12
+ # @option options [String] :version Version number
13
+ # @option options [String] :build_number Build number
14
+ # @option options [String] :data (Today) The date for the file
15
+ # @option options [String] :suffix Suffix to identify what this output is (e.g. SOURCE, UAT, QA, DEV)
16
+ # @return [String] A filename formatted such as "Apadmi-Grout-Ruby-v1.0.0(2921)-2021-06-22-DEV"
17
+ def self.binary_output_filename(options = {})
18
+ client_name = options[:client_name]
19
+ raise ":client_name shouldn't be empty" if client_name.blank?
20
+
21
+ product_name = options[:product_name]
22
+ raise ":product_name shouldn't be empty" if product_name.blank?
23
+
24
+ platform = options[:platform]
25
+ raise ":platform shouldn't be empty" if platform.blank?
26
+
27
+ version = options[:version]
28
+ raise ":version shouldn't be empty" if version.blank?
29
+
30
+ build_number = options[:build_number]
31
+ raise ":build_number shouldn't be empty" if build_number.blank?
32
+
33
+ date = options[:date] || Time.now.strftime("%Y-%m-%d")
34
+ suffix = ("-#{options[:suffix]}" unless options[:suffix].blank?) || ""
35
+
36
+ "#{client_name}-#{product_name}-#{platform}-v#{version}(#{build_number})-#{date}#{suffix}"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+
5
+ module Apadmi
6
+ module Grout
7
+ # Generic Git related utils
8
+ class GitUtils
9
+ # Gets the root of the Git repo we're in
10
+ # @return [String] The full path for the root of this Git repo
11
+ def self.git_root
12
+ stdout, stderr, = Open3.capture3("git rev-parse --show-toplevel")
13
+ raise "Failed to get git root: #{stderr}" unless stderr.strip.empty?
14
+
15
+ stdout.strip
16
+ end
17
+
18
+ # Gets the number of commits accessible from HEAD treating the history as a graph.
19
+ # See more details here: https://git-scm.com/docs/git-rev-list
20
+ # @return [String] The number of commits
21
+ def self.number_of_commits
22
+ stdout, stderr, = Open3.capture3("git rev-list HEAD --count")
23
+ raise "Failed to get commit number: #{stderr}" unless stderr.strip.empty?
24
+
25
+ stdout.strip
26
+ end
27
+
28
+ # Gets all the merges accessible from the current HEAD which matches at least one of the given grep conditions
29
+ # @param grep_conditions [Array<String>] values to be passed in as grep cases (https://git-scm.com/docs/git-log)
30
+ def self.merge_changelog(grep_conditions)
31
+ command = "git log HEAD --merges --format=%s#{grep_conditions.map { |c| " --grep #{c}" }.join(" ")}"
32
+ stdout, stderr, = Open3.capture3(command)
33
+ raise "Failed to get changelog: #{stderr}" unless stderr.strip.empty?
34
+
35
+ stdout
36
+ end
37
+ end
38
+ end
39
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Apadmi
4
4
  module Grout
5
- VERSION = "0.0.5"
5
+ VERSION = "1.2.0"
6
6
  end
7
7
  end
data/lib/apadmi_grout.rb CHANGED
@@ -16,5 +16,8 @@ require_relative "apadmi/grout/jira/wrapper/jira_wrapper"
16
16
  require_relative "apadmi/grout/jira/models/pull_request"
17
17
  require_relative "apadmi/grout/jira/models/version"
18
18
  require_relative "apadmi/grout/jira/models/flag_messages"
19
+ require_relative "apadmi/grout/jira/models/find_tickets_options"
19
20
 
20
21
  require_relative "apadmi/grout/utils/logger"
22
+ require_relative "apadmi/grout/utils/git_utils"
23
+ require_relative "apadmi/grout/utils/filename_utils"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apadmi_grout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
- - Sam
7
+ - Apadmi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-09 00:00:00.000000000 Z
11
+ date: 2022-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -66,6 +66,7 @@ files:
66
66
  - lib/apadmi/grout/di.rb
67
67
  - lib/apadmi/grout/jira/actions/find_tickets_to_move_action.rb
68
68
  - lib/apadmi/grout/jira/actions/move_jira_tickets_action.rb
69
+ - lib/apadmi/grout/jira/models/find_tickets_options.rb
69
70
  - lib/apadmi/grout/jira/models/flag_messages.rb
70
71
  - lib/apadmi/grout/jira/models/pull_request.rb
71
72
  - lib/apadmi/grout/jira/models/version.rb
@@ -74,6 +75,8 @@ files:
74
75
  - lib/apadmi/grout/release_notes/actions/issues_from_changelog_action.rb
75
76
  - lib/apadmi/grout/release_notes/models/release_notes_config.rb
76
77
  - lib/apadmi/grout/release_notes/models/release_notes_templates.rb
78
+ - lib/apadmi/grout/utils/filename_utils.rb
79
+ - lib/apadmi/grout/utils/git_utils.rb
77
80
  - lib/apadmi/grout/utils/logger.rb
78
81
  - lib/apadmi/grout/version.rb
79
82
  - lib/apadmi_grout.rb