class Fastlane::Actions::AnalyzeCommitsAction
Public Class Methods
available_options()
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 236 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: :commit_format, description: "The commit format to apply. Presets are 'default' or 'angular', or you can provide your own Regexp. Note: the supplied regex _must_ have 4 capture groups, in order: type, scope, has_exclamation_mark, and subject", default_value: "default", is_string: false, verify_block: proc do |value| case value when String unless Helper::SemanticConventionReleaseHelper.format_patterns.key?(value) UI.user_error!("Invalid format preset: #{value}") end pattern = Helper::SemanticConventionReleaseHelper.format_patterns[value] when Regexp pattern = value else UI.user_error!("Invalid option type: #{value.inspect}") end Actions.lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN] = pattern end ), FastlaneCore::ConfigItem.new( key: :releases, description: "Map types of commit to release (major, minor, patch)", default_value: { fix: "patch", feat: "minor", BREAKING_CHANGE: "major" }, type: Hash ), FastlaneCore::ConfigItem.new( key: :codepush_friendly, description: "These types are consider as codepush friendly automatically", default_value: ["chore", "test", "docs", "style", "refactor", "perf"], type: Array, optional: true ), FastlaneCore::ConfigItem.new( key: :tag_version_match, description: "To parse version number from tag name", default_value: '\d+\.\d+\.\d+' ), FastlaneCore::ConfigItem.new( key: :ignore_scopes, description: "To ignore certain scopes when calculating releases", default_value: ["skip"], type: Array, optional: true ), FastlaneCore::ConfigItem.new( key: :show_version_path, description: "True if you want to print out the version calculated for each commit", default_value: true, type: Boolean, optional: true ), FastlaneCore::ConfigItem.new( key: :debug, description: "True if you want to log out a debug info", default_value: false, type: Boolean, optional: true ) ] end
description()
click to toggle source
@!group Documentation
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 228 def self.description "Finds a tag of last release and determinates version of next release" end
details()
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 232 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)
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 34 def self.get_commits_from_hash(params) commits = Helper::SemanticConventionReleaseHelper.git_log( pretty: '%s|%b|>', start: params[:hash], debug: params[:debug] ) commits.split("|>") end
get_last_tag(params)
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 20 def self.get_last_tag(params) # Try to find the tag command = "git describe --tags --match=#{params[:match]}" Actions.sh(command, log: params[:debug]) rescue UI.message("Tag was not found for match pattern - #{params[:match]}") '' end
get_last_tag_hash(params)
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 29 def self.get_last_tag_hash(params) command = "git rev-list -n 1 refs/tags/#{params[:tag_name]}" Actions.sh(command, log: params[:debug]).chomp end
is_codepush_friendly(params)
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 156 def self.is_codepush_friendly(params) git_command = 'git rev-list --max-parents=0 HEAD' # Begining of the branch is taken for codepush analysis hash_lines = Actions.sh("#{git_command} | wc -l", log: params[:debug]).chomp hash = Actions.sh(git_command, log: params[:debug]).chomp next_major = 0 next_minor = 0 next_patch = 0 last_incompatible_codepush_version = '0.0.0' if hash_lines.to_i > 1 UI.error("#{git_command} resulted to more than 1 hash") UI.error('This usualy happens when you pull only part of a git history. Check out how you pull the repo! "git fetch" should be enough.') Actions.sh(git_command, log: true).chomp return false end # Get commits log between last version and head splitted = get_commits_from_hash( hash: hash, debug: params[:debug] ) releases = params[:releases] codepush_friendly = params[:codepush_friendly] patch_updated = false minor_updated = false major_updated = false format_pattern = lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN] splitted.each do |line| # conventional commits are in format # type: subject (fix: app crash - for example) commit = Helper::SemanticConventionReleaseHelper.parse_commit( commit_subject: line.split("|")[0], commit_body: line.split("|")[1], releases: releases, pattern: format_pattern, codepush_friendly: codepush_friendly ) if (commit[:release] == "major" || commit[:is_breaking_change]) && !major_updated next_major += 1 next_minor = 0 next_patch = 0 major_updated = true elsif commit[:release] == "minor" && !major_updated && !minor_updated next_minor += 1 next_patch = 0 minor_updated = true elsif commit[:release] == "patch" && !major_updated && !minor_updated && !patch_updated next_patch += 1 patch_updated = true end unless commit[:is_codepush_friendly] last_incompatible_codepush_version = "#{next_major}.#{next_minor}.#{next_patch}" end end Actions.lane_context[SharedValues::RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION] = last_incompatible_codepush_version end
is_releasable(params)
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 43 def self.is_releasable(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], debug: params[:debug] ) 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: params[:debug]).chomp else # Tag's format is v2.3.4-5-g7685948 # See git describe man page for more info tag_name = tag.split('-')[0...-2].join('-').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, debug: params[:debug] ) 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, debug: params[:debug] ) UI.message("Found #{splitted.length} commits since last release") releases = params[:releases] format_pattern = lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN] patch_updated = false minor_updated = false major_updated = false splitted.each do |line| parts = line.split("|") subject = parts[0].strip # conventional commits are in format # type: subject (fix: app crash - for example) commit = Helper::SemanticConventionReleaseHelper.parse_commit( commit_subject: subject, commit_body: parts[1], releases: releases, pattern: format_pattern ) unless commit[:scope].nil? # if this commit has a scope, then we need to inspect to see if that is one of the scopes we're trying to exclude scope = commit[:scope] scopes_to_ignore = params[:ignore_scopes] # if it is, we'll skip this commit when bumping versions next if scopes_to_ignore.include?(scope) #=> true end if (commit[:release] == "major" || commit[:is_breaking_change]) && !major_updated next_major += 1 next_minor = 0 next_patch = 0 major_updated = true elsif commit[:release] == "minor" && !major_updated && !minor_updated next_minor += 1 next_patch = 0 minor_updated = true elsif commit[:release] == "patch" && !major_updated && !minor_updated && !patch_updated next_patch += 1 patch_updated = true end next_version = "#{next_major}.#{next_minor}.#{next_patch}" UI.message("#{next_version}: #{subject}") if params[:show_version_path] end next_version = "#{next_major}.#{next_minor}.#{next_patch}" is_next_version_releasable = Helper::SemanticConventionReleaseHelper.semver_gt(next_version, version) Actions.lane_context[SharedValues::RELEASE_ANALYZED] = true Actions.lane_context[SharedValues::RELEASE_IS_NEXT_VERSION_HIGHER] = is_next_version_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_next_version_releasable is_next_version_releasable end
is_supported?(platform)
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 338 def self.is_supported?(platform) # you can do things like true end
output()
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 311 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)'], ['RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION', 'Last commit without codepush'], ['CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN', 'The format pattern Regexp used to match commits (mainly for internal use)'] ] end
return_value()
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 328 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)
click to toggle source
# File lib/fastlane/plugin/semantic_convention_release/actions/analyze_commits.rb, line 217 def self.run(params) is_next_version_releasable = is_releasable(params) is_codepush_friendly(params) is_next_version_releasable end