@zairakai/js-dev-tools 2.0.0 → 3.0.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/.gitlab/ci/pipeline-js-package.yml +38 -14
- package/README.md +1 -1
- package/package.json +1 -1
- package/scripts/config.sh +53 -0
- package/scripts/eslint-fix.sh +1 -0
- package/scripts/eslint.sh +1 -0
- package/scripts/knip.sh +1 -0
- package/scripts/outdated.sh +1 -0
- package/scripts/prettier-fix.sh +1 -0
- package/scripts/prettier.sh +1 -0
- package/scripts/setup-project.sh +3 -3
- package/scripts/stylelint-fix.sh +1 -0
- package/scripts/stylelint.sh +1 -0
- package/scripts/test.sh +1 -0
- package/scripts/typecheck.sh +1 -0
- package/stubs/githooks/commit-msg +44 -19
- package/stubs/githooks/prepare-commit-msg +23 -29
- package/stubs/gitlab-ci/gitlab-ci.yml.stub +1 -1
- package/stubs/gitlab-ci/gitlab-pipeline-js-app.yml.stub +1 -1
|
@@ -40,7 +40,7 @@ include:
|
|
|
40
40
|
# ================================
|
|
41
41
|
workflow:
|
|
42
42
|
rules:
|
|
43
|
-
- if: $CI_COMMIT_TAG
|
|
43
|
+
- if: $CI_COMMIT_TAG
|
|
44
44
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
45
45
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_MERGE_REQUEST_ID
|
|
46
46
|
- if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"
|
|
@@ -137,6 +137,29 @@ secret_detection:
|
|
|
137
137
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_MERGE_REQUEST_ID
|
|
138
138
|
- if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"
|
|
139
139
|
|
|
140
|
+
# A tag whose format is not the one of VERSION_TAG_REGEX (group variable) fails here,
|
|
141
|
+
# and the jobs that publish do not run for it.
|
|
142
|
+
js:tag-format:
|
|
143
|
+
<<: *base_job
|
|
144
|
+
stage: security
|
|
145
|
+
image: ${ALPINE_IMAGE}
|
|
146
|
+
rules:
|
|
147
|
+
- if: $CI_COMMIT_TAG
|
|
148
|
+
script:
|
|
149
|
+
- |
|
|
150
|
+
regex="${VERSION_TAG_REGEX:-}"
|
|
151
|
+
regex="${regex#/}"
|
|
152
|
+
regex="${regex%/}"
|
|
153
|
+
if [ -z "$regex" ]; then
|
|
154
|
+
echo "ERROR: VERSION_TAG_REGEX is not set. It is a variable of the zairakai group."
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
157
|
+
if ! printf '%s\n' "$CI_COMMIT_TAG" | grep -Eq "$regex"; then
|
|
158
|
+
echo "ERROR: the tag \"$CI_COMMIT_TAG\" does not match $VERSION_TAG_REGEX (X.Y.Z or X.Y.Z-prerelease)."
|
|
159
|
+
exit 1
|
|
160
|
+
fi
|
|
161
|
+
echo "Tag $CI_COMMIT_TAG: format OK"
|
|
162
|
+
|
|
140
163
|
# ================================
|
|
141
164
|
# INSTALL
|
|
142
165
|
# ================================
|
|
@@ -229,7 +252,7 @@ js:quality:bats:
|
|
|
229
252
|
stage: quality
|
|
230
253
|
image: ${ALPINE_IMAGE}
|
|
231
254
|
before_script:
|
|
232
|
-
- apk add --no-cache bash bats
|
|
255
|
+
- apk add --no-cache bash bats git
|
|
233
256
|
script:
|
|
234
257
|
- |
|
|
235
258
|
if [[ -d tests/bats ]]; then
|
|
@@ -291,7 +314,7 @@ js:build:
|
|
|
291
314
|
expire_in: 1 week
|
|
292
315
|
when: on_success
|
|
293
316
|
rules:
|
|
294
|
-
- if: $CI_COMMIT_TAG =~
|
|
317
|
+
- if: $CI_COMMIT_TAG =~ $VERSION_TAG_REGEX
|
|
295
318
|
- if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"
|
|
296
319
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_MERGE_REQUEST_ID
|
|
297
320
|
|
|
@@ -303,7 +326,7 @@ js:publish:
|
|
|
303
326
|
stage: publish
|
|
304
327
|
image: ${NODE_IMAGE}
|
|
305
328
|
rules:
|
|
306
|
-
- if: $CI_COMMIT_TAG =~
|
|
329
|
+
- if: $CI_COMMIT_TAG =~ $VERSION_TAG_REGEX
|
|
307
330
|
script:
|
|
308
331
|
- |
|
|
309
332
|
if [[ -z "${NPM_TOKEN:-}" ]]; then
|
|
@@ -313,14 +336,14 @@ js:publish:
|
|
|
313
336
|
fi
|
|
314
337
|
- echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > "${CI_PROJECT_DIR}/.npmrc"
|
|
315
338
|
- |
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
else
|
|
321
|
-
echo "Invalid tag format: ${CI_COMMIT_TAG}. Expected: v1.0.0"
|
|
322
|
-
exit 1
|
|
339
|
+
# A pre-release (2.3.0-rc.1) goes to the npm tag "next", so it never becomes "latest"
|
|
340
|
+
npm_tag="latest"
|
|
341
|
+
if [[ $CI_COMMIT_TAG == *-* ]]; then
|
|
342
|
+
npm_tag="next"
|
|
323
343
|
fi
|
|
344
|
+
echo "Publishing ${NPM_PACKAGE_NAME}@${CI_COMMIT_TAG} to npm (tag ${npm_tag})..."
|
|
345
|
+
npm version "${CI_COMMIT_TAG}" --no-git-tag-version --allow-same-version
|
|
346
|
+
npm publish --access public --tag "${npm_tag}"
|
|
324
347
|
environment:
|
|
325
348
|
name: production
|
|
326
349
|
url: https://www.npmjs.com/package/${NPM_PACKAGE_NAME}
|
|
@@ -333,7 +356,7 @@ js:release:
|
|
|
333
356
|
stage: release
|
|
334
357
|
image: ${RELEASE_CLI_IMAGE}
|
|
335
358
|
rules:
|
|
336
|
-
- if: $CI_COMMIT_TAG =~
|
|
359
|
+
- if: $CI_COMMIT_TAG =~ $VERSION_TAG_REGEX
|
|
337
360
|
before_script:
|
|
338
361
|
- apk add --no-cache bash git jq
|
|
339
362
|
- git config --global --add safe.directory '*'
|
|
@@ -341,7 +364,8 @@ js:release:
|
|
|
341
364
|
- git config --global user.email "ci@gitlab.com"
|
|
342
365
|
script:
|
|
343
366
|
- |
|
|
344
|
-
|
|
367
|
+
# Tags are listed newest first, with or without the old "v" prefix (v2.1.0 then 2.2.0)
|
|
368
|
+
PREVIOUS_TAG=$(git tag | sed -E 's/^v?(.*)$/\1 &/' | sort -k1,1 -Vr | cut -d' ' -f2 | grep -A1 -Fx "${CI_COMMIT_TAG}" | tail -n 1 || echo "")
|
|
345
369
|
if [[ -n "$PREVIOUS_TAG" && "$PREVIOUS_TAG" != "$CI_COMMIT_TAG" ]]; then
|
|
346
370
|
COMMITS=$(git log --pretty=format:"- %s" "${PREVIOUS_TAG}..${CI_COMMIT_TAG}" | head -20)
|
|
347
371
|
else
|
|
@@ -356,7 +380,7 @@ js:release:
|
|
|
356
380
|
--tag-name "${CI_COMMIT_TAG}" \
|
|
357
381
|
--name "Release ${CI_COMMIT_TAG}" \
|
|
358
382
|
--description "$(cat release_notes.md)" \
|
|
359
|
-
--assets-link "{\"name\":\"npm\",\"url\":\"https://www.npmjs.com/package/${NPM_PACKAGE_NAME}/v/${CI_COMMIT_TAG
|
|
383
|
+
--assets-link "{\"name\":\"npm\",\"url\":\"https://www.npmjs.com/package/${NPM_PACKAGE_NAME}/v/${CI_COMMIT_TAG}\"}"
|
|
360
384
|
artifacts:
|
|
361
385
|
paths:
|
|
362
386
|
- release_notes.md
|
package/README.md
CHANGED
|
@@ -146,7 +146,7 @@ Include in your consumer project's `.gitlab-ci.yml`:
|
|
|
146
146
|
# npm package pipeline
|
|
147
147
|
include:
|
|
148
148
|
- project: 'zairakai/npm-packages/js-dev-tools'
|
|
149
|
-
ref:
|
|
149
|
+
ref: 1.0.0 # pin to a release tag for reproducible builds
|
|
150
150
|
file: '.gitlab/ci/pipeline-js-package.yml'
|
|
151
151
|
|
|
152
152
|
variables:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zairakai/js-dev-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "The unified and centralized development toolkit for JavaScript/TypeScript projects - ESLint, Prettier, Stylelint, Knip, Vitest, Git Hooks, and GitLab CI pipeline templates",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dev-tools",
|
package/scripts/config.sh
CHANGED
|
@@ -43,6 +43,59 @@ detect_project_type() {
|
|
|
43
43
|
PROJECT_TYPE="$(detect_project_type)"
|
|
44
44
|
export PROJECT_TYPE
|
|
45
45
|
|
|
46
|
+
# ─── DOCKER AUTO-DISPATCH ──────────────────────────────────────────────────────
|
|
47
|
+
# Tool scripts that need a real Node runtime (eslint, prettier, stylelint, knip,
|
|
48
|
+
# tsc/vue-tsc, vitest, npm outdated) call maybe_dockerize right after sourcing
|
|
49
|
+
# this file. When a docker-compose stack is already running for this project,
|
|
50
|
+
# the script transparently re-execs itself inside the "node" service instead of
|
|
51
|
+
# depending on whatever Node happens to be on the host.
|
|
52
|
+
#
|
|
53
|
+
# Utility scripts (doctor.sh, install-hooks.sh, git-*.sh, setup-project.sh) never
|
|
54
|
+
# call this — they inspect or act on the host on purpose and must keep doing so.
|
|
55
|
+
#
|
|
56
|
+
# Opt out with DEV_TOOLS_NO_DOCKER=true. Override target service/mount with
|
|
57
|
+
# DEV_TOOLS_NODE_SERVICE / DEV_TOOLS_NODE_SERVICE_MOUNT if a project's compose
|
|
58
|
+
# file diverges from the "node" / "/app" convention.
|
|
59
|
+
DEV_TOOLS_DOCKER_ENV_VARS=(CI COVERAGE)
|
|
60
|
+
|
|
61
|
+
maybe_dockerize() {
|
|
62
|
+
local script_path="$1"
|
|
63
|
+
shift
|
|
64
|
+
|
|
65
|
+
# Already running inside a container — nothing to dispatch.
|
|
66
|
+
[[ -f /.dockerenv ]] && return 0
|
|
67
|
+
|
|
68
|
+
# Explicit opt-out.
|
|
69
|
+
[[ "${DEV_TOOLS_NO_DOCKER:-false}" == "true" ]] && return 0
|
|
70
|
+
|
|
71
|
+
# CI runners execute inside a single job image, not this dev compose stack.
|
|
72
|
+
[[ "${CI:-false}" == "true" || "${GITLAB_CI:-false}" == "true" ]] && return 0
|
|
73
|
+
|
|
74
|
+
command -v docker >/dev/null 2>&1 || return 0
|
|
75
|
+
[[ -f "${PROJECT_ROOT}/docker-compose.yml" ]] || return 0
|
|
76
|
+
|
|
77
|
+
local service="${DEV_TOOLS_NODE_SERVICE:-node}"
|
|
78
|
+
local mount="${DEV_TOOLS_NODE_SERVICE_MOUNT:-/app}"
|
|
79
|
+
|
|
80
|
+
# Only dispatch when the target service is already running — never start
|
|
81
|
+
# it as a side effect of running a quality check.
|
|
82
|
+
if ! (cd "$PROJECT_ROOT" && docker compose ps --status running --services 2>/dev/null | grep -qx "$service"); then
|
|
83
|
+
return 0
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
local rel_script="${script_path#"${PROJECT_ROOT}"/}"
|
|
87
|
+
local env_flags=()
|
|
88
|
+
local var
|
|
89
|
+
for var in "${DEV_TOOLS_DOCKER_ENV_VARS[@]}"; do
|
|
90
|
+
[[ -n "${!var:-}" ]] && env_flags+=(-e "$var")
|
|
91
|
+
done
|
|
92
|
+
|
|
93
|
+
log_step "Dispatching to '${service}' container..."
|
|
94
|
+
cd "$PROJECT_ROOT"
|
|
95
|
+
exec docker compose exec -T "${env_flags[@]}" "$service" bash "${mount}/${rel_script}" "$@"
|
|
96
|
+
}
|
|
97
|
+
export -f maybe_dockerize
|
|
98
|
+
|
|
46
99
|
# ─── BINARY PATHS ─────────────────────────────────────────────────────────────
|
|
47
100
|
BIN_DIR="${PROJECT_ROOT}/node_modules/.bin"
|
|
48
101
|
export ESLINT_BIN="${BIN_DIR}/eslint"
|
package/scripts/eslint-fix.sh
CHANGED
package/scripts/eslint.sh
CHANGED
package/scripts/knip.sh
CHANGED
package/scripts/outdated.sh
CHANGED
package/scripts/prettier-fix.sh
CHANGED
package/scripts/prettier.sh
CHANGED
package/scripts/setup-project.sh
CHANGED
|
@@ -382,7 +382,7 @@ replace_gitlab_ci_placeholders() {
|
|
|
382
382
|
fi
|
|
383
383
|
|
|
384
384
|
if [[ -n "$dev_tools_version" ]]; then
|
|
385
|
-
sed -i "s|
|
|
385
|
+
sed -i "s|ref: 0\.0\.0|ref: ${dev_tools_version}|g" "$target"
|
|
386
386
|
fi
|
|
387
387
|
}
|
|
388
388
|
|
|
@@ -417,7 +417,7 @@ publish_gitlab_ci_npm() {
|
|
|
417
417
|
|
|
418
418
|
track_published ".gitlab-ci.yml"
|
|
419
419
|
log_success "Published: .gitlab-ci.yml"
|
|
420
|
-
log_info "ref:
|
|
420
|
+
log_info "ref: 0.0.0 will be updated automatically on: ${PM} update @zairakai/js-dev-tools"
|
|
421
421
|
}
|
|
422
422
|
|
|
423
423
|
# ============================================================================
|
|
@@ -650,7 +650,7 @@ sync_gitlab_ci_ref() {
|
|
|
650
650
|
|
|
651
651
|
# Resolve installed version from the package's own package.json
|
|
652
652
|
local installed_version
|
|
653
|
-
installed_version="$(node -e "try{const p=require('${DEV_TOOLS_ROOT}/package.json');console.log(
|
|
653
|
+
installed_version="$(node -e "try{const p=require('${DEV_TOOLS_ROOT}/package.json');console.log((p.version||'').replace(/^v/,''))}catch(e){}" 2>/dev/null || echo "")"
|
|
654
654
|
|
|
655
655
|
[[ -n "$installed_version" ]] || return 0
|
|
656
656
|
|
package/scripts/stylelint-fix.sh
CHANGED
package/scripts/stylelint.sh
CHANGED
package/scripts/test.sh
CHANGED
package/scripts/typecheck.sh
CHANGED
|
@@ -1,34 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# Commit message validation hook
|
|
3
|
+
# Published by: zairakai/laravel-dev-tools. Same hook as php-dev-tools and js-dev-tools, aligned on the commit convention of the zairakai handbook
|
|
4
|
+
# (policies/git-rules.md), which is the only convention of the zairakai tools:
|
|
2
5
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
6
|
+
# <type>(<scope>): #TICKET <subject>
|
|
7
|
+
#
|
|
8
|
+
# - type: feat, fix, docs, style, refactor, perf, test, chore, ci or build
|
|
9
|
+
# - scope: optional, in lowercase
|
|
10
|
+
# - #TICKET: the number of the issue
|
|
11
|
+
# - the first line has 72 characters at most, and the second line is blank
|
|
12
|
+
#
|
|
13
|
+
# A work in progress follows the same format. The messages that Git writes itself
|
|
14
|
+
# (Merge, Revert, fixup!, squash!) are accepted as they are.
|
|
5
15
|
#
|
|
6
16
|
# To bypass (emergency only):
|
|
7
17
|
# git commit --no-verify
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
RED='\033[0;31m'
|
|
13
|
-
NC='\033[0m'
|
|
19
|
+
commit_msg_file="$1"
|
|
20
|
+
first_line=$(sed -n 1p "$commit_msg_file")
|
|
21
|
+
second_line=$(sed -n 2p "$commit_msg_file")
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
case "$first_line" in
|
|
24
|
+
"Merge "* | "Revert \""* | "fixup! "* | "squash! "* | "amend! "*) exit 0 ;;
|
|
25
|
+
esac
|
|
17
26
|
|
|
18
|
-
#
|
|
19
|
-
# Format: <type>(<scope>): <subject>
|
|
20
|
-
CONVENTIONAL_RE='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|init)(\(.+\))?!?: .+$'
|
|
27
|
+
PATTERN='^(feat|fix|docs|style|refactor|perf|test|chore|ci|build)(\([a-z0-9][a-z0-9._/-]*\))?: #[0-9]+ [^[:space:]].*$'
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
fail() {
|
|
23
30
|
echo ""
|
|
24
|
-
echo
|
|
31
|
+
echo "❌ $1"
|
|
25
32
|
echo ""
|
|
26
|
-
echo "
|
|
27
|
-
echo "
|
|
28
|
-
echo " fix: resolve a bug"
|
|
29
|
-
echo " chore(deps): update dependencies"
|
|
33
|
+
echo " Format of the zairakai handbook: <type>(<scope>): #TICKET <subject>"
|
|
34
|
+
echo " Types: feat, fix, docs, style, refactor, perf, test, chore, ci, build"
|
|
30
35
|
echo ""
|
|
31
|
-
echo "
|
|
36
|
+
echo " Your message: \"$first_line\""
|
|
37
|
+
echo ""
|
|
38
|
+
echo " Examples:"
|
|
39
|
+
echo " feat(auth): #102 add OAuth2 provider support"
|
|
40
|
+
echo " fix(api): #87 handle null response from payment gateway"
|
|
41
|
+
echo " docs: #31 update installation instructions"
|
|
32
42
|
echo ""
|
|
33
43
|
exit 1
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if ! [[ $first_line =~ $PATTERN ]]; then
|
|
47
|
+
fail "Invalid commit message format"
|
|
34
48
|
fi
|
|
49
|
+
|
|
50
|
+
if [[ ${#first_line} -gt 72 ]]; then
|
|
51
|
+
fail "The first line has ${#first_line} characters: the limit is 72"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [[ -n $second_line ]]; then
|
|
55
|
+
fail "The second line must be blank"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
echo "✅ Commit message OK"
|
|
59
|
+
exit 0
|
|
@@ -1,39 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# Prepare commit message hook - adds the ticket of the branch to the message
|
|
3
|
+
# Published by: zairakai/laravel-dev-tools. Same hook as php-dev-tools and js-dev-tools. The fix: the ticket goes after "type(scope): ",
|
|
4
|
+
# which is the form that the hook commit-msg asks for.
|
|
2
5
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
6
|
+
# Branch naming convention:
|
|
7
|
+
# feature/#123-description → "feat(scope): subject" becomes "feat(scope): #123 subject"
|
|
8
|
+
# fix/#456-bug-description → the same with #456
|
|
9
|
+
# hotfix/#789-critical → the same with #789
|
|
5
10
|
#
|
|
11
|
+
# Nothing is changed for a merge, a squash or an amend, when the message already has the ticket,
|
|
12
|
+
# or when its first line is not "type(scope): subject".
|
|
6
13
|
|
|
7
|
-
|
|
14
|
+
commit_msg_file="$1"
|
|
15
|
+
commit_source="$2"
|
|
8
16
|
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
case "$commit_source" in
|
|
18
|
+
merge | squash | commit) exit 0 ;;
|
|
19
|
+
esac
|
|
11
20
|
|
|
12
|
-
|
|
13
|
-
COMMIT_SOURCE=${2:-}
|
|
14
|
-
if [[ "$COMMIT_SOURCE" == "merge" || "$COMMIT_SOURCE" == "squash" || "$COMMIT_SOURCE" == "message" ]]; then
|
|
15
|
-
exit 0
|
|
16
|
-
fi
|
|
21
|
+
branch=$(git symbolic-ref --short HEAD 2>/dev/null)
|
|
17
22
|
|
|
18
|
-
# Extract ticket
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
TICKET="${BASH_REMATCH[0]}"
|
|
22
|
-
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
|
|
23
|
+
# Extract the ticket from a branch named type/#NUMBER-description
|
|
24
|
+
if [[ $branch =~ (feature|fix|hotfix)/#([0-9]+) ]]; then
|
|
25
|
+
ticket="#${BASH_REMATCH[2]}"
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# Before: feat: my change
|
|
28
|
-
# After: feat(ABC-123): my change
|
|
29
|
-
CONVENTIONAL_RE='^([a-z]+)(\(.*\))?!?: (.+)$'
|
|
30
|
-
if [[ $COMMIT_MSG =~ $CONVENTIONAL_RE ]]; then
|
|
31
|
-
TYPE="${BASH_REMATCH[1]}"
|
|
32
|
-
REMAINDER="${BASH_REMATCH[3]}"
|
|
33
|
-
echo "${TYPE}(${TICKET}): ${REMAINDER}" > "$COMMIT_MSG_FILE"
|
|
34
|
-
else
|
|
35
|
-
# Fallback: simple prefix
|
|
36
|
-
echo "${TICKET}: ${COMMIT_MSG}" > "$COMMIT_MSG_FILE"
|
|
37
|
-
fi
|
|
27
|
+
if ! grep -qE "${ticket}([^0-9]|$)" "$commit_msg_file"; then
|
|
28
|
+
sed -i.bak -E "1s/^([a-z]+(\([^)]*\))?: )/\1${ticket} /" "$commit_msg_file"
|
|
29
|
+
rm -f "$commit_msg_file.bak"
|
|
38
30
|
fi
|
|
39
31
|
fi
|
|
32
|
+
|
|
33
|
+
exit 0
|