Skip to content

Commit 60e0918

Browse files
refactoring
1 parent 529bd29 commit 60e0918

File tree

3 files changed

+173
-16
lines changed

3 files changed

+173
-16
lines changed

code2docs/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class ReadmeConfig:
2121
"""Configuration for README generation."""
2222
sections: List[str] = field(default_factory=lambda: [
2323
"overview", "how_it_works", "install", "quickstart", "api",
24-
"structure", "endpoints", "generated_docs",
24+
"structure", "endpoints", "contributing", "generated_docs",
2525
])
2626
badges: List[str] = field(default_factory=lambda: [
2727
"version", "python", "coverage", "complexity",

code2docs/generators/readme_gen.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ def _build_context(self, project_name: str) -> Dict:
8787
# Project description: LLM if available, else package docstring
8888
project_description = self._generate_description(project_name, entry_points)
8989

90+
# Metadata: author, license, contributors
91+
metadata = self._extract_project_metadata()
92+
9093
return {
9194
"project_name": project_name,
9295
"project_path": self.result.project_path,
@@ -102,6 +105,13 @@ def _build_context(self, project_name: str) -> Dict:
102105
"module_tree": module_tree,
103106
"modules": self.result.modules,
104107
"sync_markers": self.config.readme.sync_markers,
108+
# New metadata fields
109+
"author": metadata.get("author", ""),
110+
"license": metadata.get("license", ""),
111+
"license_file": metadata.get("license_file", ""),
112+
"contributors": metadata.get("contributors", []),
113+
"repo_url": self.config.repo_url,
114+
"version": metadata.get("version", "0.1.0"),
105115
}
106116

107117
def _calc_avg_complexity(self) -> float:
@@ -165,6 +175,100 @@ def _extract_project_description(self, project_name: str) -> str:
165175
return doc.strip()
166176
return ""
167177

178+
def _extract_project_metadata(self) -> Dict:
179+
"""Extract project metadata (author, license, version) from pyproject.toml or git."""
180+
metadata = {
181+
"author": "",
182+
"license": "",
183+
"license_file": "",
184+
"contributors": [],
185+
"version": "0.1.0",
186+
}
187+
188+
# Try pyproject.toml
189+
try:
190+
import tomllib
191+
pyproject_path = Path(self.result.project_path) / "pyproject.toml"
192+
if pyproject_path.exists():
193+
with open(pyproject_path, "rb") as f:
194+
data = tomllib.load(f)
195+
196+
project = data.get("project", {})
197+
metadata["version"] = project.get("version", metadata["version"])
198+
199+
# Authors
200+
authors = project.get("authors", [])
201+
if authors:
202+
if isinstance(authors[0], dict):
203+
metadata["author"] = authors[0].get("name", "")
204+
metadata["contributors"] = [a.get("name", "") for a in authors[1:] if a.get("name")]
205+
else:
206+
metadata["author"] = str(authors[0])
207+
208+
# License
209+
metadata["license"] = project.get("license", {}).get("text", "")
210+
if not metadata["license"]:
211+
metadata["license"] = project.get("license", "")
212+
except Exception:
213+
pass
214+
215+
# Try git for contributors if not found
216+
if not metadata["contributors"]:
217+
try:
218+
import subprocess
219+
result = subprocess.run(
220+
["git", "shortlog", "-sne", "HEAD"],
221+
capture_output=True, text=True, cwd=self.result.project_path
222+
)
223+
if result.returncode == 0:
224+
contributors = []
225+
for line in result.stdout.strip().split("\n")[:5]:
226+
parts = line.split("\t")
227+
if len(parts) >= 2:
228+
contributors.append(parts[1])
229+
metadata["contributors"] = contributors
230+
except Exception:
231+
pass
232+
233+
# Try git config for author if not found
234+
if not metadata["author"]:
235+
try:
236+
import subprocess
237+
name = subprocess.run(
238+
["git", "config", "user.name"],
239+
capture_output=True, text=True, cwd=self.result.project_path
240+
)
241+
email = subprocess.run(
242+
["git", "config", "user.email"],
243+
capture_output=True, text=True, cwd=self.result.project_path
244+
)
245+
if name.returncode == 0 and name.stdout.strip():
246+
author = name.stdout.strip()
247+
if email.returncode == 0 and email.stdout.strip():
248+
author += f" <{email.stdout.strip()}>"
249+
metadata["author"] = author
250+
except Exception:
251+
pass
252+
253+
# Find LICENSE file
254+
for license_file in ["LICENSE", "LICENSE.txt", "LICENSE.md", "COPYING"]:
255+
license_path = Path(self.result.project_path) / license_file
256+
if license_path.exists():
257+
metadata["license_file"] = license_file
258+
# Try to extract license name from file content
259+
if not metadata["license"]:
260+
try:
261+
content = license_path.read_text(encoding="utf-8").lower()
262+
for license_type in ["mit", "apache", "gpl", "bsd", "mpl", "lgpl"]:
263+
if license_type in content:
264+
metadata["license"] = license_type.upper()
265+
break
266+
except Exception:
267+
pass
268+
break
269+
270+
return metadata
271+
168272
def _build_manual(self, project_name: str, sections: List[str], context: Dict) -> str:
169273
"""Fallback manual README builder (orchestrator)."""
170274
section_builders = {

code2docs/templates/readme.md.j2

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
{% endif %}
1212
{% endif %}
1313

14+
{% if author or license %}
15+
**Author:** {% if author %}{{ author }}{% else %}Not specified{% endif %}
16+
**License:** {% if license %}{{ license }}{% if license_file %}[({{ license_file }})](./{{ license_file }}){% endif %}{% else %}Not specified{% endif %}
17+
{% if repo_url %}**Repository:** [{{ repo_url }}]({{ repo_url }}){% endif %}
18+
19+
{% endif %}
20+
1421
{% if "how_it_works" in sections %}
1522
## How It Works
1623

@@ -140,25 +147,71 @@ generate_docs("./my-project", config=config)
140147
{% endfor %}
141148
{% endif %}
142149

150+
{% if "contributing" in sections %}
151+
## Contributing
152+
153+
{% if contributors %}
154+
**Contributors:**
155+
{% for contributor in contributors %}
156+
- {{ contributor }}
157+
{% endfor %}
158+
{% endif %}
159+
160+
We welcome contributions! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
161+
162+
### Development Setup
163+
164+
```bash
165+
# Clone the repository
166+
git clone {{ repo_url or '<repository-url>' }}
167+
cd {{ project_name }}
168+
169+
# Install in development mode
170+
pip install -e ".[dev]"
171+
172+
# Run tests
173+
pytest
174+
```
175+
176+
{% endif %}
177+
143178
{% if "generated_docs" in sections %}
144-
## Generated Documentation
179+
## Documentation
180+
181+
This project includes comprehensive auto-generated documentation:
182+
183+
### Quick Links
184+
{% if repo_url %}
185+
- 📖 [Full Documentation]({{ repo_url }}/tree/main/docs) — API reference, module docs, architecture
186+
- 🚀 [Getting Started]({{ repo_url }}/blob/main/docs/getting-started.md) — Quick start guide
187+
- 📚 [API Reference]({{ repo_url }}/blob/main/docs/api.md) — Complete API documentation
188+
- 🔧 [Configuration]({{ repo_url }}/blob/main/docs/configuration.md) — Configuration options
189+
{% else %}
190+
- 📖 [Full Documentation](./docs) — API reference, module docs, architecture
191+
- 🚀 [Getting Started](./docs/getting-started.md) — Quick start guide
192+
- 📚 [API Reference](./docs/api.md) — Complete API documentation
193+
- 🔧 [Configuration](./docs/configuration.md) — Configuration options
194+
{% endif %}
195+
- 💡 [Examples](./examples) — Usage examples and code samples
196+
197+
### Generated Files
145198

146199
When you run `{{ project_name }}`, the following files are produced:
147200

148-
| Output | Description |
149-
|--------|-------------|
150-
| `README.md` | Project overview with badges, stats, and API summary |
151-
| `docs/api.md` | Consolidated API reference with signatures and complexity |
152-
| `docs/modules.md` | Module reference with metrics and class/function details |
153-
| `docs/architecture.md` | Architecture overview with Mermaid diagrams |
154-
| `docs/dependency-graph.md` | Module dependency graph and coupling matrix |
155-
| `docs/coverage.md` | Docstring coverage report |
156-
| `docs/getting-started.md` | Getting started guide |
157-
| `docs/configuration.md` | Configuration reference |
158-
| `docs/api-changelog.md` | API change tracking between runs |
159-
| `CONTRIBUTING.md` | Contribution guidelines |
160-
| `examples/` | Auto-generated usage examples |
161-
| `mkdocs.yml` | MkDocs site configuration |
201+
| Output | Description | Link |
202+
|--------|-------------|------|
203+
| `README.md` | Project overview (this file) | — |
204+
| `docs/api.md` | Consolidated API reference | [View](./docs/api.md) |
205+
| `docs/modules.md` | Module reference with metrics | [View](./docs/modules.md) |
206+
| `docs/architecture.md` | Architecture with diagrams | [View](./docs/architecture.md) |
207+
| `docs/dependency-graph.md` | Dependency graphs | [View](./docs/dependency-graph.md) |
208+
| `docs/coverage.md` | Docstring coverage report | [View](./docs/coverage.md) |
209+
| `docs/getting-started.md` | Getting started guide | [View](./docs/getting-started.md) |
210+
| `docs/configuration.md` | Configuration reference | [View](./docs/configuration.md) |
211+
| `docs/api-changelog.md` | API change tracking | [View](./docs/api-changelog.md) |
212+
| `CONTRIBUTING.md` | Contribution guidelines | [View](./CONTRIBUTING.md) |
213+
| `examples/` | Usage examples | [Browse](./examples) |
214+
| `mkdocs.yml` | MkDocs configuration | — |
162215
{% endif %}
163216

164217
{% if sync_markers %}<!-- code2docs:end -->{% endif %}

0 commit comments

Comments
 (0)