Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add commit_format option #24

Merged
merged 5 commits into from
Jun 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module SharedValues
RELEASE_NEXT_PATCH_VERSION = :RELEASE_NEXT_PATCH_VERSION
RELEASE_NEXT_VERSION = :RELEASE_NEXT_VERSION
RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION = :RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION
CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN = :CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN
end

class AnalyzeCommitsAction < Action
Expand Down Expand Up @@ -89,6 +90,7 @@ def self.is_releasable(params)
UI.message("Found #{splitted.length} commits since last release")
releases = params[:releases]

format_pattern = lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN]
splitted.each do |line|
parts = line.split("|")
subject = parts[0].strip
Expand All @@ -97,7 +99,8 @@ def self.is_releasable(params)
commit = Helper::SemanticReleaseHelper.parse_commit(
commit_subject: subject,
commit_body: parts[1],
releases: releases
releases: releases,
pattern: format_pattern
)

unless commit[:scope].nil?
Expand Down Expand Up @@ -169,13 +172,15 @@ def self.is_codepush_friendly(params)
releases = params[:releases]
codepush_friendly = params[:codepush_friendly]

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::SemanticReleaseHelper.parse_commit(
commit_subject: line.split("|")[0],
commit_body: line.split("|")[1],
releases: releases,
pattern: format_pattern,
codepush_friendly: codepush_friendly
)

Expand Down Expand Up @@ -229,6 +234,27 @@ def self.available_options
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::SemanticReleaseHelper.format_patterns.key?(value)
UI.user_error!("Invalid format preset: #{value}")
end

pattern = Helper::SemanticReleaseHelper.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)",
Expand Down Expand Up @@ -283,7 +309,8 @@ def self.output
['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']
['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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,14 @@ def self.build_commit_link(commit, commit_url, format)
def self.parse_commits(commits)
parsed = []
# %s|%b|%H|%h|%an|%at
format_pattern = lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN]
commits.each do |line|
splitted = line.split("|")

commit = Helper::SemanticReleaseHelper.parse_commit(
commit_subject: splitted[0],
commit_body: splitted[1]
commit_body: splitted[1],
pattern: format_pattern
)

commit[:hash] = splitted[2]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ module Fastlane

module Helper
class SemanticReleaseHelper
def self.format_patterns
return {
"default" => /^(docs|fix|feat|chore|style|refactor|perf|test)(?:\((.*)\))?(!?)\: (.*)/,
"angular" => /^(\w*)(?:\((.*)\))?(): (.*)/
}
end

# class methods that you define here become available in your action
# as `Helper::SemanticReleaseHelper.your_method`
#
Expand All @@ -18,7 +25,7 @@ def self.parse_commit(params)
commit_body = params[:commit_body]
releases = params[:releases]
codepush_friendly = params[:codepush_friendly]
pattern = /^(docs|fix|feat|chore|style|refactor|perf|test)(\((.*)\))?(!?)\: (.*)/
pattern = params[:pattern]
breaking_change_pattern = /BREAKING CHANGES?: (.*)/
codepush_pattern = /codepush?: (.*)/

Expand All @@ -32,13 +39,13 @@ def self.parse_commit(params)

unless matched.nil?
type = matched[1]
scope = matched[3]
scope = matched[2]

result[:is_valid] = true
result[:type] = type
result[:scope] = scope
result[:has_exclamation_mark] = matched[4] == '!'
result[:subject] = matched[5]
result[:has_exclamation_mark] = matched[3] == '!'
result[:subject] = matched[4]

unless releases.nil?
result[:release] = releases[type.to_sym]
Expand Down
155 changes: 155 additions & 0 deletions spec/analyze_commits_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,161 @@ def execute_lane_test(params)
expect(Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION]).to eq("0.0.3")
end

describe "commit_format" do
describe "default" do
it "should allow for certain types" do
commits = [
"docs: ...|",
"fix: ...|",
"feat: ...|",
"chore: ...|",
"style: ...|",
"refactor: ...|",
"perf: ...|",
"test: ...|"
]
test_analyze_commits(commits)

is_releasable = execute_lane_test(
match: 'v*',
releases: {
docs: "minor",
fix: "minor",
feat: "minor",
chore: "minor",
style: "minor",
refactor: "minor",
perf: "minor",
test: "minor"
}
)
expect(is_releasable).to eq(true)
expect(Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_NEXT_VERSION]).to eq("1.8.0")
end

it "should not allow for custom types" do
commits = [
"foo: ...|",
"bar: ...|",
"baz: ...|"
]
test_analyze_commits(commits)

is_releasable = execute_lane_test(
match: 'v*',
releases: {
foo: "minor",
bar: "minor",
baz: "minor"
}
)
expect(is_releasable).to eq(false)
expect(Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_NEXT_VERSION]).to eq("1.0.8")
end
end

describe "angular" do
it "should allow for default types" do
commits = [
"docs: ...|",
"fix: ...|",
"feat: ...|",
"chore: ...|",
"style: ...|",
"refactor: ...|",
"perf: ...|",
"test: ...|"
]
test_analyze_commits(commits)

is_releasable = execute_lane_test(
match: 'v*',
commit_format: 'angular',
releases: {
docs: "minor",
fix: "minor",
feat: "minor",
chore: "minor",
style: "minor",
refactor: "minor",
perf: "minor",
test: "minor"
}
)
expect(is_releasable).to eq(true)
expect(Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_NEXT_VERSION]).to eq("1.8.0")
end

it "should allow for custom types" do
commits = [
"foo: ...|",
"bar: ...|",
"baz: ...|"
]
test_analyze_commits(commits)

is_releasable = execute_lane_test(
match: 'v*',
commit_format: 'angular',
releases: {
foo: "minor",
bar: "minor",
baz: "minor"
}
)
expect(is_releasable).to eq(true)
expect(Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_NEXT_VERSION]).to eq("1.3.0")
end
end

describe "custom" do
format_pattern = /^prefix-(foo|bar|baz)(?:\.(.*))?(): (.*)/
commits = [
"prefix-foo.ios: ...|",
"prefix-foo.android: ...|",
"prefix-bar.ios: ...|",
"prefix-bar.android: ...|",
"prefix-baz.ios: ...|",
"prefix-baz.android: ...|",
"prefix-qux.ios: ...|",
"prefix-qux.android: ...|"
]

it "should allow for arbetrary formatting" do
test_analyze_commits(commits)

is_releasable = execute_lane_test(
match: 'v*',
commit_format: format_pattern,
releases: {
foo: "major",
bar: "minor",
baz: "patch"
}
)
expect(is_releasable).to eq(true)
expect(Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_NEXT_VERSION]).to eq("3.2.2")
end

it "should allow for arbetrary formatting with scope" do
test_analyze_commits(commits)

is_releasable = execute_lane_test(
match: 'v*',
commit_format: format_pattern,
releases: {
foo: "major",
bar: "minor",
baz: "patch"
},
ignore_scopes: ['android']
)
expect(is_releasable).to eq(true)
expect(Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_NEXT_VERSION]).to eq("2.1.1")
end
end
end

after do
end
end
Expand Down
52 changes: 42 additions & 10 deletions spec/conventional_changelog_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,45 @@
describe Fastlane::Actions::ConventionalChangelogAction do
describe "Conventional Changelog" do
before do
Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN] = Fastlane::Helper::SemanticReleaseHelper.format_patterns["default"]
Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_NEXT_VERSION] = '1.0.2'
Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::RELEASE_ANALYZED] = true
end

def execute_lane_test
Fastlane::FastFile.new.parse("lane :test do conventional_changelog end").runner.execute(:test)
def execute_lane_test(params = {})
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( #{params} ) end").runner.execute(:test)
end

def execute_lane_test_plain
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( format: 'plain' ) end").runner.execute(:test)
execute_lane_test(format: 'plain')
end

def execute_lane_test_slack
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( format: 'slack' ) end").runner.execute(:test)
execute_lane_test(format: 'slack')
end

def execute_lane_test_author
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( display_author: true ) end").runner.execute(:test)
execute_lane_test(display_author: true)
end

def execute_lane_test_no_header
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( display_title: false ) end").runner.execute(:test)
execute_lane_test(display_title: false)
end

def execute_lane_test_no_header_plain
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( format: 'plain', display_title: false ) end").runner.execute(:test)
execute_lane_test(format: 'plain', display_title: false)
end

def execute_lane_test_no_header_slack
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( format: 'slack', display_title: false ) end").runner.execute(:test)
execute_lane_test(format: 'slack', display_title: false)
end

def execute_lane_test_no_links
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( display_links: false ) end").runner.execute(:test)
execute_lane_test(display_links: false)
end

def execute_lane_test_no_links_slack
Fastlane::FastFile.new.parse("lane :test do conventional_changelog( format: 'slack', display_links: false ) end").runner.execute(:test)
execute_lane_test(format: 'slack', display_links: false)
end

describe 'section creation' do
Expand Down Expand Up @@ -226,6 +227,37 @@ def execute_lane_test_no_links_slack
end
end

describe "commit format" do
format_pattern = /^prefix-(foo|bar|baz)(?:\.(.*))?(): (.*)/
commits = [
"prefix-foo: sub|body|long_hash|short_hash|Jiri Otahal|time",
"prefix-bar: sub|body|long_hash|short_hash|Jiri Otahal|time",
"prefix-baz.android: sub|body|long_hash|short_hash|Jiri Otahal|time",
"prefix-qux: sub|body|long_hash|short_hash|Jiri Otahal|time"
]

before do
Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN] = format_pattern
allow(Fastlane::Actions::ConventionalChangelogAction).to receive(:get_commits_from_hash).and_return(commits)
allow(Date).to receive(:today).and_return(Date.new(2019, 5, 25))
end

it "should use the commit format" do
result = "# 1.0.2 (2019-05-25)\n\n### Bazz\n- **android:** sub ([short_hash](/long_hash))\n\n### Foo\n- sub ([short_hash](/long_hash))\n\n### Bar\n- sub ([short_hash](/long_hash))\n\n### Other\n- prefix-qux: sub ([short_hash](/long_hash))"

changelog = execute_lane_test(
order: ['baz', 'foo', 'bar', 'no_type'],
sections: {
foo: "Foo",
bar: "Bar",
baz: "Bazz",
no_type: "Other"
}
)
expect(changelog).to eq(result)
end
end

after do
end
end
Expand Down