fastlane-plugin-semantic_versioning 1.0.0 → 2.1.0

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: 85cd9cae201bc1df61f042591928d143e3be6b16f2118af031d8277872bb2602
4
- data.tar.gz: a1bc72d14b4866bf874ff0f1ad0b47e965baa895bcfed5ded778120e17a66ec8
3
+ metadata.gz: 1205dbf528eadda53b7561ee36d93418c9f12fd7e5b8baa1f93f3f338411baa8
4
+ data.tar.gz: e083a5c015ecd318254c853589dc9233aa3e86b3da96699ebeaeecf95c2630f7
5
5
  SHA512:
6
- metadata.gz: 51ea808a889665240814d26ce939f1c006c9bd03b6544a3a289e38afb460668dc51e4f723a4507b6a8f3a3112b71bb1bd407bfd2da5df513a22b085b3053337e
7
- data.tar.gz: 0227ac5c1726f2e9954f9d272bb36e99fbf83af5280e7831ffb823ccd44ed32f1b5528c57188a4bd927956e9cdcbd7940183604369fcbcf6c95e830c1e9cd85c
6
+ metadata.gz: 03b8bd862f3f5ef41791fd214864ac6d15c3928fe6e1fbf27acdb817619c6d3acae71b98c66b342a34d978795172e429fa7b0849e22313273fdbeac27a2fc4b5
7
+ data.tar.gz: c5efd5ec4a7f1e73150f105d6f82a0c54aa52926d694224286ce64fb38f5614abb916b25fb2c2933ad099bc843bad6e01f5ead837a9cacf980a3a321c811e6c9
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "fastlane/action"
2
4
  require "fastlane_core/configuration/config_item"
3
5
  require_relative "../helper/semantic_versioning_helper"
@@ -13,11 +15,13 @@ module Fastlane
13
15
  SEMVER_BUMPABLE = :SEMVER_BUMPABLE
14
16
  end
15
17
 
18
+ # Action to retrieve semantic versioning information from commit history.
16
19
  class GetVersioningInfoAction < Action
17
20
  def self.run(params)
18
21
  params[:allowed_types].map!(&:to_sym)
19
22
  params[:bump_map].transform_keys!(&:to_sym)
20
23
  params[:bump_map].transform_values!(&:to_sym)
24
+ params[:force_type] = params[:force_type]&.to_sym
21
25
 
22
26
  UI.message("The semantic_versioning plugin is working!")
23
27
 
@@ -26,12 +30,15 @@ module Fastlane
26
30
 
27
31
  commits = Helper::SemanticVersioningHelper.git_commits(
28
32
  from: Helper::SemanticVersioningHelper.git_tag_exists?(formatted_tag) ? formatted_tag : nil,
29
- allowed_types: params[:allowed_types]
33
+ allowed_types: params[:allowed_types],
34
+ bump_map: params[:bump_map]
30
35
  )
31
36
 
32
- bump_type = Helper::SemanticVersioningHelper.bump_type(commits: commits, bump_map: params[:bump_map])
33
- new_version = Helper::SemanticVersioningHelper.increase_version(current_version: current_version, bump_type: bump_type)
34
- new_changelog = Helper::SemanticVersioningHelper.build_changelog(version: new_version, commits: commits, type_map: params[:type_map])
37
+ bump_type = Helper::SemanticVersioningHelper.bump_type(commits: commits, force_type: params[:force_type])
38
+ new_version = Helper::SemanticVersioningHelper.increase_version(current_version: current_version,
39
+ bump_type: bump_type)
40
+ new_changelog = Helper::SemanticVersioningHelper.build_changelog(version: new_version, commits: commits,
41
+ type_map: params[:type_map])
35
42
  bumpable = current_version != new_version
36
43
 
37
44
  Actions.lane_context[SharedValues::SEMVER_CURRENT_VERSION] = current_version
@@ -41,9 +48,10 @@ module Fastlane
41
48
  Actions.lane_context[SharedValues::SEMVER_NEW_CHANGELOG] = new_changelog
42
49
  Actions.lane_context[SharedValues::SEMVER_BUMPABLE] = bumpable
43
50
 
44
- return bumpable
51
+ bumpable
45
52
  end
46
53
 
54
+ # :nocov:
47
55
  def self.description
48
56
  "Retrieve semantic versioning information from commit history."
49
57
  end
@@ -73,6 +81,7 @@ module Fastlane
73
81
  # Optional:
74
82
  "Reads commits from last version and determines next version and changelog."
75
83
  end
84
+ # :nocov:
76
85
 
77
86
  def self.available_options
78
87
  [
@@ -80,7 +89,8 @@ module Fastlane
80
89
  env_name: "SEMANTIC_VERSIONING_ALLOWED_TYPES",
81
90
  description: "List of allowed commit types",
82
91
  optional: true,
83
- default_value: %w[build ci docs feat fix perf refactor style test chore revert bump init],
92
+ default_value: %w[build ci docs feat fix perf refactor style test chore revert
93
+ bump init],
84
94
  type: Array),
85
95
  FastlaneCore::ConfigItem.new(key: :bump_map,
86
96
  description: "Map of commit types to their bump level (major, minor, patch)",
@@ -88,6 +98,12 @@ module Fastlane
88
98
  default_value: { breaking: :major, feat: :minor, fix: :patch },
89
99
  is_string: false,
90
100
  verify_block: ->(value) { verify_bump_map(value) }),
101
+ FastlaneCore::ConfigItem.new(key: :force_type,
102
+ env_name: "SEMANTIC_VERSIONING_FORCE_TYPE",
103
+ description: "Force a minimum bump type",
104
+ optional: true,
105
+ default_value: nil,
106
+ type: String),
91
107
  FastlaneCore::ConfigItem.new(key: :tag_format,
92
108
  env_name: "SEMANTIC_VERSIONING_TAG_FORMAT",
93
109
  description: "The format for the git tag",
@@ -99,29 +115,30 @@ module Fastlane
99
115
  description: "Map of types to section titles for the changelog." \
100
116
  "Only the specified types will be used for the changelog",
101
117
  optional: true,
102
- default_value: { breaking: "BREAKING CHANGES", feat: "Features", fix: "Bug Fixes" },
118
+ default_value: { breaking: "BREAKING CHANGES", feat: "Features",
119
+ fix: "Bug Fixes" },
103
120
  is_string: false,
104
121
  verify_block: ->(value) { verify_type_map(value) })
105
122
  ]
106
123
  end
107
124
 
108
125
  def self.verify_type_map(value)
109
- UI.user_error!("Parameter 'type_map' must be a Hash.") unless value.kind_of?(Hash)
110
- # It could be helpful to also test for valid keys, which must all be part of ConfigItem :allowed_types plus breaking.
111
- # How to check this?
126
+ UI.user_error!("Parameter 'type_map' must be a Hash.") unless value.is_a?(Hash)
112
127
  end
113
128
 
114
129
  def self.verify_bump_map(value)
115
- UI.user_error!("Parameter 'bump_map' must be a Hash.") unless value.kind_of?(Hash)
130
+ UI.user_error!("Parameter 'bump_map' must be a Hash.") unless value.is_a?(Hash)
116
131
  end
117
132
 
118
- def self.is_supported?(platform)
133
+ # :nocov:
134
+ def self.is_supported?(_platform)
119
135
  # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
120
136
  # See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
121
137
  #
122
138
  # [:ios, :mac, :android].include?(platform)
123
139
  true
124
140
  end
141
+ # :nocov:
125
142
  end
126
143
  end
127
144
  end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fastlane/action"
4
+ require_relative "../helper/semantic_versioning_helper"
5
+
6
+ module Fastlane
7
+ module Actions
8
+ # Action to prepare the Xcode project for automatic versioning
9
+ class PrepareVersioningAction < Action
10
+ def self.run(params)
11
+ xcodeproj_path = params[:xcodeproj] || Dir.glob("*.xcodeproj").first
12
+
13
+ Fastlane::UI.user_error!("Unable to determine *.xcodeproj and no :xcodeproj specified") if xcodeproj_path.nil?
14
+
15
+ project = Helper::SemanticVersioningHelper.project(xcodeproj_path)
16
+ target = Helper::SemanticVersioningHelper.main_target
17
+ main_group = Helper::SemanticVersioningHelper.main_group
18
+
19
+ info_plist_file = File.join(main_group.path, "Info.plist")
20
+ info_plist_path = File.join(project.path.dirname, info_plist_file)
21
+
22
+ target.build_configurations.each do |config|
23
+ config.build_settings["VERSIONING_SYSTEM"] = "apple-generic"
24
+ config.build_settings.delete("MARKETING_VERSION")
25
+ config.build_settings.delete("GENERATE_INFOPLIST_FILE")
26
+
27
+ config.build_settings["INFOPLIST_FILE"] = info_plist_file unless config.build_settings["INFOPLIST_FILE"]
28
+
29
+ Helper::SemanticVersioningHelper.ensure_info_plist(info_plist_path)
30
+ end
31
+ project.save
32
+ true
33
+ end
34
+
35
+ # :nocov:
36
+ def self.description
37
+ "Prepares the Xcodeproject to be used with automatic versioning by tools."
38
+ end
39
+
40
+ def self.authors
41
+ ["kassi"]
42
+ end
43
+
44
+ def self.output
45
+ # Define the shared values you are going to provide
46
+ end
47
+
48
+ def self.return_value
49
+ # If your method provides a return value, you can describe here what it does
50
+ "Truthy value when everything worked out well."
51
+ end
52
+
53
+ def self.details
54
+ # Optional:
55
+ "Changes the versioning style and makes sure that version information is extracted into Info.plist " \
56
+ "to be used with agvtool"
57
+ end
58
+ # :nocov:
59
+
60
+ def self.available_options
61
+ [
62
+ FastlaneCore::ConfigItem.new(key: :main_group,
63
+ env_name: "SEMANTIC_VERSIONING_MAIN_GROUP",
64
+ description: "The name of the main group of the xcode project",
65
+ optional: true,
66
+ default_value: nil,
67
+ type: String),
68
+ FastlaneCore::ConfigItem.new(key: :xcodeproj,
69
+ env_name: "SEMANTIC_VERSIONING_PROJECT",
70
+ description: "The path to your project file (Not the workspace). Optional if you have only one",
71
+ optional: true,
72
+ default_value: nil,
73
+ verify_block: proc do |value|
74
+ if value.end_with?(".xcworkspace")
75
+ UI.user_error!("Please pass the path to the project, not the workspace")
76
+ end
77
+ UI.user_error!("Could not find Xcode project") unless File.exist?(value)
78
+ end)
79
+ ]
80
+ end
81
+
82
+ # :nocov:
83
+ def self.is_supported?(platform)
84
+ # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
85
+ # See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
86
+ #
87
+ %i[ios mac].include?(platform)
88
+ end
89
+ # :nocov:
90
+ end
91
+ end
92
+ end
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "fastlane/action"
2
4
  require_relative "../helper/semantic_versioning_helper"
3
5
 
4
6
  module Fastlane
5
7
  module Actions
8
+ # Action to bumps the version according to semantic versioning and writes a changelog.
6
9
  class SemanticBumpAction < Action
7
10
  def self.run(params)
8
11
  unless Actions.lane_context.key?(SharedValues::SEMVER_BUMPABLE)
@@ -32,9 +35,10 @@ module Fastlane
32
35
  include: [params[:changelog_file]].compact
33
36
  )
34
37
 
35
- return true
38
+ true
36
39
  end
37
40
 
41
+ # :nocov:
38
42
  def self.description
39
43
  "Bumps the version according to semantic versioning and writes a changelog."
40
44
  end
@@ -56,6 +60,7 @@ module Fastlane
56
60
  # Optional:
57
61
  "Reads commits from last version and determines next version and changelog."
58
62
  end
63
+ # :nocov:
59
64
 
60
65
  def self.available_options
61
66
  [
@@ -74,13 +79,15 @@ module Fastlane
74
79
  ]
75
80
  end
76
81
 
77
- def self.is_supported?(platform)
82
+ # :nocov:
83
+ def self.is_supported?(_platform)
78
84
  # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
79
85
  # See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
80
86
  #
81
87
  # [:ios, :mac, :android].include?(platform)
82
88
  true
83
89
  end
90
+ # :nocov:
84
91
  end
85
92
  end
86
93
  end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "fastlane_core/ui/ui"
2
4
  require "fastlane/actions/get_version_number"
3
5
  require "git"
6
+ require "xcodeproj"
4
7
 
5
8
  module Fastlane
6
9
  UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
@@ -22,41 +25,54 @@ module Fastlane
22
25
  format.sub("$version", tag)
23
26
  end
24
27
 
25
- def self.git_tag_exists?(tag)
26
- git.tags.include?(tag)
27
- end
28
-
29
28
  # Retrieves git commits and returns them grouped by type
30
- def self.git_commits(from:, allowed_types:)
29
+ def self.git_commits(from:, allowed_types:, bump_map:)
31
30
  logs = from ? git.log(-1).between(from) : git.log(-1)
32
- logs.reverse_each.map do |commit|
33
- parse_conventional_commit(commit: commit, allowed_types: allowed_types)
34
- end.compact
31
+ logs.reverse_each.filter_map { |commit|
32
+ parse_conventional_commit(commit: commit, allowed_types: allowed_types, bump_map: bump_map)
33
+ }
35
34
  end
36
35
 
37
- def self.group_commits(commits:, allowed_types:)
38
- result = allowed_types.to_h { |type| [type, []] }
36
+ def self.parse_conventional_commit(commit:, allowed_types:, bump_map:)
37
+ types = allowed_types.join("|")
38
+ commit.message.match(/^(?<type>#{types})(\((?<scope>\S+)\))?(?<major>!)?:\s+(?<subject>[^\n\r]+)(\z|\n\n(?<body>.*\z))/m) do |match|
39
+ cc = {
40
+ type: match[:type].to_sym,
41
+ major: !match[:major].nil?,
42
+ scope: match[:scope],
43
+ subject: match[:subject],
44
+ body: match[:body],
45
+ breaking: nil,
46
+ original_message: commit.message
47
+ }
39
48
 
40
- commits.each do |commit|
41
- if commit[:breaking] && allowed_types.include?(:breaking)
42
- result[:breaking] << commit
49
+ match[:body]&.match(/^BREAKING CHANGE?: (.+)\z/) do |breaking|
50
+ cc[:breaking] = breaking[1]
43
51
  end
44
- next unless allowed_types.include?(commit[:type])
45
52
 
46
- # If the breaking change is made from the actual feature subject, don't repeat it.
47
- next if commit[:breaking] == commit[:subject]
53
+ cc[:bump] = commit_bump_type(commit: cc, bump_map: bump_map)
48
54
 
49
- result[commit[:type]] << commit
55
+ return cc
50
56
  end
57
+ end
58
+
59
+ def self.commit_bump_type(commit:, bump_map:)
60
+ return :major if commit[:major]
61
+
62
+ return bump_map[:breaking] if commit[:breaking]
51
63
 
52
- return result
64
+ bump_map[commit[:type]]
53
65
  end
54
66
 
55
- def self.bump_type(commits:, bump_map:)
56
- result = nil
67
+ def self.bump_type(commits:, force_type: nil)
68
+ return force_type if force_type == :major # can't go any higher
69
+
70
+ result = force_type
57
71
 
58
72
  commits.each do |commit|
59
- bump_type = commit[:breaking] ? bump_map[:breaking] : bump_map[commit[:type]]
73
+ return :major if commit[:major]
74
+
75
+ bump_type = commit[:bump]
60
76
  if bump_type == :major
61
77
  return :major
62
78
  elsif bump_type == :minor
@@ -66,32 +82,27 @@ module Fastlane
66
82
  end
67
83
  end
68
84
 
69
- return result
85
+ result
70
86
  end
71
87
 
72
- def self.parse_conventional_commit(commit:, allowed_types:)
73
- types = allowed_types.join("|")
74
- commit.message.match(/^(?<type>#{types})(\((?<scope>\S+)\))?(?<breaking>!)?:\s+(?<subject>[^\n\r]+)(\z|\n\n(?<body>.*\z))/m) do |match|
75
- unless allowed_types.include?(match[:type].to_sym)
76
- UI.important("Commit #{commit.sha} has invalid type: #{match[:type]}. Ignoring")
77
- break
78
- end
88
+ def self.group_commits(commits:, allowed_types:)
89
+ result = allowed_types.to_h { |type| [type, []] }
90
+ result[:none] = []
79
91
 
80
- cc = {
81
- type: match[:type].to_sym,
82
- scope: match[:scope],
83
- subject: match[:subject],
84
- body: match[:body],
85
- breaking: match[:breaking] ? match[:subject] : nil,
86
- original_message: commit.message
87
- }
92
+ commits.each do |commit|
93
+ result[:breaking] << commit if commit[:breaking] && allowed_types.include?(:breaking)
88
94
 
89
- match[:body]&.match(/^BREAKING CHANGE?: (.+)\z/) do |breaking|
90
- cc[:breaking] = breaking[1]
95
+ if commit[:major] && !allowed_types.include?(commit[:type])
96
+ result[:none] << commit
97
+ next
91
98
  end
92
99
 
93
- return cc
100
+ next unless allowed_types.include?(commit[:type])
101
+
102
+ result[commit[:type]] << commit
94
103
  end
104
+
105
+ result
95
106
  end
96
107
 
97
108
  def self.increase_version(current_version:, bump_type:)
@@ -108,7 +119,7 @@ module Fastlane
108
119
  version_array[2] += 1
109
120
  end
110
121
 
111
- return version_array.join(".")
122
+ version_array.join(".")
112
123
  end
113
124
 
114
125
  # Builds and returns th changelog for the upcoming release.
@@ -123,7 +134,7 @@ module Fastlane
123
134
  grouped_commits.each do |key, section_commits|
124
135
  next unless section_commits.any?
125
136
 
126
- lines << "### #{type_map[key]}:"
137
+ lines << "### #{type_map[key]}:" if key != :none
127
138
  lines << ""
128
139
 
129
140
  section_commits.each do |commit|
@@ -133,7 +144,7 @@ module Fastlane
133
144
  lines << ""
134
145
  end
135
146
 
136
- return "#{lines.join("\n")}\n"
147
+ "#{lines.join("\n")}\n"
137
148
  end
138
149
 
139
150
  def self.write_changelog(path:, changelog:)
@@ -154,15 +165,54 @@ module Fastlane
154
165
  .sub("$new_version", Actions.lane_context[Actions::SharedValues::SEMVER_NEW_VERSION]))
155
166
  end
156
167
 
157
- def self.git_command(args)
158
- Actions.sh("git #{args.join(' ')}").chomp
159
- end
160
-
161
168
  def self.git
162
169
  # rubocop:disable Style/ClassVars
163
170
  @@git ||= Git.open(".")
164
171
  # rubocop:enable Style/ClassVars
165
172
  end
173
+
174
+ def self.git_tag_exists?(tag)
175
+ git.tags.include?(tag)
176
+ end
177
+
178
+ def self.project(path = nil)
179
+ # rubocop:disable Style/ClassVars
180
+ @@project ||= Xcodeproj::Project.open(path)
181
+ # rubocop:enable Style/ClassVars
182
+ end
183
+
184
+ def self.main_target
185
+ project.targets.first
186
+ end
187
+
188
+ def self.current_version
189
+ @current_version ||= main_target.build_configurations.first.build_settings["MARKETING_VERSION"] || "1.0"
190
+ end
191
+
192
+ def self.main_group(name = nil)
193
+ project.main_group[name || main_target.name]
194
+ end
195
+
196
+ def self.ensure_info_plist(path)
197
+ return if File.exist?(path)
198
+
199
+ File.write(path, <<-"PLIST")
200
+ <?xml version="1.0" encoding="UTF-8"?>
201
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
202
+ <plist version="1.0">
203
+ <dict>
204
+ <key>CFBundleVersion</key>
205
+ <string>#{current_version}</string>
206
+ <key>CFBundleShortVersionString</key>
207
+ <string>#{current_version}</string>
208
+ </dict>
209
+ </plist>
210
+ PLIST
211
+
212
+ info_plist = main_group.new_file("Info.plist")
213
+ main_target.add_file_references([info_plist])
214
+ Fastlane::UI.success("Successfully created the file '#{path}' for agvtool")
215
+ end
166
216
  end
167
217
  end
168
218
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fastlane
2
4
  module SemanticVersioning
3
- VERSION = "1.0.0"
5
+ VERSION = "2.1.0"
4
6
  end
5
7
  end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "fastlane/plugin/semantic_versioning/version"
2
4
 
3
5
  module Fastlane
6
+ # Provides actions for dealing with semantic versions and conventional commits
4
7
  module SemanticVersioning
5
8
  # Return all .rb files inside the "actions" and "helper" directory
6
9
  def self.all_classes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-semantic_versioning
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karsten Silkenbäumer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-17 00:00:00.000000000 Z
11
+ date: 2024-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: xcodeproj
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.24'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.24'
27
41
  description:
28
42
  email: 993392+kassi@users.noreply.github.com
29
43
  executables: []
@@ -34,6 +48,7 @@ files:
34
48
  - README.md
35
49
  - lib/fastlane/plugin/semantic_versioning.rb
36
50
  - lib/fastlane/plugin/semantic_versioning/actions/get_versioning_info_action.rb
51
+ - lib/fastlane/plugin/semantic_versioning/actions/prepare_versioning_action.rb
37
52
  - lib/fastlane/plugin/semantic_versioning/actions/semantic_bump_action.rb
38
53
  - lib/fastlane/plugin/semantic_versioning/helper/semantic_versioning_helper.rb
39
54
  - lib/fastlane/plugin/semantic_versioning/version.rb