Intial commit
This commit is contained in:
commit
f6faf473fb
22
.devcontainer/Dockerfile
Normal file
22
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.155.1/containers/python-3/.devcontainer/base.Dockerfile
|
||||||
|
|
||||||
|
# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6
|
||||||
|
ARG VARIANT="3"
|
||||||
|
FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
|
||||||
|
|
||||||
|
# [Option] Install Node.js
|
||||||
|
ARG INSTALL_NODE="true"
|
||||||
|
ARG NODE_VERSION="lts/*"
|
||||||
|
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
||||||
|
|
||||||
|
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
|
||||||
|
# COPY requirements.txt /tmp/pip-tmp/
|
||||||
|
# RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
|
||||||
|
# && rm -rf /tmp/pip-tmp
|
||||||
|
|
||||||
|
# [Optional] Uncomment this section to install additional OS packages.
|
||||||
|
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||||
|
|
||||||
|
# [Optional] Uncomment this line to install global node packages.
|
||||||
|
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
47
.devcontainer/devcontainer.json
Normal file
47
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||||
|
// https://github.com/microsoft/vscode-dev-containers/tree/v0.155.1/containers/python-3
|
||||||
|
{
|
||||||
|
"name": "Python 3",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "Dockerfile",
|
||||||
|
"context": "..",
|
||||||
|
"args": {
|
||||||
|
// Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9
|
||||||
|
"VARIANT": "3.9",
|
||||||
|
// Options
|
||||||
|
"INSTALL_NODE": "false",
|
||||||
|
"NODE_VERSION": "lts/*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Set *default* container specific settings.json values on container create.
|
||||||
|
"settings": {
|
||||||
|
"terminal.integrated.shell.linux": "/bin/bash",
|
||||||
|
"python.pythonPath": "/usr/local/bin/python",
|
||||||
|
"python.linting.enabled": true,
|
||||||
|
"python.linting.pylintEnabled": true,
|
||||||
|
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
|
||||||
|
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
||||||
|
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
|
||||||
|
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
|
||||||
|
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
|
||||||
|
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
|
||||||
|
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
|
||||||
|
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
|
||||||
|
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Add the IDs of extensions you want installed when the container is created.
|
||||||
|
"extensions": [
|
||||||
|
"ms-python.python"
|
||||||
|
],
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
// "forwardPorts": [],
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
// "postCreateCommand": "pip3 install --user -r requirements.txt",
|
||||||
|
|
||||||
|
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||||
|
"remoteUser": "vscode"
|
||||||
|
}
|
24
.github/workflows/build.yaml
vendored
Normal file
24
.github/workflows/build.yaml
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
name: Build
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Set up Python 3.9
|
||||||
|
uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
python setup.py sdist
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: jira-tracker.tar.gz
|
||||||
|
path: dist/jira-tracker-*.tar.gz
|
54
.github/workflows/release.yaml
vendored
Normal file
54
.github/workflows/release.yaml
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
name: Publish Release
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- created
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pypi:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Set up Python 3.9
|
||||||
|
uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
- name: Update Version
|
||||||
|
run: |
|
||||||
|
sed -i "s/[0-9.]*\.[0-9.]*\.[0-9.]*/${GITHUB_REF}/g" jira_tracker/__init__.py
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
- name: build
|
||||||
|
run: |
|
||||||
|
python setup.py sdist bdist_wheel
|
||||||
|
- name: PyPi Publish
|
||||||
|
uses: pypa/gh-action-pypi-publish@v1.0.0a0
|
||||||
|
with:
|
||||||
|
user: __token__
|
||||||
|
password: ${{ secrets.PYPI_TOKEN }}
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Set up Python 3.9
|
||||||
|
uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
- name: Update Version
|
||||||
|
run: |
|
||||||
|
sed -i "s/[0-9.]*\.[0-9.]*\.[0-9.]*/${GITHUB_REF}/g" jira_tracker/__init__.py
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
python setup.py sdist
|
||||||
|
- name: Upload to release
|
||||||
|
uses: JasonEtco/upload-to-release@v0.1.1
|
||||||
|
with:
|
||||||
|
args: dist/jira-tracker-*.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
138
.gitignore
vendored
Normal file
138
.gitignore
vendored
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# 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/
|
||||||
|
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/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# 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
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .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/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2021 Joseph Manley and others
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
61
jira_tracker/__init__.py
Normal file
61
jira_tracker/__init__.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import argparse, traceback, sys
|
||||||
|
from jira_tracker.logger import logger, enable_debug_logger
|
||||||
|
from jira_tracker.jira_auth import JiraAuth
|
||||||
|
from jira_tracker.project_tracker import ProjectTracker
|
||||||
|
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="test")
|
||||||
|
parser.add_argument("-d", "--debug", help="Enables debug logging and traceback", action="store_true", dest="debug", default=False)
|
||||||
|
parser.add_argument("-v", "--version", help="Return current version number", dest="return_version", action="store_true", default=False)
|
||||||
|
parser.add_argument("--update-config", help ="Prompts input for updating config file", dest="update_config", action="store_true", default=False)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.debug:
|
||||||
|
enable_debug_logger()
|
||||||
|
|
||||||
|
if args.return_version:
|
||||||
|
print(version)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
auth = JiraAuth()
|
||||||
|
|
||||||
|
if args.update_config:
|
||||||
|
auth.stdin_configure()
|
||||||
|
auth.update_config(auth.config_location)
|
||||||
|
|
||||||
|
|
||||||
|
row_format ="{:<12}{:<64}{:>4}{:>16}"
|
||||||
|
print(row_format.format("Task","Summary","Points","Status"))
|
||||||
|
|
||||||
|
points = 0
|
||||||
|
jira_client = auth.get_client()
|
||||||
|
all_issues = []
|
||||||
|
for jira_project in jira_client.projects():
|
||||||
|
logger.debug(f"Searching Project: {jira_project.key}")
|
||||||
|
proj = ProjectTracker(jira_client, jira_project.key)
|
||||||
|
issues = sorted(proj.this_weeks_issues(), key=lambda issue: issue.status)
|
||||||
|
all_issues = all_issues + issues
|
||||||
|
for issue in issues:
|
||||||
|
if issue.status == "Done":
|
||||||
|
points = points + float(issue.points)
|
||||||
|
|
||||||
|
for issue in all_issues:
|
||||||
|
print(row_format.format(issue.name, issue.summary, issue.points, issue.status))
|
||||||
|
print(f"\nTotal points this week: {points}")
|
||||||
|
|
||||||
|
|
||||||
|
except (Exception) as e:
|
||||||
|
logger.critical(e)
|
||||||
|
if args.debug:
|
||||||
|
tb = sys.exc_info()[2]
|
||||||
|
traceback.print_tb(tb)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
61
jira_tracker/__init__.pye
Normal file
61
jira_tracker/__init__.pye
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import argparse, traceback, sys
|
||||||
|
from jira_tracker.logger import logger, enable_debug_logger
|
||||||
|
from jira_tracker.jira_auth import JiraAuth
|
||||||
|
from jira_tracker.project_tracker import ProjectTracker
|
||||||
|
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="test")
|
||||||
|
parser.add_argument("-d", "--debug", help="Enables debug logging and traceback", action="store_true", dest="debug", default=False)
|
||||||
|
parser.add_argument("-v", "--version", help="Return current version number", dest="return_version", action="store_true", default=False)
|
||||||
|
parser.add_argument("--update-config", help ="Prompts input for updating config file", dest="update_config", action="store_true", default=False)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.debug:
|
||||||
|
enable_debug_logger()
|
||||||
|
|
||||||
|
if args.return_version:
|
||||||
|
print(version)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
auth = JiraAuth()
|
||||||
|
|
||||||
|
if args.update_config:
|
||||||
|
auth.stdin_configure()
|
||||||
|
auth.update_config(auth.config_location)
|
||||||
|
|
||||||
|
|
||||||
|
row_format ="{:<12}{:<64}{:>4}{:>16}"
|
||||||
|
print(row_format.format("Task","Summary","Points","Status"))
|
||||||
|
|
||||||
|
points = 0
|
||||||
|
jira_client = auth.get_client()
|
||||||
|
all_issues = []
|
||||||
|
for jira_project in jira_client.projects():
|
||||||
|
logger.debug(f"Searching Project: {jira_project.key}")
|
||||||
|
proj = ProjectTracker(jira_client, jira_project.key)
|
||||||
|
issues = sorted(proj.this_weeks_issues(), key=lambda issue: issue.status)
|
||||||
|
all_issues = all_issues + issues
|
||||||
|
for issue in issues:
|
||||||
|
if issue.status == "Done":
|
||||||
|
points = points + float(issue.points)
|
||||||
|
|
||||||
|
for issue in all_issues:
|
||||||
|
print(row_format.format(issue.name, issue.summary, issue.points, issue.status))
|
||||||
|
print(f"\nTotal points this week: {points}")
|
||||||
|
|
||||||
|
|
||||||
|
except (Exception) as e:
|
||||||
|
logger.critical(e)
|
||||||
|
if args.debug:
|
||||||
|
tb = sys.exc_info()[2]
|
||||||
|
traceback.print_tb(tb)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
77
jira_tracker/jira_auth.py
Normal file
77
jira_tracker/jira_auth.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
from jira_tracker.logger import logger
|
||||||
|
import jira, yaml
|
||||||
|
import pathlib, os
|
||||||
|
|
||||||
|
class JiraAuth:
|
||||||
|
def __init__(self):
|
||||||
|
self.config = None
|
||||||
|
|
||||||
|
# Intialize config
|
||||||
|
self.load_config(self.config_location)
|
||||||
|
|
||||||
|
if not "token" in self.config:
|
||||||
|
self.stdin_configure()
|
||||||
|
self.update_config(self.config_location)
|
||||||
|
|
||||||
|
logger.debug("Successfully intialized JiraAuth!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def load_config(self, config_file):
|
||||||
|
self.config = {}
|
||||||
|
logger.debug(f"Loading config from: {config_file}")
|
||||||
|
|
||||||
|
|
||||||
|
if self.config_location.exists():
|
||||||
|
data = None
|
||||||
|
|
||||||
|
# Load config file
|
||||||
|
with open(config_file) as f:
|
||||||
|
data = yaml.load(f, Loader=yaml.SafeLoader)
|
||||||
|
|
||||||
|
# Update config with config data
|
||||||
|
for key in data:
|
||||||
|
self.config[key] = data[key]
|
||||||
|
else:
|
||||||
|
logger.warning(f"Config does not exist at: {config_file}")
|
||||||
|
|
||||||
|
def update_config(self, config_file):
|
||||||
|
if not config_file.exists():
|
||||||
|
config_file.parent.mkdir(parents=True)
|
||||||
|
|
||||||
|
with open(config_file, 'w') as f:
|
||||||
|
data = yaml.dump(self.config, f)
|
||||||
|
|
||||||
|
def stdin_configure(self):
|
||||||
|
|
||||||
|
# Clear keys that need new inputs
|
||||||
|
for key in ["server", "user", "token"]:
|
||||||
|
self.config[key] = ""
|
||||||
|
|
||||||
|
# Prompt sever
|
||||||
|
print("Please enter the jira server to interface with")
|
||||||
|
print("eg. jira.atlassian.com")
|
||||||
|
while not "server" in self.config or self.config["server"] == "":
|
||||||
|
self.config["server"] = input("Server: ")
|
||||||
|
|
||||||
|
# Prompt Username
|
||||||
|
print("Please enter your username")
|
||||||
|
print("Example: user@domain.tld")
|
||||||
|
while not "user" in self.config or self.config["user"] == "":
|
||||||
|
self.config["user"] = input("Username: ")
|
||||||
|
|
||||||
|
# Prompt Token
|
||||||
|
print("Please generate a token and enter it here")
|
||||||
|
print("https://id.atlassian.com/manage-profile/security/api-tokens")
|
||||||
|
while not "token" in self.config or self.config["token"] == "":
|
||||||
|
self.config["token"] = input("Token: ")
|
||||||
|
|
||||||
|
if not "points_field" in self.config:
|
||||||
|
self.config["points_field"] = "customfield_10016"
|
||||||
|
|
||||||
|
def get_client(self):
|
||||||
|
return jira.JIRA(self.config["server"], basic_auth=(self.config["user"], self.config["token"]))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config_location(self):
|
||||||
|
return pathlib.Path(str(pathlib.Path.home()), ".jira-tracker", "config.yaml")
|
16
jira_tracker/logger.py
Normal file
16
jira_tracker/logger.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
|
ch = logging.StreamHandler()
|
||||||
|
ch.setLevel(logging.INFO)
|
||||||
|
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
ch.setFormatter(formatter)
|
||||||
|
|
||||||
|
logger.addHandler(ch)
|
||||||
|
|
||||||
|
def enable_debug_logger():
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
ch.setLevel(logging.DEBUG)
|
20
jira_tracker/project_tracker.py
Normal file
20
jira_tracker/project_tracker.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from jira_tracker.logger import logger
|
||||||
|
from jira_tracker.tracker_issue import TrackerIssue
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
class ProjectTracker:
|
||||||
|
def __init__(self, jira_client, project_key):
|
||||||
|
self.jira = jira_client
|
||||||
|
self.key = project_key
|
||||||
|
|
||||||
|
def this_weeks_issues(self):
|
||||||
|
result = self.jira.search_issues(
|
||||||
|
f"project = {self.key} AND assignee = currentuser() AND ((resolutiondate >= -{datetime.datetime.today().weekday()}d AND status = Done) OR status != Done)"
|
||||||
|
)
|
||||||
|
logger.debug(f"Found {len(result)} valid records this week in {self.key}")
|
||||||
|
|
||||||
|
issues = []
|
||||||
|
for issue in result:
|
||||||
|
issues.append(TrackerIssue(issue))
|
||||||
|
|
||||||
|
return issues
|
21
jira_tracker/tracker_issue.py
Normal file
21
jira_tracker/tracker_issue.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from jira_tracker.logger import logger
|
||||||
|
|
||||||
|
class TrackerIssue:
|
||||||
|
def __init__(self, jira_issue):
|
||||||
|
self.data = jira_issue
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return str(self.data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def summary(self):
|
||||||
|
return str(self.data.fields.summary)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self):
|
||||||
|
return str(self.data.fields.status)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def points(self):
|
||||||
|
return str(self.data.fields.customfield_10016)
|
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# requirements.txt
|
||||||
|
#
|
||||||
|
# installs dependencies from ./setup.py, and the package itself,
|
||||||
|
# in editable mode
|
||||||
|
-e .
|
67
setup.py
Normal file
67
setup.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
import re
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
from codecs import open
|
||||||
|
|
||||||
|
here = path.abspath(path.dirname(__file__))
|
||||||
|
|
||||||
|
# Get the long description from the README file
|
||||||
|
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
|
||||||
|
long_description = f.read()
|
||||||
|
|
||||||
|
def read(*parts):
|
||||||
|
return open(path.join(here, *parts), 'r').read()
|
||||||
|
|
||||||
|
def find_version(*file_paths):
|
||||||
|
version_file = read(*file_paths)
|
||||||
|
version_match = re.search(r"^version = ['\"]([^'\"]*)['\"]",
|
||||||
|
version_file, re.M)
|
||||||
|
if version_match:
|
||||||
|
return version_match.group(1)
|
||||||
|
raise RuntimeError("Unable to find version string.")
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='jira-tracker',
|
||||||
|
version=find_version('jira_tracker','__init__.py'),
|
||||||
|
description='Simple Jira story point tracking tool',
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
|
||||||
|
# The project's main homepage.
|
||||||
|
url='https://github.com/josephbmanley/jira-tracker',
|
||||||
|
|
||||||
|
# Author details
|
||||||
|
author='Joseph Manley',
|
||||||
|
author_email='j@cloudsumu.com',
|
||||||
|
|
||||||
|
# Choose your license
|
||||||
|
license='MIT',
|
||||||
|
|
||||||
|
# See https://pypi.org/classifiers/
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Intended Audience :: Information Technology',
|
||||||
|
'Intended Audience :: System Administrators',
|
||||||
|
'License :: OSI Approved :: MIT License',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.3',
|
||||||
|
'Programming Language :: Python :: 3.4',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
'Programming Language :: Python :: 3.8',
|
||||||
|
'Programming Language :: Python :: 3.9'
|
||||||
|
],
|
||||||
|
keywords='Jira',
|
||||||
|
packages=['jira_tracker'],
|
||||||
|
install_requires=['argparse','jira','pyyaml','wheel'],
|
||||||
|
package_data={},
|
||||||
|
entry_points={
|
||||||
|
'console_scripts' : [
|
||||||
|
'jira-tracker=jira_tracker:main'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user