mr_bump 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|