├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── .github
└── workflows
│ └── gradle-ci.yaml
├── .gitignore
├── changelog_mediawiki.mustache
├── changelog_html.mustache
├── changelog.mustache
├── changelog.json
├── generate_changelog.sh
├── gradlew.bat
├── gradlew
├── LICENSE
├── README.md
├── src
└── main
│ └── java
│ └── se
│ └── bjurr
│ └── gitchangelog
│ └── main
│ └── Main.java
└── CHANGELOG.md
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | mavenCentral()
5 | mavenLocal()
6 | }
7 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomasbjerre/git-changelog-command-line/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | #Tue Oct 07 20:34:13 CEST 2025
3 | description="Command line tool that generates changelog from a GIT repository."
4 | group=se.bjurr.gitchangelog
5 | version=3.0.0
6 |
--------------------------------------------------------------------------------
/.github/workflows/gradle-ci.yaml:
--------------------------------------------------------------------------------
1 | name: Bundle Gradle CI
2 |
3 | on: [workflow_dispatch, push, pull_request]
4 |
5 | jobs:
6 | call-workflow:
7 | uses: tomasbjerre/.github/.github/workflows/bundle-gradle-ci.yaml@master
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .classpath
3 | .project
4 | .settings
5 | generated-src
6 | build
7 | target
8 | bin
9 | temp
10 | .gradle
11 | .couscous
12 | couscous.phar
13 | .okhttpcache
14 | node_modules
15 | index.js
16 | package.json
17 | package-lock.json
18 | node_modules
19 | docker/git-changelog-command-line.jar
20 | .vscode
21 | .sdkmanrc
22 |
23 |
--------------------------------------------------------------------------------
/changelog_mediawiki.mustache:
--------------------------------------------------------------------------------
1 | __NOTOC__
2 |
3 | = Git Changelog changelog =
4 | Changelog of Git Changelog.
5 |
6 | {{#tags}}
7 | == {{name}} ==
8 | {{#issues}}
9 | {{#hasIssue}}
10 | {{#hasLink}}
11 | === {{name}} [{{link}} {{issue}}] {{title}} ===
12 | {{/hasLink}}
13 | {{^hasLink}}
14 | === {{name}} {{issue}} {{title}} ===
15 | {{/hasLink}}
16 | {{/hasIssue}}
17 | {{^hasIssue}}
18 | === {{name}} ===
19 | {{/hasIssue}}
20 |
21 | {{#commits}}
22 | [https://github.com/tomasbjerre/git-changelog-lib/commit/{{hash}} {{hash}}] {{authorName}} {{commitTime}}
23 |
24 | {{{message}}}
25 |
26 |
27 | {{/commits}}
28 |
29 | {{/issues}}
30 | {{/tags}}
31 |
--------------------------------------------------------------------------------
/changelog_html.mustache:
--------------------------------------------------------------------------------
1 |
Git Changelog changelog
2 |
3 |
4 | Changelog of Git Changelog.
5 |
6 |
7 | {{#tags}}
8 | {{name}}
9 | {{#issues}}
10 | {{#hasIssue}}
11 | {{#hasLink}}
12 | {{name}} {{issue}} {{title}}
13 | {{/hasLink}}
14 | {{^hasLink}}
15 | {{name}} {{issue}} {{title}}
16 | {{/hasLink}}
17 | {{/hasIssue}}
18 | {{^hasIssue}}
19 | {{name}}
20 | {{/hasIssue}}
21 |
22 |
23 | {{#commits}}
24 | {{hash}} {{authorName}} {{commitTime}}
25 |
26 | {{{message}}}
27 |
28 |
29 |
30 | {{/commits}}
31 |
32 | {{/issues}}
33 | {{/tags}}
34 |
--------------------------------------------------------------------------------
/changelog.mustache:
--------------------------------------------------------------------------------
1 | # Git Changelog Command Line changelog
2 |
3 | Changelog of Git Changelog Command Line.
4 |
5 | {{#tags}}
6 | ## {{name}}
7 | {{#issues}}
8 | {{#hasIssue}}
9 | {{#hasLink}}
10 | ### {{name}} [{{issue}}]({{link}}) {{title}} {{#hasIssueType}} *{{issueType}}* {{/hasIssueType}} {{#hasLabels}} {{#labels}} *{{.}}* {{/labels}} {{/hasLabels}}
11 | {{/hasLink}}
12 | {{^hasLink}}
13 | ### {{name}} {{issue}} {{title}} {{#hasIssueType}} *{{issueType}}* {{/hasIssueType}} {{#hasLabels}} {{#labels}} *{{.}}* {{/labels}} {{/hasLabels}}
14 | {{/hasLink}}
15 | {{/hasIssue}}
16 | {{^hasIssue}}
17 | ### {{name}}
18 | {{/hasIssue}}
19 |
20 | {{#commits}}
21 | **{{{messageTitle}}}**
22 |
23 | {{#messageBodyItems}}
24 | * {{.}}
25 | {{/messageBodyItems}}
26 |
27 | [{{hash}}](https://github.com/tomasbjerre/git-changelog-command-line/commit/{{hash}}) {{authorName}} *{{commitTime}}*
28 |
29 | {{/commits}}
30 |
31 | {{/issues}}
32 | {{/tags}}
33 |
--------------------------------------------------------------------------------
/changelog.json:
--------------------------------------------------------------------------------
1 | {
2 | "templatePath": "changelog.json",
3 | "fromRepo": ".",
4 | "fromCommit": "0000000000000000000000000000000000000000",
5 | "toRef": "refs/heads/master",
6 | "ignoreCommitsIfMessageMatches": "^\\[maven-release-plugin\\].*|^\\[Gradle Release Plugin\\].*|^Merge.*",
7 | "readableTagName": "/([^/]+?)$",
8 | "dateFormat": "YYYY-MM-dd HH:mm:ss",
9 | "untaggedName": "Next release",
10 | "noIssueName": "Other changes",
11 | "timeZone": "UTC",
12 | "removeIssueFromMessage": "true",
13 | "jiraServer": "https://jiraserver/jira",
14 | "jiraIssuePattern": "\\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b",
15 | "gitHubApi": "https://api.github.com/repos/tomasbjerre/git-changelog-command-line",
16 | "gitHubIssuePattern": "#([0-9]+)",
17 | "customIssues": [
18 | {
19 | "name": "Incident",
20 | "pattern": "INC[0-9]*",
21 | "link": "http://inc/${PATTERN_GROUP}"
22 | },
23 | {
24 | "name": "CQ",
25 | "pattern": "CQ([0-9]+)",
26 | "link": "http://cq/${PATTERN_GROUP_1}"
27 | },
28 | {
29 | "name": "Bugs",
30 | "pattern": "#bug"
31 | }
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/generate_changelog.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 | ROOT_FOLDER=`pwd`
3 | cd build/libs
4 |
5 | VERSION=1.100.2
6 |
7 | java -jar git-changelog-command-line-$VERSION.jar -h
8 |
9 | #
10 | #Actual changelog to be used in root of repo
11 | #
12 |
13 | java -jar git-changelog-command-line-$VERSION.jar -gapi https://api.github.com/repos/tomasbjerre/git-changelog-command-line/ -gtok $GITHUB_OAUTH2TOKEN -t $ROOT_FOLDER/changelog.mustache -sf $ROOT_FOLDER/changelog.json -of $ROOT_FOLDER/CHANGELOG.md
14 |
15 | #java -jar git-changelog-command-line-$VERSION.jar -t $ROOT_FOLDER/changelog_mediawiki.mustache -sf $ROOT_FOLDER/changelog.json -murl http://localhost/mediawiki -mu tomas -mp tomaskod -mt "Tomas Title" -gapi https://api.github.com/repos/tomasbjerre/git-changelog-lib
16 |
17 | #
18 | #test cases
19 | #
20 |
21 | ## Print to stdout
22 | java -jar git-changelog-command-line-$VERSION.jar -t $ROOT_FOLDER/changelog.mustache -sf $ROOT_FOLDER/changelog.json --stdout -tc 224cad580426bc03027b77c1036306253cbba973
23 |
24 | ## Write to file
25 | java -jar git-changelog-command-line-$VERSION.jar -t $ROOT_FOLDER/changelog.mustache -sf $ROOT_FOLDER/changelog.json -of $ROOT_FOLDER/src/test/resources/testThatJsonCanBeUsedActual.md -tc 224cad580426bc03027b77c1036306253cbba973
26 |
27 | ## Write to file
28 | java -jar git-changelog-command-line-$VERSION.jar -t $ROOT_FOLDER/changelog.mustache -sf $ROOT_FOLDER/changelog.json -of $ROOT_FOLDER/src/test/resources/testThatCommitsCanBeIgnoredIfNoIssue.md -ini
29 |
30 | ## Ignore tags example, ignoring all 1.1x
31 | java -jar git-changelog-command-line-$VERSION.jar -t $ROOT_FOLDER/changelog.mustache -sf $ROOT_FOLDER/changelog.json -of $ROOT_FOLDER/src/test/resources/testThatTagsCanBeIgnored.md -itp ".*[0-9]{2}$"
32 |
33 | ## Create MediaWiki page
34 | java -jar git-changelog-command-line-$VERSION.jar -t $ROOT_FOLDER/changelog_mediawiki.mustache -sf $ROOT_FOLDER/changelog.json -murl http://localhost/mediawiki -mu tomas -mp tomaskod -mt "Tomas Title" -tc 224cad580426bc03027b77c1036306253cbba973
35 |
36 | ## Use variables from command line
37 | java -jar git-changelog-command-line-$VERSION.jar -ex "{\"var1\":\"value1\"}" -tec "extended variable: {{extended.var1}}" -of $ROOT_FOLDER/src/test/resources/testThatVariablesCanBeUsed.md
38 |
39 | ## Use GitLab issues
40 | java -jar git-changelog-command-line-$VERSION.jar -fc 67b9976 -tc e281256 -gls https://gitlab.com/ -glt $GITLAB_TOKEN -glpn violations-test -t $ROOT_FOLDER/changelog.mustache -of $ROOT_FOLDER/src/test/resources/gitLabChangelog.md
41 |
42 | ## Ignore tags older
43 | java -jar git-changelog-command-line-$VERSION.jar -t $ROOT_FOLDER/changelog.mustache -of $ROOT_FOLDER/src/test/resources/testThatCommitsCanBeIgnoredByTime.md -iot "2017-04-01 00:00:00"
44 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 |
74 |
75 | @rem Execute Gradle
76 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
77 |
78 | :end
79 | @rem End local scope for the variables with windows NT shell
80 | if %ERRORLEVEL% equ 0 goto mainEnd
81 |
82 | :fail
83 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
84 | rem the _cmd.exe /c_ return code!
85 | set EXIT_CODE=%ERRORLEVEL%
86 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
87 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
88 | exit /b %EXIT_CODE%
89 |
90 | :mainEnd
91 | if "%OS%"=="Windows_NT" endlocal
92 |
93 | :omega
94 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 | # SPDX-License-Identifier: Apache-2.0
19 | #
20 |
21 | ##############################################################################
22 | #
23 | # Gradle start up script for POSIX generated by Gradle.
24 | #
25 | # Important for running:
26 | #
27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
28 | # noncompliant, but you have some other compliant shell such as ksh or
29 | # bash, then to run this script, type that shell name before the whole
30 | # command line, like:
31 | #
32 | # ksh Gradle
33 | #
34 | # Busybox and similar reduced shells will NOT work, because this script
35 | # requires all of these POSIX shell features:
36 | # * functions;
37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
39 | # * compound commands having a testable exit status, especially «case»;
40 | # * various built-in commands including «command», «set», and «ulimit».
41 | #
42 | # Important for patching:
43 | #
44 | # (2) This script targets any POSIX shell, so it avoids extensions provided
45 | # by Bash, Ksh, etc; in particular arrays are avoided.
46 | #
47 | # The "traditional" practice of packing multiple parameters into a
48 | # space-separated string is a well documented source of bugs and security
49 | # problems, so this is (mostly) avoided, by progressively accumulating
50 | # options in "$@", and eventually passing that to Java.
51 | #
52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
54 | # see the in-line comments for details.
55 | #
56 | # There are tweaks for specific operating systems such as AIX, CygWin,
57 | # Darwin, MinGW, and NonStop.
58 | #
59 | # (3) This script is generated from the Groovy template
60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
61 | # within the Gradle project.
62 | #
63 | # You can find Gradle at https://github.com/gradle/gradle/.
64 | #
65 | ##############################################################################
66 |
67 | # Attempt to set APP_HOME
68 |
69 | # Resolve links: $0 may be a link
70 | app_path=$0
71 |
72 | # Need this for daisy-chained symlinks.
73 | while
74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
75 | [ -h "$app_path" ]
76 | do
77 | ls=$( ls -ld "$app_path" )
78 | link=${ls#*' -> '}
79 | case $link in #(
80 | /*) app_path=$link ;; #(
81 | *) app_path=$APP_HOME$link ;;
82 | esac
83 | done
84 |
85 | # This is normally unused
86 | # shellcheck disable=SC2034
87 | APP_BASE_NAME=${0##*/}
88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 |
118 |
119 | # Determine the Java command to use to start the JVM.
120 | if [ -n "$JAVA_HOME" ] ; then
121 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
122 | # IBM's JDK on AIX uses strange locations for the executables
123 | JAVACMD=$JAVA_HOME/jre/sh/java
124 | else
125 | JAVACMD=$JAVA_HOME/bin/java
126 | fi
127 | if [ ! -x "$JAVACMD" ] ; then
128 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
129 |
130 | Please set the JAVA_HOME variable in your environment to match the
131 | location of your Java installation."
132 | fi
133 | else
134 | JAVACMD=java
135 | if ! command -v java >/dev/null 2>&1
136 | then
137 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
138 |
139 | Please set the JAVA_HOME variable in your environment to match the
140 | location of your Java installation."
141 | fi
142 | fi
143 |
144 | # Increase the maximum file descriptors if we can.
145 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
146 | case $MAX_FD in #(
147 | max*)
148 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
149 | # shellcheck disable=SC2039,SC3045
150 | MAX_FD=$( ulimit -H -n ) ||
151 | warn "Could not query maximum file descriptor limit"
152 | esac
153 | case $MAX_FD in #(
154 | '' | soft) :;; #(
155 | *)
156 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
157 | # shellcheck disable=SC2039,SC3045
158 | ulimit -n "$MAX_FD" ||
159 | warn "Could not set maximum file descriptor limit to $MAX_FD"
160 | esac
161 | fi
162 |
163 | # Collect all arguments for the java command, stacking in reverse order:
164 | # * args from the command line
165 | # * the main class name
166 | # * -classpath
167 | # * -D...appname settings
168 | # * --module-path (only if needed)
169 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
170 |
171 | # For Cygwin or MSYS, switch paths to Windows format before running java
172 | if "$cygwin" || "$msys" ; then
173 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
174 |
175 | JAVACMD=$( cygpath --unix "$JAVACMD" )
176 |
177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
178 | for arg do
179 | if
180 | case $arg in #(
181 | -*) false ;; # don't mess with options #(
182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
183 | [ -e "$t" ] ;; #(
184 | *) false ;;
185 | esac
186 | then
187 | arg=$( cygpath --path --ignore --mixed "$arg" )
188 | fi
189 | # Roll the args list around exactly as many times as the number of
190 | # args, so each arg winds up back in the position where it started, but
191 | # possibly modified.
192 | #
193 | # NB: a `for` loop captures its iteration list before it begins, so
194 | # changing the positional parameters here affects neither the number of
195 | # iterations, nor the values presented in `arg`.
196 | shift # remove old arg
197 | set -- "$@" "$arg" # push replacement arg
198 | done
199 | fi
200 |
201 |
202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
204 |
205 | # Collect all arguments for the java command:
206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
207 | # and any embedded shellness will be escaped.
208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
209 | # treated as '${Hostname}' itself on the command line.
210 |
211 | set -- \
212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
213 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
214 | "$@"
215 |
216 | # Stop when "xargs" is not available.
217 | if ! command -v xargs >/dev/null 2>&1
218 | then
219 | die "xargs is not available"
220 | fi
221 |
222 | # Use "xargs" to parse quoted args.
223 | #
224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
225 | #
226 | # In Bash we could simply go:
227 | #
228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
229 | # set -- "${ARGS[@]}" "$@"
230 | #
231 | # but POSIX shell has neither arrays nor command substitution, so instead we
232 | # post-process each arg (as a line of input to sed) to backslash-escape any
233 | # character that might be a shell metacharacter, then use eval to reverse
234 | # that process (while maintaining the separation between arguments), and wrap
235 | # the whole thing up as a single "set" statement.
236 | #
237 | # This will of course break if any of these variables contains a newline or
238 | # an unmatched quote.
239 | #
240 |
241 | eval "set -- $(
242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
243 | xargs -n1 |
244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
245 | tr '\n' ' '
246 | )" '"$@"'
247 |
248 | exec "$JAVACMD" "$@"
249 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Git Changelog Command Line
2 |
3 | [](https://maven-badges.herokuapp.com/maven-central/se.bjurr.gitchangelog/git-changelog-command-line)
4 | [](https://www.npmjs.com/package/git-changelog-command-line)
5 | [](https://www.npmjs.com/package/git-changelog-command-line)
6 | [](https://hub.docker.com/r/tomasbjerre/git-changelog-command-line/)
7 |
8 | This is a command line tool for generating a changelog, or releasenotes, from a GIT repository. It uses the [Git Changelog Lib](https://github.com/tomasbjerre/git-changelog-lib).
9 |
10 | This is a Java application (runnable `jar`) packaged into an `NPM` package for convenience.
11 |
12 | - The runnable `jar` can be found in [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22git-changelog-command-line%22) and used like `java -jar git-changelog-command-line-*.jar ....`.
13 | - The `npm` package can be found in [NPM](https://www.npmjs.com/package/git-changelog-command-line).
14 | - The `Docker` image can be found in [Dockerhub](https://hub.docker.com/r/tomasbjerre/git-changelog-command-line) and used like `docker run --mount src="$(pwd)",target=/usr/src/git-changelog-command-line,type=bind tomasbjerre/git-changelog-command-line:X --help`.
15 |
16 | | Version | Java Version |
17 | | ------------------------ | ------------ |
18 | | version < 2.0.0 | 8 |
19 | | 2.0.0 <= version < 2.3.0 | 11 |
20 | | 2.3.0 <= version | 17 |
21 |
22 | ## Example - Simple
23 |
24 | A changelog can be created like this.
25 |
26 | ```shell
27 | npx git-changelog-command-line -std
28 | ```
29 |
30 | Or, you can specify a template:
31 |
32 | ```shell
33 | npx git-changelog-command-line -std -tec "
34 | # Changelog
35 |
36 | Changelog.
37 |
38 | {{#tags}}
39 | ## {{name}}
40 | {{#issues}}
41 | {{#hasIssue}}
42 | {{#hasLink}}
43 | ### {{name}} [{{issue}}]({{link}}) {{title}} {{#hasIssueType}} *{{issueType}}* {{/hasIssueType}} {{#hasLabels}} {{#labels}} *{{.}}* {{/labels}} {{/hasLabels}}
44 | {{/hasLink}}
45 | {{^hasLink}}
46 | ### {{name}} {{issue}} {{title}} {{#hasIssueType}} *{{issueType}}* {{/hasIssueType}} {{#hasLabels}} {{#labels}} *{{.}}* {{/labels}} {{/hasLabels}}
47 | {{/hasLink}}
48 | {{/hasIssue}}
49 | {{^hasIssue}}
50 | ### {{name}}
51 | {{/hasIssue}}
52 |
53 | {{#commits}}
54 | **{{{messageTitle}}}**
55 |
56 | {{#messageBodyItems}}
57 | * {{.}}
58 | {{/messageBodyItems}}
59 |
60 | [{{hash}}](https://github.com/{{ownerName}}/{{repoName}}/commit/{{hash}}) {{authorName}} *{{commitTime}}*
61 |
62 | {{/commits}}
63 |
64 | {{/issues}}
65 | {{/tags}}
66 | "
67 | ```
68 |
69 | ## Example - Semantic versioning from conventional commits
70 |
71 | If you are using [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/):
72 |
73 | ```shell
74 | [optional scope]:
75 |
76 | [optional body]
77 |
78 | [optional footer(s)]
79 | ```
80 |
81 | The highest version can be determined with:
82 |
83 | ```shell
84 |
85 | highestTag=$(npx git-changelog-command-line \
86 | --print-highest-version-tag)
87 |
88 | echo Last release detected as $highestTag
89 | ```
90 |
91 | You can also get the tag with `--print-highest-version-tag`. Highest version may be `1.2.3` and highest tag may be `v1.2.3`.
92 |
93 | Next version to release can be determined with:
94 |
95 | ```shell
96 | nextVersion=$(npx git-changelog-command-line \
97 | --print-next-version)
98 |
99 | echo Next release based on commits is: $nextVersion
100 | ```
101 |
102 | There are default patterns, but you can specify the patterns with:
103 |
104 | - `--major-version-pattern REGEXP`
105 | - `--minor-version-pattern REGEXP`
106 | - `--patch-version-pattern REGEXP`
107 |
108 | By default it will match anything as patch, like `chore: whatever` and not only `fix: whatever`. You can change that with:
109 |
110 | ```shell
111 | highestVersion=$(npx git-changelog-command-line \
112 | --print-highest-version)
113 |
114 | highestVersionTag=$(npx git-changelog-command-line \
115 | --print-highest-version-tag)
116 |
117 | currentVersion=$(npx git-changelog-command-line \
118 | --patch-version-pattern "^fix.*" \
119 | --print-current-version)
120 |
121 | if [ -z "$highestVersionTag" ]; then
122 | echo "This is the first version in the repo, using 0.0.1 as version"
123 | currentVersion=0.0.1
124 | else if [ "$currentVersion" == "$highestVersion" ]; then
125 | echo "No changes made that can be released"
126 | else
127 | echo "Changes detected and a new $currentVersion release can be made"
128 | fi
129 | ```
130 |
131 | A changelog can be rendered (using [Helpers](https://github.com/tomasbjerre/git-changelog-lib#Helpers)) like this:
132 |
133 | ```shell
134 | npx git-changelog-command-line \
135 | --to-ref HEAD \
136 | --stdout \
137 | --template-content "
138 | # Changelog
139 |
140 | {{#tags}}
141 | {{#ifReleaseTag .}}
142 | ## [{{name}}](https://github.com/tomasbjerre/someproject/compare/{{name}}) ({{tagDate .}})
143 |
144 | {{#ifContainsType commits type='feat'}}
145 | ### Features
146 |
147 | {{#commits}}
148 | {{#ifCommitType . type='feat'}}
149 | - {{#eachCommitScope .}} **{{.}}** {{/eachCommitScope}} {{{commitDescription .}}} ([{{hash}}](https://github.com/tomasbjerre/someproject/commit/{{hashFull}}))
150 | {{/ifCommitType}}
151 | {{/commits}}
152 | {{/ifContainsType}}
153 |
154 | {{#ifContainsType commits type='fix'}}
155 | ### Bug Fixes
156 |
157 | {{#commits}}
158 | {{#ifCommitType . type='fix'}}
159 | - {{#eachCommitScope .}} **{{.}}** {{/eachCommitScope}} {{{commitDescription .}}} ([{{hash}}](https://github.com/tomasbjerre/someproject/commit/{{hashFull}}))
160 | {{/ifCommitType}}
161 | {{/commits}}
162 | {{/ifContainsType}}
163 |
164 | {{/ifReleaseTag}}
165 | {{/tags}}
166 | "
167 | ```
168 |
169 | Or you can prepend to the current changelog. You may get `$nextVersion` from `--print-next-version` and `$highestTag` from `--print-highest-version-tag`. Somehting like this:
170 |
171 | ```shell
172 | npx git-changelog-command-line \
173 | --from-ref $highestTag \
174 | --to-ref HEAD \
175 | --prepend-to-file CHANGELOG.md \
176 | --template-content "
177 | ## $nextVersion
178 |
179 | {{#ifContainsType commits type='feat'}}
180 | ## Features
181 | {{#commits}}
182 | {{#ifCommitType . type='feat'}}
183 | {{#eachCommitScope .}} **{{.}}** {{/eachCommitScope}} {{{commitDescription .}}} ([{{hash}}](https://github.com/tomasbjerre/someproject/commit/{{hashFull}}))
184 | {{/ifCommitType}}
185 | {{/commits}}
186 | {{/ifContainsType}}
187 |
188 | {{#ifContainsType commits type='fix'}}
189 | ## Bug Fixes
190 | {{#commits}}
191 | {{#ifCommitType . type='fix'}}
192 | {{#eachCommitScope .}} **{{.}}** {{/eachCommitScope}} {{{commitDescription .}}} ([{{hash}}](https://github.com/tomasbjerre/someproject/commit/{{hashFull}}))
193 | {{/ifCommitType}}
194 | {{/commits}}
195 | {{/ifContainsType}}
196 | "
197 | ```
198 |
199 | ### Example NPM and `package.json`
200 |
201 | If you are using NPM, you may want to add this to your `package.json`:
202 |
203 | ```json
204 | {
205 | "scripts": {
206 | "build": "echo build it...",
207 | "release": "npm run set-version; npm run build && npm publish && npm run changelog",
208 | "set-version": "npm version $(npx git-changelog-command-line --print-next-version)",
209 | "changelog": "npx git-changelog-command-line -of CHANGELOG.md && git commit -a -m 'chore: changelog' && git push --follow-tags"
210 | }
211 | }
212 | ```
213 |
214 | And if you do `npm run release` it will:
215 |
216 | - Set version in `package.json`
217 | - Build the repo
218 | - Publish it
219 | - Update CHANGELOG.md
220 |
221 | ## Example - custom helpers
222 |
223 | You can supply your own helpers and use them in the template.
224 |
225 | ```shell
226 | npx git-changelog-command-line \
227 | --to-ref HEAD \
228 | --stdout \
229 | --template-content "
230 | {{#commits}}
231 | {{#startsWith messageTitle s='feat'}}
232 | Starts with feat: "{{messageTitle}}"
233 | first 10 letters of hash is: {{firstLetters hash number='10'}}
234 | {{/startsWith}}
235 | {{/commits}}
236 | " \
237 | --register-handlebars-helper "
238 | Handlebars.registerHelper('firstLetters', function(input, options) {
239 | const number = parseInt(options.hash['number'] || "0")
240 | return input.substring(0,number);
241 | });
242 |
243 | Handlebars.registerHelper('startsWith', function(from, options) {
244 | const s = options.hash['s']
245 | if (new RegExp('^' + s + '.*').test(from)) {
246 | return options.fn(this);
247 | } else {
248 | return options.inverse(this);
249 | }
250 | });
251 | "
252 | ```
253 |
254 | # Usage
255 |
256 | Or from command line:
257 |
258 | ```shell
259 | -cl, --custom-issue-link Custom issue link.
260 | Supports variables like
261 | ${PATTERN_GROUP_1} to inject variables
262 | from pattern.
263 | : any string
264 | Default: null
265 | -cn, --custom-issue-name Custom issue name.
266 | : any string
267 | Default: null
268 | -cp, --custom-issue-pattern Custom issue pattern.
269 | : any string
270 | Default: null
271 | -ct, --custom-issue-title Custom issue title.
272 | Supports variables like
273 | ${PATTERN_GROUP_1} to inject variables
274 | from pattern.
275 | : any string
276 | Default: null
277 | -df, --date-format Format to use when
278 | printing dates.
279 | : any string
280 | Default: YYYY-MM-dd HH:mm:ss
281 | -eh, --extended-headers Extended headers that
282 | will send when access JIRA.
283 | e.g. -eh CF-Access-
284 | Client-ID:abcde12345xyz.access [Supports Multiple occurrences]
285 | : any string
286 | Default: Empty list
287 | -en, --encoding Encoding to use when
288 | writing content.
289 | : any string
290 | Default: UTF-8
291 | -ex, --extended-variables Extended variables
292 | that will be available as
293 | {{extended.*}}. -ex "{\"var1\": \"
294 | val1\"}" will print out "val1"
295 | for a template like
296 | "{{extended.var1}}"
297 | : any string
298 | Default:
299 | -fre, --from-revision From revision.
300 | : any string
301 | Default: 0000000000000000000000000000000000000000
302 | -frei, --from-revision-inclusiveness Include, or exclude,
303 | specified revision.
304 | : {INCLUSIVE | EXCLUSIVE | DEFAULT}
305 | Default: DEFAULT
306 | -gapi, --github-api GitHub API. Like:
307 | https://api.github.
308 | com/repos/tomasbjerre/git-changelog-command-line/
309 | : any string
310 | Default:
311 | -ge, --github-enabled Enable parsing for
312 | GitHub issues.
313 | Default: disabled
314 | -gl, --gitlab-enabled Enable parsing for
315 | GitLab issues.
316 | Default: disabled
317 | -glp, --gitlab-issue-pattern GitLab issue pattern.
318 | : any string
319 | Default:
320 | -glpn, --gitlab-project-name GitLab project name.
321 | : any string
322 | Default:
323 | -gls, --gitlab-server GitLab server, like
324 | https://gitlab.com/.
325 | : any string
326 | Default:
327 | -glt, --gitlab-token GitLab API token.
328 | : any string
329 | Default:
330 | -gtok, --github-token GitHub API OAuth2
331 | token. You can get it from:
332 | curl -u 'yourgithubuser' -d
333 | '{"note":"Git Changelog Lib"}'
334 | https://api.github.
335 | com/authorizations
336 | : any string
337 | Default:
338 | -h, --help : an argument to print help for
339 | Default: If no specific parameter is given the whole usage text is given
340 | -handlebars-helper-file, -hhf Can be used to add
341 | extra helpers.
342 | : a file path
343 | Default: /home/bjerre/workspace/git-changelog/git-changelog-command-line/.
344 | -ini, --ignore-commits-without-issue Ignore commits that is
345 | not included in any issue.
346 | Default: disabled
347 | -iot, --ignore-older-than Ignore commits older
348 | than yyyy-MM-dd HH:mm:ss.
349 | : any string
350 | Default:
351 | -ip, --ignore-pattern Ignore commits where
352 | pattern matches message.
353 | : any string
354 | Default: ^Merge.*
355 | -itp, --ignore-tag-pattern Ignore tags that
356 | matches regular expression.
357 | Can be used to ignore
358 | release candidates and only
359 | include actual releases.
360 | : any string
361 | Default: null
362 | -jaf, --jira-additional-field Adds an additional
363 | field for Jira. When
364 | configured, we will return from
365 | Jira the result of this
366 | field, if it exists. [Supports Multiple occurrences]
367 | : any string
368 | Default: Empty list
369 | -jba, --jira-basic-auth Optional token to
370 | authenticate with Jira.
371 | : any string
372 | Default: \\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b
373 | -jbt, --jira-bearer Optional token to
374 | authenticate with Jira.
375 | : any string
376 | Default: \\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b
377 | -je, --jira-enabled Enable parsing for
378 | Jira issues.
379 | Default: disabled
380 | -jp, --jira-pattern Jira issue pattern.
381 | : any string
382 | Default: \\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b
383 | -jpw, --jira-password Optional password to
384 | authenticate with Jira.
385 | : any string
386 | Default: \\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b
387 | -js, --jiraServer, --jira-server Jira server. When a
388 | Jira server is given, the
389 | title of the Jira issues can
390 | be used in the changelog.
391 | : any string
392 | Default: null
393 | -ju, --jira-username Optional username to
394 | authenticate with Jira.
395 | : any string
396 | Default: \\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b
397 | -mavp, --major-version-pattern Commit messages
398 | matching this, optional,
399 | regular expression will
400 | trigger new major version.
401 | : any string
402 | Default: null
403 | -mivp, --minor-version-pattern Commit messages
404 | matching this, optional,
405 | regular expression will
406 | trigger new minor version.
407 | : any string
408 | Default: ^[Ff]eat.*
409 | -ni, --no-issue-name Name of virtual issue
410 | that contains commits that
411 | has no issue associated.
412 | : any string
413 | Default: No issue
414 | -of, --output-file Write output to file.
415 | : any string
416 | Default:
417 | -pavp, --patch-version-pattern Commit messages
418 | matching this, optional,
419 | regular expression will
420 | trigger new patch version.
421 | : any string
422 | Default: null
423 | -pcv, --print-current-version Like --print-next-
424 | version unless the current
425 | commit is tagged with a
426 | version, if so it will print
427 | that version.
428 | Default: disabled
429 | -pf, --path-filters Paths on the
430 | filesystem to filter on. [Supports Multiple occurrences]
431 | : any string
432 | Default: Empty list
433 | -phv, --print-highest-version Print the highest
434 | version, determined by tags in
435 | repo, and exit.
436 | Default: disabled
437 | -phvt, --print-highest-version-tag Print the tag
438 | corresponding to highest version,
439 | and exit.
440 | Default: disabled
441 | -pnv, --print-next-version Print the next
442 | version, determined by commits
443 | since highest version, and
444 | exit.
445 | Default: disabled
446 | -pt, --prepend-template Template to use when
447 | prepending. A default template
448 | will be used if not
449 | specified.
450 | : any string
451 | Default: changelog-prepend.mustache
452 | -ptf, --prepend-to-file Add the changelog to
453 | top of given file.
454 | : any string
455 | Default: null
456 | -r, --repo Repository.
457 | : any string
458 | Default: .
459 | -re, --redmine-enabled Enable parsing for
460 | Redmine issues.
461 | Default: disabled
462 | -rhh, --register-handlebars-helper Handlebar helpers,
463 | https://handlebarsjs.
464 | com/guide/block-helpers.html, to
465 | register and use in given
466 | template.
467 | : any string
468 | Default:
469 | -ri, --remove-issue-from-message Dont print any issues
470 | in the messages of
471 | commits.
472 | Default: disabled
473 | -rmp, --redmine-pattern Redmine issue pattern.
474 | : any string
475 | Default: #([0-9]+)
476 | -rmpw, --redmine-password Optional password to
477 | authenticate with Redmine.
478 | : any string
479 | Default:
480 | -rms, --redmine-server Redmine server. When a
481 | Redmine server is given, the
482 | title of the Redmine issues
483 | can be used in the
484 | changelog.
485 | : any string
486 | Default: null
487 | -rmt, --redmine-token Optional token/api-key
488 | to authenticate with
489 | Redmine.
490 | : any string
491 | Default:
492 | -rmu, --redmine-username Optional username to
493 | authenticate with Redmine.
494 | : any string
495 | Default:
496 | -rt, --readable-tag-name Pattern to extract
497 | readable part of tag.
498 | : any string
499 | Default: /([^/]+?)$
500 | -sf, --settings-file Use settings from file.
501 | : any string
502 | Default: null
503 | --show-debug-info Please run your
504 | command with this parameter
505 | and supply output when
506 | reporting bugs.
507 | Default: disabled
508 | -std, --stdout Print builder to
509 | .
510 | Default: disabled
511 | -t, --template Template to use. A
512 | default template will be used
513 | if not specified.
514 | : any string
515 | Default: changelog.mustache
516 | -tbd, --template-base-dir Base dir of templates.
517 | : any string
518 | Default: null
519 | -tec, --template-content String to use as
520 | template.
521 | : any string
522 | Default:
523 | -tps, --template-partial-suffix File ending for
524 | partials.
525 | : any string
526 | Default: .hbs
527 | -tre, --to-revision To revision.
528 | : any string
529 | Default: refs/heads/master
530 | -trei, --to-revision-inclusiveness Include, or exclude,
531 | specified revision.
532 | : {INCLUSIVE | EXCLUSIVE | DEFAULT}
533 | Default: DEFAULT
534 | -tz, --time-zone TimeZone to use when
535 | printing dates.
536 | : any string
537 | Default: UTC
538 | -ui, --use-integrations Use integrations to
539 | get more details on
540 | commits.
541 | Default: disabled
542 | -ut, --untagged-name When listing commits
543 | per tag, this will by the
544 | name of a virtual tag that
545 | contains commits not available
546 | in any git tag.
547 | : any string
548 | Default: No tag
549 | ```
550 |
551 | ## Usage - template base dir
552 |
553 | You can use [partials](http://jknack.github.io/handlebars.java/reuse.html) in your templates.
554 |
555 | `/dir/changelog.hbs`
556 |
557 | ```hbs
558 | {{#commits}}
559 | {{> commit}}
560 | {{/commits}}
561 | ```
562 |
563 | `/dir/base/commit.partial`
564 |
565 | ```hbs
566 | ## {{authorName}} - {{commitTime}}
567 | [{{hashFull}}](https://server/{{hash}})
568 | {{{message}}}
569 | ```
570 |
571 | This is configured like:
572 |
573 | ```sh
574 | npx git-changelog-command-line -std \
575 | --template-base-dir /dir/base \
576 | --template /dir/changelog.hbs
577 | ```
578 |
579 | If partials have a different ending, you can specify that with `--template-partial-suffix`.
580 |
--------------------------------------------------------------------------------
/src/main/java/se/bjurr/gitchangelog/main/Main.java:
--------------------------------------------------------------------------------
1 | package se.bjurr.gitchangelog.main;
2 |
3 | import static se.bjurr.gitchangelog.api.GitChangelogApi.gitChangelogApiBuilder;
4 | import static se.bjurr.gitchangelog.api.GitChangelogApiConstants.DEFAULT_DATEFORMAT;
5 | import static se.bjurr.gitchangelog.internal.settings.Settings.defaultSettings;
6 | import static se.softhouse.jargo.Arguments.enumArgument;
7 | import static se.softhouse.jargo.Arguments.fileArgument;
8 | import static se.softhouse.jargo.Arguments.helpArgument;
9 | import static se.softhouse.jargo.Arguments.optionArgument;
10 | import static se.softhouse.jargo.Arguments.stringArgument;
11 | import static se.softhouse.jargo.CommandLineParser.withArguments;
12 |
13 | import com.google.gson.Gson;
14 | import com.google.gson.GsonBuilder;
15 | import com.google.gson.reflect.TypeToken;
16 | import java.io.File;
17 | import java.lang.reflect.Type;
18 | import java.nio.charset.Charset;
19 | import java.nio.charset.StandardCharsets;
20 | import java.nio.file.Files;
21 | import java.text.SimpleDateFormat;
22 | import java.util.Date;
23 | import java.util.HashMap;
24 | import java.util.List;
25 | import java.util.Map;
26 | import se.bjurr.gitchangelog.api.GitChangelogApi;
27 | import se.bjurr.gitchangelog.api.GitChangelogApiConstants;
28 | import se.bjurr.gitchangelog.api.InclusivenessStrategy;
29 | import se.bjurr.gitchangelog.internal.semantic.SemanticVersion;
30 | import se.bjurr.gitchangelog.internal.settings.Settings;
31 | import se.softhouse.jargo.Argument;
32 | import se.softhouse.jargo.ArgumentException;
33 | import se.softhouse.jargo.ParsedArguments;
34 |
35 | public class Main {
36 | private static final String PARAM_REGISTER_HANDLEBARS_HELPER = "-rhh";
37 | private static final String PARAM_PRINT_HIGHEST_VERSION = "-phv";
38 | private static final String PARAM_PRINT_HIGHEST_VERSION_TAG = "-phvt";
39 | private static final String PARAM_PRINT_NEXT_VERSION = "-pnv";
40 | private static final String PARAM_PRINT_CURRENT_VERSION = "-pcv";
41 | private static final String PARAM_PATCH_VERSION_PATTERN = "-pavp";
42 | private static final String PARAM_MINOR_VERSION_PATTERN = "-mivp";
43 | private static final String PARAM_MAJOR_VERSION_PATTERN = "-mavp";
44 | private static final String PARAM_PREPEND_TO_FILE = "-ptf";
45 | public static final String PARAM_SETTINGS_FILE = "-sf";
46 | public static final String PARAM_OUTPUT_FILE = "-of";
47 | public static final String PARAM_OUTPUT_STDOUT = "-std";
48 | public static final String PARAM_TEMPLATE = "-t";
49 | public static final String PARAM_PREPEND_TEMPLATE = "-pt";
50 | public static final String PARAM_TEMPLATE_BASE_DIR = "-tbd";
51 | public static final String PARAM_TEMPLATE_PARTIAL_SUFFIX = "-tps";
52 | public static final String PARAM_REPO = "-r";
53 | public static final String PARAM_FROM_REF = "-fr";
54 | public static final String PARAM_TO_REF = "-tr";
55 | public static final String PARAM_FROM_REV = "-fre";
56 | public static final String PARAM_FROM_REV_INCLUDE = "-frei";
57 | public static final String PARAM_TO_REV = "-tre";
58 | public static final String PARAM_TO_REV_INCLUDE = "-trei";
59 | public static final String PARAM_FROM_COMMIT = "-fc";
60 | public static final String PARAM_TO_COMMIT = "-tc";
61 | public static final String PARAM_IGNORE_PATTERN = "-ip";
62 | public static final String PARAM_IGNORE_OLDER_PATTERN = "-iot";
63 | public static final String PARAM_IGNORE_TAG_PATTERN = "-itp";
64 | public static final String PARAM_JIRA_SERVER = "-js";
65 | public static final String PARAM_JIRA_ISSUE_PATTERN = "-jp";
66 | public static final String PARAM_JIRA_USERNAME = "-ju";
67 | public static final String PARAM_JIRA_PASSWORD = "-jpw";
68 | public static final String PARAM_JIRA_BASIC_AUTH = "-jba";
69 | public static final String PARAM_JIRA_BEARER = "-jbt";
70 | public static final String PARAM_JIRA_ADDITIONAL_FIELD = "-jaf";
71 | public static final String PARAM_REDMINE_SERVER = "-rms";
72 | public static final String PARAM_REDMINE_ISSUE_PATTERN = "-rmp";
73 | public static final String PARAM_REDMINE_USERNAME = "-rmu";
74 | public static final String PARAM_REDMINE_PASSWORD = "-rmpw";
75 | public static final String PARAM_REDMINE_TOKEN = "-rmt";
76 | public static final String PARAM_CUSTOM_ISSUE_NAME = "-cn";
77 | public static final String PARAM_CUSTOM_ISSUE_PATTERN = "-cp";
78 | public static final String PARAM_CUSTOM_ISSUE_LINK = "-cl";
79 | public static final String PARAM_CUSTOM_ISSUE_TITLE = "-ct";
80 | public static final String PARAM_UNTAGGED_TAG_NAME = "-ut";
81 | public static final String PARAM_TIMEZONE = "-tz";
82 | public static final String PARAM_DATEFORMAT = "-df";
83 | public static final String PARAM_NOISSUE = "-ni";
84 | public static final String PARAM_IGNORE_NOISSUE = "-ini";
85 | public static final String PARAM_READABLETAGNAME = "-rt";
86 | public static final String PARAM_REMOVEISSUE = "-ri";
87 | public static final String PARAM_GITHUBAPI = "-gapi";
88 | public static final String PARAM_GITHUBTOKEN = "-gtok";
89 | public static final String PARAM_EXTENDED_VARIABLES = "-ex";
90 | public static final String PARAM_EXTENDED_HEADERS = "-eh";
91 | public static final String PARAM_TEMPLATE_CONTENT = "-tec";
92 | public static final String PARAM_GITLABTOKEN = "-glt";
93 | public static final String PARAM_GITLABSERVER = "-gls";
94 | public static final String PARAM_GITLABPROJECTNAME = "-glpn";
95 | public static final String PARAM_GITLABISSUEPATTERN = "-glp";
96 |
97 | private static String systemOutPrintln;
98 | private static boolean recordSystemOutPrintln;
99 |
100 | public static void main(final String args[]) throws Exception {
101 | final Settings defaultSettings = defaultSettings();
102 | final Argument> helpArgument = helpArgument("-h", "--help");
103 |
104 | final Argument settingsArgument =
105 | stringArgument(PARAM_SETTINGS_FILE, "--settings-file") //
106 | .description("Use settings from file.") //
107 | .defaultValue(null) //
108 | .build();
109 | final Argument outputStdoutArgument =
110 | optionArgument(PARAM_OUTPUT_STDOUT, "--stdout") //
111 | .description("Print builder to .") //
112 | .build();
113 | final Argument outputFileArgument =
114 | stringArgument(PARAM_OUTPUT_FILE, "--output-file") //
115 | .description("Write output to file.") //
116 | .build();
117 |
118 | final Argument templatePathArgument =
119 | stringArgument(PARAM_TEMPLATE, "--template") //
120 | .description("Template to use. A default template will be used if not specified.") //
121 | .defaultValue(defaultSettings.getTemplatePath()) //
122 | .build();
123 |
124 | final Argument prependTemplatePathArgument =
125 | stringArgument(PARAM_PREPEND_TEMPLATE, "--prepend-template") //
126 | .description(
127 | "Template to use when prepending. A default template will be used if not specified.") //
128 | .defaultValue(defaultSettings.getPrependTemplatePath()) //
129 | .build();
130 |
131 | final Argument templateBaseDirArgument =
132 | stringArgument(PARAM_TEMPLATE_BASE_DIR, "--template-base-dir") //
133 | .description("Base dir of templates.") //
134 | .defaultValue(defaultSettings.getTemplateBaseDir()) //
135 | .build();
136 |
137 | final Argument templatePartialSuffixArgument =
138 | stringArgument(PARAM_TEMPLATE_PARTIAL_SUFFIX, "--template-partial-suffix") //
139 | .description("File ending for partials.") //
140 | .defaultValue(defaultSettings.getTemplateSuffix()) //
141 | .build();
142 |
143 | final Argument untaggedTagNameArgument =
144 | stringArgument(PARAM_UNTAGGED_TAG_NAME, "--untagged-name") //
145 | .description(
146 | "When listing commits per tag, this will by the name of a virtual tag that contains commits not available in any git tag.") //
147 | .defaultValue(defaultSettings.getUntaggedName()) //
148 | .build();
149 |
150 | final Argument fromRepoArgument =
151 | stringArgument(PARAM_REPO, "--repo") //
152 | .description("Repository.") //
153 | .defaultValue(defaultSettings.getFromRepo()) //
154 | .build();
155 | final Argument fromRevArgument =
156 | stringArgument(PARAM_FROM_REV, "--from-revision") //
157 | .description("From revision.") //
158 | .defaultValue(defaultSettings.getFromRevision().orElse(null)) //
159 | .build();
160 | final Argument fromRevInclusivenessStrategyArgument =
161 | enumArgument(
162 | InclusivenessStrategy.class,
163 | PARAM_FROM_REV_INCLUDE,
164 | "--from-revision-inclusiveness") //
165 | .description("Include, or exclude, specified revision.") //
166 | .defaultValue(defaultSettings.getFromRevisionStrategy()) //
167 | .build();
168 | final Argument toRevArgument =
169 | stringArgument(PARAM_TO_REV, "--to-revision") //
170 | .description("To revision.") //
171 | .defaultValue(defaultSettings.getToRevision().orElse(null)) //
172 | .build();
173 | final Argument toRevInclusivenessStrategyArgument =
174 | enumArgument(
175 | InclusivenessStrategy.class,
176 | PARAM_TO_REV_INCLUDE,
177 | "--to-revision-inclusiveness") //
178 | .description("Include, or exclude, specified revision.") //
179 | .defaultValue(defaultSettings.getFromRevisionStrategy()) //
180 | .build();
181 | final Argument fromRefArgument =
182 | stringArgument(PARAM_FROM_REF, "--from-ref") //
183 | .description("From ref.") //
184 | .defaultValue(defaultSettings.getFromRevision().orElse(null)) //
185 | .hideFromUsage() //
186 | .build();
187 | final Argument toRefArgument =
188 | stringArgument(PARAM_TO_REF, "--to-ref") //
189 | .description("To ref.") //
190 | .defaultValue(defaultSettings.getToRevision().orElse(null)) //
191 | .hideFromUsage() //
192 | .build();
193 | final Argument fromCommitArgument =
194 | stringArgument(PARAM_FROM_COMMIT, "--from-commit") //
195 | .description("From commit.") //
196 | .defaultValue(defaultSettings.getFromRevision().orElse(null)) //
197 | .hideFromUsage() //
198 | .build();
199 | final Argument toCommitArgument =
200 | stringArgument(PARAM_TO_COMMIT, "--to-commit") //
201 | .description("To commit.") //
202 | .defaultValue(defaultSettings.getToRevision().orElse(null)) //
203 | .hideFromUsage() //
204 | .build();
205 |
206 | final Argument ignoreCommitsIfMessageMatchesArgument =
207 | stringArgument(PARAM_IGNORE_PATTERN, "--ignore-pattern") //
208 | .description("Ignore commits where pattern matches message.") //
209 | .defaultValue(defaultSettings.getIgnoreCommitsIfMessageMatches()) //
210 | .build();
211 |
212 | final Argument ignoreCommitsOlderThanArgument =
213 | stringArgument(PARAM_IGNORE_OLDER_PATTERN, "--ignore-older-than") //
214 | .description("Ignore commits older than " + DEFAULT_DATEFORMAT + ".") //
215 | .build();
216 |
217 | final Argument ignoreTagsIfNameMatchesArgument =
218 | stringArgument(PARAM_IGNORE_TAG_PATTERN, "--ignore-tag-pattern") //
219 | .description(
220 | "Ignore tags that matches regular expression. Can be used to ignore release candidates and only include actual releases.") //
221 | .defaultValue(defaultSettings.getIgnoreTagsIfNameMatches().orElse(null)) //
222 | .build();
223 |
224 | final Argument jiraServerArgument =
225 | stringArgument(PARAM_JIRA_SERVER, "--jiraServer", "--jira-server") //
226 | .description(
227 | "Jira server. When a Jira server is given, the title of the Jira issues can be used in the changelog.") //
228 | .defaultValue(defaultSettings.getJiraServer().orElse(null)) //
229 | .build();
230 | final Argument jiraIssuePatternArgument =
231 | stringArgument(PARAM_JIRA_ISSUE_PATTERN, "--jira-pattern") //
232 | .description("Jira issue pattern.") //
233 | .defaultValue(defaultSettings.getJiraIssuePattern()) //
234 | .build();
235 | final Argument jiraUsernamePatternArgument =
236 | stringArgument(PARAM_JIRA_USERNAME, "--jira-username") //
237 | .description("Optional username to authenticate with Jira.") //
238 | .defaultValue(defaultSettings.getJiraIssuePattern()) //
239 | .build();
240 | final Argument jiraPasswordPatternArgument =
241 | stringArgument(PARAM_JIRA_PASSWORD, "--jira-password") //
242 | .description("Optional password to authenticate with Jira.") //
243 | .defaultValue(defaultSettings.getJiraIssuePattern()) //
244 | .build();
245 | final Argument jiraBasicAuthStringPatternArgument =
246 | stringArgument(PARAM_JIRA_BASIC_AUTH, "--jira-basic-auth") //
247 | .description("Optional token to authenticate with Jira.") //
248 | .defaultValue(defaultSettings.getJiraIssuePattern()) //
249 | .build();
250 | final Argument jiraBearerArgument =
251 | stringArgument(PARAM_JIRA_BEARER, "--jira-bearer") //
252 | .description("Optional token to authenticate with Jira.") //
253 | .defaultValue(defaultSettings.getJiraIssuePattern()) //
254 | .build();
255 | final Argument> jiraAdditionalFieldArgument =
256 | stringArgument(PARAM_JIRA_ADDITIONAL_FIELD, "--jira-additional-field") //
257 | .repeated()
258 | .description(
259 | "Adds an additional field for Jira. When configured, we will return from Jira the result of this field, if it exists.") //
260 | .build();
261 |
262 | final Argument redmineServerArgument =
263 | stringArgument(PARAM_REDMINE_SERVER, "--redmine-server") //
264 | .description(
265 | "Redmine server. When a Redmine server is given, the title of the Redmine issues can be used in the changelog.") //
266 | .defaultValue(defaultSettings.getRedmineServer().orElse(null)) //
267 | .build();
268 | final Argument redmineIssuePatternArgument =
269 | stringArgument(PARAM_REDMINE_ISSUE_PATTERN, "--redmine-pattern") //
270 | .description("Redmine issue pattern.") //
271 | .defaultValue(defaultSettings.getRedmineIssuePattern()) //
272 | .build();
273 | final Argument redmineUsernameArgument =
274 | stringArgument(PARAM_REDMINE_USERNAME, "--redmine-username") //
275 | .description("Optional username to authenticate with Redmine.") //
276 | .build();
277 | final Argument redminePasswordArgument =
278 | stringArgument(PARAM_REDMINE_PASSWORD, "--redmine-password") //
279 | .description("Optional password to authenticate with Redmine.") //
280 | .build();
281 | final Argument redmineTokenArgument =
282 | stringArgument(PARAM_REDMINE_TOKEN, "--redmine-token") //
283 | .description("Optional token/api-key to authenticate with Redmine.") //
284 | .build();
285 |
286 | final Argument customIssueNameArgument =
287 | stringArgument(PARAM_CUSTOM_ISSUE_NAME, "--custom-issue-name") //
288 | .description("Custom issue name.") //
289 | .defaultValue(null) //
290 | .build();
291 | final Argument customIssuePatternArgument =
292 | stringArgument(PARAM_CUSTOM_ISSUE_PATTERN, "--custom-issue-pattern") //
293 | .description("Custom issue pattern.") //
294 | .defaultValue(null) //
295 | .build();
296 | final Argument customIssueLinkArgument =
297 | stringArgument(PARAM_CUSTOM_ISSUE_LINK, "--custom-issue-link") //
298 | .description(
299 | "Custom issue link. Supports variables like ${PATTERN_GROUP_1} to inject variables from pattern.") //
300 | .defaultValue(null) //
301 | .build();
302 | final Argument customIssueTitleArgument =
303 | stringArgument(PARAM_CUSTOM_ISSUE_TITLE, "--custom-issue-title") //
304 | .description(
305 | "Custom issue title. Supports variables like ${PATTERN_GROUP_1} to inject variables from pattern.") //
306 | .defaultValue(null) //
307 | .build();
308 |
309 | final Argument timeZoneArgument =
310 | stringArgument(PARAM_TIMEZONE, "--time-zone") //
311 | .description("TimeZone to use when printing dates.") //
312 | .defaultValue(defaultSettings.getTimeZone()) //
313 | .build();
314 | final Argument dateFormatArgument =
315 | stringArgument(PARAM_DATEFORMAT, "--date-format") //
316 | .description("Format to use when printing dates.") //
317 | .defaultValue(defaultSettings.getDateFormat()) //
318 | .build();
319 | final Argument noIssueArgument =
320 | stringArgument(PARAM_NOISSUE, "--no-issue-name") //
321 | .description(
322 | "Name of virtual issue that contains commits that has no issue associated.") //
323 | .defaultValue(defaultSettings.getNoIssueName()) //
324 | .build();
325 | final Argument ignoreCommitsWithoutIssueArgument =
326 | optionArgument(PARAM_IGNORE_NOISSUE, "--ignore-commits-without-issue") //
327 | .description("Ignore commits that is not included in any issue.") //
328 | .build();
329 | final Argument readableTagNameArgument =
330 | stringArgument(PARAM_READABLETAGNAME, "--readable-tag-name") //
331 | .description("Pattern to extract readable part of tag.") //
332 | .defaultValue(defaultSettings.getReadableTagName()) //
333 | .build();
334 | final Argument removeIssueFromMessageArgument =
335 | optionArgument(PARAM_REMOVEISSUE, "--remove-issue-from-message") //
336 | .description("Dont print any issues in the messages of commits.") //
337 | .build();
338 |
339 | final Argument gitHubApiArgument =
340 | stringArgument(PARAM_GITHUBAPI, "--github-api") //
341 | .description(
342 | "GitHub API. Like: https://api.github.com/repos/tomasbjerre/git-changelog-command-line/") //
343 | .defaultValue("") //
344 | .build();
345 | final Argument gitHubTokenArgument =
346 | stringArgument(PARAM_GITHUBTOKEN, "--github-token") //
347 | .description(
348 | "GitHub API OAuth2 token. You can get it from: curl -u 'yourgithubuser' -d '{\"note\":\"Git Changelog Lib\"}' https://api.github.com/authorizations") //
349 | .defaultValue("") //
350 | .build();
351 |
352 | final Argument extendedVariablesArgument =
353 | stringArgument(PARAM_EXTENDED_VARIABLES, "--extended-variables") //
354 | .description(
355 | "Extended variables that will be available as {{extended.*}}. "
356 | + PARAM_EXTENDED_VARIABLES
357 | + " \"{\\\"var1\\\": \\\"val1\\\"}\" will print out \"val1\" for a template like \"{{extended.var1}}\"") //
358 | .defaultValue("") //
359 | .build();
360 |
361 | final Argument> extendedHeadersArgument =
362 | stringArgument(PARAM_EXTENDED_HEADERS, "--extended-headers") //
363 | .repeated()
364 | .description(
365 | "Extended headers that will send when access JIRA. e.g. "
366 | + PARAM_EXTENDED_HEADERS
367 | + " CF-Access-Client-ID:abcde12345xyz.access") //
368 | .build();
369 |
370 | final Argument templateContentArgument =
371 | stringArgument(PARAM_TEMPLATE_CONTENT, "--template-content") //
372 | .description("String to use as template.") //
373 | .defaultValue("") //
374 | .build();
375 |
376 | final Argument gitLabTokenArgument =
377 | stringArgument(PARAM_GITLABTOKEN, "--gitlab-token") //
378 | .description("GitLab API token.") //
379 | .defaultValue("") //
380 | .build();
381 | final Argument gitLabServerArgument =
382 | stringArgument(PARAM_GITLABSERVER, "--gitlab-server") //
383 | .description("GitLab server, like https://gitlab.com/.") //
384 | .defaultValue("") //
385 | .build();
386 | final Argument gitLabProjectNameArgument =
387 | stringArgument(PARAM_GITLABPROJECTNAME, "--gitlab-project-name") //
388 | .description("GitLab project name.") //
389 | .defaultValue("") //
390 | .build();
391 | final Argument gitLabProjectIssuePattern =
392 | stringArgument(PARAM_GITLABISSUEPATTERN, "--gitlab-issue-pattern") //
393 | .description("GitLab issue pattern.") //
394 | .defaultValue("") //
395 | .build();
396 |
397 | final Argument printHighestVersion =
398 | optionArgument(PARAM_PRINT_HIGHEST_VERSION, "--print-highest-version") //
399 | .description("Print the highest version, determined by tags in repo, and exit.") //
400 | .defaultValue(false)
401 | .build();
402 |
403 | final Argument printHighestVersionTag =
404 | optionArgument(PARAM_PRINT_HIGHEST_VERSION_TAG, "--print-highest-version-tag") //
405 | .description("Print the tag corresponding to highest version, and exit.") //
406 | .defaultValue(false)
407 | .build();
408 |
409 | final Argument printNextVersion =
410 | optionArgument(PARAM_PRINT_NEXT_VERSION, "--print-next-version") //
411 | .description(
412 | "Print the next version, determined by commits since highest version, and exit.") //
413 | .defaultValue(false)
414 | .build();
415 |
416 | final Argument printCurrentVersion =
417 | optionArgument(PARAM_PRINT_CURRENT_VERSION, "--print-current-version") //
418 | .description(
419 | "Like --print-next-version unless the current commit is tagged with a version, if so it will print that version.") //
420 | .defaultValue(false)
421 | .build();
422 |
423 | final Argument registerHandlebarsHelper =
424 | stringArgument(PARAM_REGISTER_HANDLEBARS_HELPER, "--register-handlebars-helper") //
425 | .description(
426 | "Handlebar helpers, https://handlebarsjs.com/guide/block-helpers.html, to register and use in given template.") //
427 | .defaultValue("")
428 | .build();
429 |
430 | final Argument handlebarsHelperFile =
431 | fileArgument("-handlebars-helper-file", "-hhf")
432 | .description("Can be used to add extra helpers.")
433 | .build();
434 |
435 | final Argument prependToFile =
436 | stringArgument(PARAM_PREPEND_TO_FILE, "--prepend-to-file") //
437 | .description("Add the changelog to top of given file.") //
438 | .defaultValue(null)
439 | .build();
440 |
441 | final Argument majorVersionPattern =
442 | stringArgument(PARAM_MAJOR_VERSION_PATTERN, "--major-version-pattern") //
443 | .description(
444 | "Commit messages matching this, optional, regular expression will trigger new major version.") //
445 | .defaultValue(null)
446 | .build();
447 |
448 | final Argument minorVersionPattern =
449 | stringArgument(PARAM_MINOR_VERSION_PATTERN, "--minor-version-pattern") //
450 | .description(
451 | "Commit messages matching this, optional, regular expression will trigger new minor version.") //
452 | .defaultValue(GitChangelogApiConstants.DEFAULT_MINOR_PATTERN)
453 | .build();
454 |
455 | final Argument patchVersionPattern =
456 | stringArgument(PARAM_PATCH_VERSION_PATTERN, "--patch-version-pattern") //
457 | .description(
458 | "Commit messages matching this, optional, regular expression will trigger new patch version.") //
459 | .defaultValue(GitChangelogApiConstants.DEFAULT_PATCH_PATTERN)
460 | .build();
461 |
462 | final Argument showDebugInfo =
463 | optionArgument("--show-debug-info")
464 | .description(
465 | "Please run your command with this parameter and supply output when reporting bugs.")
466 | .build();
467 |
468 | final Argument jiraEnabledArgument =
469 | optionArgument("-je", "--jira-enabled") //
470 | .description("Enable parsing for Jira issues.") //
471 | .build();
472 |
473 | final Argument githubEnabledArgument =
474 | optionArgument("-ge", "--github-enabled") //
475 | .description("Enable parsing for GitHub issues.") //
476 | .build();
477 |
478 | final Argument gitlabEnabledArgument =
479 | optionArgument("-gl", "--gitlab-enabled") //
480 | .description("Enable parsing for GitLab issues.") //
481 | .build();
482 |
483 | final Argument redmineEnabledArgument =
484 | optionArgument("-re", "--redmine-enabled") //
485 | .description("Enable parsing for Redmine issues.") //
486 | .build();
487 |
488 | final Argument useIntegrationsArgument =
489 | optionArgument("-ui", "--use-integrations") //
490 | .description("Use integrations to get more details on commits.") //
491 | .build();
492 |
493 | final Argument encodingArgument =
494 | stringArgument("-en", "--encoding") //
495 | .description("Encoding to use when writing content.") //
496 | .defaultValue(StandardCharsets.UTF_8.name())
497 | .build();
498 |
499 | final Argument> pathsArgument =
500 | stringArgument("-pf", "--path-filters") //
501 | .repeated()
502 | .description("Paths on the filesystem to filter on.") //
503 | .defaultValue(defaultSettings.getPathFilters())
504 | .build();
505 |
506 | try {
507 | final ParsedArguments arg =
508 | withArguments(
509 | helpArgument,
510 | settingsArgument,
511 | outputStdoutArgument,
512 | outputFileArgument,
513 | templatePathArgument,
514 | prependTemplatePathArgument,
515 | templateBaseDirArgument,
516 | templatePartialSuffixArgument,
517 | fromCommitArgument,
518 | fromRevArgument,
519 | toRevArgument,
520 | toRevInclusivenessStrategyArgument,
521 | fromRevInclusivenessStrategyArgument,
522 | fromRefArgument,
523 | fromRepoArgument,
524 | toCommitArgument,
525 | toRefArgument,
526 | untaggedTagNameArgument,
527 | jiraIssuePatternArgument,
528 | jiraServerArgument,
529 | redmineIssuePatternArgument,
530 | redmineServerArgument,
531 | ignoreCommitsIfMessageMatchesArgument,
532 | ignoreCommitsOlderThanArgument,
533 | customIssueLinkArgument,
534 | customIssueTitleArgument,
535 | customIssueNameArgument,
536 | customIssuePatternArgument,
537 | timeZoneArgument,
538 | dateFormatArgument,
539 | noIssueArgument,
540 | readableTagNameArgument,
541 | removeIssueFromMessageArgument,
542 | gitHubApiArgument,
543 | jiraUsernamePatternArgument,
544 | jiraPasswordPatternArgument,
545 | jiraBasicAuthStringPatternArgument,
546 | jiraBearerArgument,
547 | jiraAdditionalFieldArgument,
548 | redmineUsernameArgument,
549 | redminePasswordArgument,
550 | redmineTokenArgument,
551 | extendedVariablesArgument,
552 | extendedHeadersArgument,
553 | templateContentArgument,
554 | gitHubTokenArgument,
555 | ignoreCommitsWithoutIssueArgument,
556 | ignoreTagsIfNameMatchesArgument,
557 | gitLabTokenArgument,
558 | gitLabServerArgument,
559 | gitLabProjectNameArgument,
560 | gitLabProjectIssuePattern,
561 | printHighestVersion,
562 | printHighestVersionTag,
563 | printNextVersion,
564 | printCurrentVersion,
565 | registerHandlebarsHelper,
566 | prependToFile,
567 | majorVersionPattern,
568 | minorVersionPattern,
569 | patchVersionPattern,
570 | showDebugInfo,
571 | handlebarsHelperFile,
572 | jiraEnabledArgument,
573 | githubEnabledArgument,
574 | gitlabEnabledArgument,
575 | redmineEnabledArgument,
576 | useIntegrationsArgument,
577 | encodingArgument,
578 | pathsArgument) //
579 | .parse(args);
580 |
581 | final GitChangelogApi changelogApiBuilder =
582 | gitChangelogApiBuilder()
583 | .withUseIntegrations(arg.wasGiven(useIntegrationsArgument))
584 | .withJiraEnabled(arg.wasGiven(jiraEnabledArgument))
585 | .withRedmineEnabled(arg.wasGiven(redmineEnabledArgument))
586 | .withGitHubEnabled(arg.wasGiven(githubEnabledArgument))
587 | .withGitLabEnabled(arg.wasGiven(gitlabEnabledArgument))
588 | .withEncoding(Charset.forName(arg.get(encodingArgument)))
589 | .withPathFilters(arg.get(pathsArgument).toArray(new String[0]));
590 |
591 | if (!arg.get(registerHandlebarsHelper).trim().isEmpty()) {
592 | changelogApiBuilder.withHandlebarsHelper(arg.get(registerHandlebarsHelper));
593 | }
594 |
595 | if (arg.wasGiven(handlebarsHelperFile)) {
596 | final byte[] content = Files.readAllBytes(arg.get(handlebarsHelperFile).toPath());
597 | final String contentString = new String(content, StandardCharsets.UTF_8);
598 | changelogApiBuilder.withHandlebarsHelper(contentString);
599 | }
600 |
601 | if (arg.wasGiven(settingsArgument)) {
602 | changelogApiBuilder.withSettings(new File(arg.get(settingsArgument)).toURI().toURL());
603 | }
604 |
605 | if (arg.wasGiven(removeIssueFromMessageArgument)) {
606 | changelogApiBuilder.withRemoveIssueFromMessageArgument(true);
607 | }
608 | if (arg.wasGiven(ignoreCommitsWithoutIssueArgument)) {
609 | changelogApiBuilder.withIgnoreCommitsWithoutIssue(true);
610 | }
611 |
612 | if (arg.wasGiven(extendedVariablesArgument)) {
613 | final String jsonString = arg.get(extendedVariablesArgument);
614 | final Gson gson = new Gson();
615 | final Type type = new TypeToken