From 7c10d8d2be90c1227821a2f5b3ab23cb4d045304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Maj?= Date: Mon, 6 Jul 2026 15:56:12 +0200 Subject: [PATCH] feat(release): add CI, issue templates, PR template, CHANGELOG, badge README - GitHub Actions CI: author_check + ruff check tools/ + rpg smoke test - PR template with type checklist and author-check reminder - Issue templates: bug report, content issue, feature request, new mission proposal - CHANGELOG.md covering all 48 PRs (Keep a Changelog format) - README.md: CI badge, Python badge, updated structure (P01/P02/P03 per level) Co-Authored-By: Claude Sonnet 4.6 --- .github/ISSUE_TEMPLATE/bug_report.yml | 44 +++++ .github/ISSUE_TEMPLATE/content_issue.yml | 28 ++++ .github/ISSUE_TEMPLATE/feature_request.yml | 45 +++++ .github/ISSUE_TEMPLATE/new_mission.yml | 58 +++++++ .github/PULL_REQUEST_TEMPLATE.md | 21 +++ .github/workflows/ci.yml | 35 ++++ CHANGELOG.md | 184 +++++++++++++++++++++ README.md | 52 +++--- 8 files changed, 444 insertions(+), 23 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/content_issue.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/new_mission.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/ci.yml create mode 100644 CHANGELOG.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..e0f08d5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,44 @@ +name: Bug Report +description: Something is broken — wrong check.py gate, bad link, crash, incorrect task +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for the report! Please be as specific as possible. + + - type: input + id: location + attributes: + label: Location + description: "Which file or mission? e.g. level_3/missions/02_pydantic_models/check.py" + placeholder: "level_X/missions/YY_name/check.py" + validations: + required: true + + - type: textarea + id: what-happened + attributes: + label: What happened? + description: What did you run, what did you expect, what did you get instead? + placeholder: | + Ran: uv run python level_3/missions/02_pydantic_models/check.py + Expected: ✓ all gates pass + Got: ❌ Gate 3 fails even with correct implementation + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Minimal reproduction + description: Paste the relevant part of your task.py (or check.py output) + render: python + + - type: input + id: python-version + attributes: + label: Python version + placeholder: "uv run python --version" + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/content_issue.yml b/.github/ISSUE_TEMPLATE/content_issue.yml new file mode 100644 index 0000000..4db1132 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/content_issue.yml @@ -0,0 +1,28 @@ +name: Content Issue +description: Unclear README, misleading docstring, wrong explanation, typo +labels: ["content"] +body: + - type: input + id: location + attributes: + label: Location + description: "File path, e.g. level_2/missions/03_character_base/README.md" + placeholder: "level_X/missions/YY_name/README.md" + validations: + required: true + + - type: textarea + id: what-is-confusing + attributes: + label: What is confusing or wrong? + description: Quote the exact text and explain what should be different + validations: + required: true + + - type: textarea + id: suggested-fix + attributes: + label: Suggested improvement (optional) + description: How would you rewrite it? + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..1a6b172 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,45 @@ +name: Feature Request +description: Suggest an improvement to an existing mission, project, or tool +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + For entirely new missions or projects, please use the **New Mission / Project Proposal** template instead. + + - type: input + id: location + attributes: + label: Location + description: Which file or component would this improve? + placeholder: "e.g. level_3/missions/04_json_files/README.md" + validations: + required: true + + - type: textarea + id: problem + attributes: + label: What problem does this solve? + description: Describe the friction or gap a student hits today + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed solution + description: What would you change and how? + validations: + required: true + + - type: dropdown + id: scope + attributes: + label: Estimated scope + options: + - Tiny — wording / typo fix + - Small — a few lines in README or task.py + - Medium — new check.py gate or task variant + - Large — structural change to mission/project + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/new_mission.yml b/.github/ISSUE_TEMPLATE/new_mission.yml new file mode 100644 index 0000000..cc0c0fe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new_mission.yml @@ -0,0 +1,58 @@ +name: New Mission / Project Proposal +description: Suggest a new mission or checkpoint project for the course +labels: ["enhancement", "content"] +body: + - type: markdown + attributes: + value: | + Use this template to propose a new mission (focused concept exercise) or project (multi-concept checkpoint). + + - type: dropdown + id: type + attributes: + label: Type + options: + - Mission (single concept, ~30 min) + - Project checkpoint (multi-concept, ~1–2 h) + validations: + required: true + + - type: dropdown + id: level + attributes: + label: Level + options: + - Level 1 — Python Basics + - Level 2 — OOP and Design + - Level 3 — Validation and Persistence + - Level 4 — Interfaces + - Level 5 — Maintainability + - Level 6 — API + - Level 7 — Concurrency + validations: + required: true + + - type: input + id: concept + attributes: + label: Python concept taught + placeholder: "e.g. dataclasses.asdict, functools.lru_cache, contextlib.contextmanager" + validations: + required: true + + - type: textarea + id: game-connection + attributes: + label: RPG connection + description: How does this concept connect to the RPG game? What mechanic does it add? + placeholder: "e.g. lru_cache speeds up repeated monster stat lookups in a battle simulator" + validations: + required: true + + - type: textarea + id: why + attributes: + label: Why should this be in the course? + description: What gap does it fill? What would a student be able to do after completing it? + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4d643c9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,21 @@ +## What does this PR do? + + + +## Type + +- [ ] New mission / project +- [ ] Bug fix (broken check.py, wrong scaffold, bad link) +- [ ] Content fix (README, task.py clarity, docstring) +- [ ] Tooling (author_check, course_status, CI) +- [ ] Other + +## Checklist + +- [ ] `uv run python tools/author_check.py` — 0 errors +- [ ] New missions have: `README.md`, `task.py` (with `raise NotImplementedError`), `check.py` (with `raise SystemExit(1)` on failure) +- [ ] New projects have: `README.md`, `check.py` +- [ ] check.py uses `sys.executable`, not `"uv", "run", "python"` in subprocess calls +- [ ] No solution code leaked into `task.py` +- [ ] README commands run from repo root +- [ ] COURSE_MAP.md updated if structure changed diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ede0a8f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + author-check: + name: Author Check + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: "latest" + + - name: Set up Python + run: uv python install 3.12 + + - name: Install dependencies + run: uv sync --all-groups + + - name: Run author_check.py + run: uv run python tools/author_check.py + + - name: Lint repo tooling (tools/) + run: uv run ruff check tools/ + + - name: Smoke test — entry point + run: uv run rpg --help diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..71db102 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,184 @@ +# Changelog + +All notable changes to this project are documented here. + +Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +Versions are tagged on `main` after each milestone. + +--- + +## [1.0.0] — 2026-07-06 + +First stable release. All seven levels are complete, including two checkpoint projects and one boss fight per level. + +### Added — Release infrastructure +- GitHub Actions CI (`ci.yml`): runs `author_check.py`, `ruff check tools/`, and `uv run rpg --help` on every push and PR +- CI badge and Python badge in `README.md` +- `CHANGELOG.md` (this file) +- GitHub PR template with type checkboxes and author-check reminder +- GitHub issue templates: Bug Report, Content Issue, Feature Request, New Mission/Project Proposal + +### Added — Level 7 checkpoint projects (PR #47) +- `P01 Async Quest Aggregator` — `asyncio.gather` with per-source timeout (`asyncio.wait_for`) +- `P02 Background Report Queue` — daemon thread worker with `InMemoryJobRepository`, FastAPI integration + +### Fixed — Stabilization sprint (PR #48) +- `L7/P01`: closed timing false-positive by monkey-patching `SOURCES` with controlled coroutines +- `L7/P02`: added behavioural `threading.Event` test for `BackgroundWorker` (gate 11) +- `L6/P01`: replaced `HTTPException` with `Literal["goblin","orc","dragon"]` so Pydantic auto-422s invalid names +- `L6/P02`: repository layer now returns domain `Monster` dataclasses, not `MonsterOut` schemas +- `L5/P01`: removed `pyproject.toml` that broke uv workspace; split into `ruff.toml`, `mypy.ini`, `pyrightconfig.json` +- `L5/P02`: added `strict=True` to xfail gate, relaxed quota counts, coverage failure now raises `SystemExit(1)` +- `L4/P02`: added `@app.callback()` so Typer enables multi-command mode +- `L3/P01`: `name: str` → `name: str = Field(..., min_length=1)` in `MonsterModel`; gate count updated +- `L2/P01`: `is_alive` changed from `@property` to plain method +- `pyproject.toml`: corrected `packages` path `01_installable_cli_tool` → `03_installable_cli_tool` +- `tools/author_check.py`: smoke-tests `uv run rpg --help`; README-link checker covers L7 + +--- + +## [0.7.0] — Level 7: Concurrency and Background Work + +### Added (PR #40, #41) +- 8 missions: blocking vs background, asyncio basics, async API endpoints, job-status repository, background jobs, `ThreadPoolExecutor`, `ProcessPoolExecutor`, testing background work +- Starter: blocking tournament API (`starter_blocking_rpg_api/`) +- Boss fight (`P03`): concurrent tournament runner — FastAPI + `ProcessPoolExecutor`, full test suite + +### Fixed (PR #41 — stabilization) +- `M02`: corrected concurrency vs parallelism language +- `M03`: rewrote `async def` messaging to be pedagogically accurate +- `M06`: removed unused `import time`; AST-checks `ThreadPoolExecutor` usage inside function body +- `M07`: AST-checks `ProcessPoolExecutor` usage inside function body; guard comment +- `M05`: `SyncWorker` via `dependency_overrides` in API check +- Boss fight: restored scaffold in `tournaments.py` and `test_api.py`; require ≥6 test functions via AST +- `tools/`: L7 wired into `author_check.py`, `course_status.py`, `COURSE_MAP.md` + +--- + +## [0.6.0] — Level 6: API with FastAPI + +### Added (PR #38) +- 8 missions: FastAPI intro, path parameters, request bodies, schemas, routers, dependency injection, error handling, TestClient +- Starter: service-ready RPG engine (`starter_service_ready_rpg/`) +- Boss fight (`P03`): RPG Battle API — 7 endpoints, JSON persistence, `HeroClass` enum, `SessionCreated` schema + +### Fixed (PR #39 — stabilization) +- Renamed `def_` → `defense` in `MonsterOut` for a clean HTTP API surface +- `hero_class: str` → `HeroClass` enum for proper 422 validation; Gate 5b added +- Removed local `pyproject.toml` / `uv.lock` that broke uv workspace resolution +- Gate 8 content-type check; `BattleRequest.hero_class` in schemas; M02 README import path +- L6 README: clarified run paths (repo root vs mission folder) + +### Added (PR #46 — checkpoint projects) +- `P01 Battle Preview API` — Pydantic `Literal` type for monster validation, TestClient gates +- `P02 Monster Catalog API` — `Monster` domain dataclass, `MonsterRepository` Protocol, full API gates + +--- + +## [0.5.0] — Level 5: Maintainability + +### Added (PR #36) +- 9 missions: ruff, mypy, pyright, pytest fixtures, `parametrize`, coverage, error handling, pre-commit, GitHub Actions CI +- Starter: working RPG with 6 quality smells (`starter_unqualified_rpg/`) +- Boss fight (`P03`): full release pipeline — ruff + mypy + coverage gate + +### Fixed (PR #37 — L4 boss functional checks) +- L4 boss fight checker: fixed false-positive where `NotImplementedError` silently passed gates + +### Added (PR #45 — checkpoint projects) +- `P01 Quality Gate Rescue` — standalone ruff/mypy/coverage configs; buggy starter to fix +- `P02 Combat Regression Suite` — `xfail(strict=True)` bug regression pattern, ≥85% coverage gate + +--- + +## [0.4.0] — Level 4: Interfaces + +### Added (PR #34) +- 6 missions: Typer CLI, `argparse`, stdlib logging, Rich output, JSON + Markdown reports, installable entry point +- Starter: verbose RPG with interface smells (`starter_verbose_rpg/`) +- Boss fight (`P03`): installable CLI tool (`uv run rpg`) + +### Fixed (PR #35 — stabilization) +- Various gate and scaffold fixes following first run-through + +### Added (PR #44 — checkpoint projects) +- `P01 Quest Master CLI` — multi-command Typer CLI with `@app.callback()` +- `P02 Observable Battle Runner` — logging + Rich progress integrated into battle loop + +--- + +## [0.3.0] — Level 3: Validation and Persistence + +### Added (PR #30, #33) +- 7 missions: Pydantic models, field validators, repository pattern, JSON persistence, CSV persistence, SQLite with `sqlite3`, SQLite with SQLAlchemy +- Starter: raw RPG without validation (`starter_raw_rpg/`) +- Boss fight (`P03`): SQLite repository backend + +### Fixed (PR #31, #32 — stabilization) +- Gate corrections and scaffold fixes + +### Added (PR #43 — checkpoint projects) +- `P01 Validated Bestiary` — Pydantic `MonsterModel` with field constraints, batch validation gates +- `P02 Save Slot Manager` — JSON save/load, slot management, repository pattern + +--- + +## [0.2.0] — Level 2: OOP and Design + +### Added (PR #28) +- 10 missions: classes, `__init__`, methods, inheritance, `super()`, `dataclasses`, `__str__` / `__repr__`, `@staticmethod`, `@classmethod`, refactoring and testing +- Starter: legacy procedural RPG (`starter_legacy_rpg/`) +- Boss fight (`P03`): refactored RPG with full OOP design + +### Fixed (PR #29 — stabilization) +- Gate corrections, README paths, check.py assertion fixes + +### Added (PR #42 — checkpoint projects) +- `P01 Arena Roster` — `Hero` / `Monster` classes, `is_alive()`, arena management +- `P02 Character Sheet Builder` — dataclasses, `__str__`, optional fields + +--- + +## [0.1.0] — Level 1: Python Basics + +### Added (PR #1) +- Course architecture: `uv` workspace, `pyproject.toml`, `tools/`, `COURSE_MAP.md` + +### Added (PR #2) +- Concept progression refactor — all L1 missions ordered and scaffolded + +### Added (PR #3 – #15) — Missions 04–15 +- M04 `combat_loop` — `while` loop as combat turns +- M05 `for_loop` — iterating over enemy lists +- M06 `lists` — enemy roster management +- M07 `dicts` — character sheets as dictionaries +- M08 `functions` — `attack()`, `heal()`, `roll_damage()` +- M09 `random` — dice rolls and loot drops +- M10 `exceptions` — handling invalid moves and game-over states +- M11 `files` — writing and reading combat logs +- M12 `json` — saving game state as JSON +- M13 `modules` — splitting the game into files +- M14 `dataclass` — hero and monster as dataclasses +- M15 `pytest` — writing first tests for game logic + +### Added (PR #16 – #22) — Projects and data analysis +- Project 04: Full RPG — the complete terminal game combining all L1 concepts +- M16 `numpy` — analyzing combat log arrays +- M17 `numpy_stats` — damage distributions and balance checks +- M18 `pandas` — loading and querying combat logs as DataFrames +- M19 `groupby` — comparing hero classes and enemy difficulty +- M20 `matplotlib` — plotting combat data +- Project 05: Analytics — end-to-end analysis of generated combat logs + +### Fixed (PR #23 — review stabilization) +- Gate corrections and README polish following first review + +### Added (PR #24) +- Project 02: Turn-based combat — the first full boss fight of Level 1 + +### Fixed (PR #25, #26, #27) +- Course polish, pre-pilot sprint fixes, L1 reorganization + +--- + +[1.0.0]: https://github.com/michalmaj/python-rpg-questbook/releases/tag/v1.0.0 diff --git a/README.md b/README.md index a91b470..bee0eaa 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Python RPG Questbook +[![CI](https://github.com/michalmaj/python-rpg-questbook/actions/workflows/ci.yml/badge.svg)](https://github.com/michalmaj/python-rpg-questbook/actions/workflows/ci.yml) +[![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/downloads/) + Learn Python by building a real terminal RPG — one mechanic at a time. ## What is this? @@ -14,7 +17,7 @@ Each mission teaches one Python concept by adding a new game mechanic: - files save the combat log - data analysis asks: is the game balanced? -The course continues into professional Python territory — OOP, validation, persistence, and clean architecture — using the same RPG as the vehicle. +The course continues into professional Python territory — OOP, validation, persistence, APIs, and concurrency — using the same RPG as the vehicle. ## Setup @@ -52,44 +55,47 @@ uv run python level_1_python_basics/missions/01_hero_stats/check.py ## Course structure +Seven levels, each with focused missions and two checkpoint projects before the boss fight: + ``` level_1_python_basics/ ← Python fundamentals through terminal RPG + data analysis missions/ ← 20 focused exercises (one concept each) - projects/ ← boss fights that combine what you learned + projects/ ← 5 boss fights that combine what you learned level_2_oop_and_design/ ← OOP, refactoring, design patterns starter_legacy_rpg/ ← the code you will clean up missions/ ← 10 missions - projects/ ← boss fight: refactored RPG + projects/ ← P01 Arena Roster · P02 Character Sheet Builder · P03 boss fight level_3_validation_and_persistence/ ← Pydantic, repository pattern, SQLite starter_raw_rpg/ ← the code you will harden missions/ ← 7 missions - projects/ ← boss fight: SQLite backend + projects/ ← P01 Validated Bestiary · P02 Save Slot Manager · P03 boss fight -level_4_interfaces/ ← CLI, logging, Rich output, reports, entry points +level_4_interfaces/ ← CLI (Typer), logging, Rich output, reports, entry points starter_verbose_rpg/ ← the interface-smelly app you will improve missions/ ← 6 missions - projects/ ← boss fight: installable CLI tool - -level_5_maintainability/ ← Level 5: Production Quality and Maintainability - starter_unqualified_rpg/ ← Fully working RPG with 6 quality smells (your starting point) - missions/ ← 9 missions: ruff, mypy, pyright, fixtures, parametrize, coverage, - projects/ ← error handling, pre-commit, GitHub Actions CI - -level_6_api/ ← Level 6: API Interface with FastAPI - starter_service_ready_rpg/ ← Working RPG engine with service layer (your API will call this) - missions/ ← 8 missions: FastAPI, schemas, routers, DI, errors, tests, OpenAPI - projects/ ← boss fight: RPG Battle API (7 endpoints, JSON persistence) - -level_7_concurrency_and_background_work/ ← Level 7: Concurrency and Background Work - starter_blocking_rpg_api/ ← Blocking tournament API (your starting point) - missions/ ← 8 missions: asyncio, async endpoints, job_id, ThreadPoolExecutor, - projects/ ← ProcessPoolExecutor, SyncWorker, deterministic tests - -tools/ ← helper scripts (course_status, author_check) + projects/ ← P01 Quest Master CLI · P02 Observable Battle Runner · P03 boss fight + +level_5_maintainability/ ← ruff, mypy, pyright, pytest-cov, pre-commit, CI + starter_unqualified_rpg/ ← working RPG with 6 quality smells (your starting point) + missions/ ← 9 missions + projects/ ← P01 Quality Gate Rescue · P02 Combat Regression Suite · P03 boss fight + +level_6_api/ ← FastAPI, schemas, routers, dependency injection, TestClient + starter_service_ready_rpg/ ← working RPG engine with service layer (your API will call this) + missions/ ← 8 missions + projects/ ← P01 Battle Preview API · P02 Monster Catalog API · P03 boss fight + +level_7_concurrency_and_background_work/ ← asyncio, job_id, ThreadPoolExecutor, ProcessPoolExecutor + starter_blocking_rpg_api/ ← blocking tournament API (your starting point) + missions/ ← 8 missions + projects/ ← P01 Async Quest Aggregator · P02 Background Report Queue · P03 boss fight ``` +Each checkpoint project (`P01`, `P02`) is a standalone exercise that exercises the level's concepts. +The boss fight (`P03`) is a full-size challenge that combines everything from the level. + ## Note on global commands This repository contains intentionally incomplete starter files. Running