M README.rst +7 -0
@@ 5,6 5,13 @@ django-trello-broker
:Version: 0.3
:Author: Peter Sanchez <peter@netlandish.com> - Netlandish Inc. (http://www.netlandish.com)
+Attention
+=========
+
+DO NOT USE THIS BRANCH! This project is essentially abandoned as we no longer use Trello.
+
+This branch (redmine) in particular is just a band-aid until we create a more universal solution that will plan to share in the future. This branch is literally just a hack to get our current setup working and integrated with our Redmine install.
+
Dependencies
============
A => pyproject.toml +29 -0
@@ 0,0 1,29 @@
+[tool.black]
+line-length = 79
+target-version = ['py37', 'py38']
+include = '\.pyi?$'
+exclude = '''
+
+(
+ /(
+ \.eggs # exclude a few common directories in the
+ | \.git # root of the project
+ | \.hg
+ | \.mypy_cache
+ | \.tox
+ | \.venv
+ | env
+ | _build
+ | buck-out
+ | build
+ | dist
+ )/
+ | foo.py # also separately exclude a file named foo.py in
+ # the root of the project
+)
+'''
+
+[tool.isort]
+line_length=79
+multi_line_output=5
+include_trailing_comma=true
M trello_broker/settings.py +42 -41
@@ 1,60 1,61 @@
from django.conf import settings
-
# Hard coded for now to avoid external requirement. Will change
# if the list becomes unmanageable or once we're all moved over to Py3 :)
# https://confluence.atlassian.com/bitbucket/what-are-the-bitbucket-cloud-ip-addresses-i-should-use-to-configure-my-corporate-firewall-343343385.html
BITBUCKET_IP_ADDRESSES = [
- '131.103.20.165', # Remove after 1/10/2016
- '131.103.20.166', # Remove after 1/10/2016
-
- '104.192.143.193', # 104.192.143.192/28
- '104.192.143.194',
- '104.192.143.195',
- '104.192.143.196',
- '104.192.143.197',
- '104.192.143.198',
- '104.192.143.199',
- '104.192.143.200',
- '104.192.143.201',
- '104.192.143.202',
- '104.192.143.203',
- '104.192.143.204',
- '104.192.143.205',
- '104.192.143.206',
-
- '104.192.143.209', # 104.192.143.208/28
- '104.192.143.210',
- '104.192.143.211',
- '104.192.143.212',
- '104.192.143.213',
- '104.192.143.214',
- '104.192.143.215',
- '104.192.143.216',
- '104.192.143.217',
- '104.192.143.218',
- '104.192.143.219',
- '104.192.143.220',
- '104.192.143.221',
- '104.192.143.222',
+ "131.103.20.165", # Remove after 1/10/2016
+ "131.103.20.166", # Remove after 1/10/2016
+ "104.192.143.193", # 104.192.143.192/28
+ "104.192.143.194",
+ "104.192.143.195",
+ "104.192.143.196",
+ "104.192.143.197",
+ "104.192.143.198",
+ "104.192.143.199",
+ "104.192.143.200",
+ "104.192.143.201",
+ "104.192.143.202",
+ "104.192.143.203",
+ "104.192.143.204",
+ "104.192.143.205",
+ "104.192.143.206",
+ "104.192.143.209", # 104.192.143.208/28
+ "104.192.143.210",
+ "104.192.143.211",
+ "104.192.143.212",
+ "104.192.143.213",
+ "104.192.143.214",
+ "104.192.143.215",
+ "104.192.143.216",
+ "104.192.143.217",
+ "104.192.143.218",
+ "104.192.143.219",
+ "104.192.143.220",
+ "104.192.143.221",
+ "104.192.143.222",
]
-USE_CELERY = getattr(settings, 'TRELLO_BROKER_USE_CELERY', False)
+USE_CELERY = getattr(settings, "TRELLO_BROKER_USE_CELERY", False)
-RESTRICT_IPS = getattr(settings, 'TRELLO_BROKER_RESTRICT_IPS', False)
+RESTRICT_IPS = getattr(settings, "TRELLO_BROKER_RESTRICT_IPS", False)
# https://confluence.atlassian.com/display/BITBUCKET/What+are+the+Bitbucket+IP+addresses+I+should+use+to+configure+my+corporate+firewall
# Only needed if TRELLO_BROKER_RESTRICT_IPS is True
BITBUCKET_IPS = getattr(
- settings,
- 'TRELLO_BROKER_BITBUCKET_IPS',
- BITBUCKET_IP_ADDRESSES,
+ settings, "TRELLO_BROKER_BITBUCKET_IPS", BITBUCKET_IP_ADDRESSES,
)
-RULE_CLASSES = getattr(settings,
- 'TRELLO_BROKER_RULE_CLASSES',
- ['trello_broker.rules.DefaultRuleProc'],
+RULE_CLASSES = getattr(
+ settings,
+ "TRELLO_BROKER_RULE_CLASSES",
+ ["trello_broker.rules.DefaultRuleProc"],
)
+
+REDMINE_API_KEY = getattr(settings, "TRELLO_BROKER_REDMINE_API_KEY", None)
+
+# No trailing slash!
+REDMINE_ROOT_URL = getattr(settings, "TRELLO_BROKER_REDMINE_ROOT_URL", None)
M trello_broker/utils.py +48 -56
@@ 1,14 1,20 @@
+import json
import re
+
+import requests
+from django.template.loader import render_to_string
+
+from . import settings
+
try:
from urlparse import urljoin
except ImportError:
from urllib.parse import urljoin
-from django.template.loader import render_to_string
-from . import api
# Based on pattern from https://bitbucket.org/sntran/trello-broker
-re_pattern = re.compile(r'''
+re_pattern = re.compile(
+ r"""
( # start capturing the verb
fix # contains 'fix'
| close # or 'close'
@@ 19,79 25,65 @@ re_pattern = re.compile(r'''
\s # then a white space
[#] # and '#' to indicate the card
([0-9]+) # with the card's short id.
- ''',
+ """,
re.VERBOSE | re.IGNORECASE,
)
def process_commits(repo, json_data):
- ''' Function to parse commit messages and act on
+ """ Function to parse commit messages and act on
BitBucketRule sets.
- '''
- base_repo_url = u'{0}{1}'.format(
- json_data['canon_url'],
- json_data['repository']['absolute_url'],
+ """
+ base_repo_url = "{0}{1}".format(
+ json_data["canon_url"], json_data["repository"]["absolute_url"],
)
- base_repo_url += '/' if base_repo_url[-1] != '/' else ''
- base_commit_url = urljoin(base_repo_url, 'commits/')
- trello_token = repo.trello_board.trello_token
+ base_repo_url += "/" if base_repo_url[-1] != "/" else ""
+ base_commit_url = urljoin(base_repo_url, "commits/")
- for commit in json_data['commits']:
+ for commit in json_data["commits"]:
+ print("in commit")
proc_cards = []
- msg = commit['message']
+ msg = commit["message"]
context = {
- 'author': commit['author'],
- 'author_full': commit['raw_author'],
- 'changeset': commit['node'],
- 'changeset_full': commit['raw_node'],
- 'commit_url': commit.get(
- 'commit_url',
- urljoin(base_commit_url, commit['raw_node']),
+ "author": commit["author"],
+ "author_full": commit["raw_author"],
+ "changeset": commit["node"],
+ "changeset_full": commit["raw_node"],
+ "commit_url": commit.get(
+ "commit_url", urljoin(base_commit_url, commit["raw_node"]),
),
- 'commit_message': msg,
+ "commit_message": msg,
}
for action, card_id in re_pattern.findall(msg):
+ print(f"in {action} -> {card_id}")
if card_id in proc_cards:
# Referenced more than once in the commit msg
continue
proc_cards.append(card_id)
- use_rule = 'fix_rule' \
- if action.lower() in ['fix', 'close'] else 'ref_rule'
- rule = getattr(repo, use_rule)
- if not rule:
- continue
- # Get Card information
- card = api.get_card_from_board(
- trello_token,
- repo.trello_board.trello_id,
- card_id,
+ # Update the card.
+ card_msg = render_to_string(
+ "trello_broker/update_message.txt", context
)
- full_card_id = card['id']
+ update = {"issue": {"notes": card_msg,}}
- # Let's process the rule
- if rule.update:
- # Update the card.
- card_msg = render_to_string(
- 'trello_broker/update_message.txt',
- context,
- )
- api.add_comment_to_card(
- trello_token,
- full_card_id,
- card_msg,
- )
+ if action.lower() == "close":
+ # FYI, this is hard coded for our own use case.
+ # DO NOT USE!
+ print("updating status")
+ update["issue"]["status_id"] = 15
+ print(f"Final result: {update}")
- if rule.move:
- # Move the card
- api.move_card(
- trello_token,
- full_card_id,
- rule.trello_list.trello_id,
- )
-
- if rule.archive:
- # Archive the card
- api.archive_card(trello_token, full_card_id)
+ result = requests.put(
+ f"{settings.REDMINE_ROOT_URL}/issues/{card_id}.json",
+ data=json.dumps(update),
+ headers={
+ "X-Redmine-API-Key": settings.REDMINE_API_KEY,
+ "Content-Type": "application/json",
+ },
+ )
+ if result.status_code >= 400:
+ # XXX Log something
+ pass
M trello_broker/views.py +23 -14
@@ 1,12 1,14 @@
import json
-from django.views.generic import View
+
+from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404
-from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
-from django.http import HttpResponse, HttpResponseBadRequest, Http404
-from .models import Q, BitBucketRepo
+from django.views.decorators.csrf import csrf_exempt
+from django.views.generic import View
+
+from . import settings
+from .models import BitBucketRepo, Q
from .utils import process_commits
-from . import settings
if settings.USE_CELERY:
from .tasks import celery_process_commits
@@ 15,9 17,9 @@ else:
def trello_distribute(repo, json_data):
- ''' Helper function that decides how to process
+ """ Helper function that decides how to process
Trello interaction (celery or not)
- '''
+ """
if celery_process_commits is not None:
celery_process_commits.delay(repo.pk, json_data)
else:
@@ 29,22 31,29 @@ class BitBucketPostView(View):
return HttpResponseBadRequest()
def post(self, request, *args, **kwargs):
+ if settings.REDMINE_API_KEY is None:
+ return HttpResponseBadRequest("Redmine API key required.")
+
+ if settings.REDMINE_ROOT_URL is None:
+ return HttpResponseBadRequest("Redmine API key required.")
+
if settings.RESTRICT_IPS:
- if request.META['REMOTE_ADDR'] not in settings.BITBUCKET_IPS:
+ if request.META["REMOTE_ADDR"] not in settings.BITBUCKET_IPS:
return HttpResponseBadRequest()
try:
- json_data = json.loads(request.POST['payload'])
- repo_slug = json_data['repository']['slug']
- except (ValueError, KeyError) as e:
+ json_data = json.loads(request.POST["payload"])
+ repo_slug = json_data["repository"]["slug"]
+ except (ValueError, KeyError):
return HttpResponseBadRequest()
- access_key = \
- request.POST.get('access_key', request.GET.get('access_key', ''))
+ access_key = request.POST.get(
+ "access_key", request.GET.get("access_key", "")
+ )
query = Q(slug=repo_slug) & Q(access_key=access_key)
repo = get_object_or_404(BitBucketRepo, query)
trello_distribute(repo, json_data)
- return HttpResponse('OK')
+ return HttpResponse("OK")
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):