Class: Fastlane::Actions::AnalyzeCommitsAction

Inherits:
Action
  • Object
show all
Defined in:
lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb

Documentation collapse

Class Method Summary collapse

Class Method Details

.authorsObject



181
182
183
184
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 181

def self.authors
  # So no one will ever forget your contribution to fastlane :) You are awesome btw!
  ["xotahal"]
end

.available_optionsObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 135

def self.available_options
  # Define all options your action supports.

  # Below a few examples
  [
    FastlaneCore::ConfigItem.new(
      key: :match,
      description: "Match parameter of git describe. See man page of git describe for more info",
      verify_block: proc do |value|
        UI.user_error!("No match for analyze_commits action given, pass using `match: 'expr'`") unless value && !value.empty?
      end
    ),
    FastlaneCore::ConfigItem.new(
      key: :releases,
      description: "Map types of commit to release (major, minor, patch)",
      default_value: { fix: "patch", feat: "minor" },
      type: Hash
    ),
    FastlaneCore::ConfigItem.new(
      key: :tag_version_match,
      description: "To parse version number from tag name",
      default_value: '\d+\.\d+\.\d+'
    )
  ]
end

.descriptionObject



127
128
129
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 127

def self.description
  "Finds a tag of last release and determinates version of next release"
end

.detailsObject



131
132
133
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 131

def self.details
  "This action will find a last release tag and analyze all commits since the tag. It uses conventional commits. Every time when commit is marked as fix or feat it will increase patch or minor number (you can setup this default behaviour). After all it will suggest if the version should be released or not."
end

.get_commits_from_hash(params) ⇒ Object



32
33
34
35
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 32

def self.get_commits_from_hash(params)
  commits = Helper::SemanticReleaseHelper.git_log('%s|%b|>', params[:hash])
  commits.split("|>")
end

.get_last_tag(params) ⇒ Object



18
19
20
21
22
23
24
25
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 18

def self.get_last_tag(params)
  # Try to find the tag
  command = "git describe --tags --match=#{params[:match]}"
  Actions.sh(command, log: false)
rescue
  UI.message("Tag was not found for match pattern - #{params[:match]}")
  ''
end

.get_last_tag_hash(params) ⇒ Object



27
28
29
30
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 27

def self.get_last_tag_hash(params)
  command = "git rev-list -n 1 refs/tags/#{params[:tag_name]}"
  Actions.sh(command, log: false).chomp
end

.is_supported?(platform) ⇒ Boolean

Returns:

  • (Boolean)


186
187
188
189
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 186

def self.is_supported?(platform)
  # you can do things like
  true
end

.outputObject



161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 161

def self.output
  # Define the shared values you are going to provide
  # Example
  [
    ['RELEASE_ANALYZED', 'True if commits were analyzed.'],
    ['RELEASE_IS_NEXT_VERSION_HIGHER', 'True if next version is higher then last version'],
    ['RELEASE_LAST_TAG_HASH', 'Hash of commit that is tagged as a last version'],
    ['RELEASE_LAST_VERSION', 'Last version number - parsed from last tag.'],
    ['RELEASE_NEXT_MAJOR_VERSION', 'Major number of the next version'],
    ['RELEASE_NEXT_MINOR_VERSION', 'Minor number of the next version'],
    ['RELEASE_NEXT_PATCH_VERSION', 'Patch number of the next version'],
    ['RELEASE_NEXT_VERSION', 'Next version string in format (major.minor.patch)']
  ]
end

.return_valueObject



176
177
178
179
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 176

def self.return_value
  # If your method provides a return value, you can describe here what it does
  "Returns true if the next version is higher then the last version"
end

.run(params) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb', line 37

def self.run(params)
  # Hash of the commit where is the last version
  # If the tag is not found we are taking HEAD as reference
  hash = 'HEAD'
  # Default last version
  version = '0.0.0'

  tag = get_last_tag(match: params[:match])

  if tag.empty?
    UI.message("First commit of the branch is taken as a begining of next release")
    # If there is no tag found we taking the first commit of current branch
    hash = Actions.sh('git rev-list --max-parents=0 HEAD', log: false).chomp
  else
    # Tag's format is v2.3.4-5-g7685948
    # See git describe man page for more info
    tag_name = tag.split('-')[0].strip
    parsed_version = tag_name.match(params[:tag_version_match])

    if parsed_version.nil?
      UI.user_error!("Error while parsing version from tag #{tag_name} by using tag_version_match - #{params[:tag_version_match]}. Please check if the tag contains version as you expect and if you are using single brackets for tag_version_match parameter.")
    end

    version = parsed_version[0]
    # Get a hash of last version tag
    hash = get_last_tag_hash(tag_name: tag_name)

    UI.message("Found a tag #{tag_name} associated with version #{version}")
  end

  # converts last version string to the int numbers
  next_major = (version.split('.')[0] || 0).to_i
  next_minor = (version.split('.')[1] || 0).to_i
  next_patch = (version.split('.')[2] || 0).to_i

  # Get commits log between last version and head
  splitted = get_commits_from_hash(hash: hash)

  UI.message("Found #{splitted.length} commits since last release")
  releases = params[:releases]

  splitted.each do |line|
    # conventional commits are in format
    # type: subject (fix: app crash - for example)
    commit = Helper::SemanticReleaseHelper.parse_commit(
      commit_subject: line.split("|")[0],
      commit_body: line.split("|")[1],
      releases: releases
    )

    if commit[:release] == "major" || commit[:is_breaking_change]
      next_major += 1
      next_minor = 0
      next_patch = 0
    elsif commit[:release] == "minor"
      next_minor += 1
      next_patch = 0
    elsif commit[:release] == "patch"
      next_patch += 1
    end

    next_version = "#{next_major}.#{next_minor}.#{next_patch}"
    UI.message("#{next_version}: #{line}")
  end

  next_version = "#{next_major}.#{next_minor}.#{next_patch}"

  is_releasable = Helper::SemanticReleaseHelper.semver_gt(next_version, version)

  Actions.lane_context[SharedValues::RELEASE_ANALYZED] = true
  Actions.lane_context[SharedValues::RELEASE_IS_NEXT_VERSION_HIGHER] = is_releasable
  # Last release analysis
  Actions.lane_context[SharedValues::RELEASE_LAST_TAG_HASH] = hash
  Actions.lane_context[SharedValues::RELEASE_LAST_VERSION] = version
  # Next release analysis
  Actions.lane_context[SharedValues::RELEASE_NEXT_MAJOR_VERSION] = next_major
  Actions.lane_context[SharedValues::RELEASE_NEXT_MINOR_VERSION] = next_minor
  Actions.lane_context[SharedValues::RELEASE_NEXT_PATCH_VERSION] = next_patch
  Actions.lane_context[SharedValues::RELEASE_NEXT_VERSION] = next_version

  success_message = "Next version (#{next_version}) is higher than last version (#{version}). This version should be released."
  UI.success(success_message) if is_releasable

  is_releasable
end