Skip to content

Commit 7ec5425

Browse files
committed
docs: add documentation
1 parent b3b9968 commit 7ec5425

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+4422
-2845
lines changed

.github/workflows/documentation.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Docs
2+
on:
3+
push:
4+
branches: [main]
5+
jobs:
6+
docs:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v2
10+
- name: Set up Python 3.10
11+
uses: actions/setup-python@v2
12+
with:
13+
python-version: "3.10"
14+
- name: Run image
15+
uses: abatilo/[email protected]
16+
with:
17+
poetry-version: 1.3
18+
- name: Install dependencies
19+
run: poetry install
20+
- name: Sphinx build
21+
run: |
22+
poetry run sphinx-build docs public
23+
- name: Deploy
24+
uses: peaceiris/actions-gh-pages@v3
25+
if: ${{ github.ref == 'refs/heads/main' }}
26+
with:
27+
github_token: ${{ secrets.GITHUB_TOKEN }}
28+
publish_dir: public/

.pre-commit-config.yaml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ repos:
2020
rev: 0.1.2
2121
hooks:
2222
- id: pylama
23-
args: # arguments to configure black
24-
- --max-line-length=119
25-
# due to https://github.com/PyCQA/pycodestyle/issues/373
26-
- -i E203
23+
additional_dependencies: [toml, mypy, eradicate, pydocstyle==6.1.1]
2724

2825
- repo: https://github.com/pycqa/isort
2926
rev: 5.12.0

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ This project aims to provide dynamic sampling without relying on Sentry Dynamic
99

1010
It work by installing the library [sentry-dynamic-sampling-lib](https://github.com/SpikeeLabs/sentry-dynamic-sampling-lib) on each project that use sentry. This lib hooks into the sentry callback to change the sampling rate. To get the rate the lib calls this service.
1111

12+
Docs : [here](https://spikeelabs.github.io/sentry-dynamic-sampling-controller/)
1213

1314

14-
15-
## Development
15+
## Install
1616
```bash
1717
# install deps
1818
poetry install
@@ -40,3 +40,10 @@ python manage.py loadpermissions
4040
python manage.py runserver
4141

4242
```
43+
44+
45+
## Develop
46+
```bash
47+
# build docs
48+
sphinx-build -b html docs public
49+
```

controller/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Controller."""
12
from controller.celery import app as celery_app
23

34
__all__ = ("celery_app",)

controller/celery.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Celery."""
12
import os
23

34
from celery import Celery

controller/sentry/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Sentry App."""

controller/sentry/admin.py

Lines changed: 134 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"""Admin."""
2+
from typing import TYPE_CHECKING, Optional
3+
14
from admin_action_tools import (
25
ActionFormMixin,
36
AdminConfirmMixin,
@@ -22,6 +25,11 @@
2225
from controller.sentry.models import App, Event, Project
2326
from controller.sentry.utils import invalidate_cache
2427

28+
if TYPE_CHECKING: # pragma: no cover # pragma: no cover
29+
from django.db.models import QuerySet
30+
from django.forms import ModelForm
31+
from django.http import HttpRequest
32+
2533

2634
@admin.register(Project)
2735
class ProjectAdmin(
@@ -32,6 +40,7 @@ class ProjectAdmin(
3240
DynamicArrayMixin,
3341
admin.ModelAdmin,
3442
):
43+
"""Project Admin."""
3544

3645
list_display = [
3746
"sentry_id",
@@ -61,6 +70,14 @@ class ProjectAdmin(
6170
inlines = [ProjectEventInline]
6271

6372
def get_chart_data(self, sentry_id):
73+
"""This method return the chart data.
74+
75+
Args:
76+
sentry_id (str): sentry id
77+
78+
Returns:
79+
Optional[Tuple[dict, dict]]: tuple of data and options
80+
"""
6481
project = Project.objects.get(sentry_id=sentry_id)
6582
if project.detection_result is None:
6683
return None
@@ -123,6 +140,7 @@ class EventAdmin(
123140
PrettyTypeMixin,
124141
admin.ModelAdmin,
125142
):
143+
"""Event Admin."""
126144

127145
list_display = ["reference", "pretty_type", "timestamp", "get_project"]
128146

@@ -150,6 +168,8 @@ class AppAdmin(
150168
DynamicArrayMixin,
151169
admin.ModelAdmin,
152170
):
171+
"""App Admin."""
172+
153173
read_only_fields = ["last_seen"]
154174

155175
list_display = [
@@ -219,22 +239,48 @@ class AppAdmin(
219239
inlines = [AppEventInline]
220240

221241
@admin.display(description="Spamming Sentry")
222-
def get_event_status(self, obj):
242+
def get_event_status(self, obj: App) -> str:
243+
"""This method return a pretty event status html string.
244+
245+
Args:
246+
obj (App): The app
247+
248+
Returns:
249+
str: The pretty status
250+
"""
223251
text = '<b style="color:{};">{}</b>'
224252
if obj.project and (event := obj.project.events.last()):
225253
if event.type == EventType.DISCARD:
226254
return format_html(text, "green", "No")
227255
return format_html(text, "red", "Yes")
228256
return format_html(text, "gray", "Pending")
229257

230-
def get_changelist_actions(self, request):
258+
def get_changelist_actions(self, request: "HttpRequest") -> list[str]:
259+
"""This method return allowed changelist actions.
260+
261+
Args:
262+
request (HttpRequest): The request
263+
264+
Returns:
265+
list[str]: All possible actions
266+
"""
231267
allowed_actions = []
232268
for action in self.changelist_actions:
233269
if getattr(self, f"has_{action}_permission")(request):
234270
allowed_actions.append(action)
235271
return allowed_actions
236272

237-
def get_change_actions(self, request, object_id, form_url):
273+
def get_change_actions(self, request: "HttpRequest", object_id: str, form_url: Optional[str]) -> list[str]:
274+
"""This method return allowed change actions.
275+
276+
Args:
277+
request (HttpRequest): The request
278+
object_id (str): The App reference
279+
form_url (Optional[str]): The form_url
280+
281+
Returns:
282+
list[str]: All possible actions
283+
"""
238284
allowed_actions = []
239285
for action in self.change_actions:
240286
if getattr(self, f"has_{action}_permission")(request):
@@ -246,7 +292,19 @@ def get_change_actions(self, request, object_id, form_url):
246292
@add_form_to_action(BumpForm)
247293
@confirm_action()
248294
@admin.action(description="Bump Sample Rate")
249-
def bump_sample_rate(self, request, queryset, form: BumpForm = None): # pylint: disable=unused-argument
295+
def bump_sample_rate(
296+
self,
297+
request: "HttpRequest",
298+
queryset: "QuerySet[App]",
299+
form: BumpForm = None, # pylint: disable=unused-argument
300+
) -> None:
301+
"""This method is responsible for the bump sample rate action.
302+
303+
Args:
304+
request (HttpRequest): The request
305+
queryset (QuerySet[App]): The Apps to change
306+
form (BumpForm): The form
307+
"""
250308
new_date = timezone.now() + form.cleaned_data["duration"]
251309
queryset.update(
252310
active_sample_rate=form.cleaned_data["new_sample_rate"],
@@ -257,8 +315,15 @@ def bump_sample_rate(self, request, queryset, form: BumpForm = None): # pylint:
257315

258316
bump_sample_rate.allowed_permissions = ("bump_sample_rate",)
259317

260-
def has_bump_sample_rate_permission(self, request):
261-
"""Does the user have the bump permission?"""
318+
def has_bump_sample_rate_permission(self, request: "HttpRequest") -> bool:
319+
"""This method return True if the user have the permission for bump sample rate action.
320+
321+
Args:
322+
request (HttpRequest): The request
323+
324+
Returns:
325+
bool: Is allowed
326+
"""
262327
opts = self.opts
263328
codename = get_permission_codename("bump_sample_rate", opts)
264329

@@ -269,7 +334,19 @@ def has_bump_sample_rate_permission(self, request):
269334
@takes_instance_or_queryset
270335
@add_form_to_action(MetricForm)
271336
@admin.action(description="Enable/Disable Metrics Collection")
272-
def enable_disable_metrics(self, request, queryset, form: MetricForm = None): # pylint: disable=unused-argument
337+
def enable_disable_metrics(
338+
self,
339+
request: "HttpRequest",
340+
queryset: "QuerySet[App]",
341+
form: MetricForm = None, # pylint: disable=unused-argument
342+
) -> None:
343+
"""This method is responsible for the enable/disable metrics action.
344+
345+
Args:
346+
request (HttpRequest): The request
347+
queryset (QuerySet[App]): The Apps to change
348+
form (MetricForm): The form
349+
"""
273350
metrics = form.cleaned_data["metrics"]
274351
app: App
275352
for app in queryset:
@@ -280,8 +357,15 @@ def enable_disable_metrics(self, request, queryset, form: MetricForm = None): #
280357

281358
enable_disable_metrics.allowed_permissions = ("enable_disable_metrics",)
282359

283-
def has_enable_disable_metrics_permission(self, request):
284-
"""Does the user have the enable_disable_metrics permission?"""
360+
def has_enable_disable_metrics_permission(self, request: "HttpRequest") -> bool:
361+
"""This method return True if the user have the permission for enable/disable metrics action.
362+
363+
Args:
364+
request (HttpRequest): The request
365+
366+
Returns:
367+
bool: Is allowed
368+
"""
285369
opts = self.opts
286370
codename = get_permission_codename("enable_disable_metrics", opts)
287371

@@ -291,14 +375,27 @@ def has_enable_disable_metrics_permission(self, request):
291375
@takes_instance_or_queryset
292376
@confirm_action(display_queryset=False)
293377
@admin.action(description="Panic")
294-
def panic(self, request, queryset): # pylint: disable=unused-argument
378+
def panic(self, request: "HttpRequest", queryset: "QuerySet[App]") -> None: # pylint: disable=unused-argument
379+
"""This method activate the panic mode.
380+
381+
Args:
382+
request (HttpRequest): The request
383+
queryset (QuerySet[App]): All the Apps (unused)
384+
"""
295385
cache.set(settings.PANIC_KEY, True, timeout=None)
296386

297387
panic.allowed_permissions = ("panic",)
298388
panic.attrs = {"style": "background-color: red;"}
299389

300-
def has_panic_permission(self, request):
301-
"""Does the user have the panic permission?"""
390+
def has_panic_permission(self, request: "HttpRequest") -> bool:
391+
"""This method return True if the user have the permission for panic action.
392+
393+
Args:
394+
request (HttpRequest): The request
395+
396+
Returns:
397+
bool: Is allowed
398+
"""
302399
panic = cache.get(settings.PANIC_KEY)
303400
opts = self.opts
304401
codename = get_permission_codename("panic", opts)
@@ -307,20 +404,41 @@ def has_panic_permission(self, request):
307404
@takes_instance_or_queryset
308405
@confirm_action(display_queryset=False)
309406
@admin.action(description="UnPanic")
310-
def unpanic(self, request, queryset): # pylint: disable=unused-argument
407+
def unpanic(self, request: "HttpRequest", queryset: "QuerySet[App]") -> None: # pylint: disable=unused-argument
408+
"""This method deactivate the panic mode.
409+
410+
Args:
411+
request (HttpRequest): The request
412+
queryset (QuerySet[App]): All the Apps (unused)
413+
"""
311414
cache.delete(settings.PANIC_KEY)
312415

313416
unpanic.allowed_permissions = ("unpanic",)
314417
unpanic.attrs = {"style": "background-color: green;"}
315418

316-
def has_unpanic_permission(self, request):
317-
"""Does the user have the panic permission?"""
419+
def has_unpanic_permission(self, request: "HttpRequest") -> bool:
420+
"""This method return True if the user have the permission for unpanic action.
421+
422+
Args:
423+
request (HttpRequest): The request
424+
425+
Returns:
426+
bool: Is allowed
427+
"""
318428
panic = cache.get(settings.PANIC_KEY)
319429
opts = self.opts
320430
codename = get_permission_codename("panic", opts)
321431
return panic and request.user.has_perm("%s.%s" % (opts.app_label, codename))
322432

323433
# Save model
324-
def save_model(self, request, obj, form, change) -> None:
434+
def save_model(self, request: "HttpRequest", obj: App, form: "ModelForm", change: bool) -> None:
435+
"""This method is responsible to save app in the admin.
436+
437+
Args:
438+
request (HttpRequest): The request
439+
obj (App): The app to save
440+
form (ModelForm): form
441+
change (bool): change
442+
"""
325443
invalidate_cache(f"/sentry/apps/{obj.reference}/")
326444
return super().save_model(request, obj, form, change)

controller/sentry/apps.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
"""Sentry App."""
12
from django.apps import AppConfig
23
from django.utils.translation import gettext_lazy as _
34

45

56
class SentryConfig(AppConfig):
7+
"""Sentry App Config."""
8+
69
name = "controller.sentry"
710
verbose_name = _("sentry")

0 commit comments

Comments
 (0)