{ "info": { "author": "Greenbone Networks GmbH", "author_email": "info@greenbone.net", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Operating System :: OS Independent", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Version Control :: Git" ], "description": "![Greenbone Logo](https://www.greenbone.net/wp-content/uploads/gb_logo_resilience_horizontal.png)\n\n# Autohooks\n\n[![PyPI release](https://img.shields.io/pypi/v/autohooks.svg)](https://pypi.org/project/autohooks/)\n\nLibrary for managing and writing [git hooks](https://git-scm.com/docs/githooks)\nin Python\n\n## Why?\n\nSeveral outstanding libraries for managing and executing git hooks already\nexist. To name few: [husky](https://github.com/typicode/husky),\n[lint-staged](https://github.com/okonet/lint-staged),\n[precise-commits](https://github.com/nrwl/precise-commits) or\n[pre-commit](https://github.com/pre-commit/pre-commit).\n\nBut either they need another interpreter besides python (like husky) or they are\ntoo ambiguous (like pre-commit). pre-commit is written in python but has support\nhooks written in all kind of languages. Also it maintains the dependencies by\nitself and doesn't install in the current environment.\n\n## Solution\n\nAutohooks is a pure python library that installs a minimal\n[executable git hook](https://github.com/greenbone/autohooks/blob/master/autohooks/precommit/template).\nIf autohooks isn't installed in your current python path the hooks aren't\nexecuted. So autohooks is always opt-in by installing the package into your\ncurrent development environment. It would be even possible to run different\nversions of autohooks by switching the environment.\n\nAutohooks doesn't interfere with your work. If autohooks can't be run or fails\nexecuting a plugin, an error is shown only and the git hook will proceed.\n\n## Installation\n\nFor the installation of autohooks three steps are necessary:\n\n1. Install the autohooks package into your current environment\n2. Activate the [git hooks](https://git-scm.com/docs/githooks)\n3. Configure the plugins to be run\n\n### Install autohooks python package\n\nFor installing the autohooks python package, using\n[pipenv](https://pipenv.readthedocs.io/) is highly recommended.\n\nTo install autohooks as a development dependency run\n\n```sh\npipenv install --dev autohooks\n```\n\nAlternatively autohooks can be installed directly from GitHub\n\n```sh\npipenv install --dev -e git+https://github.com/greenbone/autohooks#egg=autohooks\n```\n\n### Activating the git hooks\n\nIf autohooks is installed from git or a source tarball, the git hooks should be\nactivated automatically. The activation can be verified by running e.g.\n`autohooks check`.\n\nInstalling autohooks from a [wheel](https://www.python.org/dev/peps/pep-0427/)\npackage will **NOT** activate the git commit hooks.\n\nTo manually activate the git hooks you can run\n\n```sh\npipenv run autohooks activate\n```\n\n### Configure plugins to be run\n\nTo actually run an action on git hooks, [autohooks plugins](#plugins) have to be\ninstalled and configured. To install e.g. python linting via pylint run\n\n```\npipenv install --dev autohooks-plugin-pylint\n```\n\nAutohooks uses the *pyproject.toml* file specified in\n[PEP518](https://www.python.org/dev/peps/pep-0518/) for its configuration.\nAdding a *[tool.autohooks]* section allows to set python modules to be run on a\nspecific git hook.\n\nExample *pyproject.toml*:\n\n```toml\n[build-system]\nrequires = [\"setuptools\", \"wheel\"]\n\n[tool.autohooks]\npre-commit = [\"autohooks.plugins.black\"]\n```\n\n## Proposed Workflow\n\nUsing [pipenv](https://pipenv.readthedocs.io/) allows to install all\ndependencies and tools with a specific version into a virtual, easily removable\nPython environment. Therefore it's best to maintain **autohooks** also via\npipenv. Because it is not required to build or run your software, it should be\n[installed as a development dependency](#install-autohooks-python-package).\nInstalling and [activating](#activating-the-git-hooks) autohooks doesn't\nactually run any check or formatting by itself. Therefore, it is required to\n[choose and install a plugin](#configure-plugins-to-be-run).\n\nIf all these tasks have been resolved, the developers are able to install\nand activate autohooks with only one single command from your project's git\nrepository:\n\n```sh\npipenv install --dev\n```\n\nBecause virtual environments are used for all dependencies including\nautohooks, the linting, formatting, etc. can only by done when running\n`git commit` within the virtual environment.\n\n```sh\n$ cd myproject\n$ pipenv install --dev\n$ pipenv shell\n(myproject)$ git commit\n```\n\nThe advantage of this process is, if the user is not running `git commit` within\nthe active virtual environment, autohooks and its plugins are not executed.\n\n```sh\n$ cd myproject\n$ git commit\n```\n\nThis allows the user to choose whether to execute the hooks by activating the\nvirtual environment or to ignore them by deactivating it.\n\n## Plugins\n\n* Python code formatting via [black](https://github.com/greenbone/autohooks-plugin-black)\n\n* Python code linting via [pylint](https://github.com/greenbone/autohooks-plugin-pylint)\n\n## How-to write a Plugin\n\nPlugins need to be available in the\n[Python import path](https://docs.python.org/3/reference/import.html). The\neasiest way to achieve this, is to upload a plugin to [PyPI](https://pypi.org/)\nand install it via [pip]() or [pipenv](http://pipenv.readthedocs.io/).\n\nAlternatively, a plugin can also be put into a *.autohooks* directory at the root\ndirectory of the git repository where the hooks should be executed.\n\nAn autohooks plugin is a Python module which provides a **precommit** function.\nThe function must accept arbitrary keywords because the keywords are likely to\nchange in future. Therefore using **\\*\\*kwargs** is highly recommended.\nCurrently only a *config* keyword argument is passed to the precommit function.\nE.g.\n\n```python3\ndef precommit(**kwargs):\n config = kwargs.get('config')\n```\n\nThe config can be used to receive settings from the *pyproject.toml* file. E.g.\n\n```toml\n[tool.autohooks.plugins.foo]\nbar = 2\n```\n\ncan be received with\n\n```python3\ndef precommit(**kwargs):\n config = kwargs.get('config')\n default_value = 1\n setting = config\n .get('tool', 'autohooks', 'plugins', 'foo')\n .get_value('bar', default_value)\n return 0\n```\n\nWith autohooks it is possible to write all kinds of plugins. Most common are\nplugins for linting and formatting.\n\n### Linting plugin\n\nUsually the standard call sequence for a linting plugin is\n\n1. get list of staged files\n2. filter list of files for a specific file type\n3. stash unrelated changes\n4. apply checks on filtered list of files by calling some external tool\n5. raise exception if something did go wrong\n6. return 1 if check was not successful\n6. stage changes made by the tool\n7. unstash unrelated changes\n8. return 0\n\nExample plugin:\n\n```python3\nimport subprocess\n\nfrom autohooks.api import ok, fail\nfrom autohooks.api.git import get_staged_status, stash_unstaged_changes\nfrom autohooks.api.path import match\n\nDEFAULT_INCLUDE = ('*.ext')\n\n\ndef get_include(config)\n if not config:\n return DEFAULT_INCLUDE\n\n config = config.get('tool', 'autohooks', 'plugins', 'foo')\n return config.get_value('include', DEFAULT_INCUDE)\n\n\ndef precommit(**kwargs):\n config = kwargs.get('config')\n include = get_include(config)\n\n files = [f for f in get_staged_status() if match(f.path, include)]\n\n if not files:\n # not files to lint\n return 0\n\n with stash_unstaged_changes(files):\n const failed = False\n for file in files:\n status = subprocess.call(['foolinter', str(file)])\n if status:\n fail('Could not validate {}'.format(str(file)))\n failed = True\n else:\n ok('Validated {}'.format(str(file)))\n\n return 1 if failed else 0\n\n### Formatting plugin\n\nUsually the standard call sequence for a formatting plugin is\n\n1. get list of staged files\n2. filter list of files for a specific file type\n3. stash unrelated changes\n4. apply formatting on filtered list of files by calling some external tool\n5. raise exception if something did go wrong\n6. stage changes made by the tool\n7. unstash unrelated changes\n8. return 0\n\nExample plugin:\n```python3\nimport subprocess\n\nfrom autohooks.api import ok, error\nfrom autohooks.api.git import (\n get_staged_status,\n stage_files_from_status_list,\n stash_unstaged_changes,\n)\nfrom autohooks.api.path import match\n\nDEFAULT_INCLUDE = ('*.ext')\n\n\ndef get_include(config)\n if not config:\n return DEFAULT_INCLUDE\n\n config = config.get('tool', 'autohooks', 'plugins', 'bar')\n return config.get_value('include', DEFAULT_INCUDE)\n\n\ndef precommit(**kwargs):\n config = kwargs.get('config')\n include = get_include(config)\n\n files = [f for f in get_staged_status() if match(f.path, include)]\n\n if not files:\n # not files to format\n return 0\n\n with stash_unstaged_changes(files):\n for file in files:\n # run formatter and raise exception if it fails\n subprocess.run(['barformatter', str(file)], check=True)\n ok('Formatted {}'.format(str(file)))\n\n return 0\n```\n\n## Maintainer\n\nThis project is maintained by [Greenbone Networks GmbH](https://www.greenbone.net/).\n\n## Contributing\n\nYour contributions are highly appreciated. Please\n[create a pull request](https://github.com/greenbone/autohooks/pulls)\non GitHub. Bigger changes need to be discussed with the development team via the\n[issues section at GitHub](https://github.com/greenbone/autohooks/issues)\nfirst.\n\n## License\n\nCopyright (C) 2019 [Greenbone Networks GmbH](https://www.greenbone.net/)\n\nLicensed under the [GNU General Public License v3.0 or later](LICENSE).", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/greenbone/autohooks", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "autohooks", "package_url": "https://pypi.org/project/autohooks/", "platform": "", "project_url": "https://pypi.org/project/autohooks/", "project_urls": { "Homepage": "https://github.com/greenbone/autohooks" }, "release_url": "https://pypi.org/project/autohooks/1.1.0/", "requires_dist": null, "requires_python": ">=3.5", "summary": "Library for managing git hooks", "version": "1.1.0" }, "last_serial": 4992858, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "305a4d401746a43f6dfe25ceb948721b", "sha256": "1cee2cb93a01ecfc9dd2a7b5fb7aa2b0c8c336251e94cf33fd6cf25e2c5baa35" }, "downloads": -1, "filename": "autohooks-1.0.0.tar.gz", "has_sig": false, "md5_digest": "305a4d401746a43f6dfe25ceb948721b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 27719, "upload_time": "2019-02-20T12:41:04", "url": "https://files.pythonhosted.org/packages/b4/9d/5db7a88ab28159d75e1ef149c84909243a6b82680565098f2f47b56c990d/autohooks-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "d44174b8b46d69e82aeada24a4e4c70d", "sha256": "3dff17e3ff68f8073a51432580809fdf384c0bd079c4aef2228b06539f0eb4a6" }, "downloads": -1, "filename": "autohooks-1.0.1.tar.gz", "has_sig": false, "md5_digest": "d44174b8b46d69e82aeada24a4e4c70d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 27721, "upload_time": "2019-02-25T11:14:38", "url": "https://files.pythonhosted.org/packages/e6/c2/6c5312c55980f44706b0dcd2d75aca43cd1f49bc7489a7de2b771467bf14/autohooks-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "dab5074da3f6cf9d5a922c5f86c85c6a", "sha256": "ef9fd5151a5b572fe8b467ead995d7abc0bd5dc71d98d056de5304590250c815" }, "downloads": -1, "filename": "autohooks-1.0.2.tar.gz", "has_sig": false, "md5_digest": "dab5074da3f6cf9d5a922c5f86c85c6a", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 27759, "upload_time": "2019-02-25T11:59:54", "url": "https://files.pythonhosted.org/packages/46/eb/767ebd6094c562ec9d561fbb4779261eeba9fa660a73292e662bcc8bf54c/autohooks-1.0.2.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "c77eaa88108eb9ad9f999b63aa2dff5f", "sha256": "2ef6e1b90d1837191bacd5faa2f4cdaafebebb7c21707b6ba22ad1879ec31326" }, "downloads": -1, "filename": "autohooks-1.1.0.tar.gz", "has_sig": false, "md5_digest": "c77eaa88108eb9ad9f999b63aa2dff5f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 34988, "upload_time": "2019-03-27T13:39:42", "url": "https://files.pythonhosted.org/packages/be/52/f4ebac5a975a79345f80dc01af5159b5fda6ad46197a3dec63e4ab0c0cf6/autohooks-1.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c77eaa88108eb9ad9f999b63aa2dff5f", "sha256": "2ef6e1b90d1837191bacd5faa2f4cdaafebebb7c21707b6ba22ad1879ec31326" }, "downloads": -1, "filename": "autohooks-1.1.0.tar.gz", "has_sig": false, "md5_digest": "c77eaa88108eb9ad9f999b63aa2dff5f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 34988, "upload_time": "2019-03-27T13:39:42", "url": "https://files.pythonhosted.org/packages/be/52/f4ebac5a975a79345f80dc01af5159b5fda6ad46197a3dec63e4ab0c0cf6/autohooks-1.1.0.tar.gz" } ] }