# How the make_content.py Script Generates Monthly HelloGitHub Issues from Templates

> Automate HelloGitHub monthly issue creation. Learn how make_content.py uses templates and string replacement for efficient content generation.

- Repository: [削微寒/HelloGitHub](https://github.com/521xueweihan/HelloGitHub)
- Tags: internals
- Published: 2026-02-25

---

**The [`make_content.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/make_content.py) script automates HelloGitHub's monthly issue creation by injecting period-specific markdown into a shared template using simple string replacement.**

The HelloGitHub repository curates a monthly collection of interesting open-source projects. To maintain consistent formatting across every issue, the [`script/make_content/make_content.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/script/make_content/make_content.py) utility generates final markdown files by merging a common template with issue-specific content, eliminating manual copy-pasting and formatting errors.

## Core Template Mechanism

The generation system relies on two placeholder strings inside [`template.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/template.md):

- `{{ hello_github_num }}` — injected with the two-digit issue number (e.g., `01`, `02`)
- `{{ hello_github_content }}` — replaced by the entire contents of the period-specific [`contentXX.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/contentXX.md) file

Rather than using a heavy templating engine like Jinja2, the script performs lightweight substitution via Python's native `str.replace()` method. This keeps the dependency footprint minimal while allowing quick manual edits to the template layout.

## Step-by-Step Generation Workflow

### 1. Argument Parsing and Routing

Execution begins in `main()` (lines 80‑98), which inspects `sys.argv` to determine the target issue. The script accepts either a two-digit issue number (e.g., `python make_content.py 02`) or the keyword `all` to trigger bulk generation.

### 2. Path Resolution and Validation

For single-issue generation, `make_content()` (lines 55‑58) constructs absolute paths for three critical files:
- [`template.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/template.md) (repository root)
- `content/<num>/content<num>.md` (period-specific source)
- `content/<num>/HelloGitHub<num>.md` (final output destination)

Before processing, `check_path()` (lines 33‑41) verifies that both the template and the source content file exist. If either is missing, the function returns `None` and halts execution.

### 3. Template Processing and Content Injection

The script loads file contents using `read_file()` (lines 44‑51). It performs two sequential replacements on the template string:
1. Replaces `{{ hello_github_num }}` with the issue number passed via command line
2. Replaces `{{ hello_github_content }}` with the raw markdown from [`contentXX.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/contentXX.md)

This merge occurs at line 65 in `make_content()`: `output_data = temple_data.replace(CONTENT_FLAG, content_data)`.

### 4. Output Generation

Finally, `write_file()` (lines 67‑68) persists the merged markdown to `content/<num>/HelloGitHub<num>.md`. The resulting file contains the standardized layout with the period's curated projects injected at the appropriate position.

## Bulk Generation Mode

When invoked with the `all` argument, `make_all_content()` (lines 71‑76) walks the repository root directory, skips the `script` folder, and iterates over every numeric subdirectory (e.g., `01`, `02`, `03`). It delegates to `make_content()` for each folder found, allowing maintainers to regenerate the entire historical archive whenever [`template.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/template.md) receives global styling updates.

## Practical Usage Examples

### Generate a Single Issue

```bash
python script/make_content/make_content.py 02

```

*Result*: Creates or overwrites [`content/02/HelloGitHub02.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/content/02/HelloGitHub02.md) by merging [`template.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/template.md) with [`content/02/content02.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/content/02/content02.md).

### Regenerate All Historical Issues

```bash
python script/make_content/make_content.py all

```

*Result*: Rewrites every [`HelloGitHubXX.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/HelloGitHubXX.md) file in the repository, propagating any template changes across all periods.

### Minimal Template Structure

```markdown

# HelloGitHub {{ hello_github_num }}

{{ hello_github_content }}

---
*Curated with ❤️ by HelloGitHub*

```

## Summary

- The [`make_content.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/make_content.py) script lives at [`script/make_content/make_content.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/script/make_content/make_content.py) and serves as HelloGitHub's automated publishing engine.
- It expects a [`template.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/template.md) file at the repository root containing `{{ hello_github_num }}` and `{{ hello_github_content }}` placeholders.
- Single issues are generated via `make_content()`, which validates paths, performs dual string replacement, and writes to `content/<XX>/HelloGitHub<XX>.md`.
- Batch processing is handled by `make_all_content()`, which iterates numeric directories and delegates to the single-issue generator.
- The implementation uses native Python `str.replace()` rather than external templating libraries for simplicity and speed.

## Frequently Asked Questions

### What are the exact placeholder strings required in template.md?

The script searches for two literal strings: `{{ hello_github_num }}` (replaced by the two-digit issue number) and `{{ hello_github_content }}` (replaced by the entire contents of the period's source file). These are defined as constants in the script and must match exactly, including spaces.

### Can I regenerate all historical issues at once?

Yes. Pass the `all` argument to the script: `python script/make_content/make_content.py all`. The `make_all_content()` function will scan all numeric directories and regenerate every merged issue file, ensuring consistent formatting across the entire archive.

### Where does the script look for input files?

According to the source code in lines 55‑58, the script resolves paths relative to the repository root: it expects [`template.md`](https://github.com/521xueweihan/HelloGitHub/blob/main/template.md) at the root level, reads content from `content/<num>/content<num>.md`, and writes output to `content/<num>/HelloGitHub<num>.md`.

### Does the script require a templating engine like Jinja2?

No. As implemented in line 65 of [`make_content.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/make_content.py), the script uses standard Python string methods (`str.replace()`) to substitute placeholders. This design choice keeps the tool lightweight and eliminates external dependencies beyond the Python standard library.