-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaction.yml
255 lines (223 loc) · 9.88 KB
/
action.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
122
123
124
125
126
127
128
129
130
131
132
133
134
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
name: 'SemVersion'
description: 'GitHub Action to find the next version of your project using Conventional Commit'
author: 'shiipou'
inputs:
allow-failure:
description: 'If set to "true" and this action was run on incorrect state, the action will fail. Else, it just skip.'
required: false
default: "true"
level-0:
description: "The regex to find commit type that won't increment any version tag."
required: false
default: '^(build|ci|docs|style|refactor|test|chore)$'
level-1:
description: "The regex to find commit type that will increment patch version tag."
required: false
default: '^(fix|perf)$'
level-2:
description: "The regex to find commit type that will increment minor version tag."
required: false
default: '^(feat)$'
level-3:
description: "The regex to find commit type that will increment major version tag."
required: false
default: "^.+!$"
release-branches:
description: "The regex to find the release branch."
required: false
default: '^(main)$'
prerelease-branches:
description: "The regex to find the pre-release branch."
required: false
default: '^(rc|beta|hotfix)$'
case-sensitive:
description: "Set if set to 'false' it didn't need to match the case of the commit message that will trigger a release. Else the case must match."
required: false
default: 'false'
outputs:
version:
description: 'The next version find by semantic-release'
value: ${{ steps.semantic-release.outputs.version }}
will-release:
description: 'Only set to "true" if the release tag will be released'
value: ${{ steps.semantic-release.outputs.will-release }}
is-prerelease:
description: 'Only set to "true" if the release tag will be a pre-release'
value: ${{ steps.semantic-release.outputs.is-prerelease }}
changelogs:
description: 'Changelog test to be added to the release'
value: ${{ steps.semantic-release.outputs.changelogs }}
runs:
using: "composite"
steps:
- name: Semantic-Release
id: semantic-release
shell: bash
env:
ALLOW_FAILURE: '${{ inputs.allow-failure }}'
LEVEL_0: '${{ inputs.level-0 }}'
LEVEL_1: '${{ inputs.level-1 }}'
LEVEL_2: '${{ inputs.level-2 }}'
LEVEL_3: '${{ inputs.level-3 }}'
RELEASE_BRANCHES_REGEX: '${{ inputs.release-branches }}'
PRERELEASE_BRANCHES_REGEX: '${{ inputs.prerelease-branches }}'
run: |
function parse_semantic_release_tag { #-> (tag: string)
# extract major/minor/patch and channel verion tag
if [[ $1 =~ (v([0-9]+)\.([0-9]+)\.([0-9]+)(-([a-zA-Z]+)\.([0-9]+))?)(-([0-9]+))?(-(.+))? ]]; then
last_version="${BASH_REMATCH[1]}"
last_channel="${BASH_REMATCH[6]}"
major_version="${BASH_REMATCH[2]}"
minor_version="${BASH_REMATCH[3]}"
patch_version="${BASH_REMATCH[4]}"
channel_version="${BASH_REMATCH[7]:-0}"
nb_commit_since_last_release="${BASH_REMATCH[9]:-0}"
else
major_version="0"
minor_version="0"
patch_version="0"
channel_version="0"
nb_commit_since_last_release="0"
fi
}
CI_COMMIT_BRANCH="${GITHUB_REF#refs/heads/}"
echo "Current branch: $CI_COMMIT_BRANCH"
# Fetch git tags and commits.
git fetch --all --tags >> /dev/null
# remove the --depth=1 made by action/checkout@v3
if [ -z "$ACT" ]; then
git fetch --unshallow >> /dev/null
fi
# Skip a release if current commit contain [skip-ci]
subject="$(git log -1 --format=%B ${{ github.sha }})"
if [[ $subject == *"[skip-ci]"* ]]; then
echo "Skip a release because the commit message contain [skip-ci]"
exit 0
fi
# find last tag from the current commit sha
_last_tag_info=$(git describe --tags ${{ github.sha }} 2>/dev/null || true)
parse_semantic_release_tag "$_last_tag_info"
if [[ $CI_COMMIT_BRANCH =~ $PRERELEASE_BRANCHES_REGEX && "$last_channel" != "" && "$last_channel" != "$CI_COMMIT_BRANCH" ]]; then
parse_semantic_release_tag "$(git describe --tags --match "v*.*.*-${CI_COMMIT_BRANCH}.*" 2>/dev/null)"
fi
diff_path="--all"
if [ $last_version ]; then
echo "Last version found: $last_version"
diff_path="${last_version}.."
fi
commit_list="$(git rev-list --oneline $diff_path --format=%h --no-commit-header)"
correct="false"
level=0
declare -A CHANGELOG
while IFS= read -r commit; do
changelog_prefix=""
commit_prefix=""
subject="$(git log -1 --format=%s $commit | head -n1)"
if [ "${{ inputs.CASE_SENSITIVE }}" == 'false' ]; then
subject=${subject,,}
fi
# Extract the commit type
commit_prefix="${subject%%[(:]*}"
# Check if commit type is breaking changes
if [ "$level" -lt "3" ] && [[ $commit_prefix =~ $LEVEL_3 ]]; then
correct="true"
level=3
# Check if prefix is in the array of level 2 prefix
elif [ "$level" -lt "2" ] && [[ $commit_prefix =~ $LEVEL_2 ]]; then
correct="true"
level=2
# Check if prefix is in the array of level 1 prefix
elif [ "$level" -lt "1" ] && [[ $commit_prefix =~ $LEVEL_1 ]]; then
correct="true"
level=1
# Check if prefix is in the array of level 0 prefix
elif [[ $commit_prefix =~ $LEVEL_0 ]]; then
correct="true"
commit_prefix="other"
fi
if [[ $commit_prefix =~ $LEVEL_3 ]]; then
changelog_prefix=":boom: BREAKING CHANGE "
elif [[ $commit_prefix =~ $LEVEL_2 ]]; then
changelog_prefix=":sparkles: "
elif [[ $commit_prefix =~ $LEVEL_1 ]]; then
changelog_prefix=":hammer: "
fi
if [[ $commit_prefix =~ $LEVEL_1 || $commit_prefix =~ $LEVEL_2 || $commit_prefix =~ $LEVEL_3 ]]; then
commit_prefix="${commit_prefix%%\!*}"
CHANGELOG["$commit_prefix"]+="- ${changelog_prefix}$subject ($commit)\n"
else
CHANGELOG["other"]+="- ${changelog_prefix}$subject ($commit)\n"
fi
echo "$subject"
done <<< "$commit_list"
is_channel=false
if [[ "$level" -gt "0" && ${CI_COMMIT_BRANCH} =~ $PRERELEASE_BRANCHES_REGEX ]]; then
is_channel=true
fi
if [[ ${CI_COMMIT_BRANCH} =~ $RELEASE_BRANCHES_REGEX && $channel_version -eq 0 || $channel_version -eq 0 ]]; then
if [ "$level" -eq "3" ]; then
# Increment major version tag
echo $(( major_version++ )) >> /dev/null
minor_version=0
patch_version=0
elif [ "$level" -eq "2" ]; then
# Increment minor version tagc
echo $(( minor_version++ )) >> /dev/null
patch_version=0
elif [ "$level" == "1" ]; then
# Increment patch version tag
echo $(( patch_version++ )) >> /dev/null
fi
fi
if [[ "$level" -gt "0" && ${CI_COMMIT_BRANCH} =~ $PRERELEASE_BRANCHES_REGEX ]]; then
# Increment channel version tag
echo $(( channel_version++ )) >> /dev/null
fi
# If prefix is not found, then check ALLOW_FAILURE and fail job when needed.
if [[ "$ALLOW_FAILURE" == "true" && "$correct" == "false" ]]; then
echo "The commit type '$commit_prefix' didn't exist in the commit message"
exit 2
fi
# If branch is release branch
if [[ ${CI_COMMIT_BRANCH} =~ $RELEASE_BRANCHES_REGEX ]]; then
next_version="${major_version}.${minor_version}.${patch_version}"
if [[ "$last_version" != "v${major_version}.${minor_version}.${patch_version}" ]]; then
MUST_RELEASE=true
echo 'IS_PRE_RELEASE=false' >> $GITHUB_OUTPUT
fi
echo 'Find a release branch'
# If branch is pre-release branch
elif [[ ${CI_COMMIT_BRANCH} =~ $PRERELEASE_BRANCHES_REGEX ]]; then
next_version="${major_version}.${minor_version}.${patch_version}-${CI_COMMIT_BRANCH}.${channel_version}"
if [[ "$last_version" != "v${major_version}.${minor_version}.${patch_version}-${CI_COMMIT_BRANCH}.${channel_version}" ]]; then
MUST_RELEASE=true
echo 'is-prerelease=true' >> $GITHUB_OUTPUT
fi
echo 'Find a pre-release branch'
# If branch is other branch
elif [[ "$ALLOW_FAILURE" == "true" ]]; then
echo "Will not update the version because current branch (${CI_COMMIT_BRANCH}) is not part of the release branches or pre-release branches."
exit 3
fi
# Generate changelog
body="## Changelog ${next_version}\n\n"
for prefix in "${!CHANGELOG[@]}"; do
# First letter of prefix to uppercase
body+="### $(tr '[:lower:]' '[:upper:]' <<< ${prefix:0:1})${prefix:1}:\n"
body+="${CHANGELOG[$prefix]}\n"
done
body+="\n\n---\n\n**Full Changelog:** [${last_version}...${next_version}](${{ github.server_url }}/${{ github.repository }}/compare/${last_version}..v${next_version})\n"
# Publish changelog as action output
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "changelogs<<$EOF" >> "$GITHUB_OUTPUT"
echo -e "${body}" >> "$GITHUB_OUTPUT"
echo "$EOF" >> "$GITHUB_OUTPUT"
search_tag="$(git tag --list v${next_version})"
if $MUST_RELEASE && [ -z "${search_tag}" ]; then
echo 'will-release=true' >> $GITHUB_OUTPUT
echo "Will release next version: ${next_version}"
else
echo 'WILL_RELEASE=false' >> $GITHUB_OUTPUT
echo 'No new release needed for theses commits'
fi
echo "version=${next_version}" >> $GITHUB_OUTPUT