-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The script automates github issue to Jita ticket mirroring. Signed-off-by: Or Shoval <[email protected]>
- Loading branch information
Showing
13 changed files
with
587 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,129 +1,3 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
pip-wheel-metadata/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
__pycache__ | ||
secret.txt | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
db.sqlite3-journal | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# IPython | ||
profile_default/ | ||
ipython_config.py | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# pipenv | ||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
# install all needed dependencies. | ||
#Pipfile.lock | ||
|
||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow | ||
__pypackages__/ | ||
|
||
# Celery stuff | ||
celerybeat-schedule | ||
celerybeat.pid | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
# Pyre type checker | ||
.pyre/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
FROM fedora:32 | ||
|
||
RUN dnf install -y python3 git pip \ | ||
&& dnf clean all \ | ||
&& rm -rf /var/cache/yum | ||
|
||
RUN pip install requests jira | ||
|
||
CMD [“echo”, “Hello World”] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,57 @@ | ||
# github2jira | ||
Scrap github issues and create Jira tickets | ||
github2jira automates mirroring of github issues to Jira tickets. | ||
|
||
The tool scans github for issues that match the desired criteria, | ||
and for each one of them creates a Jira ticket (unless it already exists). | ||
|
||
## One time configuration | ||
1. Create github token https://github.com/settings/tokens, refer it as `GITHUB_TOKEN` | ||
2. Make sure you have a Jira bot access (either a user:pass or user:token), refer as `JIRA_USERNAME`,`JIRA_TOKEN` | ||
3. Get your Jira project id, refer as `JIRA_PROJECT_ID` | ||
`curl -s -u JIRA_USERNAME:JIRA_TOKEN -X GET -H "Content-Type: application/json" <JIRA_SERVER>/rest/api/latest/project/<JIRA_PROJECT> | jq .id` | ||
|
||
## Running manually | ||
|
||
1. export the following envvars: | ||
``` | ||
export JIRA_SERVER=<..> # for example https://nmstate.atlassian.net | ||
export JIRA_PROJECT=<..> # name of the Jira project (ticket names are JIRA_PROJECT-#) | ||
export JIRA_PROJECT_ID=<..> # see "One time configuration" section | ||
export JIRA_COMPONENT=<..> # which component to set in the created tickets | ||
export GITHUB_OWNER=<..> # the x of https://github.com/x/y | ||
export GITHUB_REPO=<..> # the y of https://github.com/x/y | ||
export GITHUB_LABEL=<..> # which label to filter | ||
export JIRA_USERNAME=<..> # see "One time configuration" section | ||
export JIRA_TOKEN=<..> # see "One time configuration" section | ||
export GITHUB_TOKEN=<..> # see "One time configuration" section | ||
``` | ||
|
||
2. Run `./main.py` in order to fetch github issues and create a ticket for them | ||
|
||
### Additional settings | ||
|
||
`dryrun`: Use `./main.py --dryrun` in order to run the tool in dryrun mode. | ||
dryrun mode will fetch github issues, and report what Jira tickets it would create, | ||
but without creating them. | ||
|
||
## Running as k8s payload | ||
|
||
In order to have a fully automated mirroring process, | ||
it is suggested to run the tool as a cron jon. | ||
|
||
One of the methods to achieve it, is to run it as k8s CronJob payload. | ||
|
||
### One time configuration: Build docker image for the script | ||
|
||
1. From the project folder, run `docker build -f Dockerfile -t <image> .` | ||
once its done, push it to your image repository, or rename and push to a local registry. | ||
|
||
### Deploy as k8s payload | ||
|
||
1. Create secret.txt with the exports from the section above (include the export command). | ||
|
||
2. Create a configmap for the txt file | ||
`kubectl create configmap git-token --from-file=secret.txt` | ||
|
||
3. Deploy either a pod or a CronJob (see manifests folder). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# This file is part of the github2jira project | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
# Copyright 2021 Red Hat, Inc. | ||
# | ||
|
||
import os | ||
|
||
|
||
class Config: | ||
def __init__(self, var_names): | ||
self.var_names = var_names | ||
self.vars = {} | ||
|
||
def Load(self): | ||
for var_name in self.var_names: | ||
value = os.getenv(var_name) | ||
if value is None: | ||
print(f"Error: cant find {var_name}") | ||
return False | ||
self.vars[var_name] = value | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# This file is part of the github2jira project | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
# Copyright 2021 Red Hat, Inc. | ||
# | ||
|
||
import time | ||
import requests | ||
|
||
from datetime import datetime | ||
|
||
from config import Config | ||
|
||
SECONDS_PER_WEEK = 604800 | ||
# max github pages to process | ||
GITHUB_MAX_PAGES = 20 | ||
# process upto x weeks back | ||
MAX_DELTA_WEEKS = 4 | ||
|
||
|
||
class GithubConfig(Config): | ||
def __init__(self): | ||
super().__init__( | ||
["GITHUB_TOKEN", "GITHUB_OWNER", "GITHUB_REPO", "GITHUB_LABEL"] | ||
) | ||
|
||
|
||
class Issue: | ||
def __init__(self, issue): | ||
self.issue = issue | ||
|
||
def filter(self, expected_label): | ||
if expected_label == "": | ||
return True | ||
for label in self.issue["labels"]: | ||
if label["name"] == expected_label: | ||
return True | ||
return False | ||
|
||
def age_relevant(self, max_delta): | ||
epoch_time_now = int(time.time()) | ||
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" | ||
timestamp = self.issue["created_at"] | ||
epoch = int(datetime.strptime(timestamp, TIME_FORMAT).timestamp()) | ||
return (epoch_time_now - epoch) < (max_delta * SECONDS_PER_WEEK) | ||
|
||
@property | ||
def repo(self): | ||
return self.issue["html_url"].split("/")[4] | ||
|
||
@property | ||
def id(self): | ||
return self.issue["number"] | ||
|
||
@property | ||
def url(self): | ||
return self.issue["html_url"] | ||
|
||
@property | ||
def title(self): | ||
return self.issue["title"] | ||
|
||
|
||
class Github: | ||
def __init__(self, cfg): | ||
self.owner = cfg.vars["GITHUB_OWNER"] | ||
self.repo = cfg.vars["GITHUB_REPO"] | ||
self.expected_label = cfg.vars["GITHUB_LABEL"] | ||
self.query_url = f"https://api.github.com/repos/{self.owner}/{self.repo}/issues" | ||
self.headers = {"Authorization": f"token {cfg.vars['GITHUB_TOKEN']}"} | ||
|
||
def issues(self): | ||
for page in range(1, GITHUB_MAX_PAGES): | ||
params = {"state": "open", "page": page, "per_page": "100"} | ||
r = requests.get(self.query_url, headers=self.headers, params=params) | ||
issues = r.json() | ||
|
||
if len(issues) == 0: | ||
return | ||
|
||
for element in issues: | ||
issue = Issue(element) | ||
if "pull" in issue.url: | ||
continue | ||
|
||
if issue.filter(self.expected_label) and issue.age_relevant( | ||
MAX_DELTA_WEEKS | ||
): | ||
yield (issue) |
Oops, something went wrong.