def pre_commit(): """ This hook is invoked by git commit, and can be bypassed with --no-verify option. It takes no parameter, and is invoked before obtaining the proposed commit log message and making a commit. Exiting with non-zero status from this script causes the git commit to abort. """ repository = git.Repo() user_configuration = config.UserConfiguration() logger = output.get_root_logger('pre-commit') logger.setLevel(user_configuration.verbosity) logger.debug('Starting Pre-Commit Hook') logger.debug('Repository Working Dir: %s', repository.working_dir) try: repository_configuration = config.load_repository_configuration(repository.working_dir) except ValueError as e: logger.error(e) raise click.Abort logger.debug('Loaded repository configuration: %s', repository_configuration['CONFIG_FILE']) staging_area = staging.StagingArea(repository) logger.debug('Changed Files: %d', len(staging_area.changes)) failed_checks = checks.run_checks('pre_commit', user_configuration, repository_configuration, staging_area) if failed_checks: s = '' if failed_checks == 1 else 's' logger.error('%d check%s failed', failed_checks, s) sys.exit(failed_checks)
def cmd(verbose, revision_range): """ Verifies if the commit messages in a range of revisions have valid specifications. This command takes the same revision ranges as ``git log`` to specify which commits are processed When using the verbose mode merge commits are printed otherwise they are simply ignored """ repository = git.get_repository() if not repository: click.secho('This command must be executed inside a repository.', fg='red', bold=True) raise click.Abort commits = list(repository.iter_commits(revision_range)) invalid = 0 options = config.load_repository_configuration(repository.working_dir).get( 'specification', {}) allowed_schemes = options.get('allowed_schemes', ['https', 'offline']) allowed_formats = options.get('allowed_formats', {'uri'}) for commit in commits: is_a_merge = len(commit.parents) > 1 if is_a_merge and not verbose: continue short_hash = commit.hexsha[:7] first_line = commit.message.splitlines()[0] # TODO make configurable specification = specifications.get_specification( commit.message, allowed_formats, allowed_schemes) if specification.valid: click.secho(' ✔ ', bg='green', fg='white', nl=False) elif is_a_merge: click.secho(' ', fg='yellow', nl=False) else: invalid += 1 click.secho(' ✘ ', bg='red', fg='white', nl=False) click.secho(' {} '.format(short_hash), fg='white' if is_a_merge else 'yellow', nl=False, dim=is_a_merge) click.secho(first_line, dim=is_a_merge) if invalid: if invalid == 1: message = '1 commit has invalid specification.' else: message = '{n} commits have invalid specifications.'.format( n=invalid) click.secho(message, fg='red', bold=True) sys.exit(invalid)
def commit_msg(message_file_path): """ This hook is invoked by git commit, and can be bypassed with --no-verify option. It takes a single parameter, the name of the file that holds the proposed commit log message. Exiting with non-zero status causes the git commit to abort. :param message_file_path: the name of the file that holds the proposed commit log message :type message_file_path: string """ repository = git.Repo() branch = repository.active_branch.name user_configuration = config.UserConfiguration() logger = output.get_root_logger('commit-msg') logger.setLevel(user_configuration.verbosity) logger.debug('Starting Commit-Msg Hook') logger.debug('Path to commit message file: %s', message_file_path) logger.debug('Repository Working Dir: %s', repository.working_dir) logger.debug('Current branch: %s', branch) try: repository_configuration = config.load_repository_configuration( repository.working_dir) except ValueError as e: logger.error(str(e)) raise click.Abort logger.debug('Loaded repository configuration: %s', repository_configuration['CONFIG_FILE']) logger.debug('Opening commit message file') try: with open(message_file_path) as message_file: str_commit_message = message_file.read() except IOError: logger.error('Commit message file (%s) not found', message_file_path) raise click.Abort logger.debug('Commit Message: %s', str_commit_message) commit_message = message.CommitMessage(branch, str_commit_message) failed_checks = checks.run_checks('commit_msg', user_configuration, repository_configuration, commit_message) if failed_checks: s = '' if failed_checks == 1 else 's' logger.error('%d check%s failed', failed_checks, s) sys.exit(failed_checks)
def commit_msg(message_file_path): """ This hook is invoked by git commit, and can be bypassed with --no-verify option. It takes a single parameter, the name of the file that holds the proposed commit log message. Exiting with non-zero status causes the git commit to abort. :param message_file_path: the name of the file that holds the proposed commit log message :type message_file_path: string """ repository = git.Repo() branch = repository.active_branch.name user_configuration = config.UserConfiguration() logger = output.get_root_logger('commit-msg') logger.setLevel(user_configuration.verbosity) logger.debug('Starting Commit-Msg Hook') logger.debug('Path to commit message file: %s', message_file_path) logger.debug('Repository Working Dir: %s', repository.working_dir) logger.debug('Current branch: %s', branch) try: repository_configuration = config.load_repository_configuration(repository.working_dir) except ValueError as e: logger.error(str(e)) raise click.Abort logger.debug('Loaded repository configuration: %s', repository_configuration['CONFIG_FILE']) logger.debug('Opening commit message file') try: with open(message_file_path) as message_file: str_commit_message = message_file.read() except IOError: logger.error('Commit message file (%s) not found', message_file_path) raise click.Abort logger.debug('Commit Message: %s', str_commit_message) commit_message = message.CommitMessage(branch, str_commit_message) failed_checks = checks.run_checks('commit_msg', user_configuration, repository_configuration, commit_message) if failed_checks: s = '' if failed_checks == 1 else 's' logger.error('%d check%s failed', failed_checks, s) sys.exit(failed_checks)
def cmd(reference='HEAD'): """ Opens the specification for commit """ repository = git.get_repository() if not repository: click.secho('This command must be executed inside a repository.', fg='red', bold=True) raise click.Abort options = config.load_repository_configuration(repository.working_dir).get('specification', {}) allowed_schemes = options.get('allowed_schemes', ['https', 'offline']) allowed_formats = options.get('allowed_formats', {'uri'}) try: commit = repository.commit(reference) except git.BadName: click.secho("'{reference}' is not a valid commit reference.".format(reference=reference), fg='red', bold=True) raise click.Abort specification = specifications.get_specification(commit.message, allowed_formats, allowed_schemes) specification_format = specification.format if not specification_format: click.secho("That commit doesn't have a valid specification.", fg='red', bold=True) raise click.Abort if specification_format == 'uri': url = specification.identifier elif specification_format == 'github': origin = repository.remote('origin') # type: git.remote.Remote git_url = origin.config_reader.get('url') repository = github.extract_repository_from_url(git_url) if repository: issue = github.extract_issue_number(specification.identifier) url = 'https://github.com/{repository}/issues/{issue}'.format(**locals()) else: click.secho("{} is not a github repository.".format(git_url), fg='red', bold=True) raise click.Abort else: url = None if url: click.secho('Opening {}'.format(url)) webbrowser.open(url) else: click.secho("{} specifications aren't supported yet.".format(specification_format), fg='red', bold=True) raise click.Abort
def cmd(verbose, revision_range): """ Verifies if the commit messages in a range of revisions have valid specifications. This command takes the same revision ranges as ``git log`` to specify which commits are processed When using the verbose mode merge commits are printed otherwise they are simply ignored """ repository = git.get_repository() if not repository: click.secho('This command must be executed inside a repository.', fg='red', bold=True) raise click.Abort commits = list(repository.iter_commits(revision_range)) invalid = 0 options = config.load_repository_configuration(repository.working_dir).get('specification', {}) allowed_schemes = options.get('allowed_schemes', ['https', 'offline']) allowed_formats = options.get('allowed_formats', {'uri'}) for commit in commits: is_a_merge = len(commit.parents) > 1 if is_a_merge and not verbose: continue short_hash = commit.hexsha[:7] first_line = commit.message.splitlines()[0] # TODO make configurable specification = specifications.get_specification(commit.message, allowed_formats, allowed_schemes) if specification.valid: click.secho(' ✔ ', bg='green', fg='white', nl=False) elif is_a_merge: click.secho(' ', fg='yellow', nl=False) else: invalid += 1 click.secho(' ✘ ', bg='red', fg='white', nl=False) click.secho(' {} '.format(short_hash), fg='white' if is_a_merge else 'yellow', nl=False, dim=is_a_merge) click.secho(first_line, dim=is_a_merge) if invalid: if invalid == 1: message = '1 commit has invalid specification.' else: message = '{n} commits have invalid specifications.'.format(n=invalid) click.secho(message, fg='red', bold=True) sys.exit(invalid)
def pre_commit(): """ This hook is invoked by git commit, and can be bypassed with --no-verify option. It takes no parameter, and is invoked before obtaining the proposed commit log message and making a commit. Exiting with non-zero status from this script causes the git commit to abort. """ repository = git.Repo() user_configuration = config.UserConfiguration() logger = output.get_root_logger('pre-commit') logger.setLevel(user_configuration.verbosity) logger.debug('Starting Pre-Commit Hook') logger.debug('Repository Working Dir: %s', repository.working_dir) try: repository_configuration = config.load_repository_configuration( repository.working_dir) except ValueError as e: logger.error(e) raise click.Abort logger.debug('Loaded repository configuration: %s', repository_configuration['CONFIG_FILE']) staging_area = staging.StagingArea(repository) logger.debug('Changed Files: %d', len(staging_area.changes)) failed_checks = checks.run_checks('pre_commit', user_configuration, repository_configuration, staging_area) if failed_checks: s = '' if failed_checks == 1 else 's' logger.error('%d check%s failed', failed_checks, s) sys.exit(failed_checks)
def cmd(reference='HEAD'): """ Opens the specification for commit """ repository = git.get_repository() if not repository: click.secho('This command must be executed inside a repository.', fg='red', bold=True) raise click.Abort options = config.load_repository_configuration(repository.working_dir).get( 'specification', {}) allowed_schemes = options.get('allowed_schemes', ['https', 'offline']) allowed_formats = options.get('allowed_formats', {'uri'}) try: commit = repository.commit(reference) except git.BadName: click.secho("'{reference}' is not a valid commit reference.".format( reference=reference), fg='red', bold=True) raise click.Abort specification = specifications.get_specification(commit.message, allowed_formats, allowed_schemes) specification_format = specification.format if not specification_format: click.secho("That commit doesn't have a valid specification.", fg='red', bold=True) raise click.Abort if specification_format == 'uri': url = specification.identifier elif specification_format == 'github': origin = repository.remote('origin') # type: git.remote.Remote git_url = origin.config_reader.get('url') repository = github.extract_repository_from_url(git_url) if repository: issue = github.extract_issue_number(specification.identifier) url = 'https://github.com/{repository}/issues/{issue}'.format( **locals()) else: click.secho("{} is not a github repository.".format(git_url), fg='red', bold=True) raise click.Abort else: url = None if url: click.secho('Opening {}'.format(url)) webbrowser.open(url) else: click.secho("{} specifications aren't supported yet.".format( specification_format), fg='red', bold=True) raise click.Abort