git-release 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git_release/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git-release"
8
+ spec.version = GitRelease::VERSION
9
+ spec.authors = ["Tom Meier"]
10
+ spec.email = ["tom@venombytes.com"]
11
+ spec.description = %q{Changelog and release tag generator from GIT}
12
+ spec.summary = %q{Generate changelog from git commits and tag your release versions}
13
+ spec.homepage = "http://github.com/tommeier/git-release"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1 @@
1
+ require "git_release/version"
@@ -0,0 +1,3 @@
1
+ module GitRelease
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,200 @@
1
+ #!/bin/bash -e
2
+
3
+ ############################################################
4
+ ##### CHANGELOG FUNCTIONS #####
5
+ ############################################################
6
+
7
+ get_current_release_date() {
8
+ echo $( date "+%A %d %B, %Y %l:%M%p" )
9
+ }
10
+
11
+ changelog_divider() {
12
+ echo "+=========================================================+"
13
+ }
14
+
15
+ changelog_footer() {
16
+ local output=""
17
+ ! read -d '' output <<"EOF"
18
+ || _____ _ _ ||
19
+ || / ____| | | | ||
20
+ || | | | |__ __ _ _ __ __ _ ___| | ___ __ _ ||
21
+ || | | | '_ \\ / _` | '_ \\ / _` |/ _ \\ |/ _ \\ / _` | ||
22
+ || | |____| | | | (_| | | | | (_| | __/ | (_) | (_| | ||
23
+ || \\_____|_| |_|\\__,_|_| |_|\\__, |\\___|_|\\___/ \\__, | ||
24
+ || __/ | __/ | ||
25
+ || |___/ |___/ ||
26
+ || ||
27
+ EOF
28
+ echo "$(changelog_divider)
29
+ $output
30
+ $(changelog_divider)"
31
+ }
32
+
33
+ get_changelog_text_for_commits() {
34
+ #Pass in commits array of SHA's
35
+ #Return formatted changelog text, with tags handled
36
+ #Optional first argument for the format "--format=%H"
37
+ local previous_shopt_extglob=$(shopt -p extglob)
38
+ local existing_shopt_nocasematch=$(shopt -p nocasematch)
39
+ shopt -s nocasematch
40
+ shopt -s extglob
41
+
42
+ local commit_shas=($@)
43
+
44
+ local feature_tag_lines=""
45
+ local bug_tag_lines=""
46
+ local security_tag_lines=""
47
+ local general_release_lines=""
48
+
49
+ local log_format="--format=%s"
50
+ local log_format_matcher="\-\-format\="
51
+
52
+ #Capture line by line unless first argument provides a custom format
53
+ for i in "${!commit_shas[@]}"; do
54
+ if [[ "${i}" = '0' ]]; then
55
+ if echo "${commit_shas[$i]}" | grep -q "${log_format_matcher}"; then
56
+ log_format="${commit_shas[$i]}";
57
+ continue;
58
+ fi;
59
+ fi;
60
+
61
+ local body_result="`git show -s ${log_format} ${commit_shas[$i]}`"
62
+ local newline=$'\n'
63
+ regex="^\s*\[(features?|bugs?|security)\]\s*(.*)\s*$"
64
+ if [[ $body_result =~ $regex ]]; then
65
+ #Tagged entry
66
+ local full_tag=$BASH_REMATCH
67
+ local tag_type="${BASH_REMATCH[1]}"
68
+ #Remove leading spaces (regex in bash capturing always)
69
+ local tag_content="${BASH_REMATCH[2]##*( )}"
70
+ #Add leading 2 spaces with bullet point for tagged line prefix & remove trailing spaces
71
+ tag_content=" ${tag_content%%*( )}${newline}"
72
+ #Sort matching tags
73
+ case "$tag_type" in
74
+ [fF][eE][aA][tT][uU][rR][eE] | [fF][eE][aA][tT][uU][rR][eE][sS] )
75
+ feature_tag_lines+="${tag_content}";;
76
+ [bB][uU][gG] | [bB][uU][gG][sS] )
77
+ bug_tag_lines+="$tag_content";;
78
+ [sS][eE][cC][uU][rR][iI][tT][yY] )
79
+ security_tag_lines+="$tag_content";;
80
+ * )
81
+ general_release_lines+="$tag_content";;
82
+ esac;
83
+ else
84
+ #Normal entry
85
+ general_release_lines+="$body_result${newline}"
86
+ fi;
87
+ done;
88
+
89
+ #Return previous setup for bash
90
+ eval $previous_shopt_extglob
91
+ eval $existing_shopt_nocasematch
92
+
93
+ if [[ $feature_tag_lines != '' ]]; then
94
+ echo "Features:
95
+ ${feature_tag_lines}"
96
+ fi;
97
+ if [[ $security_tag_lines != '' ]]; then
98
+ echo "Security:
99
+ ${security_tag_lines}"
100
+ fi;
101
+ if [[ $bug_tag_lines != '' ]]; then
102
+ echo "Bugs:
103
+ ${bug_tag_lines}"
104
+ fi;
105
+ echo "$general_release_lines"
106
+ }
107
+
108
+ #generate_changelog_content "$last_tag_name" "$next_tag_name" ":all/:pulls_only"
109
+ generate_changelog_content() {
110
+ local release_name="$1"
111
+ local commit_filter="$2" #all_commits or pulls_only
112
+ local starting_point="$3" #optional
113
+ local end_point="$4" #optional
114
+ local changelog_format="--format=%s" #default -> display title
115
+
116
+ if [[ "$release_name" = "" ]]; then
117
+ echo "Error : Release name required for changelog generation."
118
+ exit 1;
119
+ fi;
120
+
121
+ case "$commit_filter" in
122
+ ':all_commits' | 'all_commits' )
123
+ #No filter
124
+ commit_filter='';;
125
+ ':pulls_only' | 'pulls_only' )
126
+ #Filter by merged pull requests only
127
+ commit_filter=$'^Merge pull request #.* from .*';
128
+ changelog_format="--format=%b";; #use body of pull requests
129
+ * )
130
+ echo "Error : Commit filter required. Please specify :all or :pulls_only."
131
+ exit 1;;
132
+ esac
133
+
134
+ local commits=$(get_commits_between_points "$starting_point" "$end_point" "$commit_filter")
135
+ local commit_output=$(get_changelog_text_for_commits "$changelog_format" $commits)
136
+ local release_date=$(get_current_release_date)
137
+
138
+ echo "$(changelog_divider)
139
+ || Release: ${release_name}
140
+ || Released on ${release_date}
141
+ $(changelog_divider)
142
+ ${commit_output}
143
+ $(changelog_divider)"
144
+ }
145
+
146
+ #generate_version_file "$version_number" "$optional_file_name"
147
+ generate_version_file(){
148
+ local version_number="$1"
149
+ if [[ "$version_number" = "" ]]; then
150
+ echo "Error : Version number required for version file generation."
151
+ exit 1;
152
+ fi;
153
+ if [[ "$2" != '' ]]; then
154
+ local version_file="$2"
155
+ else
156
+ local version_file="VERSION" #optional
157
+ fi;
158
+
159
+ touch $version_file
160
+ echo "${version_number}" > $version_file
161
+ }
162
+
163
+ #generate_changelog_file "$changelog_content" ":overwrite/:append" "$optional_file_name"
164
+ generate_changelog_file(){
165
+ local changelog_content="$1"
166
+ local generate_strategy="$2"
167
+
168
+ if [[ "$changelog_content" = "" ]]; then
169
+ echo "Error : Changelog content required for version file generation."
170
+ exit 1;
171
+ fi;
172
+ if [[ "$3" != '' ]]; then
173
+ local changelog_file="$3"
174
+ else
175
+ local changelog_file="CHANGELOG" #optional
176
+ fi;
177
+
178
+ case "$generate_strategy" in
179
+ ':overwrite' | 'overwrite' )
180
+ #Overwrite;
181
+ echo "$changelog_content
182
+ $(changelog_footer)" > $changelog_file;;
183
+ ':append' | 'append' )
184
+ if [[ ! -f $changelog_file ]]; then
185
+ #Initialise new file
186
+ touch $changelog_file;
187
+ echo "$changelog_content
188
+ $(changelog_footer)" > $changelog_file
189
+ else
190
+ #Append to start of file
191
+ local existing_content=$(cat $changelog_file);
192
+
193
+ echo "$changelog_content
194
+ $existing_content" > $changelog_file;
195
+ fi;;
196
+ * )
197
+ echo "Error : Generate strategy required. Please specify :overwrite or :append."
198
+ exit 1;;
199
+ esac
200
+ }
@@ -0,0 +1,78 @@
1
+ #!/bin/bash -e
2
+
3
+ ############################################################
4
+ ##### GIT FUNCTIONS #####
5
+ ############################################################
6
+
7
+ check_tag_exists() {
8
+ local tag_find=$(git tag -l "$1")
9
+ if [[ "$tag_find" = '' ]]; then
10
+ return 1;
11
+ else
12
+ return 0;
13
+ fi;
14
+ }
15
+
16
+ ensure_git_directory() {
17
+ if [[ ! -d '.git' ]]; then
18
+ echo "Error - Not a git repository please run from the base of your git repo." >&2
19
+ exit 1
20
+ fi;
21
+ }
22
+
23
+ ensure_git_is_clean() {
24
+ local result=$(git status --porcelain)
25
+
26
+ if [[ "$result" != '' ]]; then
27
+ result=$(git status)
28
+ echo "Error - Current branch is in a dirty state, please commit your changes first."
29
+ echo "$result"
30
+ exit 1
31
+ fi;
32
+ }
33
+
34
+ get_sha_for_tag_name() {
35
+ local result=$(git show-ref --tags --hash $1)
36
+ echo "$result"
37
+ }
38
+
39
+ get_sha_for_first_commit() {
40
+ local filter=$1
41
+ local result=$(git log --reverse --format="%H" $filter | head -1)
42
+ echo "$result"
43
+ }
44
+
45
+ get_commit_message_for_first_commit() {
46
+ local filter=$1
47
+ local result=$(git log --reverse --format="%s" $filter | head -1)
48
+ echo "$result"
49
+ }
50
+
51
+ get_commit_message_for_latest_commit() {
52
+ local filter=$1
53
+ local result=$(git log -n1 --format="%s" $filter)
54
+ echo "$result"
55
+ }
56
+
57
+ get_commits_between_points() {
58
+ local starting_point="$1" #optional
59
+ local end_point="$2" #optional
60
+ local log_filter="$3" #optional
61
+
62
+ local git_command="git log";
63
+ local log_options="--no-notes --format=%H"
64
+ local git_range=""
65
+
66
+ if [[ "$log_filter" != '' ]]; then
67
+ log_options="$log_options --grep="'"'"$log_filter"'"'""
68
+ fi;
69
+ if [[ "$starting_point" != '' && "$end_point" != '' ]]; then
70
+ git_range="${starting_point}^1..${end_point}";
71
+ elif [[ "$end_point" != '' ]]; then
72
+ git_range="${end_point}"
73
+ elif [[ "$starting_point" != '' ]]; then
74
+ git_range="${starting_point}^1..HEAD"
75
+ fi;
76
+
77
+ eval $git_command $log_options $git_range
78
+ }
@@ -0,0 +1,125 @@
1
+ #!/bin/bash -e
2
+
3
+ ############################################################
4
+ ##### GLOBALS #####
5
+ ############################################################
6
+
7
+ TAG_VERSION_NUMBER_REGEX="([0-9]+)\\.([0-9]+)\\.([0-9]+)$"
8
+
9
+ ############################################################
10
+ ##### SUPPORT FUNCTIONS #####
11
+ ############################################################
12
+
13
+ validate_version_type() {
14
+ #Confirm version type is in the accepted types
15
+ local v="$1"
16
+ local error_output="$2"
17
+
18
+ if [[ $v != "major" && $v != 'minor' && $v != 'patch' ]]; then
19
+ printf "incorrect versioning type: '%s'\\n" "$v" >&2
20
+ echo "Please set to one of 'major', 'minor' or 'patch'" >&2
21
+ echo "$error_output" >&2
22
+ exit 1
23
+ fi;
24
+ }
25
+
26
+ #git-release-deployed only
27
+ validate_deploy_tag() {
28
+ local t="$1"
29
+ local error_output="$2"
30
+
31
+ if [[ "$t" = '' ]]; then
32
+ echo "Required parameter: Please enter the deploy tag released."
33
+ echo "$error_output"
34
+ exit 1;
35
+ elif [[ "$(git tag -l $t )" = '' ]]; then
36
+ echo "Error: Unable to find tag '${t}'. Please check and try again."
37
+ exit 1;
38
+ fi;
39
+ }
40
+
41
+ ############################################################
42
+ ##### TAG FUNCTIONS #####
43
+ ############################################################
44
+
45
+ get_release_tags() {
46
+ local filter=""
47
+ local tag_names=""
48
+
49
+ if [[ $1 ]]; then
50
+ local tag_pattern=$1
51
+ filter="${tag_pattern}*"
52
+ fi;
53
+ tag_names=$(git tag -l $filter)
54
+
55
+ #<ref> tags/<release_prefix><version_number>
56
+ echo "$tag_names"
57
+ }
58
+
59
+ get_last_tag_name() {
60
+ local versioning_prefix=$1
61
+
62
+ local tags=$(get_release_tags $versioning_prefix)
63
+ echo "$tags" | tail -1
64
+ }
65
+
66
+ get_versioning_prefix_from_tag() {
67
+ local tag_name="$1"
68
+ if [[ $tag_name =~ $TAG_VERSION_NUMBER_REGEX ]]; then
69
+ local version_number=$BASH_REMATCH
70
+ local version_prefix="${tag_name%%$version_number}"
71
+ else
72
+ echo "Error : Unable to determine version prefix from '${tag_name}'"
73
+ exit 1;
74
+ fi;
75
+ echo "${version_prefix}"
76
+ }
77
+
78
+ get_version_number_from_tag() {
79
+ local tag_name="$1"
80
+ if [[ $tag_name =~ $TAG_VERSION_NUMBER_REGEX ]]; then
81
+ local full_version=$BASH_REMATCH
82
+ else
83
+ echo "Error : Unable to determine version number from '${tag_name}'"
84
+ exit 1;
85
+ fi;
86
+ #full stop delimited version number
87
+ echo "$full_version"
88
+ }
89
+
90
+ get_next_version_number_from_tag() {
91
+ local versioning_type=$1
92
+ local tag_name=$2
93
+
94
+ if [[ "$versioning_type" = "" ]]; then
95
+ echo "Error : Versioning type required. eg. major"
96
+ exit 1;
97
+ fi;
98
+
99
+ if [[ $tag_name = '' ]]; then
100
+ #No original tag name for version prefix - start increment
101
+ local tag_name="0.0.0"
102
+ fi;
103
+
104
+ if [[ $tag_name =~ $TAG_VERSION_NUMBER_REGEX ]]; then
105
+ local full_version=$BASH_REMATCH
106
+ local major_version="${BASH_REMATCH[1]}"
107
+ local minor_version="${BASH_REMATCH[2]}"
108
+ local patch_version="${BASH_REMATCH[3]}"
109
+ else
110
+ echo "Error : Unable to determine version number from '${tag_name}'"
111
+ exit 1;
112
+ fi;
113
+
114
+ #Increment version
115
+ case "$versioning_type" in
116
+ 'major' )
117
+ major_version=$(( $major_version + 1 ));;
118
+ 'minor' )
119
+ minor_version=$(( $minor_version + 1 ));;
120
+ 'patch' )
121
+ patch_version=$(( $patch_version + 1 ));;
122
+ esac
123
+
124
+ echo "${major_version}.${minor_version}.${patch_version}"
125
+ }
@@ -0,0 +1,30 @@
1
+ #!/bin/sh -e
2
+
3
+ #Language specific naming, to be overridden by whichever language is being used
4
+
5
+ ARG_ASSIGNER=" " #Argument assigner. space or = for assigning arguments
6
+ ARG_PREFIX="-" #Argument prefix (used in help text display such as '-' for '-v')
7
+ #Arguments for running script
8
+ ARG_VERSION="v"
9
+ ARG_DEPLOYED_TAG="d"
10
+ ARG_RELEASE_PREFIX="p"
11
+ ARG_START="s"
12
+ ARG_FINISH="f"
13
+ ARG_APPEND="A"
14
+ ARG_PULL_REQUESTS="P"
15
+ ARG_CHANGELOG="C"
16
+ ARG_VERSION_FILE="V"
17
+ ARG_FORCE="F"
18
+ ARG_HELP_TEXT="h"
19
+
20
+ #Display arg with language specific assigner and prefix
21
+ arg_for() {
22
+ local arg="$1"
23
+ local val="$2"
24
+ if [[ $val != '' ]]; then
25
+ echo "${ARG_PREFIX}${1}${ARG_ASSIGNER}${2}"
26
+ else
27
+ echo "${ARG_PREFIX}${1}"
28
+ fi;
29
+ }
30
+