Skip to content

Commit 403c0e5

Browse files
committed
Generate gitignore files
1 parent c96f1ad commit 403c0e5

6 files changed

Lines changed: 72 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ The generator writes:
7979
- `requirements.txt`
8080
- `requirements-dev.txt`
8181
- `Makefile`
82+
- `.gitignore`
8283
- `.github/workflows/source-sync.yml`
8384
- `.github/workflows/tests.yml`
8485
- `.github/workflows/publish.yml`

msra_codegen/config.toml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,35 @@ base = [
2323
"mypy",
2424
]
2525

26+
[gitignore]
27+
patterns = [
28+
"# Python bytecode",
29+
"__pycache__/",
30+
"*.py[cod]",
31+
"*.pyd",
32+
"# Virtual environments",
33+
".venv/",
34+
"venv/",
35+
"env/",
36+
"# Test, lint, and coverage caches",
37+
".pytest_cache/",
38+
".mypy_cache/",
39+
".ruff_cache/",
40+
".coverage",
41+
"coverage.xml",
42+
"coverage.svg",
43+
"htmlcov/",
44+
"# Build artifacts",
45+
"build/",
46+
"dist/",
47+
"*.egg-info/",
48+
"# Generated project noise",
49+
"merged.msra",
50+
"error.log",
51+
"screenshot.png",
52+
"docs/_build/",
53+
]
54+
2655
[classifiers]
2756
static = [
2857
"Operating System :: Microsoft :: Windows",

msra_codegen/gitignore.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
from typing import Any
5+
6+
from .file_utils import write_text
7+
from .generator_config import config_section
8+
from .template_engine import render_template
9+
10+
11+
def build_gitignore_context() -> dict[str, Any]:
12+
gitignore_config = config_section("gitignore")
13+
patterns = gitignore_config.get("patterns")
14+
if not isinstance(patterns, list) or not patterns:
15+
raise RuntimeError("gitignore.patterns must be a non-empty list.")
16+
17+
normalized_patterns: list[str] = []
18+
for index, pattern in enumerate(patterns):
19+
if not isinstance(pattern, str):
20+
raise TypeError(f"gitignore.patterns[{index}] must be a string.")
21+
normalized_patterns.append(pattern.rstrip())
22+
23+
return {"patterns": normalized_patterns}
24+
25+
26+
def generate_gitignore_project(output_dir: Path) -> None:
27+
context = build_gitignore_context()
28+
write_text(
29+
output_dir / ".gitignore",
30+
render_template("gitignore.tpl", context),
31+
)

msra_codegen/package_writer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
render_manager_template,
1616
write_group_package,
1717
)
18+
from .gitignore import generate_gitignore_project
1819
from .github_workflows import generate_github_workflows_project
1920
from .issue_templates import generate_github_issue_templates_project
2021
from .core_naming import abstraction_module_name_from_path, normalize_abstraction_path, normalize_script_path
@@ -151,6 +152,7 @@ def generate_project(
151152
if legacy_license_dir.exists():
152153
shutil.rmtree(legacy_license_dir)
153154
write_root_license(output_dir, project)
155+
generate_gitignore_project(output_dir)
154156
generate_github_workflows_project(project, output_dir, package_name)
155157
generate_github_issue_templates_project(project, output_dir)
156158

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{% for pattern in patterns -%}
2+
{{ pattern }}
3+
{% endfor %}

tests/codegen.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,12 +772,18 @@ test("python codegen generates both bundled msra documents without failing", ()
772772
);
773773
const normalizedSourceSyncWorkflowText = normalizeNewlines(sourceSyncWorkflowText);
774774
const normalizedPublishWorkflowText = normalizeNewlines(publishWorkflowText);
775+
const gitignoreText = readFileSync(path.join(testCase.outputDir, ".gitignore"), "utf8");
775776
assert.match(makefileText, /pip install -r requirements-dev\.txt/);
776777
assert.match(makefileText, new RegExp(`pytest --cov=${testCase.packageName}`));
777778
assert.match(makefileText, new RegExp(`python -m ruff check ${testCase.packageName} tests example\\.py docs/source/conf\\.py`));
778779
assert.match(makefileText, new RegExp(`python -m ruff check --select I --fix ${testCase.packageName} tests example\\.py docs/source/conf\\.py`));
779780
assert.match(makefileText, new RegExp(`python -m ruff format ${testCase.packageName} tests example\\.py docs/source/conf\\.py`));
780781
assert.match(makefileText, new RegExp(`python -m mypy ${testCase.packageName}`));
782+
assert.match(gitignoreText, /^# Python bytecode$/m);
783+
assert.match(gitignoreText, /^__pycache__\/$/m);
784+
assert.match(gitignoreText, /^\.pytest_cache\/$/m);
785+
assert.match(gitignoreText, /^merged\.msra$/m);
786+
assert.match(gitignoreText, /^docs\/_build\/$/m);
781787
assert.match(normalizedSourceSyncWorkflowText, /name: source-sync/);
782788
assert.match(normalizedSourceSyncWorkflowText, /workflow_dispatch:/);
783789
assert.match(normalizedSourceSyncWorkflowText, /uses: actions\/checkout@v4/);

0 commit comments

Comments
 (0)