├── logo.png
├── MANIFEST.in
├── enforce_git_message
├── __init__.py
├── main.py
└── git-templates
│ └── hooks
│ └── commit-msg
├── LICENSE
├── README.md
├── .gitignore
├── setup.py
└── docs
├── conf.py
└── index.rst
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prahladyeri/enforce-git-message/HEAD/logo.png
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | # file GENERATED by distutils, do NOT edit
2 | include setup.py
3 | #recursive-include git-templates *
4 | recursive-include enforce_git_message/git-templates *
--------------------------------------------------------------------------------
/enforce_git_message/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = "Prahlad Yeri"
2 | __email__ = "prahladyeri@yahoo.com"
3 | __copyright__ = "(c) 2019 Prahlad Yeri"
4 |
5 | __license__ = "MIT"
6 | __version__ = "1.0.1"
7 | __title__ = 'Enforce GIT Message'
8 | __description__ = 'Enforces conventional git commit messages for git repositories'
--------------------------------------------------------------------------------
/enforce_git_message/main.py:
--------------------------------------------------------------------------------
1 | import shutil, os
2 |
3 | def main():
4 | if not os.path.isdir('.git'):
5 | print('error: .git directory not found in the current path. this is not a git repository?')
6 | return
7 |
8 | template_path = os.path.expanduser("~/.git-templates/hooks/commit-msg")
9 | if shutil.which('git') == None:
10 | print('error: git not found on path. please install git and then run pip install --upgrade enforce-git-message')
11 | return
12 | if not os.path.exists(template_path):
13 | print('error: git hooks template not found on %s, please run pip install enforce-git-message' % template_path)
14 | return
15 | shutil.copy(template_path, ".git/hooks/")
16 | print("success: conventional git messages are enforced")
17 |
18 | if __name__ == "__main__":
19 | main()
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Prahlad Yeri
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/enforce_git_message/git-templates/hooks/commit-msg:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | ##
3 | # @author Prahlad Yeri
4 | # @email prahladyeri@yahoo.com
5 | # @title Git hook for enforcing conventional commit spec
6 | #
7 | # @todo Create folder ~/.git-templatesand set that value to init.templatedir git config key globally.
8 | # @todo Copy this script to ~/.git-templates/hooks/ and rename it to commit-msg.
9 | # @todo (Linux): Make the script executable.
10 | import re, sys, os
11 |
12 | examples = """+ 61c8ca9 fix: navbar not responsive on mobile
13 | + 479c48b test: prepared test cases for user authentication
14 | + a992020 chore: moved to semantic versioning
15 | + b818120 fix: button click even handler firing twice
16 | + c6e9a97 fix: login page css
17 | + dfdc715 feat(auth): added social login using twitter
18 | """
19 |
20 | def main():
21 | # example:
22 | # feat(apikey): added the ability to add api key to configuration
23 | pattern = r'(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert)(\([\w\-]+\))?:\s.*'
24 | filename = sys.argv[1]
25 | ss = open(filename, 'r').read()
26 | m = re.match(pattern, ss)
27 | if m == None:
28 | #raise Exception("conventional commit validation failed")
29 | print("\nCOMMIT FAILED!")
30 | print("\nPlease enter commit message in the conventional format and try to commit again. Examples:")
31 | print("\n" + examples)
32 | sys.exit(1)
33 |
34 | if __name__ == "__main__":
35 | main()
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 
6 | [](https://www.patreon.com/prahladyeri)
7 | [](https://paypal.me/prahladyeri)
8 | [](https://twitter.com/prahladyeri)
9 |
10 | # enforce-git-message
11 |
12 | 
13 |
14 | Enforces [conventional git commit messages](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) for all new git repositories you create by running `git init`
15 |
16 | # Installation
17 |
18 | pip install enforce-git-message
19 |
20 | # Documentation
21 |
22 | Detailed docs are available at .
23 |
24 | # Attribution
25 |
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # custom
2 | #test/
3 | docs/html
4 |
5 | # Byte-compiled / optimized / DLL files
6 | __pycache__/
7 | *.py[cod]
8 | *$py.class
9 |
10 | # C extensions
11 | *.so
12 |
13 | # Distribution / packaging
14 | .Python
15 | build/
16 | develop-eggs/
17 | dist/
18 | downloads/
19 | eggs/
20 | .eggs/
21 | lib/
22 | lib64/
23 | parts/
24 | sdist/
25 | var/
26 | wheels/
27 | *.egg-info/
28 | .installed.cfg
29 | *.egg
30 | MANIFEST
31 |
32 | # PyInstaller
33 | # Usually these files are written by a python script from a template
34 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
35 | *.manifest
36 | *.spec
37 |
38 | # Installer logs
39 | pip-log.txt
40 | pip-delete-this-directory.txt
41 |
42 | # Unit test / coverage reports
43 | htmlcov/
44 | .tox/
45 | .coverage
46 | .coverage.*
47 | .cache
48 | nosetests.xml
49 | coverage.xml
50 | *.cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 |
63 | # Flask stuff:
64 | instance/
65 | .webassets-cache
66 |
67 | # Scrapy stuff:
68 | .scrapy
69 |
70 | # Sphinx documentation
71 | docs/_build/
72 |
73 | # PyBuilder
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # pyenv
80 | .python-version
81 |
82 | # celery beat schedule file
83 | celerybeat-schedule
84 |
85 | # SageMath parsed files
86 | *.sage.py
87 |
88 | # Environments
89 | .env
90 | .venv
91 | env/
92 | venv/
93 | ENV/
94 | env.bak/
95 | venv.bak/
96 |
97 | # Spyder project settings
98 | .spyderproject
99 | .spyproject
100 |
101 | # Rope project settings
102 | .ropeproject
103 |
104 | # mkdocs documentation
105 | /site
106 |
107 | # mypy
108 | .mypy_cache/
109 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import os, sys
3 | import enforce_git_message
4 | from enforce_git_message import __version__, __description__, __author__, __email__, __license__, __title__
5 | from setuptools import setup, find_packages
6 | from setuptools.command.install import install
7 | #from subprocess import check_call
8 | #from pkg_resources import Requirement, resource_filename
9 | import site
10 | from distutils.dir_util import copy_tree
11 | #import shutil
12 |
13 | pypi_name = "enforce-git-message"
14 | pkg_name = "enforce_git_message"
15 |
16 | class PostInstallCommand(install):
17 | """Post-installation for installation mode."""
18 | def run(self):
19 | os.system("echo CUSTOM_PRE_MESSAGE")
20 | install.run(self)
21 | os.system("echo CUSTOM_POST_MESSAGE")
22 | #conf_path_temp = resource_filename(Requirement.parse(pypi_name), "git-templates")
23 | #the_path = site.getusersitepackages() # => Useless and misleading
24 | fpath = os.path.join(self.install_lib, pkg_name)
25 | fpath = os.path.join(fpath, "git-templates")
26 | tpath = os.path.join(os.path.expanduser("~"), ".git-templates")
27 | os.system("git config --global init.templatedir ~/.git-templates")
28 | copy_tree(fpath, tpath)
29 |
30 | def read(fname):
31 | return open(os.path.join(os.path.dirname(__file__), fname)).read()
32 |
33 | s = setup(
34 | name=pypi_name,
35 | version=__version__,
36 | license=__license__,
37 | description=__description__,
38 | long_description=read("README.md"),
39 | long_description_content_type='text/markdown',
40 | keywords="security,scanner",
41 | url='https://github.com/prahladyeri/%s' % pypi_name,
42 | packages=find_packages(),
43 | include_package_data=True,
44 | entry_points={
45 | "console_scripts": [
46 | "enforce-git-message = enforce_git_message.main:main",
47 | ],
48 | },
49 | install_requires=[],
50 | python_requires = ">= 3.4",
51 | author=__author__,
52 | author_email=__email__,
53 | classifiers=[
54 | "Programming Language :: Python :: 3",
55 | "License :: OSI Approved :: MIT License",
56 | "Operating System :: OS Independent",
57 | ],
58 | cmdclass={
59 | 'install': PostInstallCommand,
60 | },
61 | )
62 |
63 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # http://www.sphinx-doc.org/en/master/config
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 | #
13 | # import os
14 | # import sys
15 | # sys.path.insert(0, os.path.abspath('.'))
16 |
17 |
18 | # -- Project information -----------------------------------------------------
19 |
20 | project = 'Enforce Git Message'
21 | copyright = '2019, Prahlad Yeri'
22 | author = 'Prahlad Yeri'
23 |
24 | master_doc = 'index'
25 | # -- General configuration ---------------------------------------------------
26 |
27 | # Add any Sphinx extension module names here, as strings. They can be
28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
29 | # ones.
30 | #extensions = [
31 | #]
32 |
33 | # Add any paths that contain templates here, relative to this directory.
34 | #templates_path = ['_templates']
35 |
36 | # List of patterns, relative to source directory, that match files and
37 | # directories to ignore when looking for source files.
38 | # This pattern also affects html_static_path and html_extra_path.
39 | #exclude_patterns = []
40 |
41 |
42 | # -- Options for HTML output -------------------------------------------------
43 |
44 | # The theme to use for HTML and HTML Help pages. See the documentation for
45 | # a list of builtin themes.
46 | #
47 | #html_theme = 'alabaster'
48 | #html_theme = 'sphinxdoc'
49 | #html_theme = 'classic'
50 | #html_theme = 'nature'
51 | #html_theme = 'pyramid'
52 |
53 | # Add any paths that contain custom static files (such as style sheets) here,
54 | # relative to this directory. They are copied after the builtin static files,
55 | # so a file named "default.css" will overwrite the builtin "default.css".
56 | #html_static_path = ['_static']
57 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. toctree::
2 | :maxdepth: 2
3 | :caption: Contents:
4 |
5 | Introduction
6 | ============================
7 |
8 | .. image:: https://raw.githubusercontent.com/prahladyeri/enforce-git-message/master/logo.png
9 |
10 | `enforce-git-message `_ is a tool for enforcing `conventional git commit messages `_ for all new git repositories you create by running `git init`. For existing repositories, you can go to your source directory and simply run::
11 |
12 | enforce-git-message
13 |
14 | Examples of valid commit messages:
15 |
16 | .. code-block:: diff
17 |
18 | + 61c8ca9 fix: navbar not responsive on mobile
19 | + 479c48b test: prepared test cases for user authentication
20 | + a992020 chore: moved to semantic versioning
21 | + b818120 fix: button click even handler firing twice
22 | + c6e9a97 fix: login page css
23 | + dfdc715 feat(auth): added social login using twitter
24 |
25 | Examples of invalid commit messages resulting in an error message:
26 |
27 | .. code-block:: diff
28 |
29 | - 61c8ca9 fix for navbar not responsive on mobile
30 | - 479c48b prepared test cases for user authentication
31 | - a992020 moved to semantic versioning
32 | - b818120 fixed button click even handler firing twice
33 | - c6e9a97 login page css fix
34 | - dfdc715 added social login auth feature using twitter
35 |
36 | Installation
37 | ===========================
38 |
39 | .. code-block:: bash
40 |
41 | pip install enforce-git-message
42 |
43 | Verification
44 | ===========================
45 |
46 | Go to your source folder and try to commit with a non-conventional message like this and it should fail:
47 |
48 | .. code-block:: bash
49 |
50 | > git commit -m "added a new feature for xyz"
51 |
52 | COMMIT FAILED!
53 |
54 | Please enter commit message in the conventional format and try to commit again. Examples:
55 |
56 | + 61c8ca9 fix: navbar not responsive on mobile
57 | + 479c48b test: prepared test cases for user authentication
58 | + a992020 chore: moved to semantic versioning
59 | + b818120 fix: button click even handler firing twice
60 | + c6e9a97 fix: login page css
61 | + dfdc715 feat(auth): added social login using twitter
62 |
63 | After that, try doing the commit with a valid message and it should work:
64 |
65 | .. code-block:: bash
66 |
67 | > git commit -m "feat(test): added xyz"
68 | [master (root-commit) 8797aa0] feat(test): added xyz
69 | 6 files changed, 1 insertion(+)
70 | create mode 100644 test.java
71 | create mode 100644 foo.txt
72 | create mode 100644 bar.txt
73 |
74 | Notes
75 | ======
76 |
77 | `Read this article `_ to fully understand how the enforcement actually works by using git hooks.
78 |
79 |
80 | Attribution
81 | =============
82 |
83 | .. raw:: html
84 |
85 |
86 |
87 |
88 | Indices and tables
89 | ===========================
90 |
91 | * :ref:`genindex`
92 | * :ref:`modindex`
93 | * :ref:`search`
94 |
--------------------------------------------------------------------------------