Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .cruft.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"template": "https://github.com/56kyle/cookiecutter-robust-python.git",
"commit": "bf289288fe0cacd836ebd606dbb657193c34340f",
"checkout": null,
"context": {
"cookiecutter": {
"project_name": "maison",
"package_name": "maison",
"friendly_name": "Maison",
"min_python_version": "3.9",
"max_python_version": "3.13",
"add_rust_extension": false,
"author": "Dom Batten",
"email": "[email protected]",
"repository_provider": "github",
"repository_host": "github.com",
"repository_path": "dbatten/maison",
"version": "2.0.1",
"copyright_year": "2025",
"license": "MIT",
"development_status": "Development Status :: 5 - Production/Stable",
"_template": "https://github.com/56kyle/cookiecutter-robust-python.git",
"_commit": "bf289288fe0cacd836ebd606dbb657193c34340f"
}
},
"directory": null
}
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def docs_build(session: Session) -> None:

@nox.session(python=DEFAULT_PYTHON_VERSION, name="docs", tags=[DOCS, BUILD])
def docs(session: Session) -> None:
"""Build the project documentation (Sphinx)."""
"""Build and serve the project documentation (Sphinx)."""
session.log("Installing documentation dependencies...")
session.install("-e", ".", "--group", "docs")

Expand Down
30 changes: 30 additions & 0 deletions scripts/bump-version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Script responsible for bumping the version of the maison package."""

import argparse

from util import bump_version


def main() -> None:
"""Parses args and passes through to bump_version."""
parser: argparse.ArgumentParser = get_parser()
args: argparse.Namespace = parser.parse_args()
bump_version(increment=args.increment)


def get_parser() -> argparse.ArgumentParser:
"""Creates the argument parser for prepare-release."""
parser: argparse.ArgumentParser = argparse.ArgumentParser(
prog="bump-version", usage="python ./scripts/bump-version.py patch"
)
parser.add_argument(
"increment",
type=str,
help="Increment type to use when preparing the release.",
choices=["MAJOR", "MINOR", "PATCH", "PRERELEASE"],
)
return parser


if __name__ == "__main__":
main()
36 changes: 36 additions & 0 deletions scripts/get-release-notes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Script responsible for getting the release notes of the maison package."""

import argparse
from pathlib import Path

from util import get_latest_release_notes


RELEASE_NOTES_PATH: Path = Path("body.md")


def main() -> None:
"""Parses args and passes through to bump_version."""
parser: argparse.ArgumentParser = get_parser()
args: argparse.Namespace = parser.parse_args()
release_notes: str = get_latest_release_notes()
path: Path = RELEASE_NOTES_PATH if args.path is None else args.path
path.write_text(release_notes)


def get_parser() -> argparse.ArgumentParser:
"""Creates the argument parser for prepare-release."""
parser: argparse.ArgumentParser = argparse.ArgumentParser(
prog="get-release-notes", usage="python ./scripts/get-release-notes.py"
)
parser.add_argument(
"path",
type=Path,
metavar="PATH",
help="Path the changelog will be written to.",
)
return parser


if __name__ == "__main__":
main()
53 changes: 53 additions & 0 deletions scripts/setup-git.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Script responsible for first time setup of the project's git repo.

Since this is a first time setup script, we intentionally only use builtin Python dependencies.
"""

import argparse
import subprocess
from pathlib import Path

from util import check_dependencies
from util import existing_dir


def main() -> None:
"""Parses command line input and passes it through to setup_git."""
parser: argparse.ArgumentParser = get_parser()
args: argparse.Namespace = parser.parse_args()
setup_git(path=args.path)


def setup_git(path: Path) -> None:
"""Set up the provided cookiecutter-robust-python project's git repo."""
commands: list[list[str]] = [
["git", "init"],
["git", "branch", "-m", "master", "main"],
["git", "add", "."],
["git", "commit", "-m", "feat: initial commit"],
["git", "checkout", "-b", "develop", "main"],
]
check_dependencies(path=path, dependencies=["git"])

for command in commands:
subprocess.run(command, cwd=path, stderr=subprocess.STDOUT)


def get_parser() -> argparse.ArgumentParser:
"""Creates the argument parser for setup-git."""
parser: argparse.ArgumentParser = argparse.ArgumentParser(
prog="setup-git",
usage="python ./scripts/setup-git.py . -u 56kyle -n robust-python-demo",
description="Set up the provided cookiecutter-robust-python project's git repo.",
)
parser.add_argument(
"path",
type=existing_dir,
metavar="PATH",
help="Path to the repo's root directory (must already exist).",
)
return parser


if __name__ == "__main__":
main()
68 changes: 68 additions & 0 deletions scripts/setup-release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""Script responsible for preparing a release of the maison package."""

import argparse
import subprocess
from typing import Optional

from util import REPO_FOLDER
from util import bump_version
from util import check_dependencies
from util import create_release_branch
from util import get_bumped_package_version
from util import get_package_version


def main() -> None:
"""Parses args and passes through to setup_release."""
parser: argparse.ArgumentParser = get_parser()
args: argparse.Namespace = parser.parse_args()
setup_release(increment=args.increment)


def get_parser() -> argparse.ArgumentParser:
"""Creates the argument parser for prepare-release."""
parser: argparse.ArgumentParser = argparse.ArgumentParser(
prog="prepare-release", usage="python ./scripts/prepare-release.py patch"
)
parser.add_argument(
"increment",
nargs="?",
default=None,
type=str,
help="Increment type to use when preparing the release.",
choices=["MAJOR", "MINOR", "PATCH", "PRERELEASE"],
)
return parser


def setup_release(increment: Optional[str] = None) -> None:
"""Prepares a release of the maison package.

Sets up a release branch from the branch develop, bumps the version, and creates a release commit. Does not tag the
release or push any changes.
"""
check_dependencies(path=REPO_FOLDER, dependencies=["git"])

current_version: str = get_package_version()
new_version: str = get_bumped_package_version(increment=increment)
create_release_branch(new_version=new_version)
bump_version(increment=increment)

commands: list[list[str]] = [
["uv", "sync", "--all-groups"],
["git", "add", "."],
[
"git",
"commit",
"-m",
f"bump: version {current_version} → {new_version}",
"--no-verify",
],
]

for command in commands:
subprocess.run(command, cwd=REPO_FOLDER, capture_output=True, check=True)


if __name__ == "__main__":
main()
81 changes: 81 additions & 0 deletions scripts/setup-remote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""Script responsible for first time setup of the project's git repo's remote connection.

Since this is a first time setup script, we intentionally only use builtin Python dependencies.
"""

import argparse
import subprocess
from pathlib import Path

from util import check_dependencies
from util import existing_dir


def main() -> None:
"""Parses command line input and passes it through to setup_git."""
parser: argparse.ArgumentParser = get_parser()
args: argparse.Namespace = parser.parse_args()
setup_remote(
path=args.path,
repository_host=args.repository_host,
repository_path=args.repository_path,
)


def setup_remote(path: Path, repository_host: str, repository_path: str) -> None:
"""Set up the provided cookiecutter-robust-python project's git repo."""
commands: list[list[str]] = [
[
"git",
"remote",
"add",
"origin",
f"https://{repository_host}/{repository_path}.git",
],
[
"git",
"remote",
"set-url",
"origin",
f"https://{repository_host}/{repository_path}.git",
],
["git", "fetch", "origin"],
["git", "checkout", "main"],
["git", "push", "-u", "origin", "main"],
["git", "checkout", "develop"],
["git", "push", "-u", "origin", "develop"],
]
check_dependencies(path=path, dependencies=["git"])

for command in commands:
subprocess.run(command, cwd=path, stderr=subprocess.STDOUT)


def get_parser() -> argparse.ArgumentParser:
"""Creates the argument parser for setup-remote."""
parser: argparse.ArgumentParser = argparse.ArgumentParser(
prog="setup-remote",
usage="python ./scripts/setup-remote.py . --host github.com --path 56kyle/robust-python-demo",
description="Set up the provided cookiecutter-robust-python project's remote repo connection.",
)
parser.add_argument(
"path",
type=existing_dir,
metavar="PATH",
help="Path to the repo's root directory (must already exist).",
)
parser.add_argument(
"--host",
dest="repository_host",
help="Repository host (e.g., github.com, gitlab.com).",
)
parser.add_argument(
"--path",
dest="repository_path",
help="Repository path (e.g., user/repo, group/subgroup/repo).",
)
return parser


if __name__ == "__main__":
main()
63 changes: 63 additions & 0 deletions scripts/setup-venv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Script responsible for first time setup of the project's venv.

Since this is a first time setup script, we intentionally only use builtin Python dependencies.
"""

import argparse
import shutil
import subprocess
from pathlib import Path

from util import check_dependencies
from util import existing_dir
from util import remove_readonly


def main() -> None:
"""Parses args and passes through to setup_venv."""
parser: argparse.ArgumentParser = get_parser()
args: argparse.Namespace = parser.parse_args()
setup_venv(path=args.path, python_version=args.python_version)


def get_parser() -> argparse.ArgumentParser:
"""Creates the argument parser for setup-venv."""
parser: argparse.ArgumentParser = argparse.ArgumentParser(
prog="setup-venv", usage="python ./scripts/setup-venv.py . -p '3.9'"
)
parser.add_argument(
"path",
type=existing_dir,
metavar="PATH",
help="Path to the repo's root directory (must already exist).",
)
parser.add_argument(
"-p",
"--python",
dest="python_version",
help="The Python version that will serve as the main working version used by the IDE.",
)
return parser


def setup_venv(path: Path, python_version: str) -> None:
"""Set up the provided cookiecutter-robust-python project's venv."""
commands: list[list[str]] = [
["uv", "lock"],
["uv", "venv", ".venv"],
["uv", "python", "install", python_version],
["uv", "python", "pin", python_version],
["uv", "sync", "--all-groups"],
]
check_dependencies(path=path, dependencies=["uv"])

venv_path: Path = path / ".venv"
if venv_path.exists():
shutil.rmtree(venv_path, onerror=remove_readonly)

for command in commands:
subprocess.run(command, cwd=path, capture_output=True)


if __name__ == "__main__":
main()
Loading