hassle.hassle

  1import argparse
  2import os
  3
  4from pathier import Pathier
  5
  6from hassle import hassle_utilities
  7from hassle.generate_tests import generate_test_files
  8from hassle.run_tests import run_tests
  9
 10root = Pathier(__file__).parent
 11
 12
 13def get_args() -> argparse.Namespace:
 14    parser = argparse.ArgumentParser()
 15
 16    parser.add_argument(
 17        "package",
 18        type=str,
 19        default=".",
 20        nargs="?",
 21        help=""" The name of the package or project to use,
 22        assuming it's a subfolder of your current working directory.
 23        Can also be a full path to the package. If nothing is given,
 24        the current working directory will be used.""",
 25    )
 26
 27    parser.add_argument(
 28        "-b", "--build", action="store_true", help=""" Build the package. """
 29    )
 30
 31    parser.add_argument(
 32        "-t",
 33        "--tag_version",
 34        action="store_true",
 35        help=""" Add a git tag corresponding to the version in pyproject.toml. """,
 36    )
 37
 38    parser.add_argument(
 39        "-i",
 40        "--install",
 41        action="store_true",
 42        help=""" Install the package from source. """,
 43    )
 44
 45    parser.add_argument(
 46        "-iv",
 47        "--increment_version",
 48        type=str,
 49        default=None,
 50        help=""" Increment version in pyproject.toml.
 51        Can be one of "major", "minor", or "patch". """,
 52    )
 53
 54    parser.add_argument(
 55        "-p",
 56        "--publish",
 57        action="store_true",
 58        help=""" Publish package to PyPi.
 59        Note: You must have configured twine 
 60        and registered a PyPi account/generated an API
 61        key to use this option.""",
 62    )
 63
 64    parser.add_argument(
 65        "-rt",
 66        "--run_tests",
 67        action="store_true",
 68        help=""" Run tests for the package. """,
 69    )
 70
 71    parser.add_argument(
 72        "-gt",
 73        "--generate_tests",
 74        action="store_true",
 75        help=""" Generate tests for the package. """,
 76    )
 77
 78    parser.add_argument(
 79        "-uc",
 80        "--update_changelog",
 81        action="store_true",
 82        help=""" Update changelog file. """,
 83    )
 84
 85    parser.add_argument(
 86        "-od",
 87        "--overwrite_dependencies",
 88        action="store_true",
 89        help=""" When building a package, packagelister will be used
 90        to update the dependencies list in pyproject.toml.
 91        The default behavior is to append any new dependencies to
 92        the current list so as not to erase any manually added dependencies
 93        that packagelister may not detect. If you don't have any manually 
 94        added dependencies and want to remove any dependencies that your
 95        project no longer uses, pass this flag.""",
 96    )
 97
 98    parser.add_argument(
 99        "-ca",
100        "--commit_all",
101        type=str,
102        default=None,
103        help=""" Git stage and commit all tracked files
104        with this supplied commit message.
105        If 'build' is passed, all commits will have
106        message: 'chore: build v{current_version}""",
107    )
108
109    parser.add_argument(
110        "-s",
111        "--sync",
112        action="store_true",
113        help=""" Pull from github, then push current commit to repo. """,
114    )
115
116    parser.add_argument(
117        "-dv",
118        "--dependency_versions",
119        action="store_true",
120        help=""" Include version specifiers for dependencies in
121        pyproject.toml.""",
122    )
123
124    parser.add_argument(
125        "-up",
126        "--update",
127        type=str,
128        default=None,
129        help=""" Excpects one argument: "major", "minor", or "patch".
130        Passing "-up minor" is equivalent to passing the cli string: "-b -t -i -iv minor -uc -ca build -s".
131        To publish the updated package, the -p/--publish switch needs to be added to the cli input.""",
132    )
133
134    args = parser.parse_args()
135
136    args.package = Pathier(args.package).resolve()
137
138    if args.update:
139        args.build = True
140        args.tag_version = True
141        args.install = True
142        args.increment_version = args.update
143        args.update_changelog = True
144        args.commit_all = "build"
145        args.sync = True
146
147    if args.increment_version and args.increment_version not in [
148        "major",
149        "minor",
150        "patch",
151    ]:
152        raise ValueError(
153            f"Invalid option for -iv/--increment_version: {args.increment_version}"
154        )
155
156    if args.commit_all == "":
157        raise ValueError("Commit message for args.commit_all cannot be empty.")
158
159    return args
160
161
162def main(args: argparse.Namespace = None):
163    if not args:
164        args = get_args()
165
166    pyproject_path = args.package / "pyproject.toml"
167
168    if not pyproject_path.exists():
169        raise FileNotFoundError(f"Could not locate pyproject.toml for {args.package}")
170
171    if args.generate_tests:
172        generate_test_files(args.package)
173
174    if args.run_tests:
175        run_tests(args.package)
176
177    if args.increment_version:
178        hassle_utilities.increment_version(pyproject_path, args.increment_version)
179
180    if args.build:
181        (args.package / "dist").delete()
182        os.system(f"black {args.package}")
183        os.system(f"isort {args.package}")
184        hassle_utilities.update_dependencies(
185            pyproject_path, args.overwrite_dependencies
186        )
187        # Vermin isn't taking into account the minimum version of dependencies.
188        # Removing from now and defaulting to >=3.10
189        # hassle_utilities.update_minimum_python_version(pyproject_path)
190        hassle_utilities.generate_docs(args.package)
191        os.system(f"py -m build {args.package}")
192
193    if args.update_changelog:
194        hassle_utilities.update_changelog(pyproject_path)
195        # If we're going to add tag for current version
196        # commit changelog first
197        if args.tag_version:
198            input(
199                "Press enter to continue after optionally pruning the updated changelog..."
200            )
201            os.chdir(args.package)
202            os.system("git add CHANGELOG.md")
203            os.system('git commit CHANGELOG.md -m "chore: update changelog"')
204
205    if args.commit_all:
206        os.chdir(args.package)
207        if args.commit_all == "build":
208            version = pyproject_path.loads()["project"]["version"]
209            args.commit_all = f"chore: build v{version}"
210        os.system("git add .")
211        os.system(f'git commit -m "{args.commit_all}"')
212
213    if args.tag_version:
214        hassle_utilities.tag_version(args.package)
215
216    if args.publish:
217        os.system(f"twine upload {args.package / 'dist' / '*'}")
218
219    if args.install:
220        os.system(f"pip install {args.package} --no-deps --upgrade --no-cache-dir")
221
222    if args.sync:
223        os.chdir(args.package)
224        os.system(f"git pull --tags origin main")
225        os.system(f"git push origin main:main --tags")
226
227
228if __name__ == "__main__":
229    main(get_args())
def get_args() -> argparse.Namespace:
 14def get_args() -> argparse.Namespace:
 15    parser = argparse.ArgumentParser()
 16
 17    parser.add_argument(
 18        "package",
 19        type=str,
 20        default=".",
 21        nargs="?",
 22        help=""" The name of the package or project to use,
 23        assuming it's a subfolder of your current working directory.
 24        Can also be a full path to the package. If nothing is given,
 25        the current working directory will be used.""",
 26    )
 27
 28    parser.add_argument(
 29        "-b", "--build", action="store_true", help=""" Build the package. """
 30    )
 31
 32    parser.add_argument(
 33        "-t",
 34        "--tag_version",
 35        action="store_true",
 36        help=""" Add a git tag corresponding to the version in pyproject.toml. """,
 37    )
 38
 39    parser.add_argument(
 40        "-i",
 41        "--install",
 42        action="store_true",
 43        help=""" Install the package from source. """,
 44    )
 45
 46    parser.add_argument(
 47        "-iv",
 48        "--increment_version",
 49        type=str,
 50        default=None,
 51        help=""" Increment version in pyproject.toml.
 52        Can be one of "major", "minor", or "patch". """,
 53    )
 54
 55    parser.add_argument(
 56        "-p",
 57        "--publish",
 58        action="store_true",
 59        help=""" Publish package to PyPi.
 60        Note: You must have configured twine 
 61        and registered a PyPi account/generated an API
 62        key to use this option.""",
 63    )
 64
 65    parser.add_argument(
 66        "-rt",
 67        "--run_tests",
 68        action="store_true",
 69        help=""" Run tests for the package. """,
 70    )
 71
 72    parser.add_argument(
 73        "-gt",
 74        "--generate_tests",
 75        action="store_true",
 76        help=""" Generate tests for the package. """,
 77    )
 78
 79    parser.add_argument(
 80        "-uc",
 81        "--update_changelog",
 82        action="store_true",
 83        help=""" Update changelog file. """,
 84    )
 85
 86    parser.add_argument(
 87        "-od",
 88        "--overwrite_dependencies",
 89        action="store_true",
 90        help=""" When building a package, packagelister will be used
 91        to update the dependencies list in pyproject.toml.
 92        The default behavior is to append any new dependencies to
 93        the current list so as not to erase any manually added dependencies
 94        that packagelister may not detect. If you don't have any manually 
 95        added dependencies and want to remove any dependencies that your
 96        project no longer uses, pass this flag.""",
 97    )
 98
 99    parser.add_argument(
100        "-ca",
101        "--commit_all",
102        type=str,
103        default=None,
104        help=""" Git stage and commit all tracked files
105        with this supplied commit message.
106        If 'build' is passed, all commits will have
107        message: 'chore: build v{current_version}""",
108    )
109
110    parser.add_argument(
111        "-s",
112        "--sync",
113        action="store_true",
114        help=""" Pull from github, then push current commit to repo. """,
115    )
116
117    parser.add_argument(
118        "-dv",
119        "--dependency_versions",
120        action="store_true",
121        help=""" Include version specifiers for dependencies in
122        pyproject.toml.""",
123    )
124
125    parser.add_argument(
126        "-up",
127        "--update",
128        type=str,
129        default=None,
130        help=""" Excpects one argument: "major", "minor", or "patch".
131        Passing "-up minor" is equivalent to passing the cli string: "-b -t -i -iv minor -uc -ca build -s".
132        To publish the updated package, the -p/--publish switch needs to be added to the cli input.""",
133    )
134
135    args = parser.parse_args()
136
137    args.package = Pathier(args.package).resolve()
138
139    if args.update:
140        args.build = True
141        args.tag_version = True
142        args.install = True
143        args.increment_version = args.update
144        args.update_changelog = True
145        args.commit_all = "build"
146        args.sync = True
147
148    if args.increment_version and args.increment_version not in [
149        "major",
150        "minor",
151        "patch",
152    ]:
153        raise ValueError(
154            f"Invalid option for -iv/--increment_version: {args.increment_version}"
155        )
156
157    if args.commit_all == "":
158        raise ValueError("Commit message for args.commit_all cannot be empty.")
159
160    return args
def main(args: argparse.Namespace = None):
163def main(args: argparse.Namespace = None):
164    if not args:
165        args = get_args()
166
167    pyproject_path = args.package / "pyproject.toml"
168
169    if not pyproject_path.exists():
170        raise FileNotFoundError(f"Could not locate pyproject.toml for {args.package}")
171
172    if args.generate_tests:
173        generate_test_files(args.package)
174
175    if args.run_tests:
176        run_tests(args.package)
177
178    if args.increment_version:
179        hassle_utilities.increment_version(pyproject_path, args.increment_version)
180
181    if args.build:
182        (args.package / "dist").delete()
183        os.system(f"black {args.package}")
184        os.system(f"isort {args.package}")
185        hassle_utilities.update_dependencies(
186            pyproject_path, args.overwrite_dependencies
187        )
188        # Vermin isn't taking into account the minimum version of dependencies.
189        # Removing from now and defaulting to >=3.10
190        # hassle_utilities.update_minimum_python_version(pyproject_path)
191        hassle_utilities.generate_docs(args.package)
192        os.system(f"py -m build {args.package}")
193
194    if args.update_changelog:
195        hassle_utilities.update_changelog(pyproject_path)
196        # If we're going to add tag for current version
197        # commit changelog first
198        if args.tag_version:
199            input(
200                "Press enter to continue after optionally pruning the updated changelog..."
201            )
202            os.chdir(args.package)
203            os.system("git add CHANGELOG.md")
204            os.system('git commit CHANGELOG.md -m "chore: update changelog"')
205
206    if args.commit_all:
207        os.chdir(args.package)
208        if args.commit_all == "build":
209            version = pyproject_path.loads()["project"]["version"]
210            args.commit_all = f"chore: build v{version}"
211        os.system("git add .")
212        os.system(f'git commit -m "{args.commit_all}"')
213
214    if args.tag_version:
215        hassle_utilities.tag_version(args.package)
216
217    if args.publish:
218        os.system(f"twine upload {args.package / 'dist' / '*'}")
219
220    if args.install:
221        os.system(f"pip install {args.package} --no-deps --upgrade --no-cache-dir")
222
223    if args.sync:
224        os.chdir(args.package)
225        os.system(f"git pull --tags origin main")
226        os.system(f"git push origin main:main --tags")