fastlane-plugin-semantic_release_workflow 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +92 -0
- data/lib/fastlane/plugin/semantic_release.rb +16 -0
- data/lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb +342 -0
- data/lib/fastlane/plugin/semantic_release/actions/conventional_changelog.rb +308 -0
- data/lib/fastlane/plugin/semantic_release/helper/semantic_release_helper.rb +104 -0
- data/lib/fastlane/plugin/semantic_release/version.rb +1 -0
- metadata +176 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 36cb5c231daacc42fd1609343b0aa04fd9c1fddbd45e213aa312341d140107ab
|
4
|
+
data.tar.gz: d039e4542a1eedd3e7219a3a5ec9898ee552bd757085117e23f6d366df85dcdc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5637899f9827e5259f32429e3cd85e4368fe4eec1a363c9b16679e469463c5a656edac86993c07baabe685095c9e18438b4f0e2d38d406ea8e5f410578c63b25
|
7
|
+
data.tar.gz: 310581a7d7070d645ab7e7205c790f7ce13700fa90a5d46f52bb1eb9df252033d0700a6e5b4daadd89f2be72b6ad69da5f271af4c62916c0a53dea292e264321
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Jiří Otáhal <xotahal@gmail.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# semantic_release plugin for `fastlane`
|
2
|
+
|
3
|
+
[![CircleCI](https://circleci.com/gh/xotahal/fastlane-plugin-semantic_release.svg?style=svg)](https://circleci.com/gh/xotahal/fastlane-plugin-semantic_release) [![License](https://img.shields.io/github/license/SiarheiFedartsou/fastlane-plugin-versioning.svg)](https://github.com/SiarheiFedartsou/fastlane-plugin-versioning/blob/master/LICENSE) [![Gem Version](https://badge.fury.io/rb/fastlane-plugin-semantic_release.svg)](https://badge.fury.io/rb/fastlane-plugin-semantic_release) [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-versioning)
|
4
|
+
|
5
|
+
## Getting Started
|
6
|
+
|
7
|
+
```
|
8
|
+
fastlane add_plugin semantic_release
|
9
|
+
```
|
10
|
+
|
11
|
+
## About
|
12
|
+
|
13
|
+
Automated version managment and generator of release notes. Inspired by [semantic-release](https://github.com/semantic-release/semantic-release) for npm packages. Based on [conventional commits](https://www.conventionalcommits.org/).
|
14
|
+
|
15
|
+
### Articles
|
16
|
+
|
17
|
+
[Semantic Release for Fastlane](https://medium.com/@xotahal/semantic-release-for-fastlane-781df4cf5888?source=friends_link&sk=5c02e32daca7a68539e27e0e1bac1092) @ Medium - By Jiri Otahal
|
18
|
+
|
19
|
+
## Available Actions
|
20
|
+
|
21
|
+
### `conventional_changelog`
|
22
|
+
|
23
|
+
- parses all commits since last version
|
24
|
+
- groups those commits by their type (fix, feat, docs, refactor, chore, etc)
|
25
|
+
- and creates formated release notes either in markdown or in slack format
|
26
|
+
|
27
|
+
Available parameters:
|
28
|
+
|
29
|
+
- `format: 'slack|markdown|plain'` (defaults to `markdown`). This formats the changelog for the destination you need. If you're using this for TestFlight changelogs, we suggest using the `plain` option
|
30
|
+
- `title: 'My Title'` - is appended to the release notes title, "1.1.8 My Title (YYYY-MM-DD)"
|
31
|
+
- `display_title: true|false` (defaults to true) - allows you to hide the entire first line of the changelog
|
32
|
+
- `display_links: true|false` (defaults to true) - allows you to hide links to commits from your changelog
|
33
|
+
- `commit_url: 'https://github.com/username/repository/commit'` - prepended to the commit ID to build usable links
|
34
|
+
- View other options by searching for `available_options` in `conventional_changelog.rb`
|
35
|
+
|
36
|
+
Example:
|
37
|
+
|
38
|
+
```
|
39
|
+
notes = conventional_changelog(format: 'slack', title: 'Android Alpha')
|
40
|
+
```
|
41
|
+
|
42
|
+
<img src="https://raw.githubusercontent.com/xotahal/fastlane-plugin-semantic_release/master/docs/Changelog.png" />
|
43
|
+
|
44
|
+
### `analyze_commits`
|
45
|
+
|
46
|
+
- analyzes your git history
|
47
|
+
- finds last tag on current branch (for example ios/beta/1.3.2)
|
48
|
+
- parses the last version from tag (1.3.2)
|
49
|
+
- gets all commits since this tag
|
50
|
+
- analyzes subject of every single commit and increases version number if there is a need (check conventional commit rules)
|
51
|
+
- if next version number is higher then last version number it will recommend you to release this version
|
52
|
+
|
53
|
+
Options:
|
54
|
+
|
55
|
+
- `ignore_scopes: ['android','windows']`: allows you to ignore any commits which include a given scope, like this one: `feat(android): add functionality not relevant to the release we are producing`
|
56
|
+
|
57
|
+
Example usage:
|
58
|
+
|
59
|
+
```
|
60
|
+
isReleasable = analyze_commits(match: 'ios/beta*')
|
61
|
+
```
|
62
|
+
|
63
|
+
It provides these variables in `lane_context`.
|
64
|
+
|
65
|
+
```
|
66
|
+
['RELEASE_ANALYZED', 'True if commits were analyzed.'],
|
67
|
+
['RELEASE_IS_NEXT_VERSION_HIGHER', 'True if next version is higher then last version'],
|
68
|
+
['RELEASE_LAST_TAG_HASH', 'Hash of commit that is tagged as a last version'],
|
69
|
+
['RELEASE_LAST_VERSION', 'Last version number - parsed from last tag.'],
|
70
|
+
['RELEASE_NEXT_MAJOR_VERSION', 'Major number of the next version'],
|
71
|
+
['RELEASE_NEXT_MINOR_VERSION', 'Minor number of the next version'],
|
72
|
+
['RELEASE_NEXT_PATCH_VERSION', 'Patch number of the next version'],
|
73
|
+
['RELEASE_NEXT_VERSION', 'Next version string in format (major.minor.patch)'],
|
74
|
+
```
|
75
|
+
|
76
|
+
And you can access these like this:
|
77
|
+
|
78
|
+
`next_version = lane_context[SharedValues::RELEASE_NEXT_VERSION]`
|
79
|
+
|
80
|
+
<img src="https://raw.githubusercontent.com/xotahal/fastlane-plugin-semantic_release/master/docs/Analyze.png" />
|
81
|
+
|
82
|
+
## Tests
|
83
|
+
|
84
|
+
To run the test suite (contained in `./spec`), call `bundle exec rake`
|
85
|
+
|
86
|
+
## Questions
|
87
|
+
|
88
|
+
If you need anything ping us on [twitter](http://bit.ly/t-xotahal).
|
89
|
+
|
90
|
+
| Jiri Otahal |
|
91
|
+
| -------------------------------------------------------------------------------------------------------------------------------------- |
|
92
|
+
| [<img src="https://avatars3.githubusercontent.com/u/3531955?v=4" width="100px;" style="border-radius:50px"/>](http://bit.ly/t-xotahal) |
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'fastlane/plugin/semantic_release/version'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module SemanticRelease
|
5
|
+
# Return all .rb files inside the "actions" and "helper" directory
|
6
|
+
def self.all_classes
|
7
|
+
Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# By default we want to import all available actions and helpers
|
13
|
+
# A plugin can contain any number of actions and plugins
|
14
|
+
Fastlane::SemanticRelease.all_classes.each do |current|
|
15
|
+
require current
|
16
|
+
end
|
@@ -0,0 +1,342 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/semantic_release_helper'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
module SharedValues
|
7
|
+
RELEASE_ANALYZED = :RELEASE_ANALYZED
|
8
|
+
RELEASE_IS_NEXT_VERSION_HIGHER = :RELEASE_IS_NEXT_VERSION_HIGHER
|
9
|
+
RELEASE_IS_NEXT_VERSION_COMPATIBLE_WITH_CODEPUSH = :RELEASE_IS_NEXT_VERSION_COMPATIBLE_WITH_CODEPUSH
|
10
|
+
RELEASE_LAST_TAG_HASH = :RELEASE_LAST_TAG_HASH
|
11
|
+
RELEASE_LAST_VERSION = :RELEASE_LAST_VERSION
|
12
|
+
RELEASE_NEXT_MAJOR_VERSION = :RELEASE_NEXT_MAJOR_VERSION
|
13
|
+
RELEASE_NEXT_MINOR_VERSION = :RELEASE_NEXT_MINOR_VERSION
|
14
|
+
RELEASE_NEXT_PATCH_VERSION = :RELEASE_NEXT_PATCH_VERSION
|
15
|
+
RELEASE_NEXT_VERSION = :RELEASE_NEXT_VERSION
|
16
|
+
RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION = :RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION
|
17
|
+
CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN = :CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN
|
18
|
+
end
|
19
|
+
|
20
|
+
class AnalyzeCommitsAction < Action
|
21
|
+
def self.get_last_tag(params)
|
22
|
+
# Try to find the tag
|
23
|
+
command = "git describe --tags --match=#{params[:match]}"
|
24
|
+
Actions.sh(command, log: params[:debug])
|
25
|
+
rescue
|
26
|
+
UI.message("Tag was not found for match pattern - #{params[:match]}")
|
27
|
+
''
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get_last_tag_hash(params)
|
31
|
+
command = "git rev-list -n 1 refs/tags/#{params[:tag_name]}"
|
32
|
+
Actions.sh(command, log: params[:debug]).chomp
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.get_commits_from_hash(params)
|
36
|
+
commits = Helper::SemanticReleaseHelper.git_log(
|
37
|
+
pretty: '%s|%b|>',
|
38
|
+
start: params[:hash],
|
39
|
+
debug: params[:debug]
|
40
|
+
)
|
41
|
+
commits.split("|>")
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.is_releasable(params)
|
45
|
+
# Hash of the commit where is the last version
|
46
|
+
# If the tag is not found we are taking HEAD as reference
|
47
|
+
hash = 'HEAD'
|
48
|
+
# Default last version
|
49
|
+
version = '0.0.0'
|
50
|
+
|
51
|
+
tag = get_last_tag(
|
52
|
+
match: params[:match],
|
53
|
+
debug: params[:debug]
|
54
|
+
)
|
55
|
+
|
56
|
+
if tag.empty?
|
57
|
+
UI.message("First commit of the branch is taken as a begining of next release")
|
58
|
+
# If there is no tag found we taking the first commit of current branch
|
59
|
+
hash = Actions.sh('git rev-list --max-parents=0 HEAD', log: params[:debug]).chomp
|
60
|
+
else
|
61
|
+
# Tag's format is v2.3.4-5-g7685948
|
62
|
+
# See git describe man page for more info
|
63
|
+
tag_name = tag.split('-')[0...-2].join('-').strip
|
64
|
+
parsed_version = tag_name.match(params[:tag_version_match])
|
65
|
+
|
66
|
+
if parsed_version.nil?
|
67
|
+
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.")
|
68
|
+
end
|
69
|
+
|
70
|
+
version = parsed_version[0]
|
71
|
+
# Get a hash of last version tag
|
72
|
+
hash = get_last_tag_hash(
|
73
|
+
tag_name: tag_name,
|
74
|
+
debug: params[:debug]
|
75
|
+
)
|
76
|
+
|
77
|
+
UI.message("Found a tag #{tag_name} associated with version #{version}")
|
78
|
+
end
|
79
|
+
|
80
|
+
# converts last version string to the int numbers
|
81
|
+
next_major = (version.split('.')[0] || 0).to_i
|
82
|
+
next_minor = (version.split('.')[1] || 0).to_i
|
83
|
+
next_patch = (version.split('.')[2] || 0).to_i
|
84
|
+
|
85
|
+
is_next_version_compatible_with_codepush = true
|
86
|
+
|
87
|
+
# Get commits log between last version and head
|
88
|
+
splitted = get_commits_from_hash(
|
89
|
+
hash: hash,
|
90
|
+
debug: params[:debug]
|
91
|
+
)
|
92
|
+
|
93
|
+
UI.message("Found #{splitted.length} commits since last release")
|
94
|
+
releases = params[:releases]
|
95
|
+
|
96
|
+
format_pattern = lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN]
|
97
|
+
splitted.each do |line|
|
98
|
+
parts = line.split("|")
|
99
|
+
subject = parts[0].strip
|
100
|
+
# conventional commits are in format
|
101
|
+
# type: subject (fix: app crash - for example)
|
102
|
+
commit = Helper::SemanticReleaseHelper.parse_commit(
|
103
|
+
commit_subject: subject,
|
104
|
+
commit_body: parts[1],
|
105
|
+
releases: releases,
|
106
|
+
pattern: format_pattern
|
107
|
+
)
|
108
|
+
|
109
|
+
unless commit[:scope].nil?
|
110
|
+
# 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
|
111
|
+
scope = commit[:scope]
|
112
|
+
scopes_to_ignore = params[:ignore_scopes]
|
113
|
+
# if it is, we'll skip this commit when bumping versions
|
114
|
+
next if scopes_to_ignore.include?(scope) #=> true
|
115
|
+
end
|
116
|
+
|
117
|
+
if commit[:release] == "major" || commit[:is_breaking_change]
|
118
|
+
next_major += 1
|
119
|
+
next_minor = 0
|
120
|
+
next_patch = 0
|
121
|
+
elsif commit[:release] == "minor"
|
122
|
+
next_minor += 1
|
123
|
+
next_patch = 0
|
124
|
+
elsif commit[:release] == "patch"
|
125
|
+
next_patch += 1
|
126
|
+
end
|
127
|
+
|
128
|
+
unless commit[:is_codepush_friendly]
|
129
|
+
is_next_version_compatible_with_codepush = false
|
130
|
+
end
|
131
|
+
|
132
|
+
next_version = "#{next_major}.#{next_minor}.#{next_patch}"
|
133
|
+
UI.message("#{next_version}: #{subject}") if params[:show_version_path]
|
134
|
+
end
|
135
|
+
|
136
|
+
next_version = "#{next_major}.#{next_minor}.#{next_patch}"
|
137
|
+
|
138
|
+
is_next_version_releasable = Helper::SemanticReleaseHelper.semver_gt(next_version, version)
|
139
|
+
|
140
|
+
Actions.lane_context[SharedValues::RELEASE_ANALYZED] = true
|
141
|
+
Actions.lane_context[SharedValues::RELEASE_IS_NEXT_VERSION_HIGHER] = is_next_version_releasable
|
142
|
+
Actions.lane_context[SharedValues::RELEASE_IS_NEXT_VERSION_COMPATIBLE_WITH_CODEPUSH] = is_next_version_compatible_with_codepush
|
143
|
+
# Last release analysis
|
144
|
+
Actions.lane_context[SharedValues::RELEASE_LAST_TAG_HASH] = hash
|
145
|
+
Actions.lane_context[SharedValues::RELEASE_LAST_VERSION] = version
|
146
|
+
# Next release analysis
|
147
|
+
Actions.lane_context[SharedValues::RELEASE_NEXT_MAJOR_VERSION] = next_major
|
148
|
+
Actions.lane_context[SharedValues::RELEASE_NEXT_MINOR_VERSION] = next_minor
|
149
|
+
Actions.lane_context[SharedValues::RELEASE_NEXT_PATCH_VERSION] = next_patch
|
150
|
+
Actions.lane_context[SharedValues::RELEASE_NEXT_VERSION] = next_version
|
151
|
+
|
152
|
+
success_message = "Next version (#{next_version}) is higher than last version (#{version}). This version should be released."
|
153
|
+
UI.success(success_message) if is_next_version_releasable
|
154
|
+
|
155
|
+
is_next_version_releasable
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.is_codepush_friendly(params)
|
159
|
+
git_command = 'git rev-list --max-parents=0 HEAD'
|
160
|
+
# Begining of the branch is taken for codepush analysis
|
161
|
+
hash_lines = Actions.sh("#{git_command} | wc -l", log: params[:debug]).chomp
|
162
|
+
hash = Actions.sh(git_command, log: params[:debug]).chomp
|
163
|
+
next_major = 0
|
164
|
+
next_minor = 0
|
165
|
+
next_patch = 0
|
166
|
+
last_incompatible_codepush_version = '0.0.0'
|
167
|
+
|
168
|
+
if hash_lines.to_i > 1
|
169
|
+
UI.error("#{git_command} resulted to more than 1 hash")
|
170
|
+
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.')
|
171
|
+
Actions.sh(git_command, log: true).chomp
|
172
|
+
return false
|
173
|
+
end
|
174
|
+
|
175
|
+
# Get commits log between last version and head
|
176
|
+
splitted = get_commits_from_hash(
|
177
|
+
hash: hash,
|
178
|
+
debug: params[:debug]
|
179
|
+
)
|
180
|
+
releases = params[:releases]
|
181
|
+
codepush_friendly = params[:codepush_friendly]
|
182
|
+
|
183
|
+
format_pattern = lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN]
|
184
|
+
splitted.each do |line|
|
185
|
+
# conventional commits are in format
|
186
|
+
# type: subject (fix: app crash - for example)
|
187
|
+
commit = Helper::SemanticReleaseHelper.parse_commit(
|
188
|
+
commit_subject: line.split("|")[0],
|
189
|
+
commit_body: line.split("|")[1],
|
190
|
+
releases: releases,
|
191
|
+
pattern: format_pattern,
|
192
|
+
codepush_friendly: codepush_friendly
|
193
|
+
)
|
194
|
+
|
195
|
+
if commit[:release] == "major" || commit[:is_breaking_change]
|
196
|
+
next_major += 1
|
197
|
+
next_minor = 0
|
198
|
+
next_patch = 0
|
199
|
+
elsif commit[:release] == "minor"
|
200
|
+
next_minor += 1
|
201
|
+
next_patch = 0
|
202
|
+
elsif commit[:release] == "patch"
|
203
|
+
next_patch += 1
|
204
|
+
end
|
205
|
+
|
206
|
+
unless commit[:is_codepush_friendly]
|
207
|
+
last_incompatible_codepush_version = "#{next_major}.#{next_minor}.#{next_patch}"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
Actions.lane_context[SharedValues::RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION] = last_incompatible_codepush_version
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.run(params)
|
215
|
+
is_next_version_releasable = is_releasable(params)
|
216
|
+
is_codepush_friendly(params)
|
217
|
+
|
218
|
+
is_next_version_releasable
|
219
|
+
end
|
220
|
+
|
221
|
+
#####################################################
|
222
|
+
# @!group Documentation
|
223
|
+
#####################################################
|
224
|
+
|
225
|
+
def self.description
|
226
|
+
"Finds a tag of last release and determinates version of next release"
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.details
|
230
|
+
"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."
|
231
|
+
end
|
232
|
+
|
233
|
+
def self.available_options
|
234
|
+
# Define all options your action supports.
|
235
|
+
|
236
|
+
# Below a few examples
|
237
|
+
[
|
238
|
+
FastlaneCore::ConfigItem.new(
|
239
|
+
key: :match,
|
240
|
+
description: "Match parameter of git describe. See man page of git describe for more info",
|
241
|
+
verify_block: proc do |value|
|
242
|
+
UI.user_error!("No match for analyze_commits action given, pass using `match: 'expr'`") unless value && !value.empty?
|
243
|
+
end
|
244
|
+
),
|
245
|
+
FastlaneCore::ConfigItem.new(
|
246
|
+
key: :commit_format,
|
247
|
+
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",
|
248
|
+
default_value: "default",
|
249
|
+
is_string: false,
|
250
|
+
verify_block: proc do |value|
|
251
|
+
case value
|
252
|
+
when String
|
253
|
+
unless Helper::SemanticReleaseHelper.format_patterns.key?(value)
|
254
|
+
UI.user_error!("Invalid format preset: #{value}")
|
255
|
+
end
|
256
|
+
|
257
|
+
pattern = Helper::SemanticReleaseHelper.format_patterns[value]
|
258
|
+
when Regexp
|
259
|
+
pattern = value
|
260
|
+
else
|
261
|
+
UI.user_error!("Invalid option type: #{value.inspect}")
|
262
|
+
end
|
263
|
+
Actions.lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN] = pattern
|
264
|
+
end
|
265
|
+
),
|
266
|
+
FastlaneCore::ConfigItem.new(
|
267
|
+
key: :releases,
|
268
|
+
description: "Map types of commit to release (major, minor, patch)",
|
269
|
+
default_value: { fix: "patch", feat: "minor" },
|
270
|
+
type: Hash
|
271
|
+
),
|
272
|
+
FastlaneCore::ConfigItem.new(
|
273
|
+
key: :codepush_friendly,
|
274
|
+
description: "These types are consider as codepush friendly automatically",
|
275
|
+
default_value: ["chore", "test", "docs"],
|
276
|
+
type: Array,
|
277
|
+
optional: true
|
278
|
+
),
|
279
|
+
FastlaneCore::ConfigItem.new(
|
280
|
+
key: :tag_version_match,
|
281
|
+
description: "To parse version number from tag name",
|
282
|
+
default_value: '\d+\.\d+\.\d+'
|
283
|
+
),
|
284
|
+
FastlaneCore::ConfigItem.new(
|
285
|
+
key: :ignore_scopes,
|
286
|
+
description: "To ignore certain scopes when calculating releases",
|
287
|
+
default_value: [],
|
288
|
+
type: Array,
|
289
|
+
optional: true
|
290
|
+
),
|
291
|
+
FastlaneCore::ConfigItem.new(
|
292
|
+
key: :show_version_path,
|
293
|
+
description: "True if you want to print out the version calculated for each commit",
|
294
|
+
default_value: true,
|
295
|
+
type: Boolean,
|
296
|
+
optional: true
|
297
|
+
),
|
298
|
+
FastlaneCore::ConfigItem.new(
|
299
|
+
key: :debug,
|
300
|
+
description: "True if you want to log out a debug info",
|
301
|
+
default_value: false,
|
302
|
+
type: Boolean,
|
303
|
+
optional: true
|
304
|
+
)
|
305
|
+
]
|
306
|
+
end
|
307
|
+
|
308
|
+
def self.output
|
309
|
+
# Define the shared values you are going to provide
|
310
|
+
# Example
|
311
|
+
[
|
312
|
+
['RELEASE_ANALYZED', 'True if commits were analyzed.'],
|
313
|
+
['RELEASE_IS_NEXT_VERSION_HIGHER', 'True if next version is higher then last version'],
|
314
|
+
['RELEASE_IS_NEXT_VERSION_COMPATIBLE_WITH_CODEPUSH', 'True if next version is compatible with codepush'],
|
315
|
+
['RELEASE_LAST_TAG_HASH', 'Hash of commit that is tagged as a last version'],
|
316
|
+
['RELEASE_LAST_VERSION', 'Last version number - parsed from last tag.'],
|
317
|
+
['RELEASE_NEXT_MAJOR_VERSION', 'Major number of the next version'],
|
318
|
+
['RELEASE_NEXT_MINOR_VERSION', 'Minor number of the next version'],
|
319
|
+
['RELEASE_NEXT_PATCH_VERSION', 'Patch number of the next version'],
|
320
|
+
['RELEASE_NEXT_VERSION', 'Next version string in format (major.minor.patch)'],
|
321
|
+
['RELEASE_LAST_INCOMPATIBLE_CODEPUSH_VERSION', 'Last commit without codepush'],
|
322
|
+
['CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN', 'The format pattern Regexp used to match commits (mainly for internal use)']
|
323
|
+
]
|
324
|
+
end
|
325
|
+
|
326
|
+
def self.return_value
|
327
|
+
# If your method provides a return value, you can describe here what it does
|
328
|
+
"Returns true if the next version is higher then the last version"
|
329
|
+
end
|
330
|
+
|
331
|
+
def self.authors
|
332
|
+
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
|
333
|
+
["xotahal"]
|
334
|
+
end
|
335
|
+
|
336
|
+
def self.is_supported?(platform)
|
337
|
+
# you can do things like
|
338
|
+
true
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/semantic_release_helper'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
module SharedValues
|
7
|
+
end
|
8
|
+
|
9
|
+
class ConventionalChangelogAction < Action
|
10
|
+
def self.get_commits_from_hash(params)
|
11
|
+
commits = Helper::SemanticReleaseHelper.git_log(
|
12
|
+
pretty: '%s|%b|%H|%h|%an|%at|>',
|
13
|
+
start: params[:hash],
|
14
|
+
debug: params[:debug]
|
15
|
+
)
|
16
|
+
commits.split("|>")
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.run(params)
|
20
|
+
# Get next version number from shared values
|
21
|
+
analyzed = lane_context[SharedValues::RELEASE_ANALYZED]
|
22
|
+
|
23
|
+
# If analyze commits action was not run there will be no version in shared
|
24
|
+
# values. We need to run the action to get next version number
|
25
|
+
unless analyzed
|
26
|
+
UI.user_error!("Release hasn't been analyzed yet. Run analyze_commits action first please.")
|
27
|
+
# version = other_action.analyze_commits(match: params[:match])
|
28
|
+
end
|
29
|
+
|
30
|
+
last_tag_hash = lane_context[SharedValues::RELEASE_LAST_TAG_HASH]
|
31
|
+
version = lane_context[SharedValues::RELEASE_NEXT_VERSION]
|
32
|
+
|
33
|
+
# Get commits log between last version and head
|
34
|
+
commits = get_commits_from_hash(
|
35
|
+
hash: last_tag_hash,
|
36
|
+
debug: params[:debug]
|
37
|
+
)
|
38
|
+
parsed = parse_commits(commits)
|
39
|
+
|
40
|
+
commit_url = params[:commit_url]
|
41
|
+
format = params[:format]
|
42
|
+
|
43
|
+
result = note_builder(format, parsed, version, commit_url, params)
|
44
|
+
|
45
|
+
result
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.note_builder(format, commits, version, commit_url, params)
|
49
|
+
sections = params[:sections]
|
50
|
+
|
51
|
+
result = ""
|
52
|
+
|
53
|
+
# Begining of release notes
|
54
|
+
if params[:display_title] == true
|
55
|
+
title = version
|
56
|
+
title += " #{params[:title]}" if params[:title]
|
57
|
+
title += " (#{Date.today})"
|
58
|
+
|
59
|
+
result = style_text(title, format, "title").to_s
|
60
|
+
result += "\n\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
params[:order].each do |type|
|
64
|
+
# write section only if there is at least one commit
|
65
|
+
next if commits.none? { |commit| commit[:type] == type }
|
66
|
+
|
67
|
+
result += style_text(sections[type.to_sym], format, "heading").to_s
|
68
|
+
result += "\n"
|
69
|
+
|
70
|
+
commits.each do |commit|
|
71
|
+
next if commit[:type] != type || commit[:is_merge]
|
72
|
+
|
73
|
+
result += "-"
|
74
|
+
|
75
|
+
unless commit[:scope].nil?
|
76
|
+
formatted_text = style_text("#{commit[:scope]}:", format, "bold").to_s
|
77
|
+
result += " #{formatted_text}"
|
78
|
+
end
|
79
|
+
|
80
|
+
result += " #{commit[:subject]}"
|
81
|
+
|
82
|
+
if params[:display_links] == true
|
83
|
+
styled_link = build_commit_link(commit, commit_url, format).to_s
|
84
|
+
result += " (#{styled_link})"
|
85
|
+
end
|
86
|
+
|
87
|
+
if params[:display_author]
|
88
|
+
result += " - #{commit[:author_name]}"
|
89
|
+
end
|
90
|
+
|
91
|
+
result += "\n"
|
92
|
+
end
|
93
|
+
result += "\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
if commits.any? { |commit| commit[:is_breaking_change] == true }
|
97
|
+
result += style_text("BREAKING CHANGES", format, "heading").to_s
|
98
|
+
result += "\n"
|
99
|
+
|
100
|
+
commits.each do |commit|
|
101
|
+
next unless commit[:is_breaking_change]
|
102
|
+
result += "- #{commit[:breaking_change]}" # This is the only unique part of this loop
|
103
|
+
|
104
|
+
if params[:display_links] == true
|
105
|
+
styled_link = build_commit_link(commit, commit_url, format).to_s
|
106
|
+
result += " (#{styled_link})"
|
107
|
+
end
|
108
|
+
|
109
|
+
if params[:display_author]
|
110
|
+
result += " - #{commit[:author_name]}"
|
111
|
+
end
|
112
|
+
|
113
|
+
result += "\n"
|
114
|
+
end
|
115
|
+
|
116
|
+
result += "\n"
|
117
|
+
end
|
118
|
+
|
119
|
+
# Trim any trailing newlines
|
120
|
+
result = result.rstrip!
|
121
|
+
|
122
|
+
result
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.style_text(text, format, style)
|
126
|
+
# formats the text according to the style we're looking to use
|
127
|
+
|
128
|
+
# Skips all styling
|
129
|
+
case style
|
130
|
+
when "title"
|
131
|
+
if format == "markdown"
|
132
|
+
"# #{text}"
|
133
|
+
elsif format == "slack"
|
134
|
+
"*#{text}*"
|
135
|
+
else
|
136
|
+
text
|
137
|
+
end
|
138
|
+
when "heading"
|
139
|
+
if format == "markdown"
|
140
|
+
"### #{text}"
|
141
|
+
elsif format == "slack"
|
142
|
+
"*#{text}*"
|
143
|
+
else
|
144
|
+
"#{text}:"
|
145
|
+
end
|
146
|
+
when "bold"
|
147
|
+
if format == "markdown"
|
148
|
+
"**#{text}**"
|
149
|
+
elsif format == "slack"
|
150
|
+
"*#{text}*"
|
151
|
+
else
|
152
|
+
text
|
153
|
+
end
|
154
|
+
else
|
155
|
+
text # catchall, shouldn't be needed
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.build_commit_link(commit, commit_url, format)
|
160
|
+
# formats the link according to the output format we need
|
161
|
+
short_hash = commit[:short_hash]
|
162
|
+
hash = commit[:hash]
|
163
|
+
url = "#{commit_url}/#{hash}"
|
164
|
+
|
165
|
+
case format
|
166
|
+
when "slack"
|
167
|
+
"<#{url}|#{short_hash}>"
|
168
|
+
when "markdown"
|
169
|
+
"[#{short_hash}](#{url})"
|
170
|
+
else
|
171
|
+
url
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.parse_commits(commits)
|
176
|
+
parsed = []
|
177
|
+
# %s|%b|%H|%h|%an|%at
|
178
|
+
format_pattern = lane_context[SharedValues::CONVENTIONAL_CHANGELOG_ACTION_FORMAT_PATTERN]
|
179
|
+
commits.each do |line|
|
180
|
+
splitted = line.split("|")
|
181
|
+
|
182
|
+
commit = Helper::SemanticReleaseHelper.parse_commit(
|
183
|
+
commit_subject: splitted[0],
|
184
|
+
commit_body: splitted[1],
|
185
|
+
pattern: format_pattern
|
186
|
+
)
|
187
|
+
|
188
|
+
commit[:hash] = splitted[2]
|
189
|
+
commit[:short_hash] = splitted[3]
|
190
|
+
commit[:author_name] = splitted[4]
|
191
|
+
commit[:commit_date] = splitted[5]
|
192
|
+
|
193
|
+
parsed.push(commit)
|
194
|
+
end
|
195
|
+
|
196
|
+
parsed
|
197
|
+
end
|
198
|
+
|
199
|
+
#####################################################
|
200
|
+
# @!group Documentation
|
201
|
+
#####################################################
|
202
|
+
|
203
|
+
def self.description
|
204
|
+
"Get commits since last version and generates release notes"
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.details
|
208
|
+
"Uses conventional commits. It groups commits by their types and generates release notes in markdown or slack format."
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.available_options
|
212
|
+
# Define all options your action supports.
|
213
|
+
|
214
|
+
# Below a few examples
|
215
|
+
[
|
216
|
+
FastlaneCore::ConfigItem.new(
|
217
|
+
key: :format,
|
218
|
+
description: "You can use either markdown, slack or plain",
|
219
|
+
default_value: "markdown",
|
220
|
+
optional: true
|
221
|
+
),
|
222
|
+
FastlaneCore::ConfigItem.new(
|
223
|
+
key: :title,
|
224
|
+
description: "Title for release notes",
|
225
|
+
optional: true
|
226
|
+
),
|
227
|
+
FastlaneCore::ConfigItem.new(
|
228
|
+
key: :commit_url,
|
229
|
+
description: "Uses as a link to the commit",
|
230
|
+
optional: true
|
231
|
+
),
|
232
|
+
FastlaneCore::ConfigItem.new(
|
233
|
+
key: :order,
|
234
|
+
description: "You can change the order of groups in release notes",
|
235
|
+
default_value: ["feat", "fix", "refactor", "perf", "chore", "test", "docs", "no_type"],
|
236
|
+
type: Array,
|
237
|
+
optional: true
|
238
|
+
),
|
239
|
+
FastlaneCore::ConfigItem.new(
|
240
|
+
key: :sections,
|
241
|
+
description: "Map type to section title",
|
242
|
+
default_value: {
|
243
|
+
feat: "Features",
|
244
|
+
fix: "Bug fixes",
|
245
|
+
refactor: "Code refactoring",
|
246
|
+
perf: "Performance improvements",
|
247
|
+
chore: "Building system",
|
248
|
+
test: "Testing",
|
249
|
+
docs: "Documentation",
|
250
|
+
no_type: "Other work"
|
251
|
+
},
|
252
|
+
type: Hash,
|
253
|
+
optional: true
|
254
|
+
),
|
255
|
+
FastlaneCore::ConfigItem.new(
|
256
|
+
key: :display_author,
|
257
|
+
description: "Whether you want to show the author of the commit",
|
258
|
+
default_value: false,
|
259
|
+
type: Boolean,
|
260
|
+
optional: true
|
261
|
+
),
|
262
|
+
FastlaneCore::ConfigItem.new(
|
263
|
+
key: :display_title,
|
264
|
+
description: "Whether you want to hide the title/header with the version details at the top of the changelog",
|
265
|
+
default_value: true,
|
266
|
+
type: Boolean,
|
267
|
+
optional: true
|
268
|
+
),
|
269
|
+
FastlaneCore::ConfigItem.new(
|
270
|
+
key: :display_links,
|
271
|
+
description: "Whether you want to display the links to commit IDs",
|
272
|
+
default_value: true,
|
273
|
+
type: Boolean,
|
274
|
+
optional: true
|
275
|
+
),
|
276
|
+
FastlaneCore::ConfigItem.new(
|
277
|
+
key: :debug,
|
278
|
+
description: "True if you want to log out a debug info",
|
279
|
+
default_value: false,
|
280
|
+
type: Boolean,
|
281
|
+
optional: true
|
282
|
+
)
|
283
|
+
]
|
284
|
+
end
|
285
|
+
|
286
|
+
def self.output
|
287
|
+
# Define the shared values you are going to provide
|
288
|
+
# Example
|
289
|
+
[]
|
290
|
+
end
|
291
|
+
|
292
|
+
def self.return_value
|
293
|
+
# If your method provides a return value, you can describe here what it does
|
294
|
+
"Returns generated release notes as a string"
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.authors
|
298
|
+
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
|
299
|
+
["xotahal"]
|
300
|
+
end
|
301
|
+
|
302
|
+
def self.is_supported?(platform)
|
303
|
+
# you can do things like
|
304
|
+
true
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'fastlane_core/ui/ui'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
|
5
|
+
|
6
|
+
module Helper
|
7
|
+
class SemanticReleaseHelper
|
8
|
+
def self.format_patterns
|
9
|
+
return {
|
10
|
+
"default" => /^(docs|fix|feat|chore|style|refactor|perf|test)(?:\((.*)\))?(!?)\: (.*)/,
|
11
|
+
"angular" => /^(\w*)(?:\((.*)\))?(): (.*)/
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# class methods that you define here become available in your action
|
16
|
+
# as `Helper::SemanticReleaseHelper.your_method`
|
17
|
+
#
|
18
|
+
def self.git_log(params)
|
19
|
+
command = "git log --pretty='#{params[:pretty]}' --reverse #{params[:start]}..HEAD"
|
20
|
+
Actions.sh(command, log: params[:debug]).chomp
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.parse_commit(params)
|
24
|
+
commit_subject = params[:commit_subject].strip
|
25
|
+
commit_body = params[:commit_body]
|
26
|
+
releases = params[:releases]
|
27
|
+
codepush_friendly = params[:codepush_friendly]
|
28
|
+
pattern = params[:pattern]
|
29
|
+
breaking_change_pattern = /BREAKING CHANGES?: (.*)/
|
30
|
+
codepush_pattern = /codepush?: (.*)/
|
31
|
+
|
32
|
+
matched = commit_subject.match(pattern)
|
33
|
+
result = {
|
34
|
+
is_valid: false,
|
35
|
+
subject: commit_subject,
|
36
|
+
is_merge: !(commit_subject =~ /^Merge/).nil?,
|
37
|
+
type: 'no_type'
|
38
|
+
}
|
39
|
+
|
40
|
+
unless matched.nil?
|
41
|
+
type = matched[1]
|
42
|
+
scope = matched[2]
|
43
|
+
|
44
|
+
result[:is_valid] = true
|
45
|
+
result[:type] = type
|
46
|
+
result[:scope] = scope
|
47
|
+
result[:has_exclamation_mark] = matched[3] == '!'
|
48
|
+
result[:subject] = matched[4]
|
49
|
+
|
50
|
+
unless releases.nil?
|
51
|
+
result[:release] = releases[type.to_sym]
|
52
|
+
end
|
53
|
+
unless codepush_friendly.nil?
|
54
|
+
result[:is_codepush_friendly] = codepush_friendly.include?(type)
|
55
|
+
end
|
56
|
+
|
57
|
+
unless commit_body.nil?
|
58
|
+
breaking_change_matched = commit_body.match(breaking_change_pattern)
|
59
|
+
codepush_matched = commit_body.match(codepush_pattern)
|
60
|
+
|
61
|
+
unless breaking_change_matched.nil?
|
62
|
+
result[:is_breaking_change] = true
|
63
|
+
result[:breaking_change] = breaking_change_matched[1]
|
64
|
+
end
|
65
|
+
unless codepush_matched.nil?
|
66
|
+
result[:is_codepush_friendly] = codepush_matched[1] == 'ok'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
result
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.semver_gt(first, second)
|
75
|
+
first_major = (first.split('.')[0] || 0).to_i
|
76
|
+
first_minor = (first.split('.')[1] || 0).to_i
|
77
|
+
first_patch = (first.split('.')[2] || 0).to_i
|
78
|
+
|
79
|
+
second_major = (second.split('.')[0] || 0).to_i
|
80
|
+
second_minor = (second.split('.')[1] || 0).to_i
|
81
|
+
second_patch = (second.split('.')[2] || 0).to_i
|
82
|
+
|
83
|
+
# Check if next version is higher then last version
|
84
|
+
if first_major > second_major
|
85
|
+
return true
|
86
|
+
elsif first_major == second_major
|
87
|
+
if first_minor > second_minor
|
88
|
+
return true
|
89
|
+
elsif first_minor == second_minor
|
90
|
+
if first_patch > second_patch
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
return false
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.semver_lt(first, second)
|
100
|
+
return !semver_gt(first, second)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
module Fastlane module SemanticRelease VERSION = "1.0.0" end end
|
metadata
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fastlane-plugin-semantic_release_workflow
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Phong Nguyen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pry
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec_junit_formatter
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.49.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.49.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-require_tools
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: fastlane
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 2.117.1
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 2.117.1
|
139
|
+
description:
|
140
|
+
email: phongnguyen180993@gmail.com
|
141
|
+
executables: []
|
142
|
+
extensions: []
|
143
|
+
extra_rdoc_files: []
|
144
|
+
files:
|
145
|
+
- LICENSE
|
146
|
+
- README.md
|
147
|
+
- lib/fastlane/plugin/semantic_release.rb
|
148
|
+
- lib/fastlane/plugin/semantic_release/actions/analyze_commits.rb
|
149
|
+
- lib/fastlane/plugin/semantic_release/actions/conventional_changelog.rb
|
150
|
+
- lib/fastlane/plugin/semantic_release/helper/semantic_release_helper.rb
|
151
|
+
- lib/fastlane/plugin/semantic_release/version.rb
|
152
|
+
homepage: https://github.com/phongnguyen93/fastlane-plugin-semantic_release
|
153
|
+
licenses:
|
154
|
+
- MIT
|
155
|
+
metadata: {}
|
156
|
+
post_install_message:
|
157
|
+
rdoc_options: []
|
158
|
+
require_paths:
|
159
|
+
- lib
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
requirements: []
|
171
|
+
rubygems_version: 3.0.3
|
172
|
+
signing_key:
|
173
|
+
specification_version: 4
|
174
|
+
summary: Automated version managment, generator of release notes, create gitlab release
|
175
|
+
then notify
|
176
|
+
test_files: []
|