diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 339701f..16c20cb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,12 +15,6 @@ * Linux: [https://graphviz.org/download](https://graphviz.org/download/) * Windows: [https://graphviz.org/download](https://graphviz.org/download/) -To confirm these system dependencies are configured correctly: - -```text -$ make bootstrap -$ make doctor -``` ### Installation diff --git a/Makefile b/Makefile index a559c3a..c28dfc1 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,6 @@ $(DEPENDENCIES): poetry.lock @ rm -rf ~/Library/Preferences/pypoetry @ poetry config virtualenvs.in-project true poetry install - @ touch $@ ifndef CI poetry.lock: pyproject.toml diff --git a/README.md b/README.md index 9bd4fd5..7418db2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# Wppt +# Wppt +#### Webhook Payload Proxy Transformer [![Unix Build Status](https://img.shields.io/github/actions/workflow/status/grafuls/wppt/main.yml?branch=main&label=linux)](https://github.com/grafuls/wppt/actions) [![Coverage Status](https://img.shields.io/codecov/c/gh/grafuls/wppt)](https://codecov.io/gh/grafuls/wppt) @@ -10,7 +11,7 @@ Wppt(Pronounced: [ˈwɪpɪt]) provides an easy way to intercept, manage, manipul Some services/platforms don't provide an easy-to-use integration vehicle for transforming and syncing requests, payloads and automation e.g. Gitlab -> Jira. Instead of paying for an expensive third-party service to provide integrations you can do this easily yourself on-premise. -## How wppt Does Work? +## How Does `wppt` Work? Wppt leverages Flask dynamic routing. The endpoint is variable and defined via one or multiple yaml files. Based on the endpoint url, `wppt` parses all the yaml files stored on the `transformers` directory, and retrieves the outgoing webhook url and the translations. It then parses all the translations and converts the existing data from the incoming webhook into a new payload structure as defined on the yaml. @@ -24,7 +25,7 @@ gitlab2jira: translations: data: name: '[{data[project][name]}][{data[object_kind]}] {data[object_attributes][title]}' - description: 'Description: {data[object_attributes][description]}\nURL:{data[object_attributes][url]}' + description: 'Description: {data[object_attributes][description]}\nURL:{data[object_attributes][url]}' ``` Given the following incoming webhook payload to `http://{FQDN}:5005/gitlab2jira/`: diff --git a/bin/checksum b/bin/checksum new file mode 100755 index 0000000..73e0196 --- /dev/null +++ b/bin/checksum @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import hashlib +import sys + + +def run(paths): + sha = hashlib.sha1() + + for path in paths: + try: + with open(path, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b''): + sha.update(chunk) + except IOError: + sha.update(path.encode()) + + print(sha.hexdigest()) + + +if __name__ == '__main__': + run(sys.argv[1:]) \ No newline at end of file diff --git a/bin/open b/bin/open new file mode 100755 index 0000000..079de50 --- /dev/null +++ b/bin/open @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import sys + + +COMMANDS = { + 'linux': "open", + 'win32': "cmd /c start", + 'cygwin': "cygstart", + 'darwin': "open", +} + + +def run(path): + command = COMMANDS.get(sys.platform, "open") + os.system(command + ' ' + path) + + +if __name__ == '__main__': + run(sys.argv[-1]) \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..a65cb25 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,19 @@ +# Use the official Python base image +FROM python:3.11 +LABEL authors="grafuls" + +RUN apt-get install git patch + +# Set the working directory inside the container +WORKDIR /opt +RUN git clone https://github.com/redhat-performance/wppt +WORKDIR /opt/wppt + +# Install Poetry +RUN pip install poetry + +# Install project dependencies +RUN make install + +# Set the entrypoint command to run the project +CMD ["make", "run",] diff --git a/pyproject.toml b/pyproject.toml index 82a2626..0b19272 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,14 +10,14 @@ license = "GPL3" authors = ["Gonzalo Rafuls "] readme = "README.md" -homepage = "https://pypi.org/project/wppt" -documentation = "https://wppt.readthedocs.io" +homepage = "https://github.com/redhat-performance/wppt" +documentation = "https://github.com/redhat-performance/wppt/blob/main/README.md" repository = "https://github.com/redhat-performance/wppt" keywords = [] classifiers = [ # TODO: update this list to match your application: https://pypi.org/pypi?%3Aaction=list_classifiers - "Development Status :: 1 - Planning", + "Development Status :: 3 - Alpha", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", @@ -29,9 +29,9 @@ classifiers = [ python = "^3.11" -# TODO: Remove these and add your library's requirements -flask = "*" -requests = "*" +flask = "3.0.2" +requests = "2.31.0" +pyyaml = "6.0.1" [tool.poetry.dev-dependencies] @@ -39,7 +39,7 @@ requests = "*" black = "^22.1" tomli = "*" # missing 'black' dependency isort = "^5.10" -ipdb = "*" # missing 'black' dependency +ipdb = "0.13.13" # missing 'black' dependency # Linters mypy = "^1.0" @@ -68,10 +68,6 @@ sniffer = "*" MacFSEvents = { version = "*", platform = "darwin" } pync = { version = "*", platform = "darwin" } -[tool.poetry.scripts] - -wppt = "wppt.cli:main" - [tool.black] quiet = true diff --git a/wppt/app.py b/wppt/app.py index dccc92e..1048ce3 100644 --- a/wppt/app.py +++ b/wppt/app.py @@ -1,6 +1,6 @@ #! /usr/bin/env python -from flask import Flask, request +from flask import Flask, request, jsonify, Response import requests import json @@ -16,7 +16,7 @@ def hello(): @app.route("//", methods=["POST"]) -def dinamic_transformer(transformer: str): +def dinamic_transformer(transformer: str) -> Response: data = request.json definitions = parse_definitions(TRANSFORMERS_PATH) for _transformer, definition in definitions.items(): @@ -24,23 +24,32 @@ def dinamic_transformer(transformer: str): if definition.get("enabled"): translations = definition.get("translations") webhook_url = definition.get("target_webhook") + + headers = {"Content-`type": "application/json"} + try: + traverse_format_dict(translations, data) + except KeyError as ಠ_ಠ: + return jsonify(f"{ಠ_ಠ}", 400) + + response = requests.post( + webhook_url, headers=headers, data=json.dumps(translations) + ) + + if response.status_code not in (200, 201, 202, 204): + payload = { + "status_code": response.status_code, + "error": response.text, + "message": f"Failed to send the transformed webhook for {_transformer}.", + } + return jsonify(payload) else: - return f"Transformer {_transformer} is disabled", 200 - - headers = {"Content-type": "application/json"} - try: - traverse_format_dict(translations, data) - except KeyError as ಠ_ಠ: - return f"{ಠ_ಠ}", 400 - import ipdb;ipdb.set_trace() - response = requests.post( - webhook_url, headers=headers, data=json.dumps(translations) - ) - - print(response.status_code) - print(response.text) - - return f"Transformers executed.", 200 + return jsonify(f"Transformer {_transformer} is disabled", 400) + + response = { + "status_code": 200, + "message": "Transformers executed.", + } + return jsonify(response) if __name__ == "__main__":