-
-
Notifications
You must be signed in to change notification settings - Fork 102
/
tasks.py
190 lines (164 loc) · 5.58 KB
/
tasks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
""" Invoke tasks for timetagger
"""
import os
import sys
import shutil
import importlib
import subprocess
from invoke import task
# ---------- Per project config ----------
NAME = "timetagger"
LIBNAME = NAME.replace("-", "_")
# ----------------------------------------
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
if not os.path.isdir(os.path.join(ROOT_DIR, LIBNAME)):
sys.exit("package NAME seems to be incorrect.")
@task
def tests(ctx, cover=False):
"""Perform unit tests. Use --cover to open a webbrowser to show coverage."""
import pytest # noqa
test_path = "tests"
res = pytest.main(
["-v", f"--cov={LIBNAME}", "--cov-report=term", "--cov-report=html", test_path]
)
if res:
sys.exit(res)
if cover:
import webbrowser
webbrowser.open(os.path.join(ROOT_DIR, "htmlcov", "index.html"))
@task
def lint(ctx):
"""Validate the code style (e.g. undefined names)"""
try:
importlib.import_module("flake8")
except ImportError:
sys.exit("You need to ``pip install flake8`` to lint")
# We use flake8 with minimal settings
# http://pep8.readthedocs.io/en/latest/intro.html#error-codes
cmd = [
sys.executable,
"-m",
"flake8",
ROOT_DIR,
"--max-line-length=999",
"--extend-ignore=N,E731,E203,F541,D,B",
"--exclude=build,dist,*.egg-info",
]
ret_code = subprocess.call(cmd, cwd=ROOT_DIR)
if ret_code == 0:
print("No style errors found")
else:
sys.exit(ret_code)
@task
def checkformat(ctx):
"""Check whether the code adheres to the style rules. Use autoformat to fix."""
black_wrapper(False)
@task
def format(ctx):
"""Automatically format the code (using black)."""
black_wrapper(True)
def black_wrapper(writeback):
"""Helper function to invoke black programatically."""
check = [] if writeback else ["--check"]
exclude = "|".join(["cangivefilenameshere"])
sys.argv[1:] = check + ["--exclude", exclude, ROOT_DIR]
import black
black.main()
@task
def clean(ctx):
"""Clean the repo of temp files etc."""
# Walk over all files and delete based on name
for root, dirs, files in os.walk(ROOT_DIR):
for dname in dirs:
if dname in (
"__pycache__",
".cache",
".hypothesis",
"_build",
".mypy_cache",
):
shutil.rmtree(os.path.join(root, dname))
print("Removing", dname)
for fname in files:
if fname.endswith((".pyc", ".pyo")) or fname in (".coverage"):
os.remove(os.path.join(root, fname))
print("Removing", fname)
# Delete specific files and directories
for fname in [
"docs/site",
"htmlcov",
".pytest_cache",
"dist",
"build",
LIBNAME + ".egg-info",
]:
filename = os.path.join(ROOT_DIR, fname)
if os.path.isfile(filename):
os.remove(filename)
print("Removing", filename)
elif os.path.isdir(filename):
shutil.rmtree(filename)
print("Removing", filename)
@task
def bumpversion(ctx, version):
"""Bump the version. If no version is specified, show the current version."""
version = version.lstrip("v")
# Check that we're not missing any libraries
for x in ("setuptools", "twine"):
try:
importlib.import_module(x)
except ImportError:
sys.exit(f"You need to ``pip install {x}`` to do a version bump")
# Check that there are no outstanding changes
lines = (
subprocess.check_output(["git", "status", "--porcelain"]).decode().splitlines()
)
lines = [line for line in lines if not line.startswith("?? ")]
if lines:
print("Cannot bump version because there are outstanding changes:")
print("\n".join(lines))
return
# Get the version definition
filename = os.path.join(ROOT_DIR, LIBNAME, "__init__.py")
with open(filename, "rb") as f:
lines = f.read().decode().splitlines()
for line_index, line in enumerate(lines):
if line.startswith("__version__ = "):
break
else:
raise ValueError("Could not find version definition")
# Only show the version?
if not version.strip("x-"):
print(lines[line_index])
return
# Apply change
lines[line_index] = lines[line_index].split("=")[0] + f'= "{version}"'
with open(filename, "wb") as f:
f.write(("\n".join(lines).strip() + "\n").encode())
# Ask confirmation
subprocess.run(["git", "diff"])
while True:
x = input("Is this diff correct? [Y/N]: ")
if x.lower() == "y":
break
elif x.lower() == "n":
print("Cancelling (git checkout)")
subprocess.run(["git", "checkout", filename])
return
# Git
print("Git commit and tag")
subprocess.run(["git", "add", filename])
subprocess.run(["git", "commit", "-m", f"Bump version to {version}"])
subprocess.run(["git", "tag", f"v{version}"])
print(f"git push origin main v{version}")
subprocess.run(["git", "push", "origin", "main", f"v{version}"])
# Pypi
input("\nHit enter to upload to pypi: ")
dist_dir = os.path.join(ROOT_DIR, "dist")
if os.path.isdir(dist_dir):
shutil.rmtree(dist_dir)
subprocess.run([sys.executable, "setup.py", "sdist", "bdist_wheel"])
subprocess.run([sys.executable, "-m", "twine", "upload", dist_dir + "/*"])
# Bye bye
print("Success!")
print("Don't forget to write release notes!")