auto-semver/semver/__init__.py

179 lines
6.3 KiB
Python
Raw Normal View History

2018-06-01 20:28:30 +02:00
import argparse
import re
import subprocess
import sys
import traceback
2020-06-26 19:26:06 +02:00
from enum import IntEnum
from semver.utils import get_tag_version
2020-02-21 23:44:15 +01:00
from semver.logger import logging, logger, console_logger
2020-06-26 19:26:06 +02:00
from semver.bump import bump_version
2019-11-22 21:30:58 +01:00
2018-05-23 21:41:35 +02:00
try:
from configparser import ConfigParser
except ImportError:
# Python < 3
from ConfigParser import ConfigParser
2019-11-25 19:35:15 +01:00
version = '0.0.0'
2020-06-26 19:26:06 +02:00
class VersionType(IntEnum):
MAJOR = 0
MINOR = 1
PATCH = 2
2018-06-04 23:56:15 +02:00
# Define common exceptions;
NO_MERGE_FOUND = Exception('No merge found')
NOT_MAIN_BRANCH = Exception('Not merging into a main branch')
NO_GIT_FLOW = Exception('No git flow branch found')
2020-02-28 17:56:50 +01:00
# Important regex
GET_COMMIT_MESSAGE = re.compile(r"Merge (branch|pull request) '?([^']+)'? (into|from) (?:'(.+)'|[^\/]+\/([^\n\\]+))")
2020-02-28 17:56:50 +01:00
class SemVer(object):
2018-05-25 21:10:05 +02:00
# Merge pull request #1 from RightBrain-Networks/feature/PLAT-185-versioning
def __init__(self,global_user=False):
self.global_user = '--local' if global_user else '--global'
self.merged_branch = None
self.main_branch = None
self.version_type = None
2018-05-25 20:14:29 +02:00
self.main_branches = self._setting_to_array('main_branches')
self.major_branches = self._setting_to_array('major_branches')
self.minor_branches = self._setting_to_array('minor_branches')
self.patch_branches = self._setting_to_array('patch_branches')
2018-05-25 20:14:29 +02:00
def _setting_to_array(self, setting):
config = ConfigParser()
config.read('./.bumpversion.cfg')
value = config.get('semver', setting)
# filter() removes empty string which is what we get if setting is blank
2018-05-25 20:14:29 +02:00
return list(filter(bool, [v.strip() for v in value.split(',')]))
# based on commit message see what branches are involved in the merge
def get_branches(self):
p = subprocess.Popen(['git', 'log', '-1'], stdout=subprocess.PIPE,
2018-05-23 21:09:14 +02:00
cwd='.')
2018-05-24 22:36:45 +02:00
#check current branch
b = subprocess.Popen(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], stdout=subprocess.PIPE,
cwd='.')
2018-05-23 21:41:35 +02:00
message = str(p.stdout.read())
2018-06-01 19:53:13 +02:00
branch = b.stdout.read().decode('utf-8').rstrip()
2020-02-21 23:44:15 +01:00
logger.info('Main branch is ' + branch)
matches = GET_COMMIT_MESSAGE.search(message.replace('\\n','\n').replace('\\',''))
if matches:
2018-05-24 22:36:45 +02:00
if str(matches.group(4)) == branch:
self.merged_branch = matches.group(2)
else:
2020-02-27 22:56:15 +01:00
self.merged_branch = matches.group(5)
2018-05-24 22:36:45 +02:00
self.main_branch = branch
return bool(matches)
# based on branches involved see what type of versioning should be done
def get_version_type(self):
2020-02-21 23:44:15 +01:00
logger.info('Merged branch is ' + self.merged_branch)
merged_prefix = None
2019-12-16 22:48:34 +01:00
matches = re.findall("[^\/]*/", self.merged_branch)
if len(matches) >= 1:
merged_prefix = matches[-1][0:-1]
if merged_prefix:
for prefix in self.major_branches:
if prefix == merged_prefix:
2020-06-26 19:26:06 +02:00
self.version_type = VersionType.MAJOR
return self.version_type
for prefix in self.minor_branches:
if prefix == merged_prefix:
2020-06-26 19:26:06 +02:00
self.version_type = VersionType.MINOR
return self.version_type
for prefix in self.patch_branches:
if prefix == merged_prefix:
2020-06-26 19:26:06 +02:00
self.version_type = VersionType.PATCH
return self.version_type
return False
# setup git settings so we can commit and tag
def setup_git_user(self):
# setup git user
p = subprocess.Popen(['git', 'config', self.global_user, 'user.email',
'"versioner@semver.com"'],
2018-05-23 21:09:14 +02:00
cwd='.')
p = subprocess.Popen(['git', 'config', self.global_user, 'user.name',
'"Semantic Versioner"'],
2018-05-23 21:09:14 +02:00
cwd='.')
p.wait()
return self
# use bumpversion to increment the appropriate version type
def version_repo(self):
2019-11-22 21:30:58 +01:00
config_file = ""
with open(".bumpversion.cfg", "r") as file:
config_file = file.read()
# version repo
logger.debug("Running bumpversion of type: " + str(self.version_type.name))
2020-06-26 19:26:06 +02:00
bump_version(get_tag_version(), self.version_type)
return self
def commit_and_push(self):
# push versioning commit
2018-05-24 22:36:45 +02:00
p = subprocess.Popen(['git', 'push', 'origin', self.main_branch],
2018-05-23 21:09:14 +02:00
cwd='.')
p.wait()
# push versioning tag
p = subprocess.Popen(['git', 'push', 'origin', '--tags'],
2018-05-23 21:09:14 +02:00
cwd='.')
p.wait()
return self
# 1) get branches from last commit message
# 2) see if we're merging into a main branch
# 3) see what type of versioning we should do
# 4) version the repo
2018-06-01 20:28:30 +02:00
def run(self,push=True):
if not self.get_branches():
2018-06-04 23:56:15 +02:00
raise NO_MERGE_FOUND
if self.main_branch not in self.main_branches:
2018-06-04 23:56:15 +02:00
raise NOT_MAIN_BRANCH
if not self.get_version_type():
2018-06-04 23:56:15 +02:00
raise NO_GIT_FLOW
2018-06-04 23:47:51 +02:00
if push:
self.setup_git_user()
self.version_repo()
2018-06-01 20:28:30 +02:00
if push:
self.commit_and_push()
return self
2018-05-23 21:09:14 +02:00
def main():
parser = argparse.ArgumentParser(description='Bump Semantic Version.')
parser.add_argument('-n','--no-push', help='Do not try to push', action='store_false', dest='push')
parser.add_argument('-g','--global-user', help='Set git user at a global level, helps in jenkins', action='store_true', dest='global_user')
parser.add_argument('-D', '--debug', help='Sets logging level to DEBUG', action='store_true', dest='debug', default=False)
args = parser.parse_args()
2020-02-21 23:44:15 +01:00
if args.debug:
console_logger.setLevel(logging.DEBUG)
try:
SemVer(global_user=args.global_user).run(push=args.push)
except Exception as e:
2020-02-21 23:44:15 +01:00
logger.error(e)
if args.debug:
tb = sys.exc_info()[2]
traceback.print_tb(tb)
2018-06-04 23:56:15 +02:00
if e == NO_MERGE_FOUND:
exit(1)
elif e == NOT_MAIN_BRANCH:
exit(2)
elif e == NO_GIT_FLOW:
exit(3)
else:
exit(128)
2018-05-23 21:09:14 +02:00
if __name__ == '__main__':
try: main()
except: raise