Skip to content

Commit 511655d

Browse files
committed
feat: add preparations for moving to org
1 parent c64d44b commit 511655d

File tree

7 files changed

+85
-11
lines changed

7 files changed

+85
-11
lines changed

.env

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Default environment variables for cookiecutter-robust-python
2+
# Users can override these by creating a .env.local file (not committed to git)
3+
4+
# App author name used for cache directory paths
5+
COOKIECUTTER_ROBUST_PYTHON_APP_AUTHOR=robust-python
6+
7+
# Main branch name (typically used for stable releases)
8+
COOKIECUTTER_ROBUST_PYTHON_MAIN_BRANCH=main
9+
10+
# Development branch name (where feature development occurs)
11+
COOKIECUTTER_ROBUST_PYTHON_DEVELOP_BRANCH=develop

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,7 @@ Thumbs.db # Windows thumbnail cache
6262
debug.log
6363
nohup.out
6464

65+
# Local environment overrides
66+
.env.local
67+
6568
/.idea/

docs/maintenance.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,29 @@ uv sync # This installs deps from the template's pyproject.toml into a .venv for
2222

2323
Refer to the [Getting Started: Contributing to the Template](getting-started-template-contributing.md) guide for initial setup details.
2424

25+
## Customizing Template Development with .env.local
26+
27+
The template uses environment variables to make demo generation and repository management scripts user-agnostic. Default values are provided in `.env` at the template repository root.
28+
29+
### Available Environment Variables
30+
31+
- `COOKIECUTTER_ROBUST_PYTHON_APP_AUTHOR` - App author name used for cache directory paths (default: `robust-python`)
32+
- `COOKIECUTTER_ROBUST_PYTHON_MAIN_BRANCH` - Main branch name for version control (default: `main`)
33+
- `COOKIECUTTER_ROBUST_PYTHON_DEVELOP_BRANCH` - Development branch name (default: `develop`)
34+
35+
### Overriding Defaults
36+
37+
If you maintain your own forks of the demo repositories or use different branch conventions, create a `.env.local` file at the template repository root (this file is git-ignored and will not be committed):
38+
39+
```bash
40+
# .env.local (not committed to git)
41+
COOKIECUTTER_ROBUST_PYTHON_APP_AUTHOR=my-org
42+
COOKIECUTTER_ROBUST_PYTHON_MAIN_BRANCH=master
43+
COOKIECUTTER_ROBUST_PYTHON_DEVELOP_BRANCH=development
44+
```
45+
46+
Alternatively, you can set these as system environment variables directly, and the `.env.local` file will override them if present.
47+
2548
## Task Automation for Template Maintenance
2649

2750
The template repository uses its own `noxfile.py` at the **template repository root** (separate from the `noxfile.py` generated in projects) to automate common template maintenance tasks. These tasks run within the template's development environment.

noxfile.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import nox
77
import platformdirs
8+
from dotenv import load_dotenv
89
from nox.command import CommandFailed
910
from nox.sessions import Session
1011

@@ -18,10 +19,19 @@
1819
TEMPLATE_FOLDER: Path = REPO_ROOT / "{{cookiecutter.project_name}}"
1920

2021

22+
# Load environment variables from .env and .env.local (if present)
23+
_env_file: Path = REPO_ROOT / ".env"
24+
_env_local_file: Path = REPO_ROOT / ".env.local"
25+
if _env_file.exists():
26+
load_dotenv(_env_file)
27+
if _env_local_file.exists():
28+
load_dotenv(_env_local_file, override=True)
29+
30+
APP_AUTHOR: str = os.getenv("COOKIECUTTER_ROBUST_PYTHON_APP_AUTHOR", "robust-python")
2131
COOKIECUTTER_ROBUST_PYTHON_CACHE_FOLDER: Path = Path(
2232
platformdirs.user_cache_path(
2333
appname="cookiecutter-robust-python",
24-
appauthor="56kyle",
34+
appauthor=APP_AUTHOR,
2535
ensure_exists=True,
2636
)
2737
).resolve()

scripts/lint-from-demo.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
from pathlib import Path
23
from typing import Annotated
34

@@ -28,22 +29,23 @@ def lint_from_demo(
2829
no_cache: Annotated[bool, typer.Option("--no-cache", "-n")] = False
2930
) -> None:
3031
"""Runs precommit in a generated project and matches the template to the results."""
32+
develop_branch: str = os.getenv("COOKIECUTTER_ROBUST_PYTHON_DEVELOP_BRANCH", "develop")
3133
with in_new_demo(
3234
demos_cache_folder=demos_cache_folder,
3335
add_rust_extension=add_rust_extension,
3436
no_cache=no_cache
3537
) as demo_path:
3638
require_clean_and_up_to_date_repo()
37-
git("checkout", "develop")
39+
git("checkout", develop_branch)
3840
git("branch", "-D", "temp/lint-from-demo", ignore_error=True)
39-
git("checkout", "-b", "temp/lint-from-demo", "develop")
41+
git("checkout", "-b", "temp/lint-from-demo", develop_branch)
4042
pre_commit.main.main(["run", "--all-files", "--show-diff-on-failure"])
4143

4244
for path in IGNORED_FILES:
4345
git("checkout", "HEAD", "--", path)
4446
git("add", ".")
4547
git("commit", "-m", "meta: lint-from-demo", "--no-verify")
46-
retrocookie(instance_path=demo_path, commits=["develop..temp/lint-from-demo"])
48+
retrocookie(instance_path=demo_path, commits=[f"{develop_branch}..temp/lint-from-demo"])
4749

4850

4951
if __name__ == '__main__':

scripts/update-demo.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import sys
23
from pathlib import Path
34
from typing import Annotated
@@ -23,12 +24,13 @@ def update_demo(
2324
) -> None:
2425
"""Runs precommit in a generated project and matches the template to the results."""
2526
try:
27+
develop_branch: str = os.getenv("COOKIECUTTER_ROBUST_PYTHON_DEVELOP_BRANCH", "develop")
2628
demo_name: str = get_demo_name(add_rust_extension=add_rust_extension)
2729
demo_path: Path = demos_cache_folder / demo_name
2830
typer.secho(f"Updating demo project at {demo_path=}.", fg="yellow")
2931
with work_in(demo_path):
3032
require_clean_and_up_to_date_repo()
31-
git("checkout", "develop")
33+
git("checkout", develop_branch)
3234
cruft.update(
3335
project_dir=demo_path,
3436
template_path=REPO_FOLDER,

scripts/util.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,32 @@
1717
import cruft
1818
import typer
1919
from cookiecutter.utils import work_in
20+
from dotenv import load_dotenv
2021
from typer.models import OptionInfo
2122

2223

2324
REPO_FOLDER: Path = Path(__file__).resolve().parent.parent
2425

2526

27+
def _load_env() -> None:
28+
"""Load environment variables from .env and .env.local (if present).
29+
30+
.env.local takes precedence over .env for any overlapping variables.
31+
"""
32+
env_file: Path = REPO_FOLDER / ".env"
33+
env_local_file: Path = REPO_FOLDER / ".env.local"
34+
35+
if env_file.exists():
36+
load_dotenv(env_file)
37+
38+
if env_local_file.exists():
39+
load_dotenv(env_local_file, override=True)
40+
41+
42+
# Load environment variables at module import time
43+
_load_env()
44+
45+
2646
FolderOption: partial[OptionInfo] = partial(
2747
typer.Option, dir_okay=True, file_okay=False, resolve_path=True, path_type=Path
2848
)
@@ -66,14 +86,17 @@ def run_command(command: str, *args: str, ignore_error: bool = False) -> Optiona
6686

6787
def require_clean_and_up_to_date_repo() -> None:
6888
"""Checks if the repo is clean and up to date with any important branches."""
89+
main_branch: str = os.getenv("COOKIECUTTER_ROBUST_PYTHON_MAIN_BRANCH", "main")
90+
develop_branch: str = os.getenv("COOKIECUTTER_ROBUST_PYTHON_DEVELOP_BRANCH", "develop")
91+
6992
git("fetch")
7093
git("status", "--porcelain")
71-
if not is_branch_synced_with_remote("develop"):
72-
raise ValueError("develop is not synced with origin/develop")
73-
if not is_branch_synced_with_remote("main"):
74-
raise ValueError("main is not synced with origin/main")
75-
if not is_ancestor("main", "develop"):
76-
raise ValueError("main is not an ancestor of develop")
94+
if not is_branch_synced_with_remote(develop_branch):
95+
raise ValueError(f"{develop_branch} is not synced with origin/{develop_branch}")
96+
if not is_branch_synced_with_remote(main_branch):
97+
raise ValueError(f"{main_branch} is not synced with origin/{main_branch}")
98+
if not is_ancestor(main_branch, develop_branch):
99+
raise ValueError(f"{main_branch} is not an ancestor of {develop_branch}")
77100

78101

79102
def is_branch_synced_with_remote(branch: str) -> bool:

0 commit comments

Comments
 (0)