release-me-sh 0.11.11 → 0.12.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-me-sh",
3
- "version": "0.11.11",
3
+ "version": "0.12.0",
4
4
  "description": "Fast minimal release workflow script written in Bash with plugins and presets support",
5
5
  "keywords": [
6
6
  "bash",
@@ -20,12 +20,20 @@
20
20
  "license": "Apache-2.0",
21
21
  "author": "Davlatjon Shavkatov <opensource@dalisoft.uz>",
22
22
  "bin": {
23
- "release-me": "release-me.sh",
24
- "release-me-sh": "release-me.sh"
23
+ "release-me": "release.sh",
24
+ "release-me-sh": "release.sh"
25
25
  },
26
- "files": ["presets", "plugins", "release-me.sh"],
26
+ "files": [
27
+ "presets",
28
+ "plugins",
29
+ "release.sh"
30
+ ],
27
31
  "browserslist": {
28
- "production": [">0.5%", "not dead", "not op_mini all"],
32
+ "production": [
33
+ ">0.5%",
34
+ "not dead",
35
+ "not op_mini all"
36
+ ],
29
37
  "development": [
30
38
  "last 3 chrome version",
31
39
  "last 3 firefox version",
@@ -44,19 +52,19 @@
44
52
  "docs:write-heading-ids": "docusaurus write-heading-ids"
45
53
  },
46
54
  "devDependencies": {
47
- "@biomejs/biome": "^1.8.3",
48
- "@docusaurus/core": "3.5.1",
49
- "@docusaurus/module-type-aliases": "^3.5.1",
50
- "@docusaurus/preset-classic": "3.5.1",
51
- "@docusaurus/types": "^3.5.1",
52
- "@evilmartians/lefthook": "^1.7.12",
53
- "@ls-lint/ls-lint": "^2.2.3",
54
- "@swc/core": "^1.7.10",
55
+ "@biomejs/biome": "^2.5.15",
56
+ "@docusaurus/core": "3.10.2",
57
+ "@docusaurus/module-type-aliases": "^3.10.2",
58
+ "@docusaurus/preset-classic": "3.10.2",
59
+ "@docusaurus/types": "^3.10.2",
60
+ "@evilmartians/lefthook": "^2.1.15",
61
+ "@ls-lint/ls-lint": "^2.3.1",
62
+ "@swc/core": "^1.16.13",
55
63
  "commitlint-rs-npm": "dalisoft/commitlint-rs-npm#v0.1.11",
56
- "dprint": "^0.47.2",
57
- "prism-react-renderer": "^2.3.1",
58
- "prismjs": "^1.29.0",
59
- "swc-loader": "^0.2.6"
64
+ "dprint": "^0.58.0",
65
+ "prism-react-renderer": "^2.4.1",
66
+ "prismjs": "^1.30.0",
67
+ "swc-loader": "^0.2.7"
60
68
  },
61
69
  "engines": {
62
70
  "node": ">=18.19.1"
@@ -106,62 +106,54 @@ release() {
106
106
  # Committing a `npm` tag
107
107
  log "Committing npm tag..."
108
108
  log_verbose "Git hash: ${CHECKOUT_SHA}!"
109
- if [ -n "${NPM_TOKEN-}" ]; then
110
-
111
- # Don't load this plugin if
112
- # - `--dry-run` used
113
- # - `package.json` is missing
114
- # - `package.json` is not changed on `Git` tracking
115
- if ! ${IS_DRY_RUN-}; then
116
- if [ ! -f package.json ] || [ -z "$(git diff --name-only package.json 2>/dev/null)" ]; then
117
- log "Project does not have package.json or package.json not changed"
109
+
110
+ # Don't load this plugin if
111
+ # - `--dry-run` used
112
+ # - `package.json` is missing
113
+ # - `package.json` is not changed on `Git` tracking
114
+ if ! ${IS_DRY_RUN-}; then
115
+ if [ ! -f package.json ] || [ -z "$(git diff --name-only package.json 2>/dev/null)" ]; then
116
+ log "Project does not have package.json or package.json not changed"
117
+ return 1
118
+ fi
119
+ prepare
120
+ git add package.json
121
+
122
+ if ${IS_WORKSPACE-}; then
123
+ if [ -z "${PKG_NAME}" ]; then
124
+ log_verbose "[npm-post] Workspace defined but no package name defined"
118
125
  return 1
119
126
  fi
120
- prepare
121
- git add package.json
122
-
123
- if ${IS_WORKSPACE-}; then
124
- if [ -z "${PKG_NAME}" ]; then
125
- log_verbose "[npm-post] Workspace defined but no package name defined"
126
- return 1
127
- fi
128
-
129
- if [ -z "${GPG_NO_SIGN-}" ] && [ -n "${GPG_KEY-}" ] && [ -n "${GPG_KEY_ID-}" ]; then
130
- git commit --sign -m "chore(${PKG_NAME}): update \`package.json\` version to ${NEXT_RELEASE_VERSION-} [skip ci]" --no-verify
131
- elif [ -z "${SSH_NO_SIGN-}" ] && [ -n "${SSH_PUBLIC_KEY-}" ]; then
132
- git commit --sign -m "chore(${PKG_NAME}): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
133
- else
134
- git commit --no-gpg-sign -m "chore(${PKG_NAME}): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
135
- fi
127
+
128
+ if [ -z "${GPG_NO_SIGN-}" ] && [ -n "${GPG_KEY-}" ] && [ -n "${GPG_KEY_ID-}" ]; then
129
+ git commit --sign -m "chore(${PKG_NAME}): update \`package.json\` version to ${NEXT_RELEASE_VERSION-} [skip ci]" --no-verify
130
+ elif [ -z "${SSH_NO_SIGN-}" ] && [ -n "${SSH_PUBLIC_KEY-}" ]; then
131
+ git commit --sign -m "chore(${PKG_NAME}): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
136
132
  else
137
- if [ -z "${GPG_NO_SIGN-}" ] && [ -n "${GPG_KEY-}" ] && [ -n "${GPG_KEY_ID-}" ]; then
138
- git commit --sign -m "chore(ci): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
139
- elif [ -z "${SSH_NO_SIGN-}" ] && [ -n "${SSH_PUBLIC_KEY-}" ]; then
140
- git commit --sign -m "chore(ci): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
141
- else
142
- git commit --no-gpg-sign -m "chore(ci): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
143
- fi
133
+ git commit --no-gpg-sign -m "chore(${PKG_NAME}): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
144
134
  fi
145
-
146
- if [ -n "${GIT_REMOTE_ORIGIN}" ]; then
147
- # GitHub workflow re-trigger hack to make it work properly
148
- git pull
149
- git push --no-verify
150
- CHECKOUT_SHA=$(git rev-parse HEAD)
151
- log "Committed npm [${NEXT_RELEASE_TAG-}] tag"
135
+ else
136
+ if [ -z "${GPG_NO_SIGN-}" ] && [ -n "${GPG_KEY-}" ] && [ -n "${GPG_KEY_ID-}" ]; then
137
+ git commit --sign -m "chore(ci): update \`package.json\` version to ${NEXT_RELEASE_VERSION-} [skip ci]" --no-verify
138
+ elif [ -z "${SSH_NO_SIGN-}" ] && [ -n "${SSH_PUBLIC_KEY-}" ]; then
139
+ git commit --sign -m "chore(ci): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
152
140
  else
153
- log "Committing npm [${NEXT_RELEASE_TAG}] tag failed"
141
+ git commit --no-gpg-sign -m "chore(ci): update \`package.json\` version to ${NEXT_RELEASE_VERSION} [skip ci]" --no-verify
154
142
  fi
143
+ fi
155
144
 
156
- cleanup
145
+ if [ -n "${GIT_REMOTE_ORIGIN}" ]; then
146
+ # GitHub workflow re-trigger hack to make it work properly
147
+ git pull
148
+ git push --no-verify
149
+ CHECKOUT_SHA=$(git rev-parse HEAD)
150
+ log "Committed npm [${NEXT_RELEASE_TAG-}] tag"
157
151
  else
158
- log "Skipped committing npm [${NEXT_RELEASE_TAG}] tag in DRY-RUN mode."
152
+ log "Committing npm [${NEXT_RELEASE_TAG}] tag failed"
159
153
  fi
154
+
155
+ cleanup
160
156
  else
161
- echo "
162
- npm Token is not found
163
- Please export npm Token so this plugin can be used
164
- "
165
- exit 1
157
+ log "Skipped committing npm [${NEXT_RELEASE_TAG}] tag in DRY-RUN mode."
166
158
  fi
167
159
  }
package/plugins/npm.sh CHANGED
@@ -2,40 +2,43 @@
2
2
  set -eu
3
3
 
4
4
  release() {
5
- # Publish a `npm` tag
6
- if [ -n "${NPM_TOKEN-}" ]; then
7
- log "Publishing npm tag..."
8
- log_verbose "npm tag: ${NEXT_RELEASE_TAG-} and version: ${NEXT_RELEASE_VERSION-}!"
5
+ # Publish a `npm` tag with token or Trusted publishing (OIDC)
6
+ log "Publishing npm tag..."
7
+ log_verbose "npm tag: ${NEXT_RELEASE_TAG-} and version: ${NEXT_RELEASE_VERSION-}!"
9
8
 
10
- # Don't load this plugin if
11
- # - `--dry-run` used
12
- # - `package.json` is missing
13
- if ! ${IS_DRY_RUN-}; then
14
- if [ ! -f package.json ]; then
15
- log "Project does not have package.json"
16
- return 1
17
- fi
9
+ # Don't load this plugin if
10
+ # - `--dry-run` used
11
+ # - `package.json` is missing
12
+ if ! ${IS_DRY_RUN-}; then
13
+ if [ ! -f package.json ]; then
14
+ log "Project does not have package.json"
15
+ return 1
16
+ fi
18
17
 
18
+ if [ -n "${NPM_TOKEN-}" ]; then
19
19
  TEMP_FILE=$(mktemp)
20
20
  printf "%s\n" "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >>"${TEMP_FILE}"
21
+ export NODE_AUTH_TOKEN="${NPM_TOKEN}"
22
+ fi
21
23
 
22
- # Bump `package.json` `version` for properly publishing
23
- sed -i.bak "s/\"version\": \"[^\"]*\",/\"version\": \"${NEXT_BUILD_VERSION-}\",/" "package.json"
24
- rm -rf package.json.bak
24
+ # Bump `package.json` `version` for properly publishing
25
+ sed -i.bak "s/\"version\": \"[^\"]*\",/\"version\": \"${NEXT_BUILD_VERSION-}\",/" "package.json"
26
+ rm -rf package.json.bak
25
27
 
26
- export NODE_AUTH_TOKEN="${NPM_TOKEN}"
28
+ # without a token npm >= 11.5.1 exchanges the CI's OIDC token
29
+ # (Trusted publishing) for a short-lived publish token
30
+ if [ -n "${TEMP_FILE-}" ]; then
27
31
  npm publish --provenance --userconfig "${TEMP_FILE}"
32
+ else
33
+ npm publish --provenance
34
+ fi
28
35
 
29
- log "Published [${NEXT_RELEASE_TAG}]!"
36
+ log "Published [${NEXT_RELEASE_TAG}]!"
37
+
38
+ if [ -n "${TEMP_FILE-}" ]; then
30
39
  rm -rf "${TEMP_FILE}"
31
- else
32
- log "Skipped npm tag [${NEXT_RELEASE_TAG}] in DRY-RUN mode."
33
40
  fi
34
41
  else
35
- echo "
36
- npm Token is not found
37
- Please export npm Token so this plugin can be used
38
- "
39
- exit 1
42
+ log "Skipped npm tag [${NEXT_RELEASE_TAG}] in DRY-RUN mode."
40
43
  fi
41
44
  }
@@ -4,7 +4,7 @@ set -eu
4
4
  # RegExp as variable
5
5
  regexp_commit_primary="^([a-z]+)(\(([^\)]+)\))?:\ (.+)$"
6
6
  regexp_commit_major="^([a-z]+)(\(([^\)]+)\))?!?:\ (.+)$"
7
- string_commit_major="^BREAKING CHANGE(: )?(.+)"
7
+ string_commit_major="BREAKING[ -]CHANGE:"
8
8
 
9
9
  # Release types
10
10
  RELEASE_SKIP_TYPES=("build" "chore" "style" "ci" "skip ci")
@@ -4,7 +4,7 @@ set -eu
4
4
  # RegExp as variable
5
5
  regexp_commit_primary="^([a-z]+)(\(([^\)]+)\))?:\ (.+)$"
6
6
  regexp_commit_major="^([a-z]+)(\(([^\)]+)\))?!?:\ (.+)$"
7
- string_commit_major="^BREAKING CHANGE(: )?(.+)"
7
+ string_commit_major="BREAKING[ -]CHANGE:"
8
8
 
9
9
  # Release types
10
10
  RELEASE_SKIP_TYPES=("build" "chore" "style" "ci" "skip ci")
package/release.sh ADDED
@@ -0,0 +1,482 @@
1
+ #!/usr/bin/env bash
2
+ set -eu
3
+ shopt -s inherit_errexit
4
+
5
+ readonly CLI_PREFIX="[release-me]"
6
+ readonly DESCRIPTION="Fast minimal release workflow script written in Bash with plugins and presets support"
7
+ readonly USAGE="${CLI_PREFIX} Usage: release-me [options]
8
+ ${DESCRIPTION}
9
+
10
+ Options:
11
+ -d, --dry-run Dry run. Skip tag creation, only show logs (if exists).
12
+ -w, --workspace Use in workspace environment for publishing workspaces separately.
13
+ --use-version Use project version from manifest. Requires workspace and a valid manifest.
14
+ --verbose Verbose mode, shows more detailed logs.
15
+ --quiet Quiet mode, shows less logs than default behavior.
16
+ --plugins=* Plugins option for loading plugins.
17
+ --preset= Presets option for parsing commits.
18
+ --stable If project has a \`0.x\` version, it will bump to \`1.x\`.
19
+ --pre-release Mark project release as non-production ready.
20
+ -h, --help Show this help.
21
+ -v, --version Show version.
22
+ "
23
+
24
+ ##############################
25
+ ####### Root variables #######
26
+ ##############################
27
+ READLINK=$(readlink -f -- "$0")
28
+ SCRIPT_DIR=$(dirname -- "${READLINK}")
29
+ CURRENT_DATE=$(date +'%Y-%m-%d')
30
+ IS_GIT_REPO=$(git rev-parse --is-inside-work-tree 2>/dev/null || printf "%s" "")
31
+ GIT_LOG_ENTRY_SEPARATOR='____'
32
+ GIT_LOG_COMMIT_SEPARATOR='START_OF_COMMIT'
33
+ GIT_LOG_FORMAT="${GIT_LOG_COMMIT_SEPARATOR}%n%h${GIT_LOG_ENTRY_SEPARATOR}%H${GIT_LOG_ENTRY_SEPARATOR}%s${GIT_LOG_ENTRY_SEPARATOR}%b"
34
+ GIT_LOG_PARSE_REGEX="(.*)${GIT_LOG_ENTRY_SEPARATOR}(.*)${GIT_LOG_ENTRY_SEPARATOR}(.*)(${GIT_LOG_ENTRY_SEPARATOR}(.*)?)"
35
+ GIT_REMOTE_ORIGIN=$(git remote get-url origin 2>/dev/null || printf "%s" "")
36
+ GIT_REPO_NAME=
37
+
38
+ if [[ "${GIT_REMOTE_ORIGIN}" == "git@"* ]]; then
39
+ GIT_REPO_NAME=$(git remote get-url origin | cut -d ':' -f 2 | sed s/.git//)
40
+ elif [[ "${GIT_REMOTE_ORIGIN}" == "https"* ]]; then
41
+ GIT_REPO_NAME=$(git remote get-url origin | cut -d ':' -f 2 | sed s/\\/\\/github.com\\///)
42
+ fi
43
+
44
+ IS_WORKSPACE=false
45
+ IS_USE_PKG_VERSION=false
46
+ IS_DRY_RUN=false
47
+ IS_QUIET=false
48
+ IS_VERBOSE=false
49
+ IS_STABLE_VERSION=false
50
+ PRE_RELEASE_VERSION=false
51
+ PLUGINS=("git")
52
+ PRESET="conventional-commits"
53
+
54
+ # set `verbose` on `CI`
55
+ if [[ -n "${CI:-}" ]]; then
56
+ IS_VERBOSE=true
57
+ fi
58
+
59
+ ##############################
60
+ ###### Helpers & Utils #######
61
+ ##############################
62
+
63
+ # proper handling of lines counter
64
+ # as `grep -c '^'` fails if there nothing
65
+ # and `wc -l` if there 1 commit
66
+ # so this utility was made
67
+
68
+ glc() {
69
+ local COUNT=0
70
+ while read -r line; do
71
+ if [[ -n "${line}" ]]; then
72
+ COUNT=$((COUNT + 1))
73
+ fi
74
+ done <<<"$(cat /dev/stdin)"
75
+
76
+ printf "%s" "${COUNT}"
77
+ }
78
+
79
+ parse_options() {
80
+ while :; do
81
+ local KEY="${1-}"
82
+ case "${KEY}" in
83
+ -v | --version)
84
+ printf "%s" "${CLI_PREFIX} last version available at GitHub"
85
+ exit 0
86
+ ;;
87
+ -h | -\? | --help)
88
+ printf "%s" "${USAGE}"
89
+ exit 0
90
+ ;;
91
+ -w | --workspace)
92
+ IS_WORKSPACE=true
93
+ ;;
94
+ --plugins=*)
95
+ local IFS=','
96
+ read -ra PLUGINS <<<"${KEY#*=}"
97
+ ;;
98
+ --preset=*)
99
+ read -r PRESET <<<"${KEY#*=}"
100
+ ;;
101
+ --stable)
102
+ IS_STABLE_VERSION=true
103
+ PRE_RELEASE_VERSION=false
104
+ ;;
105
+ --pre-release)
106
+ # shellcheck disable=2034
107
+ PRE_RELEASE_VERSION=true
108
+ IS_STABLE_VERSION=false
109
+ ;;
110
+ --use-version)
111
+ IS_USE_PKG_VERSION=true
112
+ ;;
113
+ -d | --dry-run)
114
+ # shellcheck disable=2034
115
+ IS_DRY_RUN=true
116
+ ;;
117
+ -q | --quiet)
118
+ IS_QUIET=true
119
+ IS_VERBOSE=false
120
+ ;;
121
+ --verbose)
122
+ IS_VERBOSE=true
123
+ IS_QUIET=false
124
+ # export GIT_TRACE=1
125
+ ;;
126
+ -?*)
127
+ printf "%s" "${CLI_PREFIX} Unknown option: ${KEY}"
128
+ exit 1
129
+ ;;
130
+ ?*)
131
+ printf "%s" "${CLI_PREFIX} Unknown argument: ${KEY}"
132
+ exit 1
133
+ ;;
134
+ *)
135
+ break
136
+ ;;
137
+ esac
138
+ shift
139
+ done
140
+ }
141
+
142
+ is_valid_commit_type() {
143
+ local key="$1"
144
+ shift
145
+ local arr=("$@")
146
+
147
+ for element in "${arr[@]}"; do
148
+ if [[ "${key}" == "${element}"* ]]; then
149
+ return 0
150
+ fi
151
+ done
152
+ return 1
153
+ }
154
+
155
+ ##############################
156
+ ##### Logging helpers #######
157
+ ##############################
158
+ log() {
159
+ if ! ${IS_QUIET}; then
160
+ if [[ "${2-}" == "-q" ]]; then
161
+ printf "%b\n" "$1"
162
+ else
163
+ printf "%b\n" "${CLI_PREFIX} $1"
164
+ fi
165
+ fi
166
+ }
167
+ log_verbose() {
168
+ if ${IS_VERBOSE}; then
169
+ if [[ "${2-}" == "-q" ]]; then
170
+ printf "%b\n" "$1"
171
+ else
172
+ printf "%b\n" "${CLI_PREFIX} $1"
173
+ fi
174
+ fi
175
+ }
176
+
177
+ ##############################
178
+ ##### Early exit errors ######
179
+ ##############################
180
+
181
+ if [[ "${IS_GIT_REPO}" != true ]]; then
182
+ log "Current directory is not a Git repository!"
183
+ exit 1
184
+ fi
185
+
186
+ parse_options "$@"
187
+
188
+ up_to_date() {
189
+ log "${CLI_PREFIX} $1" -q
190
+ printf "%s\n" "${CLI_PREFIX} Your project is up-to-date"
191
+ exit 0
192
+ }
193
+
194
+ if [[ "${PRESET}" != "" ]]; then
195
+ SOURCE_PRESET_FILE="${SCRIPT_DIR}/presets/${PRESET}.sh"
196
+ # shellcheck disable=SC1090 source=/dev/null
197
+ source "${SOURCE_PRESET_FILE}"
198
+ fi
199
+
200
+ ##############################
201
+ ##### Package variables ######
202
+ ##############################
203
+
204
+ PKG_NAME=""
205
+ NEXT_VERSION=(0 0 0)
206
+ CURRENT_VERSION=(0 0 0)
207
+
208
+ parse_packages() {
209
+ if ! ${IS_WORKSPACE}; then
210
+ return 0
211
+ fi
212
+
213
+ if [[ -f "./package.json" ]]; then
214
+ PKG_NAME=$(awk -F': ' '/"name":/ {gsub(/[",]/, "", $2); print $2}' "./package.json")
215
+ if ${IS_USE_PKG_VERSION}; then
216
+ PKG_VERSION=$(awk -F': ' '/"version":/ {gsub(/[",]/, "", $2); print $2}' "./package.json")
217
+ fi
218
+ elif [[ -f "./Cargo.toml" ]]; then
219
+ PKG_NAME=$(sed -n 's/^name = "\(.*\)"/\1/p' "./Cargo.toml")
220
+ if ${IS_USE_PKG_VERSION}; then
221
+ PKG_VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' "./Cargo.toml")
222
+ fi
223
+ elif [[ -f "./setup.py" ]]; then
224
+ PKG_NAME=$(sed -n "s/.*name=['\"]\([^'\"]*\)['\"].*/\1/p" "./setup.py")
225
+ if ${IS_USE_PKG_VERSION}; then
226
+ PKG_VERSION=$(sed -n 's/^ *version\s*=\s*["'\'']\([^"'\'']*\)["'\''].*/\1/p' "./setup.py")
227
+ fi
228
+ else
229
+ cat <<EOF
230
+ This project currently supports only Node.js, Rust and Python projects.
231
+ Please wait for updates to get support in other languages!
232
+ EOF
233
+ exit 1
234
+ fi
235
+
236
+ if ${IS_WORKSPACE} && [[ -z "${PKG_NAME}" ]]; then
237
+ cat <<EOF
238
+ This release aims to being workspace release
239
+ but missing name and could not be release
240
+ EOF
241
+ exit 1
242
+ fi
243
+
244
+ if ${IS_USE_PKG_VERSION}; then
245
+ local IFS='.'
246
+ read -ra NEXT_VERSION <<<"${PKG_VERSION}"
247
+ CURRENT_VERSION=("${NEXT_VERSION[@]}")
248
+ fi
249
+
250
+ log_verbose "Workspace mode is enabled"
251
+ log_verbose "Workspace project name: ${PKG_NAME}"
252
+ }
253
+
254
+ ##############################
255
+ ####### Git variables ########
256
+ ##############################
257
+
258
+ GIT_LAST_PROJECT_TAG=""
259
+ GIT_LAST_PROJECT_TAG_VER=""
260
+
261
+ get_git_variables() {
262
+ GIT_TAGS_LIST=$(git for-each-ref --sort=creatordate --format '%(refname)' refs/tags)
263
+
264
+ if ${IS_WORKSPACE}; then
265
+ GIT_LAST_PROJECT_TAG=$(printf "%b" "${GIT_TAGS_LIST}" | grep "${PKG_NAME}" | tail -1 | cut -d '/' -f 3-)
266
+ else
267
+ GIT_LAST_PROJECT_TAG=$(printf "%s" "${GIT_TAGS_LIST}" | tail -1 | cut -d '/' -f 3-)
268
+ fi
269
+
270
+ if [[ ${GIT_LAST_PROJECT_TAG} != "" ]]; then
271
+ GIT_LAST_PROJECT_TAG_VER=$(printf "%s" "${GIT_LAST_PROJECT_TAG}" | rev | cut -d 'v' -f 1 | rev)
272
+ fi
273
+
274
+ if [[ -n "${GIT_LAST_PROJECT_TAG_VER}" ]]; then
275
+ if ! ${IS_USE_PKG_VERSION}; then
276
+ mapfile -d '.' -t NEXT_VERSION < <(printf '%s' "${GIT_LAST_PROJECT_TAG_VER}")
277
+ CURRENT_VERSION=("${NEXT_VERSION[@]}")
278
+ fi
279
+
280
+ if [[ "${IS_STABLE_VERSION}" == false && ${PRE_RELEASE_VERSION} == false && "${NEXT_VERSION[0]}" -gt 0 ]]; then
281
+ IS_STABLE_VERSION=true
282
+ fi
283
+ fi
284
+ }
285
+
286
+ ##############################
287
+ ######## Git handling ########
288
+ ##############################
289
+
290
+ GIT_LOGS=""
291
+
292
+ get_git_commits() {
293
+ local IFS=
294
+ local GIT_LOGS_LENGTH=0
295
+
296
+ # Fast early-catch empty repository
297
+ if ! git rev-parse HEAD 1>/dev/null 2>&1; then
298
+ log "You have not committed yet
299
+ You have to commit your initial/first commit."
300
+ exit 1
301
+ fi
302
+
303
+ # Check if exists last tag and is not empty
304
+ if [[ -n "${GIT_LAST_PROJECT_TAG}" ]]; then
305
+ log_verbose "Last project tag [${GIT_LAST_PROJECT_TAG}] found"
306
+ # Get and cache commits variable, so later
307
+ # can be checked for commits length and avaibality
308
+ if ${IS_WORKSPACE}; then
309
+ GIT_LOGS=$(git log "${GIT_LAST_PROJECT_TAG}...HEAD" --grep "${PKG_NAME}" --pretty=format:"${GIT_LOG_FORMAT}" --reverse)
310
+ GIT_LOGS_LENGTH=$(git log "${GIT_LAST_PROJECT_TAG}...HEAD" --grep "${PKG_NAME}" --pretty=format:"%s" | glc -)
311
+ else
312
+ GIT_LOGS=$(git log "${GIT_LAST_PROJECT_TAG}...HEAD" --pretty=format:"${GIT_LOG_FORMAT}" --reverse)
313
+ GIT_LOGS_LENGTH=$(git rev-list --count "${GIT_LAST_PROJECT_TAG}...HEAD")
314
+ fi
315
+ else
316
+ log_verbose "Last project tag not found"
317
+ if ${IS_WORKSPACE}; then
318
+ GIT_LOGS=$(git log HEAD --grep "${PKG_NAME}" --pretty=format:"${GIT_LOG_FORMAT}" --reverse)
319
+ GIT_LOGS_LENGTH=$(git log HEAD --grep "${PKG_NAME}" --pretty=format:"%s" | glc -)
320
+ else
321
+ GIT_LOGS=$(git log HEAD --pretty=format:"${GIT_LOG_FORMAT}" --reverse)
322
+ GIT_LOGS_LENGTH=$(git rev-list --count HEAD)
323
+ fi
324
+ fi
325
+
326
+ if [[ ${GIT_LOGS_LENGTH} -eq 0 ]]; then
327
+ up_to_date "Your project has no new commits"
328
+ else
329
+ if [[ -n "${GIT_LAST_PROJECT_TAG}" ]]; then
330
+ log_verbose "Found ${GIT_LOGS_LENGTH} commits since last release"
331
+ else
332
+ log_verbose "Found ${GIT_LOGS_LENGTH} commits but did not found any release"
333
+ fi
334
+ fi
335
+ }
336
+
337
+ ##############################
338
+ #### Git commits handling ####
339
+ ##############################
340
+ NEXT_BUILD_VERSION=""
341
+ NEXT_RELEASE_VERSION=""
342
+ NEXT_RELEASE_TAG=""
343
+ RELEASE_BODY=""
344
+
345
+ PATCH_UPGRADED=false
346
+ MINOR_UPGRADED=false
347
+ MAJOR_UPGRADED=false
348
+
349
+ process_commit_entry() {
350
+ local commit="$1"
351
+ local commit_body_extra="$2"
352
+
353
+ if [[ "${commit}" =~ ${GIT_LOG_PARSE_REGEX} ]]; then
354
+ if [[ -n "${commit_body_extra}" ]]; then
355
+ if [[ -n "${BASH_REMATCH[5]-}" ]]; then
356
+ BASH_REMATCH[5]="${BASH_REMATCH[5]}"$'\n'"${commit_body_extra}"
357
+ else
358
+ BASH_REMATCH[5]="${commit_body_extra}"
359
+ fi
360
+ fi
361
+ log_verbose "${BASH_REMATCH[3]}" "-q"
362
+ CHECKOUT_SHA=${BASH_REMATCH[1]}
363
+
364
+ preset_command=$(command -v parse_commit)
365
+ if [[ -n "${preset_command}" ]]; then
366
+ parse_commit BASH_REMATCH
367
+ fi
368
+ fi
369
+ }
370
+
371
+ handle_git_commits() {
372
+ log_verbose "Analyzing commits...\n"
373
+
374
+ local IFS=
375
+ local commit=""
376
+ local commit_body_extra=""
377
+ while read -r line || [[ -n "${line}" ]]; do
378
+ if [[ "${line}" == "${GIT_LOG_COMMIT_SEPARATOR}" ]]; then
379
+ if [[ -n "${commit}" ]]; then
380
+ process_commit_entry "${commit}" "${commit_body_extra}"
381
+ fi
382
+ commit=""
383
+ commit_body_extra=""
384
+ read -r commit || commit=""
385
+ else
386
+ if [[ -n "${commit}" ]]; then
387
+ if [[ -z "${commit_body_extra}" ]]; then
388
+ commit_body_extra="${line}"
389
+ else
390
+ commit_body_extra+=$'\n'"${line}"
391
+ fi
392
+ fi
393
+ fi
394
+ done <<<"${GIT_LOGS}"
395
+ if [[ -n "${commit}" ]]; then
396
+ process_commit_entry "${commit}" "${commit_body_extra}"
397
+ fi
398
+ log_verbose "" "-q"
399
+ log_verbose "Analyzed commits!"
400
+
401
+ log_verbose "Preparing changes diff..."
402
+ build_release
403
+ log_verbose "Prepared changes diff!"
404
+
405
+ log_verbose "Analyzing updates..."
406
+ if [[ "${IS_STABLE_VERSION}" == true && "${NEXT_VERSION[0]}" -eq 0 ]]; then
407
+ NEXT_VERSION=(1 0 0)
408
+ elif [[ ${MAJOR_UPGRADED} == true && "${NEXT_VERSION[0]}" -gt 0 ]]; then
409
+ NEXT_VERSION[0]=$((NEXT_VERSION[0] + 1))
410
+ NEXT_VERSION[1]=0
411
+ NEXT_VERSION[2]=0
412
+ elif ${MINOR_UPGRADED} || [[ ${MAJOR_UPGRADED} == true && "${NEXT_VERSION[0]}" -eq 0 ]]; then
413
+ NEXT_VERSION[1]=$((NEXT_VERSION[1] + 1))
414
+ NEXT_VERSION[2]=0
415
+ elif ${PATCH_UPGRADED}; then
416
+ NEXT_VERSION[2]=$((NEXT_VERSION[2] + 1))
417
+ fi
418
+
419
+ local IFS='.'
420
+ NEXT_BUILD_VERSION="${NEXT_VERSION[*]}"
421
+ CURRENT_BUILD_VERSION="${CURRENT_VERSION[*]}"
422
+
423
+ if [[ "${NEXT_BUILD_VERSION}" == "${CURRENT_BUILD_VERSION}" ]]; then
424
+ up_to_date "Your project has no incremental update"
425
+ else
426
+ log_verbose "Analyzing updates done!"
427
+ fi
428
+
429
+ CURRENT_RELEASE_TAG=""
430
+
431
+ if ${IS_WORKSPACE}; then
432
+ NEXT_RELEASE_VERSION="v${NEXT_BUILD_VERSION}"
433
+ NEXT_RELEASE_TAG="${PKG_NAME}-${NEXT_RELEASE_VERSION}"
434
+ CURRENT_RELEASE_TAG="${PKG_NAME}-v${CURRENT_BUILD_VERSION}"
435
+ else
436
+ NEXT_RELEASE_VERSION="v${NEXT_BUILD_VERSION}"
437
+ NEXT_RELEASE_TAG="${NEXT_RELEASE_VERSION}"
438
+ CURRENT_RELEASE_TAG="v${CURRENT_BUILD_VERSION}"
439
+ fi
440
+
441
+ if [[ -n "${GIT_LAST_PROJECT_TAG_VER}" ]]; then
442
+ RELEASE_DIFF_URL="https://github.com/${GIT_REPO_NAME}/compare/${CURRENT_RELEASE_TAG}...${NEXT_RELEASE_TAG}"
443
+ RELEASE_BODY_TITLE="[${NEXT_RELEASE_TAG}](${RELEASE_DIFF_URL}) (${CURRENT_DATE})"
444
+ else
445
+ RELEASE_BODY_TITLE="${NEXT_RELEASE_TAG} (${CURRENT_DATE})"
446
+ fi
447
+
448
+ RELEASE_BODY="# ${RELEASE_BODY_TITLE}\n${RELEASE_BODY}"
449
+ }
450
+
451
+ ##############################
452
+ ######## Handle push ########
453
+ ##############################
454
+
455
+ handle_pushes() {
456
+ log_verbose "Applying changes..."
457
+ log_verbose "Found tag commit [${CHECKOUT_SHA}]"
458
+
459
+ for plugin in "${PLUGINS[@]}"; do
460
+ log_verbose "Loading plugin \`${plugin}\`..."
461
+ local SOURCE_PLUGIN_FILE="${SCRIPT_DIR}/plugins/${plugin}.sh"
462
+ # shellcheck disable=SC1090 source=/dev/null
463
+ source "${SOURCE_PLUGIN_FILE}"
464
+ release_command=$(command -v release)
465
+ if [[ -n "${release_command}" ]]; then
466
+ release
467
+ fi
468
+ unset release
469
+ log_verbose "Applied plugin ${plugin}!"
470
+ done
471
+
472
+ log_verbose "Applied changes!"
473
+ }
474
+
475
+ ##############################
476
+ ######### Initialize #########
477
+ ##############################
478
+ parse_packages
479
+ get_git_variables
480
+ get_git_commits
481
+ handle_git_commits
482
+ handle_pushes