Skip to content

Commit

Permalink
Add support for Jira
Browse files Browse the repository at this point in the history
  • Loading branch information
ricardobranco777 committed Sep 17, 2023
1 parent 12d042c commit 11763d5
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 49 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ RUN zypper addrepo https://download.opensuse.org/repositories/SUSE:/CA/openSUSE_
python3-dulwich \
python3-python-dateutil \
python3-pytz \
python3-atlassian-python-api \
python3-bugzilla \
python3-PyGithub \
python3-python-gitlab \
Expand Down
20 changes: 9 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# bugme

Show bug and issue status for Bugzilla, Github, Gitlab & Redmine
Show bug and issue status for Bugzilla, Github, Gitlab, Jira & Redmine

Docker image available at `ghcr.io/ricardobranco777/bugme:latest`

Expand Down Expand Up @@ -38,12 +38,13 @@ Copy [creds-example.json](creds-example.json) to `~/creds.json` and run:

```
$ podman run --rm -v ~/creds.json:/root/creds.json:ro bugme bsc#1213811 gh#containers/podman#19529 poo#133910 gl#gitlab-org/gitlab#424503 gsd#qac/container-release-bot#7 ghcr.io/ricardobranco777/bugme
URL STATUS UPDATED TITLE
https://bugzilla.suse.com/show_bug.cgi?id=1213811 NEW Tue Sep 05 16:21:37 CEST 2023 podman network unreachable after starting docker
https://github.com/containers/podman/issues/19529 closed Tue Aug 08 08:56:56 CEST 2023 Unexpected error with --volumes-from
https://progress.opensuse.org/issues/133910 Resolved Thu Aug 17 08:50:53 CEST 2023 We need a suite of tests to check volume operations in container runtimes
https://gitlab.com/gitlab-org/gitlab/-/issues/424503 opened Fri Sep 08 18:46:24 CEST 2023 Prepare UI/UX when monetisation transition period ends (cut-off)
https://gitlab.suse.de/qac/container-release-bot/-/issues/7 opened Thu Sep 15 15:57:32 CEST 2022 Explore new schedule options
TAG STATUS UPDATED TITLE
bsc#1213811 NEW 2 days ago podman network unreachable after starting docker
gh#containers/podman#19529 CLOSED 1 month ago Unexpected error with --volumes-from
poo#133910 RESOLVED 1 month ago We need a suite of tests to check volume operations in container runtimes
gl#gitlab-org/gitlab#424503 OPENED 5 days ago Prepare UI/UX when monetisation transition period ends (cut-off)
gsd#qac/container-release-bot#7 OPENED 1 year ago Explore new schedule options
jsc#SCL-8 IN PROGRESS 1 year ago Documentation
```

To scan a repository:
Expand All @@ -58,13 +59,10 @@ $ podman run --rm -v ~/creds.json:/root/creds.json:ro -v ~/suse/os-autoinst-dist
- gh#: Github
- gl#: Gitlab
- gsd#: SUSE's Gitlab
- jsc#: SUSE's Jira
- poo#: openSUSE's Redmine

## Requirements

- Docker or Podman to run the Docker image.
- Python 3.11+ and [requirements](requirements-dev.txt) to run stand-alone.

## TODO

- Jira
5 changes: 3 additions & 2 deletions bugme.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from typing import Any, Generator

from scantags import scan_tags
from services import get_item, Item, MyBugzilla, MyGithub, MyGitlab, MyRedmine
from services import get_item, Item, MyBugzilla, MyGithub, MyGitlab, MyJira, MyRedmine
from utils import dateit


Expand Down Expand Up @@ -75,6 +75,7 @@ def get_items(

host_to_cls = {
"github.com": MyGithub,
"jira.suse.com": MyJira,
"progress.opensuse.org": MyRedmine,
}

Expand Down Expand Up @@ -118,7 +119,7 @@ def print_items(
"""
keys = {
"tag": "<40",
"status": "<10",
"status": "<15",
"created": "<15" if time_format == "timeago" else "<30",
"updated": "<15" if time_format == "timeago" else "<30",
}
Expand Down
6 changes: 6 additions & 0 deletions creds-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
"user": "[email protected]",
"api_key": "BUGZILLA_API_KEY"
},
"jira.suse.com": {
"cookies": {
"JIRASESSIONID": "JIRA_SESSION_ID",
"atlassian.xsrf.token": "JIRA_TOKEN"
}
},
"progress.opensuse.org": {
"username": "rbranco",
"key": "REDMINE_API_KEY"
Expand Down
6 changes: 6 additions & 0 deletions creds.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
},
"github.com": {"login_or_token": os.environ["BUGME_GITHUB_TOKEN"]},
"gitlab.com": {"private_token": os.environ["GITLAB_API_KEY"]},
"jira.suse.com": {
"cookies": {
"JIRASESSIONID": os.environ["JIRA_SESSION_ID"],
"atlassian.xsrf.token": os.environ["JIRA_TOKEN"],
}
},
"progress.opensuse.org": {
"key": os.environ["REDMINE_API_KEY"],
"username": os.environ["REDMINE_USER"],
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
atlassian-python-api
dulwich
PyGithub
python-bugzilla
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
atlassian-python-api==3.41.2
certifi==2023.7.22
cffi==1.15.1
charset-normalizer==3.2.0
cryptography==41.0.3
Deprecated==1.2.14
dulwich==0.21.6
idna==3.4
oauthlib==3.2.2
pycparser==2.21
PyGithub==1.59.1
PyJWT==2.8.0
Expand All @@ -15,6 +17,7 @@ python-gitlab==3.15.0
python-redmine==2.4.0
pytz==2023.3.post1
requests==2.31.0
requests-oauthlib==1.3.1
requests-toolbelt==1.0.0
six==1.16.0
urllib3==2.0.4
Expand Down
4 changes: 3 additions & 1 deletion scantags.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
from dulwich.repo import Repo

FILE_PATTERN = "*.pm"
LINE_PATTERN = r"soft_fail.*?((?:bsc|poo)#[0-9]+|(?:gh|gl|gsd)#[^#]+#[0-9]+)"
LINE_PATTERN = (
r"soft_fail.*?((?:bsc|poo)#[0-9]+|(?:gh|gl|gsd)#[^#]+#[0-9]+|jsc#[A-Z]+-[0-9]+)"
)


def git_branch(directory: str = ".") -> str:
Expand Down
73 changes: 57 additions & 16 deletions services.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from urllib.parse import urlparse, parse_qs
from typing import Any

from atlassian import Jira # type: ignore
from atlassian.errors import ApiError # type: ignore
from bugzilla import Bugzilla # type: ignore
from bugzilla.exceptions import BugzillaError # type: ignore
from github import Github, GithubException
Expand All @@ -27,6 +29,7 @@
"gh": "github.com",
"gl": "gitlab.com",
"gsd": "gitlab.suse.de",
"jsc": "jira.suse.com",
"poo": "progress.opensuse.org",
}

Expand Down Expand Up @@ -74,12 +77,10 @@ def get_item(string: str) -> Item | None:
issue_id = os.path.basename(url.path)
elif hostname.startswith("bugzilla"):
issue_id = parse_qs(url.query)["id"][0]
elif hostname == "progress.opensuse.org":
issue_id = os.path.basename(url.path)
else:
return None
issue_id = os.path.basename(url.path)
return Item(
item_id=int(issue_id),
item_id=issue_id,
host=hostname,
repo=repo,
)
Expand All @@ -91,7 +92,7 @@ def get_item(string: str) -> Item | None:
repo = ""
try:
return Item(
item_id=int(issue),
item_id=issue,
host=CODE_TO_HOST[code],
repo=repo,
)
Expand All @@ -113,7 +114,7 @@ def __init__(self, url: str):
def __repr__(self) -> str:
return f"{self.__class__.__name__}(url='{self.url}')"

def _not_found(self, item_id: int, url: str, tag: str) -> Item:
def _not_found(self, item_id: str, url: str, tag: str) -> Item:
now = datetime.now()
return Item(
id=item_id,
Expand All @@ -126,7 +127,7 @@ def _not_found(self, item_id: int, url: str, tag: str) -> Item:
json="{}",
)

def get_item(self, item_id: int = -1, **kwargs) -> Item | None:
def get_item(self, item_id: str = "", **kwargs) -> Item | None:
"""
This method must be overriden if get_items() isn't overriden
"""
Expand Down Expand Up @@ -161,7 +162,7 @@ def __del__(self):
except (AttributeError, BugzillaError):
pass

def get_item(self, item_id: int = -1, **kwargs) -> Item | None:
def get_item(self, item_id: str = "", **kwargs) -> Item | None:
"""
Get Bugzilla item
"""
Expand Down Expand Up @@ -204,7 +205,7 @@ def get_items(self, items: list[dict]) -> list[Item | None]:

def _to_item(self, info: Any) -> Item:
return Item(
id=info.id,
id=str(info.id),
status=info.status,
title=info.summary,
created=info.creation_time,
Expand All @@ -228,21 +229,21 @@ def __init__(self, url: str, creds: dict):
self.client = Github(**creds)
self.tag = "gh"

def get_item(self, item_id: int = -1, **kwargs) -> Item | None:
def get_item(self, item_id: str = "", **kwargs) -> Item | None:
"""
Get Github issue
"""
repo = kwargs.pop("repo")
try:
info = self.client.get_repo(repo, lazy=True).get_issue(item_id)
info = self.client.get_repo(repo, lazy=True).get_issue(int(item_id))
except (GithubException, RequestException) as exc:
if getattr(exc, "status", None) == 404:
return self._not_found(
item_id,
"{self.url}/{repo}/issues/{item_id}",
"{self.tag}#{repo}#{item_id}",
)
logging.error("Github: get_issue(%s, %s): %s", repo, item_id, exc)
logging.error("Github: get_item(%s, %s): %s", repo, item_id, exc)
return None
return self._to_item(info, repo)

Expand Down Expand Up @@ -277,7 +278,7 @@ def __del__(self):
except (AttributeError, GitlabError):
pass

def get_item(self, item_id: int = -1, **kwargs) -> Item | None:
def get_item(self, item_id: str = "", **kwargs) -> Item | None:
"""
Get Gitlab issue
"""
Expand All @@ -292,7 +293,7 @@ def get_item(self, item_id: int = -1, **kwargs) -> Item | None:
f"{self.tag}#{repo}#{item_id}",
)
logging.error(
"Gitlab: %s: get_issue(%s, %s): %s", self.url, repo, item_id, exc
"Gitlab: %s: get_item(%s, %s): %s", self.url, repo, item_id, exc
)
return None
return self._to_item(info, repo)
Expand All @@ -319,7 +320,7 @@ def __init__(self, url: str, creds: dict):
super().__init__(url)
self.client = Redmine(url=self.url, raise_attr_exception=False, **creds)

def get_item(self, item_id: int = -1, **kwargs) -> Item | None:
def get_item(self, item_id: str = "", **kwargs) -> Item | None:
"""
Get Redmine ticket
"""
Expand All @@ -330,7 +331,7 @@ def get_item(self, item_id: int = -1, **kwargs) -> Item | None:
item_id, f"{self.url}/issues/{item_id}", f"{self.tag}#{item_id}"
)
except (BaseRedmineError, RequestException) as exc:
logging.error("Redmine: %s: get_issue(%d): %s", self.url, item_id, exc)
logging.error("Redmine: %s: get_item(%d): %s", self.url, item_id, exc)
return None
return self._to_item(info)

Expand All @@ -345,3 +346,43 @@ def _to_item(self, info: Any) -> Item:
tag=f"{self.tag}#{info.id}",
json=json.dumps(info.raw(), **JSON_OPTIONS), # type: ignore
)


class MyJira(Service):
"""
Redmine
"""

def __init__(self, url: str, creds: dict):
super().__init__(url)
self.client = Jira(url=self.url, **creds)

def get_item(self, item_id: str = "", **kwargs) -> Item | None:
"""
Get Jira ticket
"""
try:
info = self.client.issue(item_id)
except (ApiError, RequestException) as exc:
try:
if exc.response.status_code == 404:
return self._not_found(
item_id, f"{self.url}/browse/{item_id}", f"{self.tag}#{item_id}"
)
except AttributeError:
pass
logging.error("Jira: %s: get_item(%s): %s", self.url, item_id, exc)
return None
return self._to_item(info)

def _to_item(self, info: Any) -> Item:
return Item(
id=info["key"],
status=info["fields"]["status"]["name"],
title=info["fields"]["summary"],
created=info["fields"]["created"],
updated=info["fields"]["updated"],
url=f"{self.url}/browse/{info['key']}",
tag=f"{self.tag}#{info['key']}",
json=json.dumps(info, **JSON_OPTIONS), # type: ignore
)
Loading

0 comments on commit 11763d5

Please sign in to comment.