mr_bump 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/bin/mr_bump +109 -0
- data/lib/mr_bump/config.rb +25 -0
- data/lib/mr_bump/slack.rb +110 -0
- data/lib/mr_bump/version.rb +55 -0
- data/lib/mr_bump.rb +98 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjQ1NzQ4YzlkMWI2MDJkZmYwYTY0MWRjNGFlOTY3NjUyMTgwZTc0YQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YWMwNTc5MjFlODY3ZDhjY2QwMmRjNTQyZDg1OGU0YjY5NGU3YTA4MQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NzI5ZGJmNmY4NDhmZmYxNTgxZWMxODU5ZmVkMTM5NDYzYjNmYTc1ZmM0ZmU2
|
10
|
+
OGMwNjhhOWY4YTU3MWNjY2ZkNGI3NjUxMmI0ODg0NDg2ZmFkNGY0YjcxZmY1
|
11
|
+
NWVhZTQ1YmZmNWQwMTFiZGQyZjBlYzljNzhmMzIxYjVhNTdkMmE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YjM0OGVmOWJkNDViNzdlZDFjZjAwNjYzMzg5ZjExMDM3Yzc3ZmQ2MjFhNmU2
|
14
|
+
NmFmNjRjOWU2Mjg1ZmI2YzBkOTRkNTgxYzQ5MGU4MTZiYTYzZjU2YzI1YTNh
|
15
|
+
MWM4YTQ3M2FmZjAyMGI1ZWE5NDZmNjIwODk4YzBhZTQyYWQ2NDM=
|
data/bin/mr_bump
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Small script to tag releases and update changelogs
|
3
|
+
require 'mr_bump'
|
4
|
+
|
5
|
+
release = !MrBump.current_branch[/^release/].nil?
|
6
|
+
master = !MrBump.current_branch[/^master$/].nil?
|
7
|
+
|
8
|
+
unless release || master
|
9
|
+
puts 'Need to be on either release or master branch'
|
10
|
+
exit 1
|
11
|
+
end
|
12
|
+
|
13
|
+
unless system('git remote update > /dev/null 2>&1')
|
14
|
+
puts 'Failed to update remotes. (Connectivity problems?)'
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
|
18
|
+
unless `git rev-parse @` == `git rev-parse @{u}`
|
19
|
+
puts 'Not up to date with origin! Please run git pull'
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
unless File.file?('CHANGELOG.md')
|
24
|
+
puts "Couldn't find CHANGELOG.md. ensure you are in the root of the git checkout"
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
if release
|
29
|
+
last_release = MrBump.current_uat
|
30
|
+
current_uat_major = MrBump.current_uat_major
|
31
|
+
changes = MrBump.change_log_items_for_range(last_release, "release/#{current_uat_major}")
|
32
|
+
else
|
33
|
+
last_release = MrBump.current_master
|
34
|
+
changes = MrBump.change_log_items_for_range(last_release, 'master')
|
35
|
+
end
|
36
|
+
|
37
|
+
new_release = last_release.bump_patch
|
38
|
+
changes = changes.join('')
|
39
|
+
md_changes = "# #{new_release}#{changes}\n\n"
|
40
|
+
|
41
|
+
puts 'Changelog additions'
|
42
|
+
puts '----------'
|
43
|
+
puts md_changes
|
44
|
+
puts '----------'
|
45
|
+
|
46
|
+
loop do
|
47
|
+
print '[A]ccept these changes / Manually [E]dit / [C]ancel Release : '
|
48
|
+
choice = gets.chomp.upcase
|
49
|
+
|
50
|
+
case choice
|
51
|
+
when 'A'
|
52
|
+
MrBump.file_prepend('CHANGELOG.md', md_changes)
|
53
|
+
break
|
54
|
+
when 'E'
|
55
|
+
MrBump.file_prepend('CHANGELOG.md', md_changes)
|
56
|
+
system 'nano CHANGELOG.md'
|
57
|
+
loop do
|
58
|
+
log = File.open('CHANGELOG.md', 'r').read
|
59
|
+
md_changes = log.split("\n\n").first.split("\n").drop(1)
|
60
|
+
puts 'Modified Changelog additions'
|
61
|
+
puts '----------'
|
62
|
+
puts md_changes
|
63
|
+
puts '----------'
|
64
|
+
print '[A]ccept modified changes / [C]ancel Release : '
|
65
|
+
choice2 = gets.chomp.upcase
|
66
|
+
if choice2 == 'C'
|
67
|
+
exit 1
|
68
|
+
elsif choice2 == 'A'
|
69
|
+
break
|
70
|
+
else
|
71
|
+
puts "I'm sorry Dave; I'm afraid I can't do that."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
break
|
75
|
+
when 'C'
|
76
|
+
exit 1
|
77
|
+
else
|
78
|
+
puts "I'm sorry Dave; I'm afraid I can't do that."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
`git commit -m 'Bump version to #{new_release}' CHANGELOG.md`
|
83
|
+
`git tag #{new_release}`
|
84
|
+
`git push && git push --tags`
|
85
|
+
|
86
|
+
MrBump.slack_notifier(new_release, md_changes.join("\n"))
|
87
|
+
|
88
|
+
config_file = MrBump.config_file()
|
89
|
+
branch_type = release ? "release" : 'master'
|
90
|
+
bump_cmd_exists = config_file.key?('post_bump') &&
|
91
|
+
config_file['post_bump'].key?(branch_type)
|
92
|
+
if bump_cmd_exists
|
93
|
+
loop do
|
94
|
+
puts 'Would you like to execute post bump commands? '
|
95
|
+
print '[Y]es execute / [N]o Im done : '
|
96
|
+
choice = gets.chomp.upcase
|
97
|
+
|
98
|
+
case choice
|
99
|
+
when 'Y'
|
100
|
+
post_command = config_file['post_bump'][branch_type]
|
101
|
+
system post_command
|
102
|
+
break
|
103
|
+
when 'N'
|
104
|
+
break
|
105
|
+
else
|
106
|
+
puts "I'm sorry Dave; I'm afraid I can't do that."
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module MrBump
|
4
|
+
# This class sets up access to the config file
|
5
|
+
class Config
|
6
|
+
attr_reader :config_file
|
7
|
+
|
8
|
+
def initialize(config_file = nil)
|
9
|
+
@config_file = config_file || default_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def config
|
13
|
+
@config ||= if File.exist?(@config_file)
|
14
|
+
YAML.load_file(@config_file) || {}
|
15
|
+
else
|
16
|
+
{}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_file
|
21
|
+
File.join(".mr_bump")
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'slack-notifier'
|
2
|
+
module MrBump
|
3
|
+
# This class uses a slack webhook to push notifications to slack
|
4
|
+
class Slack
|
5
|
+
|
6
|
+
def initialize(opts)
|
7
|
+
raise ArgumentError, 'No Slack webhook found.' unless opts["webhook_url"]
|
8
|
+
@webhook = opts["webhook_url"]
|
9
|
+
@username = opts["username"] || 'Mr Bump'
|
10
|
+
if opts['jira_url']
|
11
|
+
@jira_url = opts['jira_url']
|
12
|
+
else
|
13
|
+
@jira_url = nil
|
14
|
+
end
|
15
|
+
if opts['icon']
|
16
|
+
@icon = (opts['icon'].is_a? Array) ? opts['icon'].sample : opts['icon']
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def bump(version, changes)
|
21
|
+
options = {}
|
22
|
+
options[:icon_url] = @icon if @icon
|
23
|
+
options[:attachments] = [attatchment(version, changes)]
|
24
|
+
notifier.ping 'There is a new version bump!', options
|
25
|
+
end
|
26
|
+
|
27
|
+
def notifier
|
28
|
+
@notifier ||= ::Slack::Notifier.new(@webhook, username: @username)
|
29
|
+
end
|
30
|
+
|
31
|
+
def user
|
32
|
+
`git config user.name`.gsub(/\n/, '')
|
33
|
+
end
|
34
|
+
|
35
|
+
def git_url
|
36
|
+
@git_url ||= `git remote get-url origin`
|
37
|
+
end
|
38
|
+
|
39
|
+
def git_user
|
40
|
+
git_url[/[^@]+/].partition('//').last
|
41
|
+
end
|
42
|
+
|
43
|
+
def git_icon
|
44
|
+
'https://avatars.githubusercontent.com/' + git_user
|
45
|
+
end
|
46
|
+
|
47
|
+
def git_link
|
48
|
+
'https://github.com/' + git_user
|
49
|
+
end
|
50
|
+
|
51
|
+
def repo_name
|
52
|
+
`git config --get remote.origin.url`[/[\w\.]+(?=\.git$)/]
|
53
|
+
end
|
54
|
+
|
55
|
+
def jira_ids(changes)
|
56
|
+
changes.split('* ').map { |i| i.split(' - ',3)[1]}.compact
|
57
|
+
end
|
58
|
+
|
59
|
+
def jira_urls(changes)
|
60
|
+
jira_ids(changes).map do |ticket|
|
61
|
+
if ticket!= 'UNKNOWN'
|
62
|
+
'<' + @jira_url + '/browse/' + ticket + '|Jira link - ' + ticket + ">\n"
|
63
|
+
end
|
64
|
+
end.join
|
65
|
+
end
|
66
|
+
|
67
|
+
def jira_field(changes)
|
68
|
+
if @jira_url && !@jira_url.empty?
|
69
|
+
{value: jira_urls(changes), short: true, unfurl_links: false}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_sha(id)
|
74
|
+
`git log --grep=#{id} --merges --format=format:%H`.split("\n").first
|
75
|
+
end
|
76
|
+
|
77
|
+
def git_repo_url
|
78
|
+
'https://' + git_url.partition('@').last.gsub(".git\n", '')
|
79
|
+
end
|
80
|
+
|
81
|
+
def git_shas(changes)
|
82
|
+
jira_ids(changes).map do |ticket|
|
83
|
+
if ticket!= 'UNKNOWN' && !get_sha(ticket).nil?
|
84
|
+
'<' + git_repo_url + '/commit/' + get_sha(ticket) + '|Git merge link - ' + ticket + ">\n"
|
85
|
+
end
|
86
|
+
end.join
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def attatchment(version, changes)
|
91
|
+
{
|
92
|
+
fallback: changes,
|
93
|
+
color: "#009de4",
|
94
|
+
author_name: user,
|
95
|
+
author_icon: git_icon,
|
96
|
+
author_link: git_link,
|
97
|
+
fields: [
|
98
|
+
{title: 'Version', value: version, short: true},
|
99
|
+
{title: 'Repository', value: repo_name, short: true},
|
100
|
+
{title: 'Change Log', value: changes, short: false},
|
101
|
+
jira_field(changes),
|
102
|
+
{value: git_shas(changes), short: true}
|
103
|
+
],
|
104
|
+
mrkdwn_in: ["text", "title", "fallback", "fields"]
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module MrBump
|
2
|
+
# This class enables comparison and bumping of sementic versions and
|
3
|
+
# conversion to and from strings
|
4
|
+
class Version
|
5
|
+
include Comparable
|
6
|
+
attr_reader :major, :minor, :patch
|
7
|
+
def initialize(version_str)
|
8
|
+
regex = Regexp.new('^([0-9]+)(\.([0-9]+)(\.([0-9]*))?)?')
|
9
|
+
numbers = version_str.match(regex).captures
|
10
|
+
@major = numbers[0].to_i
|
11
|
+
@minor = (numbers.size > 2) ? numbers[2].to_i : 0
|
12
|
+
@patch = (numbers.size > 4) ? numbers[4].to_i : 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def <=>(other)
|
16
|
+
major_com = major <=> other.major
|
17
|
+
minor_com = (major_com == 0) ? minor <=> other.minor : major_com
|
18
|
+
(minor_com == 0) ? patch <=> other.patch : minor_com
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"#{major}.#{minor}.#{patch}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def bump_major
|
26
|
+
dup.bump_major!
|
27
|
+
end
|
28
|
+
|
29
|
+
def bump_major!
|
30
|
+
@major += 1
|
31
|
+
@minor = 0
|
32
|
+
@patch = 0
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def bump_minor
|
37
|
+
dup.bump_minor!
|
38
|
+
end
|
39
|
+
|
40
|
+
def bump_minor!
|
41
|
+
@minor += 1
|
42
|
+
@patch = 0
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def bump_patch
|
47
|
+
dup.bump_patch!
|
48
|
+
end
|
49
|
+
|
50
|
+
def bump_patch!
|
51
|
+
@patch += 1
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/mr_bump.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'mr_bump/version'
|
2
|
+
require 'mr_bump/slack'
|
3
|
+
require 'mr_bump/config'
|
4
|
+
|
5
|
+
module MrBump
|
6
|
+
def self.current_branch
|
7
|
+
@current_branch ||= `git rev-parse --abbrev-ref HEAD`
|
8
|
+
@current_branch.strip
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.current_uat_major
|
12
|
+
prefix = 'origin/release/'
|
13
|
+
vers = `git branch -r`
|
14
|
+
regex = Regexp.new("^#{prefix}(\\d+\\.\\d+\\.0)$")
|
15
|
+
vers = vers.each_line.map do |branch|
|
16
|
+
branch = branch.strip
|
17
|
+
MrBump::Version.new(branch.gsub(regex, '\1')) if branch[regex]
|
18
|
+
end.compact
|
19
|
+
vers.max
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.current_uat
|
23
|
+
uat = current_uat_major
|
24
|
+
vers = `git tag -l`
|
25
|
+
vers = vers.each_line.map do |branch|
|
26
|
+
MrBump::Version.new(branch) rescue nil
|
27
|
+
end.compact
|
28
|
+
vers.select { |ver| ver.major == uat.major && ver.minor == uat.minor }.max
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.current_master
|
32
|
+
uat = current_uat_major
|
33
|
+
vers = `git tag -l`
|
34
|
+
vers = vers.each_line.map do |branch|
|
35
|
+
MrBump::Version.new(branch) rescue nil
|
36
|
+
end.compact
|
37
|
+
vers.select { |ver| ver < uat }.max
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.story_information(merge_str)
|
41
|
+
branch_fmt = '(?<fix_type>bugfix|feature|hotfix)/(?<dev_id>\w+[-_]?\d+)?'
|
42
|
+
merge_pr_fmt = "^Merge pull request #(?<pr_number>\\d+) from \\w+/#{branch_fmt}"
|
43
|
+
merge_manual_fmt = "^Merge branch '#{branch_fmt}'"
|
44
|
+
matches = Regexp.new(merge_pr_fmt + '|' + merge_manual_fmt).match(merge_str)
|
45
|
+
if matches
|
46
|
+
type = matches['fix_type'].capitalize
|
47
|
+
dev_id = (matches['dev_id'].nil? ? 'UNKNOWN' : matches['dev_id'])
|
48
|
+
"#{type} - #{dev_id} - "
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.merge_logs(rev, head)
|
53
|
+
git_cmd = "git log --pretty='format:%B' --grep '(^Merge pull request | into #{current_branch}$)' --merges -E"
|
54
|
+
log = `#{git_cmd} #{rev}..#{head}`
|
55
|
+
log.each_line.map(&:strip).select { |str| !(str.nil? || str == '' || str[0] == '#') }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.ignored_merges_regex
|
59
|
+
@ignored_merges_regex ||= begin
|
60
|
+
ignored_branch = '(release|master|develop)'
|
61
|
+
regex_pr = "^Merge pull request #\\d+ from Intellection/#{ignored_branch}"
|
62
|
+
regex_manual = "^Merge branch '?#{ignored_branch}"
|
63
|
+
Regexp.new("#{regex_pr}|#{regex_manual}")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.change_log_items_for_range(rev, head)
|
68
|
+
chunked_log = merge_logs(rev, head).chunk { |change| change[/^Merge/].nil? }
|
69
|
+
chunked_log.each_slice(2).map do |merge_str, comment|
|
70
|
+
merge_str = merge_str[1][0]
|
71
|
+
unless merge_str[ignored_merges_regex]
|
72
|
+
"\n* #{story_information(merge_str)}" + comment[1].join("\n ")
|
73
|
+
end
|
74
|
+
end.compact
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.file_prepend(file, str)
|
78
|
+
new_contents = ''
|
79
|
+
File.open(file, 'r') do |fd|
|
80
|
+
contents = fd.read
|
81
|
+
new_contents = str + contents
|
82
|
+
end
|
83
|
+
File.open(file, 'w') do |fd|
|
84
|
+
fd.write(new_contents)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.config_file
|
88
|
+
MrBump::Config.new().config
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.slack_notifier(version, changelog)
|
92
|
+
if config_file.key? 'slack'
|
93
|
+
MrBump::Slack.new(config_file["slack"]).bump(version, changelog)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mr_bump
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Richard Fitzgerald
|
8
|
+
- Josh Bryant
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-08-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: slack-notifier
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.0'
|
28
|
+
description: Bump versions
|
29
|
+
email: richard.fitzgerald36@gmail.com
|
30
|
+
executables:
|
31
|
+
- mr_bump
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- bin/mr_bump
|
36
|
+
- lib/mr_bump.rb
|
37
|
+
- lib/mr_bump/config.rb
|
38
|
+
- lib/mr_bump/slack.rb
|
39
|
+
- lib/mr_bump/version.rb
|
40
|
+
homepage: https://github.com/xulaus/mr_bump
|
41
|
+
licenses: []
|
42
|
+
metadata: {}
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 2.4.8
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: BUMP!
|
63
|
+
test_files: []
|