Skip to content

Commit

Permalink
feat(slack): use external tickforge slack api to find slack user if p…
Browse files Browse the repository at this point in the history
…rovided
  • Loading branch information
uptickmetachu committed Apr 3, 2024
1 parent 8914b6f commit 221c04c
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 21 deletions.
2 changes: 1 addition & 1 deletion charts/gitops/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ apiVersion: v1
appVersion: "1.0"
description: GitOps Server Helm chart.
name: gitops
version: 0.10.3
version: 0.10.4
2 changes: 1 addition & 1 deletion gitops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from . import monkeypatches # NOQA
from .utils.cli import success, warning

__version__ = "0.10.3"
__version__ = "0.10.4"


# Checking gitops version matches cluster repo version.
Expand Down
56 changes: 38 additions & 18 deletions gitops_server/utils/slack.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import dataclasses
import json
import logging
import os
import urllib.request
from collections.abc import Iterable
from typing import Optional

import httpx

logger = logging.getLogger("gitops")

SLACK_URL = os.environ.get("SLACK_URL")
SLACK_TOKEN = os.environ.get("SLACK_TOKEN")
TICKFORGE_SLACK_KEY = os.environ.get("TICKFORGE_SLACK_KEY")
TICKFORGE_URL = os.environ.get("TICKFORGE_URL")


@dataclasses.dataclass
class SlackUser:
Expand All @@ -27,34 +29,52 @@ def __str__(self) -> str:
return f"<!subteam^{self.id}|{self.name}>"


async def post(message):
async def post(message: str) -> None:
"""Post a message to a slack channel
Uses the environment variable `SLACK_URL` to know which channel to post to.
This URL is obtained by registering an integration with Slack.
"""
logger.info("POSTING TO SLACK")
url = os.environ["SLACK_URL"]
data = {"text": message}
async with httpx.AsyncClient() as client:
response = await client.post(url, json=data)
response = await client.post(SLACK_URL, json=data)
if response.status_code >= 300:
logger.warning("Failed to post a message to slack (see below):")
logger.error(f"{message}", exc_info=True)


def find_commiter_slack_user(name: str, email: str) -> Optional["SlackUser"]:
token = os.environ.get("SLACK_TOKEN", "")
if not token:
async def _tickforge_find_slack_user(name: str, email: str) -> SlackUser | None:
"""Find a slack user by name or email using the tickforge API
This shim exists for our own internal alternative filtering requirements
"""
if TICKFORGE_URL and TICKFORGE_SLACK_KEY:
async with httpx.AsyncClient() as client:
response = await client.get(
f"{TICKFORGE_URL}/api/slack/search",
params={"name": name, "email": email},
headers={"x-tickforge-slack-key": TICKFORGE_SLACK_KEY},
)
return response.json() # type:ignore
else:
return None

with urllib.request.urlopen( # noqa:S310
urllib.request.Request(
"https://slack.com/api/users.list?limit=300&pretty=1",
headers={"Authorization": f"Bearer {token}"},

async def find_commiter_slack_user(name: str, email: str) -> SlackUser | None:
"""Find a slack user by name or email using the slack API"""
if not SLACK_TOKEN:
return None

if TICKFORGE_SLACK_KEY and TICKFORGE_URL:
return await _tickforge_find_slack_user(name, email)

async with httpx.AsyncClient() as client:
response = await client.get(
"https://slack.com/api/users.list?limit=1000&pretty=1",
headers={"Authorization": f"Bearer {SLACK_TOKEN}"},
)
) as response:
data = json.loads(response.read())
data = response.json()

if not data["ok"]:
raise Exception(data["error"])
Expand Down Expand Up @@ -91,9 +111,9 @@ def pairwise_tuples(x: str) -> list[tuple[str, str]]:
def search(name: str, email: str, users: list[SlackUser]) -> SlackUser | None:
def scoring_fn(user: SlackUser) -> float:
return (
jaccard_similarity(pairwise_tuples(user.email), pairwise_tuples(email))
+ jaccard_similarity(pairwise_tuples(name), pairwise_tuples(user.name))
+ jaccard_similarity(pairwise_tuples(name), pairwise_tuples(user.real_name))
jaccard_similarity(pairwise_tuples(user.email.lower()), pairwise_tuples(email.lower()))
+ jaccard_similarity(pairwise_tuples(name.lower()), pairwise_tuples(user.name.lower()))
+ jaccard_similarity(pairwise_tuples(name.lower()), pairwise_tuples(user.real_name.lower()))
)

matches = sorted([(scoring_fn(u), u) for u in users], key=lambda x: x[0], reverse=True)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "gitops"
version = "0.10.3"
version = "0.10.4"
description = "Manage multiple apps across one or more k8s clusters."
authors = ["Jarek Głowacki <jarekwg@gmail.com>"]
license = "BSD"
Expand Down

0 comments on commit 221c04c

Please sign in to comment.