Skip to content

Commit

Permalink
Megacommit.. sorry
Browse files Browse the repository at this point in the history
- Run `black`
- Fix Dockerfile
- Add `feature_request` and `interrupts` strategies
- Start `datadog` + `trello` plugins (missing tests)
  • Loading branch information
Corentin Chary committed Oct 28, 2018
1 parent 69d77d5 commit e47f962
Show file tree
Hide file tree
Showing 20 changed files with 623 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
db.sqlite*

*~
\#*
.\#*

###
### What follows is from https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore
Expand Down Expand Up @@ -116,3 +118,6 @@ ENV/

# Rope project settings
.ropeproject

# Git itself
.git
15 changes: 9 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
FROM python:3
FROM ubuntu:latest

RUN apt-get update && \
apt-get install -y python3 python3-dev python3-pip && \
apt-get clean

ENV PYTHONUNBUFFERED 1
ENV ROOT=/opt/mlt

RUN mkdir $ROOT
WORKDIR $ROOT

ADD requirements.txt $ROOT/
RUN pip3 install -r requirements.txt gunicorn

RUN mkdir static storage
VOLUME ["$ROOT/storage/", "$ROOT/static/"]

ADD requirements.txt $ROOT/
RUN pip install -r requirements.txt gunicorn

ADD . $ROOT/
RUN pip install -e $ROOT/
RUN pip3 install -e $ROOT/

EXPOSE 8000

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pip install -r requirements.txt
./manage.py migrate --run-syncdb
./manage.py createsuperuser
./manage.py runserver
# Go to http://127.0.0.1:8000/admin and create a "board"
```

## Configuration
Expand All @@ -35,13 +36,13 @@ See [local_settings](examples/local_settings.py).
docker build . -t my_little_ticket
docker run --rm -it -p 8000:8000 \
--name=my_little_ticket \
--volume=examples/local_settings.py:/opt/mlt/my_little_ticket/local_settings.py \
--volume=examples/local_settings.py:/opt/mlt/my_little_ticket/local_settings.py \
my_little_ticket
```

## Authentication

This project is using [django-allauth](https://django-allauth.readthedocs.io/en/latest/).
This project uses [django-allauth](https://django-allauth.readthedocs.io/en/latest/).

## API

Expand Down
132 changes: 132 additions & 0 deletions my_little_ticket/plugins/datadog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
"""my-little-ticket Datadog plugin."""
import logging
import time

import datadog

from my_little_ticket.plugins import base

from django.conf import settings


DEFAULT_DATADOG_API_HOST = getattr(settings, "DATADOG_API_HOST", None)
DEFAULT_DATADOG_APP_KEY = getattr(settings, "DATADOG_APP_KEY", None)
DEFAULT_DATADOG_API_KEY = getattr(settings, "DATADOG_API_KEY", None)

# TODO: There could also be one for events (as monitors create events).

class MonitorPlugin(base.Plugin):
"""my-little-ticket Datadog plugin.
This is not super useful yet, it's probably a better idea to plugin datadog monitors
to jira or trello and fetch status from there.
params:
```python
{
'api_host': 'https://api.datadoghq.com', // Url to root API.
'api_key': '', // API Key
'app_key': '', // API Key
'params': {}, // Get tickets matching these params (see Datadog API).
}
```
"""

def __init__(self, params=None):
"""Create an instance of the plugin."""
super(MonitorPlugin, self).__init__(params)
if params is None:
params = {}

self._api = None

self.api_host = params.get("api_host", DEFAULT_DATADOG_API_HOST)
self.api_key = params.get("api_key", DEFAULT_DATADOG_API_KEY)
self.app_key = params.get("app_key", DEFAULT_DATADOG_APP_KEY)
if "params" in params:
self.params = params["params"]
else:
self.params = {}

@property
def short_name(self):
"""Return the short name."""
return "datadog"

@property
def name(self):
"""Return the name."""
return "Datadog"

@property
def description(self):
"""Return the description."""
return "Returns monitors from Datadog."

@property
def link(self):
"""Return the link."""
# TODO: Fill ?q= from self.params
return "%s/monitors/manage" % self.api_host

@property
def api(self):
"""Get a Datadog api."""
if not self._api:
# This isn't super nice if somebody else in the same
# process is uinsg it...
datadog.initialize(
api_key=self.api_key, app_key=self.app_key, api_host=self.api_host
)
self._api = datadog.api

return self._api

def tickets(self):
"""Return the tickets."""
ret = {}

if not self.api:
return ret

monitors = self.api.Monitor.get_all(**self.params)
for monitor in monitors:
ticket = self._to_ticket(monitor)
if ticket is not None:
ret[ticket["uuid"]] = ticket
return ret

def _to_ticket(self, monitor):
"""Return a status or None."""
logging.debug("Handling %s" % (monitor))

tags = list(monitor['tags'])
assignee = None
priority = None
summary = monitor['name']
text = monitor['message']
status = monitor['overall_state']
created_on = monitor['created']
updated_on = monitor['modified']

ticket = base.Ticket(
ext_id=monitor['id'],
summary=summary,
text=text,
link="https://%s/monitors/%d" % (self.api_host, monitor['id']),
project=str(monitor['org_id']),
type=monitor['type'],
assignee=assignee,
status=status,
priority=priority,
tags=tags,
created_on=created_on,
modified_on=updated_on,
raw=monitor,
)
return ticket

def info(self, ticket):
"""Return info that might be interesting for this ticket."""
data = {}
return data
65 changes: 65 additions & 0 deletions my_little_ticket/plugins/feature_request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""Feature request strategy."""

from my_little_ticket.plugins import base


class FeatureRequestStrategy(base.Strategy):
"""FeatureRequestStrategy strategy.
Uses votes to sort.
"""

def __init__(self, params):
"""Constructor."""
super(FeatureRequestStrategy, self).__init__(params)
self.params = params

def short_name(self):
"""See base.Strategy."""
return "feature-request"

def name(self):
"""See base.Strategy."""
return "Feature request"

def description(self):
"""Score based on votes."""
return """
Feature request strategy. Uses the number of votes to determine a score.
The more voters, the higher the feature request will go.
"""

def group(self, ticket):
"""See base.Strategy."""
status = ticket.status or "unknown"

if status.lower() in ["block", "blocked", "idle"]:
return "Waiting"
elif status.lower() in ["in progress"]:
return "In Progress"
elif status.lower() in ["closed", "fixed", "resolved"]:
return "X Implemented"
else:
return "Feature Requests"

def _get_votes(self, ticket):
raw = ticket.raw or {}
return raw.get("fields", {}).get("votes", {}).get("votes", 0)

def status(self, ticket):
"""See base.Strategy."""
score = self._get_votes(ticket)
if score == 0: # Nobody cares
return self.STATUS_DANGER
elif score <= 3: # Some people
return self.STATUS_WARNING
elif score <= 6: # At least a team
return self.STATUS_INFO
else: # More than a team
return self.STATUS_SUCCESS

def score(self, ticket):
"""See base.Strategy."""
score = self._get_votes(ticket)
# Multiply by itself to make more differences between scores.
return score * score
43 changes: 43 additions & 0 deletions my_little_ticket/plugins/feature_request_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Test for the default strategy plugin."""

import unittest
import uuid
from django import test

from my_little_ticket.tickets.models import Ticket
from my_little_ticket_criteo.plugins import feature_request


class FeatureRequestStrategyTestCase(test.TestCase):
"""Tests for DefaultStrategy."""

def test_basic(self):
"""Check if the default strategy works."""
tickets = (
Ticket(
id=1,
uuid=uuid.uuid4(),
summary="Foo",
text="Foo foo",
link="http://bug/foo",
),
Ticket(
id=2,
uuid=uuid.uuid4(),
summary="bar",
text="bar bar",
link="http://bug/bar",
),
)
strategy = feature_request.FeatureRequestStrategy(params={})
result = strategy.scores(tickets)
self.assertEqual(len(result), len(tickets))
strategy.group(tickets[0])
strategy.status(tickets[0])


# FIXME: More tests here.


if __name__ == "__main__":
unittest.main()

0 comments on commit e47f962

Please sign in to comment.