Skip to content

Commit 8badff2

Browse files
Merge pull request #14 from mozilla/pr1-cleanup
2 parents 8c8f0e7 + 72403a3 commit 8badff2

File tree

20 files changed

+244
-133
lines changed

20 files changed

+244
-133
lines changed

infra/gunicorn_conf.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
# From: https://github.com/tiangolo/uvicorn-gunicorn-docker/blob/2daa3e3873c837d5781feb4ff6a40a89f791f81b/docker-images/gunicorn_conf.py
1+
"""
2+
Conf file extracted from:
3+
https://github.com/tiangolo/uvicorn-gunicorn-docker/blob/2daa3e3873c837d5781feb4ff6a40a89f791f81b/docker-images/gunicorn_conf.py
4+
"""
25
# pylint: disable=invalid-name
36

47
import multiprocessing

poetry.lock

Lines changed: 69 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ atlassian-python-api = "^3.20.1"
1717
dockerflow = "2022.1.0"
1818
PyYAML = "^6.0"
1919
types-PyYAML = "^6.0.4"
20+
Jinja2 = "^3.0.3"
2021

2122

2223
[tool.poetry.dev-dependencies]
@@ -44,7 +45,7 @@ testpaths = [
4445
[tool.pylint]
4546
[tool.pylint.'MESSAGES CONTROL']
4647
disable = [
47-
"C0114", #missing-module-docstring
48+
# "C0114", #missing-module-docstring
4849
"C0115", #missing-class-docstring
4950
"C0116", #missing-function-docstring
5051
"C0301", #line-too-long

src/app/api.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
"""
2+
Core FastAPI app (setup, middleware)
3+
"""
14
import logging
25
import time
36
from datetime import datetime
47

58
import uvicorn # type: ignore
69
from fastapi import FastAPI, Request
710
from fastapi.responses import RedirectResponse
11+
from fastapi.staticfiles import StaticFiles
812

913
from src.app.environment import get_settings
1014
from src.app.log import configure_logging
@@ -21,6 +25,7 @@
2125

2226
app.include_router(monitor_router)
2327
app.include_router(jbi_router)
28+
app.mount("/static", StaticFiles(directory="src/static"), name="static")
2429

2530

2631
@app.get("/", include_in_schema=False)

src/app/environment.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"""
2+
Module dedicated to interacting with the environment (variables, version.json)
3+
"""
14
import json
25
import os
36
from functools import lru_cache

src/app/log.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"""
2+
Dedicated module for logging configuration and setup
3+
"""
14
import logging
25
import logging.config
36
import sys

src/app/monitor.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"""
2+
Router dedicated to Dockerflow APIs
3+
"""
14
from typing import Dict
25

36
from fastapi import APIRouter, Depends, Request

src/jbi/configuration.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"""
2+
Parsing and validating the YAML configuration occurs within this module
3+
"""
14
import importlib
25
import logging
36
from inspect import signature
@@ -43,6 +46,7 @@ def process_actions(action_configuration) -> Dict[str, Dict]:
4346
for yaml_action_key, inner_action_dict in action_configuration.items():
4447
inner_action_dict.setdefault("action", "src.jbi.whiteboard_actions.default")
4548
inner_action_dict.setdefault("enabled", False)
49+
inner_action_dict.setdefault("parameters", {})
4650
validate_action_yaml_jbi_naming(
4751
yaml_action_key=yaml_action_key, action_dict=inner_action_dict
4852
)
@@ -53,24 +57,18 @@ def process_actions(action_configuration) -> Dict[str, Dict]:
5357

5458
def validate_action_yaml_jbi_naming(yaml_action_key, action_dict):
5559
# Validate yaml_action_key == parameters.whiteboard_tag
56-
try:
57-
action_parameters = action_dict.get("parameters")
58-
wb_tag = action_parameters.get("whiteboard_tag")
59-
if yaml_action_key != wb_tag:
60-
raise ConfigError(
61-
f"Expected action key '{wb_tag}', found `{yaml_action_key}."
62-
"(from the `parameters.whiteboard_tag` field)."
63-
)
64-
except (TypeError, AttributeError) as exception:
65-
raise ConfigError("Action is not properly setup.") from exception
60+
wb_tag = action_dict["parameters"].get("whiteboard_tag")
61+
if yaml_action_key != wb_tag:
62+
raise ConfigError(
63+
f"Expected action key '{wb_tag}', found `{yaml_action_key}."
64+
"(from the `parameters.whiteboard_tag` field)."
65+
)
6666

6767

6868
def validate_action_yaml_module(action_dict: Dict[str, Any]):
6969
# Validate action: exists, has init function, and has expected params
7070
try:
7171
action: str = action_dict.get("action") # type: ignore
72-
print(action_dict)
73-
print(action)
7472
action_parameters: Optional[Dict[str, Any]] = action_dict.get("parameters")
7573
action_module: ModuleType = importlib.import_module(action)
7674
if not action_module:

src/jbi/router.py

Lines changed: 15 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1+
"""
2+
Router dedicated to Jira Bugzilla Integration APIs
3+
"""
14
import logging
2-
from typing import Dict, Optional
5+
from typing import Optional
36

47
from fastapi import APIRouter, Depends, Request
58
from fastapi.responses import HTMLResponse
9+
from fastapi.templating import Jinja2Templates
610

711
from src.app import environment
812
from src.jbi import configuration
913

14+
templates = Jinja2Templates(directory="src/templates")
15+
1016
api_router = APIRouter(tags=["JBI"])
1117

1218
jbi_logger = logging.getLogger("src.jbi")
@@ -54,110 +60,13 @@ def get_actions_by_type(action_type: Optional[str] = None):
5460

5561

5662
@api_router.get("/powered_by_jbi", response_class=HTMLResponse)
57-
def powered_by_jbi(enabled: Optional[bool] = None):
63+
def powered_by_jbi(request: Request, enabled: Optional[bool] = None):
5864
data = configuration.get_yaml_configurations()
59-
num_configs = len(data)
60-
html = f"""
61-
<html>
62-
<head>
63-
<title>Powered by JBI</title>
64-
<style>{get_css_style()}
65-
</style>
66-
</head>
67-
<body>
68-
<h1>Powered by JBI</h1>
69-
<p>{num_configs} collections.</p>
70-
<div id="collections"> {create_inner_html_table(data=data, enable_query=enabled)} </div>
71-
</body>
72-
</html>
73-
"""
74-
return html
75-
76-
77-
def create_inner_html_table(data: Dict, enable_query: Optional[bool]):
78-
agg_table = ""
79-
header = """
80-
<tr>
81-
<th>Key</th>
82-
<th>Action</th>
83-
<th>Contact</th>
84-
<th>Description </th>
85-
<th>Enabled</th>
86-
<th>Parameters</th>
87-
</tr>
88-
"""
89-
for key, value in data.items():
90-
enabled = value.get("enabled")
91-
if enable_query is None or enabled is enable_query:
92-
parameters = ", ".join(
93-
f"{k}={v}" for k, v in value.get("parameters").items()
94-
)
95-
per_row = f"""
96-
<tr>
97-
<td class="key">{key}</td>
98-
<td class="action">{value.get("action")}</td>
99-
<td class="contact">{value.get("contact")}</td>
100-
<td class="description">{value.get("description")}</td>
101-
<td class="enabled">{enabled}</td>
102-
<td class="parameters">{parameters}</td>
103-
</tr>"""
104-
agg_table += per_row
105-
106-
html = f"""
107-
<table>
108-
<thead>{header}</thead>
109-
<tbody class="list">{agg_table}</tbody>
110-
</table>
111-
"""
112-
return html
113-
114-
115-
def get_css_style():
116-
return """body {
117-
font-family: sans-serif;
118-
}
119-
120-
table {
121-
border-collapse: collapse;
122-
margin: 25px 0;
123-
font-size: 0.9em;
124-
min-width: 400px;
125-
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
126-
}
127-
128-
thead tr {
129-
background-color: #009879;
130-
color: #ffffff;
131-
text-align: left;
132-
}
133-
134-
th, td {
135-
padding: 12px 15px;
136-
}
137-
138-
tbody tr {
139-
border-bottom: 1px solid #dddddd;
140-
}
141-
142-
tbody tr:nth-of-type(even) {
143-
background-color: #f3f3f3;
144-
}
145-
146-
tbody tr:last-of-type {
147-
border-bottom: 2px solid #009879;
148-
}
149-
150-
.sort:after {
151-
content: "▼▲";
152-
padding-left: 10px;
153-
opacity: 0.5;
154-
}
155-
.sort.desc:after {
156-
content: "▲";
157-
opacity: 1;
158-
}
159-
.sort.asc:after {
160-
content: "▼";
161-
opacity: 1;
65+
context = {
66+
"request": request,
67+
"title": "Powered by JBI",
68+
"num_configs": len(data),
69+
"data": data,
70+
"enable_query": enabled,
16271
}
163-
"""
72+
return templates.TemplateResponse("powered_by_template.html", context)

src/jbi/services.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"""
2+
Services and functions that can be used to create custom actions
3+
"""
14
import logging
25

36
import bugzilla as rh_bugzilla # type: ignore

0 commit comments

Comments
 (0)