Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 1 addition & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# github-webhook-server

A Flask-based webhook server for managing GitHub repositories. It handles tasks such as repository setup, branch protection, and webhook configuration.
A [FastAPI-based](https://fastapi.tiangolo.com) webhook server for managing GitHub repositories. It handles tasks such as repository setup, branch protection, and webhook configuration.

Pre-build container images available in:

Expand Down Expand Up @@ -264,22 +264,3 @@ Webhooks are automatically created for GitHub repositories based on settings def
### Usage Guide

To use the webhook server, first prepare the `config.yaml` file with the necessary repository and server configurations. Set the required environment variables, including `WEBHOOK_SERVER_LOG_FILE` and `WEBHOOK_SERVER_DATA_DIR`. Build and start the server using the instructions in the 'Build container' section.

### Development

To run locally you need to export some os environment variables

```bash
poetry install

WEBHOOK_SERVER_DATA_DIR=/tmp/webhook_server_data

mkdir -p $WEBHOOK_SERVER_DATA_DIR
cp -f webhook-server.private-key.pem $WEBHOOK_SERVER_DATA_DIR/webhook-server.private-key.pem
cp -f config.yaml $WEBHOOK_SERVER_DATA_DIR/config.yaml
export WEBHOOK_SERVER_PORT=5003

export FLASK_DEBUG=1
export WEBHOOK_SERVER_DATA_DIR=$WEBHOOK_SERVER_DATA_DIR
poetry run python webhook_server_container/app.py
```
2 changes: 1 addition & 1 deletion docker-compose-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ services:
- ./containers:/containers:Z # optional, to cache podman pull containers
environment:
- WEBHOOK_SERVER_LOG_FILE=/tmp/webhook_server.log
- FLASK_DEBUG=1 # Debug Flask server to get logs to console.
- PUID=1000
- PGID=1000
- TZ=Asia/Jerusalem
- DEVELOPMENT=false # Set to true when developing.
- UVICORN_MAX_WORKERS=50 # defaults to 10 if not set and running in production
ports:
- "5000:5000"
privileged: true
Expand Down
7 changes: 5 additions & 2 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#!/bin/bash

SERVER_RUN_CMD="poetry run uvicorn webhook_server_container.app:FastAPI_APP --host 0.0.0.0 --port 5000 "
UVICORN_WORKERS="${UVICORN_MAX_WORKERS:=10}"

set -ep

poetry run python webhook_server_container/utils/github_repository_settings.py
poetry run python webhook_server_container/utils/webhook.py

if [[ -z $DEVELOPMENT ]]; then
poetry run uwsgi --disable-logging --post-buffering --master --enable-threads --http 0.0.0.0:5000 --wsgi-file webhook_server_container/app.py --callable FLASK_APP --processes 4 --threads 2
eval "${SERVER_RUN_CMD} --workers ${UVICORN_WORKERS}"
else
poetry run python webhook_server_container/app.py
eval "${SERVER_RUN_CMD} --reload"
fi
831 changes: 783 additions & 48 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ Download = "https://quay.io/repository/myakove/github-webhook-server"
python = "^3.8"
poetry-dynamic-versioning = {extras = ["plugin"], version = "^1.0.0"}
pygithub = "^2.0.0"
flask = "^3.0.0"
pyyaml = "^6.0"
build = "^1.0.0"
shortuuid = "^1.0.11"
Expand All @@ -43,6 +42,9 @@ requests = "^2.31.0"
jira = "^3.8.0"
pyhelper-utils = "^0.0.25"
uwsgi = "^2.0.26"
fastapi = "^0.111.0"
python-simple-logger = "^1.0.30"
uvicorn = "^0.30.1"

[tool.poetry.group.dev.dependencies]
ipdb = "^0.13.13"
Expand Down
2 changes: 1 addition & 1 deletion renovate.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"$schema": "https://docs.renovatebot.com/renovate-schema.json", "packageRules": [{"matchPackagePatterns": ["poetry-dynamic-versioning", "pygithub", "flask", "pyyaml", "build", "shortuuid", "colorlog", "colorama", "ruff", "timeout-sampler", "requests", "jira", "pyhelper-utils", "uwsgi", "ipdb", "ipython"], "groupName": "poetry-deps"}]}
{"$schema": "https://docs.renovatebot.com/renovate-schema.json", "packageRules": [{"matchPackagePatterns": ["poetry-dynamic-versioning", "pygithub", "pyyaml", "build", "shortuuid", "colorlog", "colorama", "ruff", "timeout-sampler", "requests", "jira", "pyhelper-utils", "uwsgi", "fastapi", "python-simple-logger", "uvicorn", "ipdb", "ipython"], "groupName": "poetry-deps"}]}
49 changes: 18 additions & 31 deletions webhook_server_container/app.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,46 @@
import os

from fastapi import Request
import requests
import urllib3
from flask import request
from simple_logger.logger import get_logger


from webhook_server_container.libs.github_api import GitHubApi
from webhook_server_container.utils.constants import (
APP_ROOT_PATH,
FLASK_APP,
)
from webhook_server_container.utils.constants import FastAPI_APP

APP_ROOT_PATH = "/webhook_server"
REPOSITORIES_APP_API = {}
MISSING_APP_REPOSITORIES = []
urllib3.disable_warnings()

LOGGER = get_logger(name="app")

@FLASK_APP.route(f"{APP_ROOT_PATH}/healthcheck")

@FastAPI_APP.get(f"{APP_ROOT_PATH}/healthcheck")
def healthcheck():
return "alive"
return {"status": requests.status_codes.codes.ok, "message": "Alive"}


@FLASK_APP.route(APP_ROOT_PATH, methods=["POST"])
def process_webhook():
process_failed_msg = "Process failed"
@FastAPI_APP.post(APP_ROOT_PATH)
async def process_webhook(request: Request):
process_failed_msg = {"status": requests.status_codes.codes.server_error, "Message": "Process failed"}
try:
hook_data = request.json
hook_data = await request.json()
except Exception as ex:
FLASK_APP.logger.error(f"Error get JSON from request: {ex}")
LOGGER.error(f"Error get JSON from request: {ex}")
return process_failed_msg

try:
api = GitHubApi(hook_data=hook_data)
except Exception as ex:
FLASK_APP.logger.error(f"Failed to initialized GitHubApi instance: {ex}")
LOGGER.error(f"Failed to initialized GitHubApi instance: {ex}")
return process_failed_msg

github_event = request.headers.get("X-GitHub-Event")
event_log = f"Event type: {github_event}. event ID: {request.headers.get('X-GitHub-Delivery')}"
try:
api.process_hook(data=github_event, event_log=event_log)
return "process success"
return {"status": requests.status_codes.codes.ok, "Message": "process success"}

except Exception as ex:
FLASK_APP.logger.error(f"Failed to process hook: {ex}")
LOGGER.error(f"Failed to process hook: {ex}")
return process_failed_msg


def main():
FLASK_APP.logger.info(f"Starting {FLASK_APP.name} app")
FLASK_APP.run(
port=5000,
host="0.0.0.0",
use_reloader=bool(os.getenv("WEBHOOK_SERVER_USE_RELOAD", False)),
debug=bool(os.getenv("WEBHOOK_SERVER_USE_DEBUG", False)),
)


if __name__ == "__main__":
main()
Loading