Skip to content

Commit

Permalink
Add an option to generate CHANGELOG in reverse order
Browse files Browse the repository at this point in the history
Scrap logger and use secho with colors instead
Abort if version is not bumped
Generate CHANGELOG in reverse
  • Loading branch information
dormant-user committed Oct 24, 2021
1 parent ca50b1a commit 30571e7
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 131 deletions.
127 changes: 67 additions & 60 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,114 +1,121 @@
Change Log
==========

0.0.1 (08/30/2021)
0.2.5 (10/23/2021)
------------------
- Initial commit
- Add an option to generate `CHANGELOG` in reverse order
- Scrap logger and use secho with colors instead
- Abort if version is not bumped
- Generate CHANGELOG in reverse

0.0.2 (08/30/2021)
0.2.4 (10/14/2021)
------------------
- Add basic way to get details from `git log`
- Add project urls to pypi package

0.0.3 (08/30/2021)
0.2.3 (10/14/2021)
------------------
- Get content required for a CHANGELOG
- Use click to make the changelog-generator to make it as a CLI tool
- Update docstrings and README.md

0.0.4 (08/30/2021)
0.2.2 (10/14/2021)
------------------
- Add version numbers for each change
- Rename variable names
- Make Change Log the title as a heading

0.0.5 (08/30/2021)
0.2.1 (10/14/2021)
------------------
- Get the number of commits automatically
- Add three digit version numbers
- Add title to the generated CHANGELOG

0.0.6 (08/30/2021)
0.2.0 (08/31/2021)
------------------
- Wrap everything inside a class
- Print run time at the end
- Remove timestamp from CHANGELOG

0.0.7 (08/30/2021)
0.1.9 (08/31/2021)
------------------
- Get the commit info from the trunk branch
- Add a destructor method
- Add docstrings
- Update CHANGELOG

0.0.8 (08/30/2021)
0.1.8 (08/31/2021)
------------------
- Add pre-commit for linting, isort and flake8
- Support up to 6 digit version numbers
- Fix versions() getting called repeatedly
- Add logger info

0.0.9 (08/30/2021)
0.1.7 (08/31/2021)
------------------
- Add sphinx documentation
- README markdown and __init__ support for sphinx documentation
- Create gen_docs.sh
- Hook up the doc generation process to pre-commit
- bump version to run build

0.1.0 (08/30/2021)
0.1.6 (08/31/2021)
------------------
- onboard docs.yml but only prints a statement
- Update sample code in README.md
- Bump version to 0.1.6

0.1.1 (08/30/2021)
0.1.5 (08/31/2021)
------------------
- Alter time counter in destructor method
- Update README.md, .gitignore, CHANGELOG
- Bump version

0.1.4 (08/31/2021)
------------------
- auto upload to pypi when tagged a release version

0.1.3 (08/31/2021)
------------------
- revert change on python-publish.yml

0.1.2 (08/30/2021)
------------------
- Create a pypi package
- Move generator.py within a source directory
- Add __init__.py, CHANGELOT, LICENSE, MANIFEST.in, setup.cfg, setup.py, version.py

0.1.3 (08/31/2021)
------------------
- revert change on python-publish.yml

0.1.4 (08/31/2021)
0.1.1 (08/30/2021)
------------------
- auto upload to pypi when tagged a release version

0.1.5 (08/31/2021)
0.1.0 (08/30/2021)
------------------
- Alter time counter in destructor method
- Update README.md, .gitignore, CHANGELOG
- Bump version
- onboard docs.yml but only prints a statement

0.1.6 (08/31/2021)
0.0.9 (08/30/2021)
------------------
- Update sample code in README.md
- Bump version to 0.1.6
- Add sphinx documentation
- README markdown and __init__ support for sphinx documentation
- Create gen_docs.sh
- Hook up the doc generation process to pre-commit

0.1.7 (08/31/2021)
0.0.8 (08/30/2021)
------------------
- bump version to run build
- Add pre-commit for linting, isort and flake8

0.1.8 (08/31/2021)
0.0.7 (08/30/2021)
------------------
- Support up to 6 digit version numbers
- Fix versions() getting called repeatedly
- Add logger info
- Get the commit info from the trunk branch
- Add a destructor method
- Add docstrings

0.1.9 (08/31/2021)
0.0.6 (08/30/2021)
------------------
- Update CHANGELOG
- Wrap everything inside a class
- Print run time at the end

0.2.0 (08/31/2021)
0.0.5 (08/30/2021)
------------------
- Remove timestamp from CHANGELOG
- Get the number of commits automatically
- Add three digit version numbers

0.2.1 (10/14/2021)
0.0.4 (08/30/2021)
------------------
- Add title to the generated CHANGELOG
- Add version numbers for each change
- Rename variable names

0.2.2 (10/14/2021)
0.0.3 (08/30/2021)
------------------
- Make Change Log the title as a heading
- Get content required for a CHANGELOG

0.2.3 (10/14/2021)
0.0.2 (08/30/2021)
------------------
- Use click to make the changelog-generator to make it as a CLI tool
- Update docstrings and README.md
- Add basic way to get details from `git log`

0.2.4 (10/14/2021)
0.0.1 (08/30/2021)
------------------
- Add project urls to pypi package
- Initial commit
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ Generate CHANGELOG from git commit history
pip install changelog-generator
```

###### Regular CHANGELOG
```shell
changelog
```

###### CHANGELOG in reverse order
```shell
changelog reverse
```

### Pre-Commit
Install `pre-commit` to run `flake8` and `isort` for linting and `sphinx` for documentation generator.

Expand Down
99 changes: 61 additions & 38 deletions changemaker/generator.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import logging
from datetime import datetime
from importlib import reload
from os import path, remove, system
from pathlib import PurePath
from subprocess import check_output
from time import perf_counter
from typing import Union

from click import command, pass_context
from click import argument, command, pass_context, secho


class Generator:
Expand All @@ -28,28 +25,22 @@ def __init__(self):
- Removes ``CHANGELOG`` if a previous version is available.
- Older versions are not required, since ``git log`` captures all the commits anyway.
"""
reload(logging)
logging.basicConfig(
format='%(asctime)s - %(levelname)s - [%(module)s:%(lineno)d] - %(funcName)s - %(message)s',
datefmt='%b-%d-%Y %I:%M:%S %p'
)
self.logger = logging.getLogger(PurePath(__file__).stem)
self.logger.setLevel(logging.INFO)
branches = check_output("git branch", shell=True).decode('utf-8').replace('* ', '').strip().split('\n')
self.trunk = 'main' if 'main' in branches else 'master'
self.logger.info(f'Identified trunk branch to be {self.trunk}')
secho(message=f'Identified trunk branch to be {self.trunk}', fg='bright_green')
self.source = 'source_change_log.txt'
self.change = 'CHANGELOG'
self.logger.info('Writing git log into a temp file.')
secho(message='Writing git log into a temp file.', fg='bright_green')
system(f'git log --reverse > {self.source}')
if path.isfile(self.change):
secho(message='WARNING: Found existing CHANGELOG. Recreating now.', fg='bright_yellow')
remove(self.change)

def __del__(self):
"""Removes the source file as it is temporary and prints the run time."""
self.logger.info('Removing temp file.')
secho(message='Removing temp file.', fg='bright_green')
remove(self.source)
self.logger.info(f'CHANGELOG was created in: {round(float(perf_counter()), 2)}s')
secho(message=f'CHANGELOG was created in: {round(float(perf_counter()), 2)}s', fg='bright_green')

def get_commits(self) -> int:
"""Scans for the number of commits in the ``trunk`` branch.
Expand All @@ -59,7 +50,7 @@ def get_commits(self) -> int:
Number of commits.
"""
commits = int(check_output(f"git rev-list --count {self.trunk}", shell=True).decode('utf-8').split('\n')[0])
self.logger.info(f'Number of commits: {commits}')
secho(message=f'Number of commits: {commits}', fg='bright_green')
return commits

def versions(self) -> Union[list, None]:
Expand Down Expand Up @@ -102,7 +93,7 @@ def get_source(self) -> list:
log = file.read().splitlines()
return log

def run(self) -> None:
def generator(self) -> list:
"""Triggers the conversion process.
Notes:
Expand All @@ -113,37 +104,69 @@ def run(self) -> None:
See Also:
- Destructor ``__del__`` method executes upon exit which deletes the ``source_change_log.txt`` file.
Returns:
list:
List of snippets that has to be written to ``CHANGELOG`` file.
"""
versions = self.versions()
log = self.get_source()
self.logger.info('Generating CHANGELOG')
secho(message='Generating CHANGELOG', fg='bright_green')
iterator = 0
output = []
for index, element in enumerate(log):
element = element.strip()
if element.startswith('commit') or element.startswith('Author'):
continue
if element.startswith('Date'):
ind = log.index(element)
element = ' '.join(element.lstrip('Date:').strip().split()[0:-1])
datetime_obj = datetime.strptime(element, "%a %b %d %H:%M:%S %Y")
element = f'{versions[iterator]} ({datetime_obj.strftime("%m/%d/%Y")})'
iterator += 1
log[ind + 1] = '-' * len(element)
# log.pop(ind + 1) # Use this to leave a blank line instead of '----'
elif element:
if element[0].isdigit():
element = element.replace(element[0:2], '-')
if not element[0] == '-':
element = f'- {element}'
if not element:
output.append('^^')
else:
output.append(element + '\n')
return [snippet for snippet in ''.join(output).split('^^')]

def run(self, reverse: bool = False):
"""Writes the snippets into a ``CHANGELOG`` file.
Args:
reverse: Takes a boolean argument whether or not to generate the ``CHANGELOG`` in reverse.
"""
snippets = self.generator()
snippets.reverse() if reverse else None
with open(self.change, 'a') as file:
file.write('Change Log\n==========\n\n')
for index, element in enumerate(log):
element = element.strip()
if not element.startswith('commit') and not element.startswith('Author'):
if element.startswith('Date'):
ind = log.index(element)
element = ' '.join(element.lstrip('Date:').strip().split()[0:-1])
datetime_obj = datetime.strptime(element, "%a %b %d %H:%M:%S %Y")
element = f'{versions[iterator]} ({datetime_obj.strftime("%m/%d/%Y")})'
iterator += 1
log[ind + 1] = '-' * len(element)
# log.pop(ind + 1) # Use this to leave a blank line instead of '----'
elif element:
if element[0].isdigit():
element = element.replace(element[0:2], '-')
if not element[0] == '-':
element = f'- {element}'
file.write(element + '\n')
for index, each_snippet in enumerate(snippets):
file.write(f'{each_snippet}\n' if index + 1 < len(snippets) else each_snippet)


@command()
@pass_context
def main(*args):
"""Generate change log file."""
Generator().run()
@argument('reverse', required=False)
def main(*args, reverse: str = None):
"""Generate change log file.
Run 'changelog reverse' to generate changelog in reverse order.
"""
if reverse:
if reverse.lower() == 'reverse':
secho(message='Generating CHANGELOG from commit history in reverse order.', fg='bright_yellow')
Generator().run(reverse=True)
else:
secho(message='The only allowed options are:\n\t1. changelog\n\t2. changelog reverse', fg='bright_red')
else:
Generator().run()


if __name__ == '__main__':
Expand Down
13 changes: 12 additions & 1 deletion docs/README.html
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,19 @@ <h3>Navigate to the repository and run:<a class="headerlink" href="#navigate-to-
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>pip install changelog-generator
</pre></div>
</div>
</section>
<section id="regular-changelog">
<h3>Regular CHANGELOG<a class="headerlink" href="#regular-changelog" title="Permalink to this headline"></a></h3>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>changelog
</pre></div>
</div>
</section>
<section id="changelog-in-reverse-order">
<h3>CHANGELOG in reverse order<a class="headerlink" href="#changelog-in-reverse-order" title="Permalink to this headline"></a></h3>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>changelog reverse
</pre></div>
</div>
</section>
</section>
<section id="pre-commit">
<h2>Pre-Commit<a class="headerlink" href="#pre-commit" title="Permalink to this headline"></a></h2>
Expand Down Expand Up @@ -100,6 +109,8 @@ <h3><a href="index.html">Table of Contents</a></h3>
<li><a class="reference internal" href="#pypi-module">Pypi Module</a></li>
<li><a class="reference internal" href="#usage">Usage</a><ul>
<li><a class="reference internal" href="#navigate-to-the-repository-and-run">Navigate to the repository and run:</a></li>
<li><a class="reference internal" href="#regular-changelog">Regular CHANGELOG</a></li>
<li><a class="reference internal" href="#changelog-in-reverse-order">CHANGELOG in reverse order</a></li>
</ul>
</li>
<li><a class="reference internal" href="#pre-commit">Pre-Commit</a></li>
Expand Down Expand Up @@ -151,7 +162,7 @@ <h3>Navigation</h3>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2021, Vignesh Sivanandha Rao.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 4.2.0.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 4.1.2.
</div>
</body>
</html>
Loading

0 comments on commit 30571e7

Please sign in to comment.