Skip to content

Commit 3ec86a6

Browse files
committed
feat: add pypi script
1 parent 86648da commit 3ec86a6

10 files changed

Lines changed: 147 additions & 56 deletions

File tree

clit/config.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Configuration helpers."""
22
import json
3+
import os
4+
from typing import List
35

46
from clit.constants import CONFIG_DIR
57

@@ -29,3 +31,27 @@ def dump(self, new_data):
2931
if isinstance(new_data, set):
3032
new_data = list(new_data)
3133
self.full_path.write_text(json.dumps(new_data))
34+
35+
36+
def cast_to_directory_list(check_existing: bool = True):
37+
"""Cast from a string of directories separated by colons.
38+
39+
Useful functions for the prettyconf module.
40+
41+
Optional check existing directories: throw an error if any directory does not exist.
42+
"""
43+
44+
def cast_function(value) -> List[str]:
45+
"""Cast function expected by prettyconf."""
46+
expanded_dirs = [os.path.expanduser(dir_).rstrip("/") for dir_ in value.split(":")]
47+
48+
if check_existing:
49+
non_existent = [d for d in expanded_dirs if not os.path.isdir(d)]
50+
if non_existent:
51+
raise RuntimeError(
52+
"Some directories were not found or are not directories: {}".format(":".join(non_existent))
53+
)
54+
55+
return expanded_dirs
56+
57+
return cast_function

clit/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33

44
SECTION_SYMLINKS_FILES = "symlinks/files"
55
SECTION_SYMLINKS_DIRS = "symlinks/dirs"
6-
PYCHARM_APP_FULL_PATH = "/Applications/PyCharm.app/Contents/MacOS/pycharm"
6+
PYCHARM_MACOS_APP_PATH = Path("/Applications/PyCharm.app/Contents/MacOS/pycharm")
77
CONFIG_DIR = Path("~/.config/dotfiles/").expanduser()

clit/dev.py

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
"""Development helpers."""
22
import os
3+
from pathlib import Path
4+
from shutil import rmtree
35
from subprocess import call, check_output
46
from typing import Tuple
57

68
import click
7-
import crayons
89
from plumbum import FG, RETCODE
910

10-
from clit.constants import PYCHARM_APP_FULL_PATH
11+
from clit.constants import PYCHARM_MACOS_APP_PATH
12+
from clit.files import shell
13+
from clit.ui import prompt
1114

1215

1316
@click.command()
@@ -24,8 +27,8 @@ def pycharm_cli(files):
2427
else:
2528
real_file = check_output(["which", possible_file]).decode().strip()
2629
full_paths.append(real_file)
27-
command_line = [PYCHARM_APP_FULL_PATH] + full_paths
28-
print(crayons.green("Calling PyCharm with {}".format(" ".join(command_line))))
30+
command_line = [PYCHARM_MACOS_APP_PATH] + full_paths
31+
click.secho(f"Calling PyCharm with {' '.join(command_line)}", fg="green")
2932
call(command_line)
3033

3134

@@ -41,7 +44,7 @@ def pytest_run(delete: bool, failed: bool, count: int, reruns: int, class_names_
4144
from plumbum.cmd import time as time_cmd, rm
4245

4346
if delete:
44-
print(crayons.green("Removing .pytest directory", bold=True))
47+
click.secho("Removing .pytest directory", fg="green", bold=True)
4548
rm["-rf", ".pytest"] & FG
4649

4750
pytest_plus_args = ["pytest", "-vv", "--run-intermittent"]
@@ -65,6 +68,102 @@ def pytest_run(delete: bool, failed: bool, count: int, reruns: int, class_names_
6568
pytest_plus_args.append("-s")
6669
pytest_plus_args.extend(targets)
6770

68-
print(crayons.green("Running tests: time {}".format(" ".join(pytest_plus_args)), bold=True))
71+
click.secho(f"Running tests: time {' '.join(pytest_plus_args)}", fg="green", bold=True)
6972
rv = time_cmd[pytest_plus_args] & RETCODE(FG=True)
7073
exit(rv)
74+
75+
76+
class PyPICommands:
77+
"""Commands executed by this helper script."""
78+
79+
# https://github.com/peritus/bumpversion
80+
BUMP_VERSION = "bumpversion {part}"
81+
BUMP_VERSION_DRY_RUN = f"{BUMP_VERSION} --dry-run --verbose"
82+
83+
# https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-cli
84+
CHANGELOG = "conventional-changelog -i CHANGELOG.md -p angular"
85+
86+
BUILD_SETUP_PY = "python setup.py sdist bdist_wheel --universal"
87+
88+
# https://poetry.eustace.io/
89+
BUILD_POETRY = "poetry build"
90+
91+
GIT_ADD = "git add ."
92+
GIT_COMMIT = "git commit -m'{}'"
93+
GIT_PUSH = "git push"
94+
GIT_TAG = "git tag v{}"
95+
96+
# https://github.com/pypa/twine
97+
# I tried using "poetry publish -u $TWINE_USERNAME -p $TWINE_PASSWORD"; the command didn't fail, but nothing was uploaded
98+
# I also tried setting $TWINE_USERNAME and $TWINE_PASSWORD on the environment, but then "twine upload" didn't work for some reason.
99+
TWINE_UPLOAD = "twine upload dist/*"
100+
101+
# https://www.npmjs.com/package/conventional-github-releaser
102+
GITHUB_RELEASE = "conventional-github-releaser -p angular -v"
103+
104+
105+
@click.group()
106+
def pypi():
107+
"""Commands to publish packages on PyPI."""
108+
pass
109+
110+
111+
@pypi.command()
112+
@click.option("--part", default="minor", type=click.Choice(["major", "minor", "patch"]))
113+
def full(part):
114+
"""The full process to upload to PyPI (bump version, changelog, package, upload)."""
115+
bump_dry_run_cmd = PyPICommands.BUMP_VERSION_DRY_RUN.format(part=part)
116+
bump = shell(bump_dry_run_cmd)
117+
if bump.returncode != 0:
118+
exit(bump.returncode)
119+
120+
chosen_lines = shell(
121+
f'{bump_dry_run_cmd} 2>&1 | rg -e "would.+bump" -e "new version" | rg -o "\'(.+)\'"', return_lines=True
122+
)
123+
new_version = chosen_lines[0].strip("'")
124+
commit_message = chosen_lines[1].strip("'")
125+
print(f"New version: {new_version}\nCommit message: {commit_message}")
126+
prompt("Were all versions correctly bumped?")
127+
128+
shell(PyPICommands.BUMP_VERSION.format(part=part))
129+
shell(f"{PyPICommands.CHANGELOG} -s")
130+
131+
try:
132+
dist_dir = (Path(os.curdir) / "dist").resolve()
133+
print(f"Removing previous builds on {dist_dir}")
134+
rmtree(str(dist_dir))
135+
except OSError:
136+
pass
137+
138+
shell(PyPICommands.BUILD_POETRY)
139+
shell("ls -l dist")
140+
prompt("Was a dist/ directory created with a .tar.gz and a wheel?")
141+
142+
shell("git diff")
143+
prompt("Is the git diff correct?")
144+
145+
prompt(
146+
"Last confirmation (point of no return):"
147+
+ "Changes will be committed, files will be uploaded to PyPI, a GitHub release will be created"
148+
)
149+
150+
print("Add files, commit and push")
151+
for command in (PyPICommands.GIT_ADD, PyPICommands.GIT_COMMIT.format(commit_message), PyPICommands.GIT_PUSH):
152+
shell(command)
153+
154+
print("Create the tag but don't push it yet (conventional-github-releaser will do that)")
155+
shell(PyPICommands.GIT_TAG.format(new_version))
156+
157+
print("Upload the files to PyPI via Twine")
158+
shell(PyPICommands.TWINE_UPLOAD)
159+
160+
print("Create a GitHub release")
161+
shell(PyPICommands.GITHUB_RELEASE)
162+
163+
print(f"The new version {new_version} was uploaded to PyPI")
164+
165+
166+
@pypi.command()
167+
def changelog():
168+
"""Preview the changelog."""
169+
shell(f"{PyPICommands.CHANGELOG} -u | less")

clit/environments.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from prettyconf import config
66

7-
from libwaa.prettyconf import cast_to_directory_list
7+
from clit.config import cast_to_directory_list
88

99
config.starting_path = os.path.expanduser("~/.config/clit")
1010

clit/files.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from typing import List
1010

1111
import click
12-
import crayons
1312
from plumbum import FG
1413

1514
from clit import CONFIG, LOGGER, read_config, save_config
@@ -123,11 +122,11 @@ def sync_dir(source_dirs: List[str], destination_dirs: List[str], dry_run: bool
123122
rsync_args = "{dry_run}{kill}-trOlhDuzv --modify-window=2 --progress {exclude} {src}/ {dest}/".format(
124123
dry_run="-n " if dry_run else "",
125124
kill="--del " if kill else "",
126-
exclude=" ".join(["--exclude={}".format(e) for e in RSYNC_EXCLUDE]),
125+
exclude=" ".join([f"--exclude={e}" for e in RSYNC_EXCLUDE]),
127126
src=src_dir,
128127
dest=full_dest_dir,
129128
)
130-
print(crayons.green("rsync {}".format(rsync_args)))
129+
click.secho(f"rsync {rsync_args}", fg="green")
131130
os.makedirs(full_dest_dir, exist_ok=True)
132131
rsync[split(rsync_args)] & FG
133132

@@ -140,12 +139,12 @@ def sync_dir(source_dirs: List[str], destination_dirs: List[str], dry_run: bool
140139
def backup_full(ctx, dry_run: bool, kill: bool, pictures: bool):
141140
"""Perform all backups in a single script."""
142141
if pictures:
143-
print(crayons.green("Pictures backup", bold=True))
142+
click.secho("Pictures backup", bold=True, fg="green")
144143
from clit.environments import PICTURE_DIRS, BACKUP_DIRS
145144

146145
sync_dir(PICTURE_DIRS, BACKUP_DIRS, dry_run, kill)
147146
else:
148-
print(crayons.red("Choose one of the options below."))
147+
click.secho("Choose one of the options below.", fg="red")
149148
print(ctx.get_help())
150149

151150

clit/ui.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@ def notify(title, message):
1919
Path(__file__).name, title, message
2020
)
2121
)
22+
23+
24+
def prompt(message: str) -> None:
25+
"""Display a prompt with a message."""
26+
input(f"{message}\nPress ENTER to continue or Ctrl-C to abort")

libwaa/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

libwaa/prettyconf.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

poetry.lock

Lines changed: 3 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ git-local-prune = "clit.git:prune_local_branches"
2929
git-vacuum = "clit.git:vacuum"
3030
pycharm-cli = "clit.files:pycharm_cli"
3131
pytest-run = "clit.files:pytest_run"
32+
pypi = "clit.dev:pypi"
3233

3334
[tool.poetry.dependencies]
34-
python = "^3.6"
35+
python = "^3.6 || ^3.7"
3536
argcomplete = "*"
3637
click = "*"
3738
colorlog = "*"
38-
crayons = "*"
3939
requests = "*"
4040
SQLAlchemy = "*"
4141
plumbum = "*"

0 commit comments

Comments
 (0)