Skip to content

Commit 703cf10

Browse files
committed
Added sphinx documentation
1 parent cdea04d commit 703cf10

13 files changed

+353
-7
lines changed

doc/Makefile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = source
9+
BUILDDIR = build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
doc:
18+
sphinx-apidoc -f -o source/ ../gitWebhook/
19+
20+
# Catch-all target: route all unknown targets to Sphinx using the new
21+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
22+
%: Makefile
23+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

doc/source/conf.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Configuration file for the Sphinx documentation builder.
2+
#
3+
# For the full list of built-in configuration values, see the documentation:
4+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
5+
6+
# -- Project information -----------------------------------------------------
7+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8+
9+
project = 'gitWebhook'
10+
copyright = '2024, TCA'
11+
author = 'TCA'
12+
release = '0.2'
13+
14+
# -- General configuration ---------------------------------------------------
15+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
16+
17+
extensions = [
18+
"sphinx.ext.autodoc",
19+
"sphinx.ext.viewcode",
20+
"sphinx.ext.napoleon",
21+
]
22+
23+
templates_path = ['_templates']
24+
exclude_patterns = []
25+
26+
27+
28+
# -- Options for HTML output -------------------------------------------------
29+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
30+
31+
html_theme = 'sphinx_rtd_theme'
32+
html_static_path = ['_static']

doc/source/gitWebhook.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
gitWebhook Module
2+
==================
3+
4+
.. automodule:: gitWebhook
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

doc/source/index.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.. gitWebhook documentation master file, created by
2+
sphinx-quickstart on Thu Apr 18 14:07:22 2024.
3+
You can adapt this file completely to your liking, but it should at least
4+
contain the root `toctree` directive.
5+
6+
Welcome to gitWebhook's documentation!
7+
======================================
8+
9+
gitWebhook is a Python package that provides Flask blueprints for creating webhooks for various git services.
10+
As of right now GitHub, GitLab and Gitea webhooks are supported.
11+
The package provides these blueprints as subclasses of Flask's Blueprint class, so they can be easily integrated into existing Flask applications, and expanded with custom behavior.
12+
13+
.. toctree::
14+
:maxdepth: 2
15+
:caption: Contents:
16+
17+
modules
18+
19+
tutorials
20+
21+
Indices and tables
22+
==================
23+
24+
* :ref:`genindex`
25+
* :ref:`modindex`
26+
* :ref:`search`

doc/source/modules.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
gitWebhook
2+
==========
3+
4+
.. toctree::
5+
:maxdepth: 4
6+
7+
gitWebhook
8+
9+
Webhook Configuration Options
10+
-----------------------------
11+
12+
The classes contained in this module share some common configuration options that allow you to customize the behavior of the webhook.
13+
This occurs via arguments passed to the classes during instantiation.
14+
Since all webhook blueprint classes inherit from :class:`webhookBlueprint`, the configuration options are shared among all classes.
15+
16+
The following configuration options are available:
17+
18+
- **webhookToken** (*str*) - The secret key that the webhook will use to verify the authenticity of incoming requests.
19+
- **log** (*logging.Logger*) - The logger that the webhook will use to log messages.
20+
- **name** (*str*) - The name of the webhook blueprint.
21+
- **github** (*bool*) - Whether the webhook should support GitHub webhooks.
22+
- **gitlab** (*bool*) - Whether the webhook should support GitLab webhooks.
23+
- **gitea** (*bool*) - Whether the webhook should support Gitea webhooks.
24+
- **ipWhitelist** (*List[str]*) - A list of IP addresses that are allowed to send requests to the webhook.
25+
26+
None of these options are mandatory, but you should at least provide a `webhookToken` to ensure that the webhook is secure.
27+
28+
Logging
29+
-------
30+
31+
All of the blueprints in this module will log events to the provided logger if one is provided.
32+
All internal errors are logged at the `ERROR` level.
33+
Arrival of a request is logged at the `INFO` level.
34+
While all failed requests are logged at the `WARNING` level.
35+
Use this information to filter what sort of events you want to receive.
36+

doc/source/tutorials.rst

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
Tutorials
2+
==========
3+
4+
Here are some tutorials on how to use gitWebhook.
5+
All tutorials assume you have git installed on your system, and initialized in the directory you are working in.
6+
This repository must be configured to connect via SSH to the remote repository using pre-configured SSH keys so that the webhook can just call::
7+
8+
git pull
9+
10+
with no issues.
11+
12+
Automatic deployment with GitHub using Webhooks
13+
------------------------------------------------
14+
15+
In this tutorial, we will setup a simple automatic deployment system using GitHub Webhooks.
16+
This will allow you to automatically deploy your code to your server whenever you push to your GitHub repository.
17+
18+
First we are going to set up the backend server that will receive the webhook requests from GitHub.
19+
We need to have gitWebhook installed on the server, so run::
20+
21+
pip install gitAppWebhook
22+
23+
to make sure you have both Flask and gitWebhook installed.
24+
Then create a new file called `webhook.py` and add the following code::
25+
26+
from gitWebhook import pullerWebhookBlueprint
27+
from flask import Flask
28+
29+
TOKEN = ""
30+
31+
app = Flask(__name__)
32+
wb = pullerWebhookBlueprint(token, url_prefix="/")
33+
app.register_blueprint(wb)
34+
35+
if __name__ == "__main__":
36+
app.run()
37+
38+
This code once run will start a Flask server that listens for POST requests on the root URL from either GitHub, GitLab or Gitea using :class:`pullerWebhookBlueprint`.
39+
The `TOKEN` variable is the secret token that you will use to authenticate the requests from GitHub.
40+
You can set this to any string you want, but make sure it is a strong secret.
41+
You can also set the `url_prefix` to any URL you want, but for this tutorial we will use the root URL.
42+
43+
You can now run the server by running the following command::
44+
45+
python webhook.py
46+
47+
This will start the server on the default Flask url and port.
48+
Naturally if you are running this on a production server, you will want to use a proper WSGI server like Gunicorn or uWSGI.
49+
Flask production deployment is outside the scope of this tutorial, but you can find more information in the `Flask documentation <https://flask.palletsprojects.com/en/1.1.x/deploying/>`_.
50+
51+
After the server is running all that is left is to create a webhook on GitHub.
52+
Go to your repository on GitHub and click on the `Settings` tab.
53+
Then click on the `Webhooks` tab on the left side of the page.
54+
Click on the `Add webhook` button and you will be presented with a form to fill in the details of the webhook.
55+
Don't forget to set the `Content type` to `application/json` and the `Secret` to the same value as the `TOKEN` variable in the `webhook.py` file.
56+
57+
GitHub has a fairly well documented and easy to use webhook interface, so you can find more information on how to set up a webhook on GitHub in the `GitHub documentation <https://developer.github.com/webhooks/creating/>`_.
58+
If you have configured everything correctly you should now be able to push to your repository and see the changes automatically deployed to your server.
59+
60+
How to setup automatic testing with gitWebhook
61+
----------------------------------------------
62+
63+
This example is very similar to the previous one, but alongside deploying the code we will also run tests on the code.
64+
Like previously we will start by setting up the backend server that will receive the webhook requests from GitHub.
65+
We need to have gitWebhook installed on the server, so run::
66+
67+
pip install gitAppWebhook
68+
69+
and then create a new file called `webhook.py` and add the following code::
70+
71+
from gitWebhook import pullerWebhookBlueprint
72+
from flask import Flask
73+
from tests import yourTestSuite
74+
75+
TOKEN = ""
76+
77+
app = Flask(__name__)
78+
wb = pullerWebhookBlueprint(token, url_prefix="/", tests=yourTestSuite)
79+
80+
if __name__ == "__main__":
81+
app.run()
82+
83+
After that you need to create a new file called `tests.py` and add the following code::
84+
85+
import unittest
86+
87+
class YourTestSuite(unittest.TestCase):
88+
def test_something(self):
89+
self.assertTrue(True)
90+
91+
yourTestSuite = unittest.TestLoader().loadTestsFromTestCase(YourTestSuite)
92+
93+
This code will start a Flask server that listens for POST requests on the root URL from either GitHub, GitLab or Gitea using :class:`pullerWebhookBlueprint`.
94+
Upon receiving a request, the server will pull the changes from git, run the tests in the `tests.py` file, return the result to GitHub and if the tests failed return the repository to the pre merge state.

gitWebhook/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
"""Python module providing Flask blueprints for handling GitHub and GitLab webhooks."""
1+
"""Python module providing Flask blueprints for handling various git app wehbooks."""
22

33
from .webhook import webhookBlueprint
44
from .abstractWebhook import gitWebhookBlueprintABC
55
from .pullerWebhook import pullerWebhookBlueprint
66
from .functionWebhook import functionWebhookBlueprint
77

8+
__exports__ = [webhookBlueprint, gitWebhookBlueprintABC, pullerWebhookBlueprint, functionWebhookBlueprint]
9+
10+
for e in __exports__:
11+
e.__module__ = __name__
12+
813
__all__ = ["webhookBlueprint", "gitWebhookBlueprintABC", "pullerWebhookBlueprint", "functionWebhookBlueprint"]

gitWebhook/abstractWebhook.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,33 @@ class gitWebhookBlueprintABC(ABC):
77

88
@abstractmethod
99
def __init__(self, webhookToken:str | None, name:str="webhook", *args, **kwargs):
10+
"""Initialize the webhook blueprint, register the recieveWebhook method as a POST endpoint.
11+
12+
Args:
13+
webhookToken (str | None): The token used to verify the webhook. If None, no verification is done.
14+
name (str, optional): Unique blueprint name. Defaults to "webhook".
15+
args: Additional arguments to pass to the Blueprint constructor.
16+
kwargs: Additional keyword arguments to pass to the Blueprint constructor.
17+
"""
1018
...
1119

1220
@abstractmethod
1321
def receiveWebhook(self) -> Response:
22+
"""Method that acts as a POST endpoint for the webhook blueprint.
23+
24+
Returns:
25+
Response: The response to the webhook request.
26+
"""
1427
...
1528

1629
@abstractmethod
1730
def processWebhook(self, data: dict[str, Any]) -> tuple[int, str]:
31+
"""Process the webhook data and return a status code and message.
32+
33+
Args:
34+
data (dict[str, Any]): The webhook data.
35+
36+
Returns:
37+
tuple[int, str]: The status code and message.
38+
"""
1839
...

gitWebhook/functionWebhook.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,41 @@
11
from .webhook import webhookBlueprint
22
from typing import Callable, Any
3+
from logging import Logger
34

45
class functionWebhookBlueprint(webhookBlueprint):
56
"""A subclass of webhookBlueprint that processes the webhook data using a list of functions. The functions should return True if the webhook data is valid, and False otherwise. If the function returns a string, it will be included in the output."""
67

7-
def __init__(self, webhookToken: str | None, functions: list[Callable[[dict[str, Any]], bool | str]], *args, **kwargs):
8-
super().__init__(webhookToken, *args, **kwargs)
8+
def __init__(self, webhookToken: str | None, functions: list[Callable[[dict[str, Any]], bool | str]], log:Logger | None = None, name:str="webhook", github:bool=True, gitlab:bool=True, gitea:bool=True, ipWhitelist:list[str] | None = None, *args, **kwargs):
9+
"""Initialize the webhook blueprint with a list of functions to process the webhook data.
10+
11+
Args:
12+
webhookToken (str | None): The token used to verify the webhook. If None, no verification is done.
13+
functions (list[Callable[[dict[str, Any]], bool | str]]): List of functions that will process the webhook data.
14+
log (Logger | None, optional): Optional logger that will be used by this blueprint. Defaults to None.
15+
name (str, optional): Flask blueprint name. Must be unique. Defaults to "webhook".
16+
github (bool, optional): Whether the blueprint should process webhook requests from GitHub. Defaults to True.
17+
gitlab (bool, optional): Whether the blueprint should process webhook requests from GitLab. Defaults to True.
18+
gitea (bool, optional): Whether the blueprint should process webhook requests from Gitea or other requests using basic auth. Defaults to True.
19+
ipWhitelist (list[str] | None, optional): Optional whitelist that all incoming requests will be checked against. Defaults to None.
20+
args: Additional arguments to pass to the Blueprint constructor.
21+
kwargs: Additional keyword arguments to pass to the Blueprint constructor.
22+
"""
23+
super().__init__(webhookToken, log, name, github, gitlab, gitea, ipWhitelist, *args, **kwargs)
924
self.functions = functions
1025

1126
def processWebhook(self, data: dict[str, Any]) -> tuple[int, str]:
27+
"""Process the webhook data using the list of functions.
28+
If any function returns False, the process will return a 400 status code.
29+
If any function returns an invalid type, the process will return a 500 status code.
30+
Otherwise, the process will return a 200 status code.
31+
All function outputs are returned to git as a string.
32+
33+
Args:
34+
data (dict[str, Any]): The webhook data.
35+
36+
Returns:
37+
tuple[int, str]: The status code and message.
38+
"""
1239
if self.log is not None:
1340
self.log.debug(f"Processing webhook: {data}")
1441
output = []

gitWebhook/pullerWebhook.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,39 @@
88
class pullerWebhookBlueprint(webhookBlueprint):
99
"""A subclass of webhookBlueprint that processes the webhook data by pulling from a git repository and running tests."""
1010

11-
def __init__(self, webhookToken: str | None, tests: TestSuite | None = None, log: Logger | None = None, name: str = "webhook", gitCommand: str = "/usr/bin/git", commandEnv: dict[str, str] | None = None, *args, **kwargs):
12-
super().__init__(webhookToken, log, name, *args, **kwargs)
11+
def __init__(self, webhookToken: str | None, tests: TestSuite | None = None, log:Logger | None = None, name:str="webhook", github:bool=True, gitlab:bool=True, gitea:bool=True, ipWhitelist:list[str] | None = None, gitCommand: str = "/usr/bin/git", commandEnv: dict[str, str] | None = None, *args, **kwargs):
12+
"""Initialize the webhook blueprint for pulling from a git repository and running tests.
13+
14+
Args:
15+
webhookToken (str | None): The token used to verify the webhook. If None, no verification is done.
16+
tests (TestSuite | None, optional): An optional unittest.TestSuite that will be ran after pulling from git. Defaults to None.
17+
log (Logger | None, optional): Optional logger that will be used by this blueprint. Defaults to None.
18+
name (str, optional): Flask blueprint name. Must be unique. Defaults to "webhook".
19+
github (bool, optional): Whether the blueprint should process webhook requests from GitHub. Defaults to True.
20+
gitlab (bool, optional): Whether the blueprint should process webhook requests from GitLab. Defaults to True.
21+
gitea (bool, optional): Whether the blueprint should process webhook requests from Gitea or other requests using basic auth. Defaults to True.
22+
ipWhitelist (list[str] | None, optional): Optional whitelist that all incoming requests will be checked against. Defaults to None.
23+
gitCommand (str, optional): Path to the git executable. Defaults to "/usr/bin/git".
24+
commandEnv (dict[str, str] | None, optional): Optional environment that will be used by git during pulling. Defaults to None.
25+
"""
26+
super().__init__(webhookToken, log, name, github, gitlab, gitea, ipWhitelist, *args, **kwargs)
1327
self.tests = tests
1428
self.gitCommand = gitCommand
1529
if commandEnv is None:
1630
commandEnv = dict(GIT_SSH_COMMAND="/usr/bin/ssh")
1731
self.commandEnv = commandEnv
1832

1933
def processWebhook(self, data: dict[str, Any]) -> tuple[int, str]:
34+
"""Process the webhook data by pulling from a git repository and running tests.
35+
If the tests are not provided, only the pull will be done.
36+
Otherwise the tests will be ran and if they fail the merge will be aborted.
37+
38+
Args:
39+
data (dict[str, Any]): The webhook data.
40+
41+
Returns:
42+
tuple[int, str]: The status code and message.
43+
"""
2044
if self.log is not None:
2145
self.log.debug(f"Processing webhook: {data}")
2246
process = run([self.gitCommand, "pull"], env=self.commandEnv)

0 commit comments

Comments
 (0)