Source code for zensols.pybuild.tag

"""A utility class that represents a Git tag.

"""
__author__ = 'Paul Landes'

from typing import Dict, List, Union
import logging
import sys
from io import TextIOWrapper
import json
from pathlib import Path
from datetime import datetime
from git import Repo, TagReference
from zensols.pybuild import Version

logger = logging.getLogger(__name__)


[docs]class Tag(object): """Represents a Git tag. It's main use is determining the last tag in a sorted (by version) used to increment to the next version. However, it also creates tags and provides additional information about existing tags. All tags have an implicit format by sorting in decimal format (i.e. ``<major>.<minor>.<version>``). """ def __init__(self, repo_dir: Path = Path('.'), message: str = 'none', dry_run: bool = False): """Initialize. :param repo_dir: the root Git repo directory :param message: the message to use when creating new tags :param dry_run: if ``True`` do not create new tags """ logger.debug('creating tag witih repo dir: {}'.format(repo_dir)) if isinstance(repo_dir, Path): repo_dir = str(repo_dir.resolve()) self.repo = Repo(repo_dir) assert not self.repo.bare self.message = message self.dry_run = dry_run
[docs] def get_entries(self) -> List[Dict[str, str]]: """Return a list of dicts, each with information about the tag. Keys:: - name: the name of the tag - ver: the version of the tag (in format ``v<major>.<minor>.<debug>``) - date: date the tag was created - tag: the tag without the prefix (i.e. sans ``v``) - message: the comment given at tag creation """ tags = self.repo.tags logger.debug('tags: {}'.format(tags)) tag_entries = [] for tag in tags: logger.debug('{} ({})'.format(tag, type(tag))) name = str(tag) ver = Version.from_string(name) date = None if hasattr(tag.object, 'tagged_date'): date = tag.object.tagged_date if ver is not None: tag_entries.append({'name': name, 'ver': ver, 'date': date, 'tag': tag, 'message': tag.object.message}) tag_entries = sorted(tag_entries, key=lambda t: t['ver']) return tag_entries
@property def last_tag_entry(self) -> Dict[str, str]: """Return the last entry given by ``get_entries``. :py:meth:`Tag.get_entries` """ entries = self.get_entries() logger.debug('entires: {}'.format(entries)) if (len(entries) > 0): return entries[-1] @property def last_tag(self) -> str: """Return the last tag. """ entry = self.last_tag_entry if entry: return entry['ver'].format(prefix='') @property def last_commit(self): """Return rhe last commit ID (sha1). """ commits = list(self.repo.iter_commits('HEAD')) if len(commits) > 0: return commits[0] @property def build_info(self) -> Dict[str, Union[str, dict]]: """Return information about the last commit and a build time with the current time. """ inf = {'build_date': datetime.now().isoformat()} last_entry = self.last_tag_entry if last_entry: tag = last_entry['tag'] message = None if hasattr(tag.object, 'message'): message = tag.object.message inf.update({'tag': last_entry['ver'].format(prefix=''), 'name': last_entry['name'], 'message': message}) c = self.last_commit if c: inf['commit'] = {'author': str(c.author), 'date': c.committed_datetime.isoformat(), 'sha': str(c), 'summary': c.summary} return inf
[docs] def to_json(self, indent: int = 4, writer: TextIOWrapper = sys.stdout) -> str: """Return build information in JSON format. """ json.dump(self.build_info, writer, indent=4)
[docs] def delete_last_tag(self): """Delete the last commit tag. """ entry = self.last_tag_entry tag = entry['tag'] name = entry['name'] logger.info('deleting: {}'.format(name)) if not self.dry_run: TagReference.delete(self.repo, tag)
[docs] def recreate_last_tag(self): """Delete the last tag and create a new one on the latest commit. """ entry = self.last_tag_entry tag = entry['tag'] name = entry['name'] msg = entry['message'] logger.info('deleting: {}'.format(name)) if not self.dry_run: TagReference.delete(self.repo, tag) logger.info('creating {} with commit <{}>'.format(name, msg)) if not self.dry_run: TagReference.create(self.repo, name, message=msg)
[docs] def create(self): """Create a new tag on the latest commit. """ entry = self.last_tag_entry if entry is None: ver = Version.from_string('v0.0.0') else: ver = entry['ver'] ver.increment('debug') new_tag_name = str(ver) logger.info('creating {} with commit <{}>'.format( new_tag_name, self.message)) if not self.dry_run: TagReference.create(self.repo, new_tag_name, message=self.message)