11"""Development helpers."""
22import os
3+ from pathlib import Path
4+ from shutil import rmtree
35from subprocess import call , check_output
46from typing import Tuple
57
68import click
7- import crayons
89from 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 } \n Commit 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" )
0 commit comments