コード例 #1
0
def check(user_configuration, repository_configuration, staging_area):
    """
    Codevalidator check

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param staging_area:
    :type staging_area: git_hooks.models.staging.StagingArea
    :return: If check passed or not
    :rtype: turnstile.checks.CheckResult
    """

    result = checks.CheckResult()

    logger = output.get_sub_logger('pre-commit', 'codevalidator')
    logger.debug('Starting Codevalidator check...')
    if not staging_area.changes:
        logger.debug('No files to check.')
        raise checks.CheckIgnore

    codevalidator_rc = staging_area.working_dir / '.codevalidatorrc'

    with staging_area:
        codevalidator_output = codevalidator(files_to_check=staging_area.files,
                                             temporary_dir=staging_area.temporary_directory,
                                             custom_config=codevalidator_rc)
        result.successful = not codevalidator_output
        if not result.successful:
            result.details.append(codevalidator_output)

    return result
コード例 #2
0
def run_checks(
    hook_name,
    user_configuration,
    repository_configuration,
    check_object,
):
    """
    Runs checks for hooks

    :param hook_name: Which hook is running the checks
    :type hook_name: str
    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param check_object: Object to check, either a CommitMessage or a StagingArea
    :return: Number of failed checks
    :rtype: int
    """

    logger = output.get_sub_logger(hook_name.replace('_', '-'), 'run_checks')
    failed_checks = 0
    checklist = repository_configuration.get('checks', [])
    checklist = [x.replace('-', '_') for x in checklist]
    logger.debug('Configured Checks: %s', checklist)
    check_functions = list(get_checks(hook_name))
    logger.debug('Available Checks: %s', [f[0] for f in check_functions])
    checks_to_run = (check for check_name, check in check_functions
                     if check_name in checklist)
    for check in checks_to_run:

        try:
            result = check(user_configuration, repository_configuration,
                           check_object)
        except CheckIgnore:
            logger.debug('Check was ignored')
            continue

        if result.successful:
            logger.info('✔ %s', check.description)
            for detail in result.details:
                logger.info('  %s', detail)
        else:
            failed_checks += 1
            logger.error('✘ %s', check.description)
            for detail in result.details:
                logger.error('  %s', detail)
    return failed_checks
コード例 #3
0
def remove_hook(name, path):
    """
    Remove a hook from path

    :type name: str
    :type path: Path
    """

    logger = output.get_sub_logger('manager-remove', 'remove_hook')
    logger.debug('Removing %s hook.', name)
    if not path.exists():
        logger.debug('%s Hook doesn\'t exist.', name)
    elif click.confirm('Are you sure you want to remove {} hook?'.format(name)):
        path.unlink()
        logger.info('Removed %s hook', name)
    else:
        logger.info('Kept %s hook.', name)
コード例 #4
0
ファイル: install.py プロジェクト: jmcs/turnstile
def install_hook(name, path, wrapper_command):
    """
    Installs a hook in path

    :type name: str
    :type path: Path
    :type wrapper_command: str
    """
    logger = output.get_sub_logger('manager-install', 'install_hook')
    logger.debug('Installing %s hook.', name)
    if not path.exists() or click.confirm('{} hook already exists. Do you want to overwrite it?'.format(name)):
        with path.open('wb+') as pre_commit_hook:
            pre_commit_hook.write(wrapper_command.encode('utf-8'))
        path.chmod(0o755)  # -rwxr-xr-x
        logger.info('Installed %s hook', name)
    else:
        logger.info('Skipped %s hook installation.', name)
コード例 #5
0
ファイル: install.py プロジェクト: LappleApple/turnstile
def install_hook(name, path, wrapper_command):
    """
    Installs a hook in path

    :type name: str
    :type path: Path
    :type wrapper_command: str
    """
    logger = output.get_sub_logger('manager-install', 'install_hook')
    logger.debug('Installing %s hook.', name)
    if not path.exists() or click.confirm('{} hook already exists. Do you want to overwrite it?'.format(name)):
        with path.open('wb+') as pre_commit_hook:
            pre_commit_hook.write(wrapper_command.encode('utf-8'))
        path.chmod(0o755)  # -rwxr-xr-x
        logger.info('Installed %s hook', name)
    else:
        logger.info('Skipped %s hook installation.', name)
コード例 #6
0
def get_checks(hook_name):
    """
    Load all the checks for the hook

    :param hook_name: Which hook is fetching the checks
    :type hook_name: str
    :rtype: [str, FunctionType]
    """
    logger = output.get_sub_logger(hook_name.replace('_', '-'), 'get_checks')

    group_name = 'turnstile.{}'.format(hook_name)
    for entry_point in pkg_resources.iter_entry_points(group_name):
        try:
            module = entry_point.load()
        except ImportError:  # pragma: no cover
            logger.error('%s not found', entry_point.name)
            continue
        check = module.check  # type: FunctionType
        yield entry_point.name, check
コード例 #7
0
ファイル: specification.py プロジェクト: jmcs/turnstile
def check(user_configuration, repository_configuration, commit_message):
    """
    Check if the specification is valid.

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """

    logger = output.get_sub_logger('commit-msg', 'specification')
    logger.debug('Starting specification check...')
    logger.debug('Commit Message: %s', commit_message.message)

    if commit_message.message.startswith('Merge'):
        logger.debug("Commit is a merge, ignoring.")
        raise checks.CheckIgnore

    check_options = repository_configuration.get('specification', {})
    allowed_schemes = check_options.get('allowed_schemes',
                                        ['https', 'offline'])
    allowed_formats = check_options.get('allowed_formats', {'uri'})
    logger.debug("Allowed schemes: %s", allowed_schemes)

    result = checks.CheckResult()
    specification = specifications.get_specification(commit_message.message,
                                                     allowed_formats,
                                                     allowed_schemes)
    is_valid_uri = specification.valid

    logger.debug('Specification: %s', specification)
    logger.debug("Specification is valid: %s", is_valid_uri)

    result.successful = is_valid_uri
    if not is_valid_uri:
        result.add_detail(
            '{spec} is not a valid specification.'.format(spec=specification))

    return result
コード例 #8
0
ファイル: __init__.py プロジェクト: LappleApple/turnstile
def get_checks(hook_name):
    """
    Load all the checks for the hook

    :param hook_name: Which hook is fetching the checks
    :type hook_name: str
    :rtype: [str, FunctionType]
    """
    logger = output.get_sub_logger(hook_name.replace('_', '-'), 'get_checks')

    group_name = 'turnstile.{}'.format(hook_name)
    for entry_point in pkg_resources.iter_entry_points(group_name):
        try:
            module = entry_point.load()
        except ImportError:  # pragma: no cover
            logger.error('%s not found', entry_point.name)
            continue
        check = module.check  # type: FunctionType
        yield entry_point.name, check
コード例 #9
0
ファイル: __init__.py プロジェクト: isnok/turnstile
def run_checks(hook_name, user_configuration, repository_configuration, check_object, ):
    """
    Runs checks for hooks

    :param hook_name: Which hook is running the checks
    :type hook_name: str
    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param check_object: Object to check, either a CommitMessage or a StagingArea
    :return: Number of failed checks
    :rtype: int
    """

    logger = output.get_sub_logger(hook_name.replace('_', '-'), 'run_checks')
    failed_checks = 0
    checklist = repository_configuration.get('checks', [])
    checklist = [x.replace('-', '_') for x in checklist]
    logger.debug('Configured Checks: %s', checklist)
    check_functions = list(get_checks(hook_name))
    logger.debug('Available Checks: %s', [f[0] for f in check_functions])
    checks_to_run = (check for check_name, check in check_functions if check_name in checklist)
    for check in checks_to_run:

        try:
            result = check(user_configuration, repository_configuration, check_object)
        except CheckIgnore:
            logger.debug('Check was ignored')
            continue

        if result.successful:
            logger.info('✔ %s', check.description)
            for detail in result.details:
                logger.info('  %s', detail)
        else:
            failed_checks += 1
            logger.error('✘ %s', check.description)
            for detail in result.details:
                logger.error('  %s', detail)
    return failed_checks
コード例 #10
0
def check(user_configuration, repository_configuration, commit_message):
    """
    Check if the specification is valid.

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """

    logger = output.get_sub_logger("commit-msg", "specification")
    logger.debug("Starting specification check...")
    logger.debug("Commit Message: %s", commit_message.message)

    if commit_message.message.startswith("Merge"):
        logger.debug("Commit is a merge, ignoring.")
        raise checks.CheckIgnore

    check_options = repository_configuration.get("specification", {})
    allowed_schemes = check_options.get("allowed_schemes", ["https", "offline"])
    allowed_formats = check_options.get("allowed_formats", {"uri"})
    logger.debug("Allowed schemes: %s", allowed_schemes)

    result = checks.CheckResult()
    specification = specifications.get_specification(commit_message.message, allowed_formats, allowed_schemes)
    is_valid_uri = specification.valid

    logger.debug("Specification: %s", specification)
    logger.debug("Specification is valid: %s", is_valid_uri)

    result.successful = is_valid_uri
    if not is_valid_uri:
        result.add_detail("{spec} is not a valid specification.".format(spec=specification))

    return result
コード例 #11
0
def codevalidator(files_to_check, temporary_dir=None, custom_config=None, fix=False):
    """
    Wrapper around codevalidator

    :param files_to_check: list of files to check
    :type files_to_check: list
    :param temporary_dir: temporary dir used, this is used to remove it from the output
    :param custom_config: path to custom codevalidatorrc if any
    :type custom_config: pathlib.Path
    :param fix: whether to try to fix the files or not
    :type fix: bool
    :return: codevalidator output
    """

    logger = output.get_sub_logger('pre-commit', 'codevalidator')

    arguments = ['codevalidator', '-v']
    arguments.extend(str(path) for path in files_to_check)

    if custom_config.is_file():
        arguments.extend(['-c', str(custom_config.resolve())])

    if fix:
        arguments.extend(['-f', '--no-backup'])

    logger.debug('Command Arguments: %s', arguments)

    process = subprocess.Popen(arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    stdout, stderr = process.communicate()
    logger.debug('Standard Output: %s', stdout)
    logger.debug('Standard Error: %s', stderr)

    codevalidator_output = stdout + stderr

    if temporary_dir:
        codevalidator_output = remove_temporary_path(codevalidator_output, temporary_dir)

    return codevalidator_output
コード例 #12
0
def check(user_configuration, repository_configuration, commit_message):
    """
    Prevents commits to master

    >>> import turnstile.models.message as message

    >>> commit = message.CommitMessage('master', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result = check(None, None, commit)
    >>> result.successful
    False
    >>> result.details
    ['Master branch is protected.']

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """
    logger = output.get_sub_logger('commit-msg', 'protect-master')

    logger.debug('Starting protect-master check...')

    result = checks.CheckResult()
    branch = commit_message.branch
    logger.debug('Branch: %s', branch)

    is_allowed = branch != 'master'
    result.successful = is_allowed
    if not is_allowed:
        result.add_detail("Master branch is protected.")

    return result
コード例 #13
0
def check(user_configuration, repository_configuration, commit_message):
    """
    Prevents commits to master

    >>> import turnstile.models.message as message

    >>> commit = message.CommitMessage('master', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result = check(None, None, commit)
    >>> result.successful
    False
    >>> result.details
    ['Master branch is protected.']

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """
    logger = output.get_sub_logger("commit-msg", "protect-master")

    logger.debug("Starting protect-master check...")

    result = checks.CheckResult()
    branch = commit_message.branch
    logger.debug("Branch: %s", branch)

    is_allowed = branch != "master"
    result.successful = is_allowed
    if not is_allowed:
        result.add_detail("Master branch is protected.")

    return result
コード例 #14
0
def check(user_configuration, repository_configuration, commit_message):
    """
    Check if the release of release branches matches a pattern. By default this pattern is ^R(?:\d|\_|\.)+$ but it's
    configurable

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """

    logger = output.get_sub_logger('commit-msg', 'branch-release')
    logger.debug('Starting branch-release check...')

    result = checks.CheckResult()
    branch = commit_message.branch
    logger.debug('Branch: %s', branch)
    if not branch.startswith('release/'):
        logger.debug("%s isn't a release branch, ignoring.", branch)
        raise checks.CheckIgnore

    check_options = repository_configuration.get('branch-release', {})
    pattern = check_options.get('pattern', '^R(?:\d|\_|\.)+$')
    branch_type, release = branch.split('/', 1)

    matches_pattern = bool(re.match(pattern, release))
    result.successful = matches_pattern
    if not matches_pattern:
        template = "'{release}' doesn't match '{pattern}'."
        result.add_detail(template.format(release=release, pattern=pattern))

    return result
コード例 #15
0
def check(user_configuration, repository_configuration, commit_message):
    """
    Check if the branch type is allowed. The branch type is the prefix of the branch name, for example feature/CD-100 is
    a feature branch.

    By default only master is allowed
    >>> import turnstile.models.message as message
    >>> commit_1 = message.CommitMessage('master', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result_1 = check(None, {}, commit_1)
    >>> result_1.successful, result_1.details
    (True, [])

    >>> commit_2 = message.CommitMessage('feature/ABC', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result_2 = check(None, {}, commit_2)
    >>> result_2.successful, result_2.details
    (False, ["'feature' type is not allowed. Allowed types are: master."])

    But you can configure it
    >>> allow_feature_release = {'branch-type': {'allowed': ['feature', 'release']}}
    >>> commit_3 = message.CommitMessage('feature/ABC', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result_3 = check(None, allow_feature_release, commit_3)
    >>> result_3.successful, result_3.details
    (True, [])

    >>> allow_feature_release = {'branch-type': {'allowed': ['feature', 'release']}}
    >>> commit_4 = message.CommitMessage('other/ABC', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result_4 = check(None, allow_feature_release, commit_4)
    >>> result_4.successful, result_4.details
    (False, ["'other' type is not allowed. Allowed types are: feature, release, master."])

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """
    logger = output.get_sub_logger('commit-msg', 'branch-type')

    logger.debug('Starting branch-type check...')

    result = checks.CheckResult()
    branch = commit_message.branch
    logger.debug('Branch: %s', branch)

    check_options = repository_configuration.get('branch-type', {})
    allowed = check_options.get('allowed', [])

    logger.debug('Allowed Patterns: %s', allowed)

    # add a / after type name because branches should be TYPE/* and master is always allowed
    is_allowed = branch == 'master' or any(
        branch.startswith(branch_type + '/') for branch_type in allowed)
    result.successful = is_allowed
    if not is_allowed:
        branch_type = branch.split('/').pop(0)
        allowed.append('master')  # make it clear it can also be master
        template = "'{branch_type}' type is not allowed. Allowed types are: {allowed}."
        result.add_detail(
            template.format(branch_type=branch_type,
                            allowed=', '.join(allowed)))

    return result
コード例 #16
0
ファイル: branch_pattern.py プロジェクト: jmcs/turnstile
def check(user_configuration, repository_configuration, commit_message):
    """
    Check if the branch name matches the allowed pattern. Master is always allowed

    By default this check only allows master
    >>> import turnstile.models.message as message
    >>> commit = message.CommitMessage('master', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result = check(None, {}, commit)
    >>> result.successful, result.details
    (True, [])

    >>> commit = message.CommitMessage('feature/42', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result = check(None, {}, commit)
    >>> result.successful, result.details
    (False, ["feature/42 doesn't match any allowed pattern."])

    But you can add more allowed patterns
    >>> allow_feature_release = {'branch-pattern': {'allowed': ['^feature/', '^release/R']}}
    >>> commit = message.CommitMessage('release/R10', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result = check(None, allow_feature_release, commit)
    >>> result.successful, result.details
    (True, [])

    >>> allow_feature_release = {'branch-pattern': {'allowed': ['^feature/', '^release/R']}}
    >>> commit = message.CommitMessage('release/R10', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result = check(None, allow_feature_release, commit)
    >>> result.successful, result.details
    (True, [])

    >>> allow_feature_release = {'branch-pattern': {'allowed': ['^feature/', '^release/R']}}
    >>> commit = message.CommitMessage('release/broken', 'https://github.com/jmcs/turnstile/issues/42 message')
    >>> result = check(None, allow_feature_release, commit)
    >>> result.successful, result.details
    (False, ["release/broken doesn't match any allowed pattern."])

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """
    logger = output.get_sub_logger('commit-msg', 'branch-pattern')

    logger.debug('Starting branch-pattern check...')

    result = checks.CheckResult()
    branch = commit_message.branch
    logger.debug('Branch: %s', branch)

    check_options = repository_configuration.get('branch-pattern', {})
    allowed = check_options.get('allowed', [])
    allowed.append('master')  # master is always allowed

    logger.debug('Allowed Patterns: %s', allowed)

    is_allowed = any(re.match(pattern, branch) for pattern in allowed)
    result.successful = is_allowed
    if not is_allowed:
        template = "{branch} doesn't match any allowed pattern."
        result.add_detail(template.format(branch=branch))

    return result
コード例 #17
0
ファイル: branch_type.py プロジェクト: LappleApple/turnstile
def check(user_configuration, repository_configuration, commit_message):
    """
    Check if the branch type is allowed. The branch type is the prefix of the branch name, for example feature/CD-100 is
    a feature branch.

    By default only master is allowed
    >>> import turnstile.models.message as message
    >>> commit_1 = message.CommitMessage('master', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result_1 = check(None, {}, commit_1)
    >>> result_1.successful, result_1.details
    (True, [])

    >>> commit_2 = message.CommitMessage('feature/ABC', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result_2 = check(None, {}, commit_2)
    >>> result_2.successful, result_2.details
    (False, ["'feature' type is not allowed. Allowed types are: master."])

    But you can configure it
    >>> allow_feature_release = {'branch-type': {'allowed': ['feature', 'release']}}
    >>> commit_3 = message.CommitMessage('feature/ABC', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result_3 = check(None, allow_feature_release, commit_3)
    >>> result_3.successful, result_3.details
    (True, [])

    >>> allow_feature_release = {'branch-type': {'allowed': ['feature', 'release']}}
    >>> commit_4 = message.CommitMessage('other/ABC', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result_4 = check(None, allow_feature_release, commit_4)
    >>> result_4.successful, result_4.details
    (False, ["'other' type is not allowed. Allowed types are: feature, release, master."])

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """
    logger = output.get_sub_logger('commit-msg', 'branch-type')

    logger.debug('Starting branch-type check...')

    result = checks.CheckResult()
    branch = commit_message.branch
    logger.debug('Branch: %s', branch)

    check_options = repository_configuration.get('branch-type', {})
    allowed = check_options.get('allowed', [])

    logger.debug('Allowed Patterns: %s', allowed)

    # add a / after type name because branches should be TYPE/* and master is always allowed
    is_allowed = branch == 'master' or any(branch.startswith(branch_type + '/') for branch_type in allowed)
    result.successful = is_allowed
    if not is_allowed:
        branch_type = branch.split('/').pop(0)
        allowed.append('master')  # make it clear it can also be master
        template = "'{branch_type}' type is not allowed. Allowed types are: {allowed}."
        result.add_detail(template.format(branch_type=branch_type, allowed=', '.join(allowed)))

    return result
コード例 #18
0
def check(user_configuration, repository_configuration, commit_message):
    """
    Check if the branch name matches the allowed pattern. Master is always allowed

    By default this check only allows master
    >>> import turnstile.models.message as message
    >>> commit = message.CommitMessage('master', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result = check(None, {}, commit)
    >>> result.successful, result.details
    (True, [])

    >>> commit = message.CommitMessage('feature/42', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result = check(None, {}, commit)
    >>> result.successful, result.details
    (False, ["feature/42 doesn't match any allowed pattern."])

    But you can add more allowed patterns
    >>> allow_feature_release = {'branch-pattern': {'allowed': ['^feature/', '^release/R']}}
    >>> commit = message.CommitMessage('release/R10', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result = check(None, allow_feature_release, commit)
    >>> result.successful, result.details
    (True, [])

    >>> allow_feature_release = {'branch-pattern': {'allowed': ['^feature/', '^release/R']}}
    >>> commit = message.CommitMessage('release/R10', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result = check(None, allow_feature_release, commit)
    >>> result.successful, result.details
    (True, [])

    >>> allow_feature_release = {'branch-pattern': {'allowed': ['^feature/', '^release/R']}}
    >>> commit = message.CommitMessage('release/broken', 'https://github.com/zalando-bus/turnstile/issues/42 message')
    >>> result = check(None, allow_feature_release, commit)
    >>> result.successful, result.details
    (False, ["release/broken doesn't match any allowed pattern."])

    :param user_configuration: User specific configuration
    :type user_configuration: git_hooks.common.config.UserConfiguration
    :param repository_configuration: Repository specific configuration
    :type repository_configuration: dict
    :param commit_message:
    :type commit_message: git_hooks.models.message.CommitMessage
    :return: If check passed or not
    :rtype: git_hooks.checks.CheckResult
    """
    logger = output.get_sub_logger('commit-msg', 'branch-pattern')

    logger.debug('Starting branch-pattern check...')

    result = checks.CheckResult()
    branch = commit_message.branch
    logger.debug('Branch: %s', branch)

    check_options = repository_configuration.get('branch-pattern', {})
    allowed = check_options.get('allowed', [])
    allowed.append('master')  # master is always allowed

    logger.debug('Allowed Patterns: %s', allowed)

    is_allowed = any(re.match(pattern, branch) for pattern in allowed)
    result.successful = is_allowed
    if not is_allowed:
        template = "{branch} doesn't match any allowed pattern."
        result.add_detail(template.format(branch=branch))

    return result