Skip to content

Commit dbf8313

Browse files
committed
feat: add new scripts in scripts folder and move some of the initial setup logic into them
1 parent 0181f59 commit dbf8313

File tree

5 files changed

+152
-21
lines changed

5 files changed

+152
-21
lines changed

tests/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
PYTHON_VERSIONS: list[str] = [f"3.{VERSION_SLUG}" for VERSION_SLUG in range(MIN_PYTHON_SLUG, MAX_PYTHON_SLUG + 1)]
1919
DEFAULT_PYTHON_VERSION: str = PYTHON_VERSIONS[1]
2020

21-
21+
FIRST_TIME_SETUP_NOX_SESSIONS: list[str] = ["setup-git", "setup-venv", "setup-repo"]
2222
TYPE_CHECK_NOX_SESSIONS: list[str] = [f"typecheck-{python_version}" for python_version in PYTHON_VERSIONS]
2323
TESTS_NOX_SESSIONS: list[str] = [f"tests-{python_version}" for python_version in PYTHON_VERSIONS]
2424
CHECK_NOX_SESSIONS: list[str] = [f"check-{python_version}" for python_version in PYTHON_VERSIONS]

{{cookiecutter.project_name}}/noxfile.py

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
]
2424
DEFAULT_PYTHON_VERSION: str = PYTHON_VERSIONS[-1]
2525

26-
REPO_ROOT: Path = Path(__file__).parent
26+
REPO_ROOT: Path = Path(__file__).parent.resolve()
27+
SCRIPTS_FOLDER: Path = REPO_ROOT / "scripts"
2728
CRATES_FOLDER: Path = REPO_ROOT / "rust"
2829
PACKAGE_NAME: str = "{{cookiecutter.package_name}}"
2930
GITHUB_USER: str = "{{cookiecutter.github_user}}"
@@ -44,31 +45,16 @@ def setup_repo(session: Session) -> None:
4445
@nox.session(python=None, name="setup-git")
4546
def setup_git(session: Session) -> None:
4647
"""Set up the git repo for the current project."""
47-
session.run("git", "init")
48-
session.run("git", "branch", "-M", "main")
49-
5048
session.run(
51-
"git", "remote", "add", "origin", f"https://github.com/{GITHUB_USER}/{PACKAGE_NAME}.git", "||", "true"
49+
"python", SCRIPTS_FOLDER / "setup-git.py", REPO_ROOT, "-u", GITHUB_USER, "-n", PACKAGE_NAME, external=True
5250
)
53-
session.run("git", "remote", "set-url", "origin", f"https://github.com/{GITHUB_USER}/{PACKAGE_NAME}.git")
54-
session.run("git", "fetch", "origin")
55-
56-
session.run("git", "push", "-u", "origin", "main")
57-
session.run("git", "checkout", "-b", "develop", "main")
58-
session.run("git", "push", "-u", "origin", "develop")
59-
60-
session.run("git", "add", ".")
61-
session.run("git", "commit", "-m", "feat: initial commit")
62-
session.run("git", "push", "origin", "develop")
6351

6452

6553
@nox.session(python=None, name="setup-venv")
6654
def setup_venv(session: Session) -> None:
67-
session.run("uv", "lock", external=True)
68-
session.run("uv", "venv", ".venv", external=True)
69-
session.run("uv", "python", "install", PYTHON_VERSIONS[0], external=True)
70-
session.run("uv", "python", "pin", PYTHON_VERSIONS[0], external=True)
71-
session.run("uv", "sync", "--all-groups", external=True)
55+
session.run(
56+
"python", SCRIPTS_FOLDER / "setup-venv.py", REPO_ROOT, "-p", PYTHON_VERSIONS[0], external=True
57+
)
7258

7359

7460
@nox.session(python=DEFAULT_PYTHON_VERSION, name="pre-commit")
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""Script responsible for coordinating first time project setup."""
2+
import argparse
3+
import subprocess
4+
from pathlib import Path
5+
6+
from util import check_dependencies
7+
from util import existing_dir
8+
9+
10+
def main() -> None:
11+
"""Parses command line input and passes it through to setup_git."""
12+
parser: argparse.ArgumentParser = get_parser()
13+
args: argparse.Namespace = parser.parse_args()
14+
setup_git(path=args.path, github_user=args.github_user, repo_name=args.repo_name)
15+
16+
17+
def setup_git(path: Path, github_user: str, repo_name: str) -> None:
18+
"""Set up the provided cookiecutter-robust-python project for the first time."""
19+
commands: list[list[str]] = [
20+
["git", "init"],
21+
["git", "branch", "-M", "main"],
22+
["git", "remote", "add", "origin", f"https://github.com/{github_user}/{repo_name}.git", "||", "true"],
23+
["git", "remote", "set-url", "origin", f"https://github.com/{github_user}/{repo_name}.git"],
24+
["git", "fetch", "origin"],
25+
["git", "push", "-u", "origin", "main"],
26+
["git", "checkout", "-b", "develop", "main"],
27+
["git", "push", "-u", "origin", "develop"],
28+
["git", "add", "."],
29+
["git", "commit", "-m", "feat: initial commit"],
30+
["git", "push", "origin", "develop"]
31+
]
32+
check_dependencies(path=path, dependencies=["git"])
33+
34+
for command in commands:
35+
subprocess.run(command, cwd=path, capture_output=True)
36+
37+
38+
def get_parser() -> argparse.ArgumentParser:
39+
"""Creates the argument parser for setup-git."""
40+
parser: argparse.ArgumentParser = argparse.ArgumentParser(
41+
prog="setup-git",
42+
usage="python ./scripts/setup-git.py . -u 56kyle -n robust-python-demo",
43+
description="Set up the provided cookiecutter-robust-python project's git repo.",
44+
)
45+
parser.add_argument(
46+
"path",
47+
type=existing_dir,
48+
metavar="PATH",
49+
help="Path to the repo's root directory (must already exist).",
50+
)
51+
parser.add_argument("-u", "--user", dest="github_user", help="GitHub user name.")
52+
parser.add_argument("-n", "--name", dest="repo_name", help="Name of the repo.")
53+
return parser
54+
55+
56+
if __name__ == '__main__':
57+
main()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""Script responsible for coordinating first time project setup."""
2+
import argparse
3+
import subprocess
4+
from pathlib import Path
5+
6+
from util import check_dependencies
7+
from util import existing_dir
8+
9+
10+
def main() -> None:
11+
"""Parses args and passes through to setup_venv."""
12+
parser: argparse.ArgumentParser = get_parser()
13+
args: argparse.Namespace = parser.parse_args()
14+
setup_venv(path=args.path, python_version=args.python_version)
15+
16+
17+
def get_parser() -> argparse.ArgumentParser:
18+
"""Creates the argument parser for setup-venv."""
19+
parser: argparse.ArgumentParser = argparse.ArgumentParser(
20+
prog="setup-venv",
21+
usage="python ./scripts/setup-venv.py . -p '3.9'"
22+
)
23+
parser.add_argument(
24+
"path",
25+
type=existing_dir,
26+
metavar="PATH",
27+
help="Path to the repo's root directory (must already exist).",
28+
)
29+
parser.add_argument(
30+
"-p",
31+
"--python",
32+
dest="python_version",
33+
help="The Python version that will serve as the main working version used by the IDE."
34+
)
35+
return parser
36+
37+
38+
def setup_venv(path: Path, python_version: str) -> None:
39+
"""Set up the provided cookiecutter-robust-python project's venv."""
40+
commands: list[list[str]] = [
41+
["uv", "lock"],
42+
["uv", "venv", ".venv"],
43+
["uv", "python", "install", python_version],
44+
["uv", "python", "pin", python_version],
45+
["uv", "sync", "--all-groups"]
46+
]
47+
check_dependencies(path=path, dependencies=["uv"])
48+
49+
for command in commands:
50+
subprocess.run(command, cwd=path, capture_output=True)
51+
52+
53+
if __name__ == '__main__':
54+
main()
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""Module containing util"""
2+
import argparse
3+
import subprocess
4+
from pathlib import Path
5+
6+
7+
class MissingDependencyError(Exception):
8+
"""Exception raised when a depedency is missing from the system running setup-repo."""
9+
def __init__(self, project: Path, dependency: str):
10+
super().__init__("\n".join([
11+
f"Unable to find {dependency=}.",
12+
f"Please ensure that {dependency} is installed before setting up the repo at {project.absolute()}"
13+
]))
14+
15+
16+
def check_dependencies(path: Path, dependencies: list[str]) -> None:
17+
"""Checks for any passed dependencies."""
18+
for dependency in dependencies:
19+
try:
20+
subprocess.check_call([dependency, "--version"], cwd=path)
21+
except subprocess.CalledProcessError:
22+
raise MissingDependencyError(path, dependency)
23+
24+
25+
def existing_dir(value: str) -> Path:
26+
"""Responsible for validating argparse inputs and returning them as pathlib Path's if they meet criteria."""
27+
path = Path(value).expanduser().resolve()
28+
29+
if not path.exists():
30+
raise argparse.ArgumentTypeError(f"{path} does not exist.")
31+
if not path.is_dir():
32+
raise argparse.ArgumentTypeError(f"{path} is not a directory.")
33+
34+
return path

0 commit comments

Comments
 (0)