diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 08797ca..d88fe80 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -4,6 +4,7 @@ on: push: branches: - '**' + workflow_dispatch: env: REGISTRY: gitea.kawaii-alyssa.dev @@ -41,6 +42,24 @@ jobs: name: Unit Tests needs: build runs-on: ubuntu-latest + # cargo build never touches a database (no compile-time-checked sqlx + # macros are used anywhere), but the tests do -- #[sqlx::test] spins up + # a real, freshly-migrated database per test, which needs an actual + # Postgres server to connect to and CREATE DATABASE against. + services: + postgres: + image: postgres:15-alpine + env: + POSTGRES_USER: test + POSTGRES_PASSWORD: test + POSTGRES_DB: test + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 steps: - name: Checkout uses: actions/checkout@v4 @@ -61,6 +80,8 @@ jobs: restore-keys: rust-${{ runner.os }}- - name: Run tests + env: + DATABASE_URL: postgres://test:test@localhost:5432/test run: cargo test --release --locked docker: diff --git a/.gitignore b/.gitignore index 848b12a..ccab045 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /.claude +/.idea .env diff --git a/README.md b/README.md index f16cb4c..14fd9e3 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,35 @@ -# 🎲 Dota Random +# 🎲 Dota Random 🌸 -> "I-it's not like I made a whole randomizer just so YOU could have chaotic fun in your games or anything... b-baka." +> "I-it's not like I made a whole randomizer just so YOU could have chaotic fun in your games or anything... b-baka." 💢 -Fine, FINE. Since you're making me explain it: this is a Dota 2 hero + item build randomizer. You pick how much chaos you want — scope it to melee heroes, lock item tags, disable half the randomness if you're a coward — and it rolls you a hero, a full item build (slot 1 is *always* boots, don't argue with me about it), neutral item candidates per stage, enchantments, and tells you when you're allowed to buy your Aghanim's. Not that I care if you actually use it properly. +Fine, FINE. Since you're making me explain it: this is a Dota 2 hero + item build randomizer. You pick how much chaos you want — scope it to melee heroes, lock item tags, disable half the randomness if you're a coward — and it rolls you a hero, a full item build (slot 1 is *always* boots, don't argue with me about it), neutral item candidates per stage, enchantments, and tells you when you're allowed to buy your Aghanim's. Not that I care if you actually use it properly. 🎀 -It's not a toy. ...Okay it's kind of a toy. Shut up. +It's not a toy. ...Okay it's kind of a toy. Shut up. ✨ -## What it actually does +## 🌷 What it actually does - **Hero scope** — filter by attack type and/or primary attribute, or leave it wide open if you're feeling brave - **Item scope** — restrict rolls to items carrying specific purpose tags (Physical Damage, Disable, Sustain, etc.) -- **Slot 1 is always boots** — every existing boots item in the game is eligible, including separate grades like Boots of Travel / Boots of Travel 2 and Dagon's five levels, each rolled as its own distinct outcome +- **Slot 1 is always boots** 👢 — every existing boots item in the game is eligible, including separate grades like Boots of Travel / Boots of Travel 2 and Dagon's five levels, each rolled as its own distinct outcome - **Neutral items, honestly modeled** — each active tier suggests 2 real candidates, because the app can't actually control what drops in your match. You click whichever one you got, or browse the full tier if neither matches -- **Enchantments, guaranteed** — no RNG-within-RNG nonsense here. If enchantment rolling is on, you get one, scoped correctly to your hero's primary attribute (including the "works on literally any hero" ones — yes, those exist, no I didn't forget about them) +- **Enchantments, guaranteed** ⭐ — no RNG-within-RNG nonsense here. If enchantment rolling is on, you get one, scoped correctly to your hero's primary attribute (including the "works on literally any hero" ones — yes, those exist, no I didn't forget about them) - **Aghanim's Scepter & Shard roll as normal items now** — no special-cased fake probability. You also get to say whether you're "allowed" to buy them mid-build or only after your 6 slots are full, for whenever they don't get rolled naturally -- **Reroll anything** — hero, a single item slot, a specific neutral tier, a specific enchantment tier. Rerolling your hero also refreshes your neutral items and enchantments, since a new hero deserves a fresh itemization pass, o-obviously +- **Reroll anything** 🔁 — hero, a single item slot, a specific neutral tier, a specific enchantment tier. Rerolling your hero also refreshes your neutral items and enchantments, since a new hero deserves a fresh itemization pass, o-obviously - **Manual override, always available** — disable randomness for any slot/dimension and pick it yourself instead -## Stack +## 💐 Stack Not that you need to know this to use it, but since you're being nosy: -| Layer | Tech | -|---|---| -| Backend | Rust, [axum](https://github.com/tokio-rs/axum), [sqlx](https://github.com/launchbadge/sqlx) (Postgres) | -| Frontend | React, TypeScript, Vite, Tailwind CSS | -| Database | PostgreSQL | +| Layer | Tech | +|-------------|--------------------------------------------------------------------------------------------------------------------------------------| +| Backend | Rust, [axum](https://github.com/tokio-rs/axum), [sqlx](https://github.com/launchbadge/sqlx) (Postgres) | +| Frontend | React, TypeScript, Vite, Tailwind CSS | +| Database | PostgreSQL | | Data source | Scraped live from [Liquipedia](https://liquipedia.net/dota2/) via Python scripts (no hardcoded/stale game data, thank you very much) | -| Deployment | Docker Compose + a Gitea Actions CI/CD pipeline | +| Deployment | Docker Compose + a Gitea Actions CI/CD pipeline | -## Getting it running (pay attention, I'm not repeating myself) +## 🌼 Getting it running (pay attention, I'm not repeating myself) ### 1. Database @@ -53,7 +53,7 @@ python scripts/scrape_items.py sqlx migrate run ``` -Yes, this means the roster stays current with whatever patch Liquipedia reflects. Rerun the scripts whenever you want fresh data. I'm not doing that part for you. +Yes, this means the roster stays current with whatever patch Liquipedia reflects. Rerun the scripts whenever you want fresh data. I'm not doing that part for you. 🌱 ### 2. Backend @@ -71,7 +71,7 @@ npm install npm run dev ``` -Runs on `:5173` with a dev proxy to the backend, so it just works. You're welcome. +Runs on `:5173` with a dev proxy to the backend, so it just works. You're welcome. 💗 ### 4. Or just use Docker Compose @@ -79,9 +79,9 @@ Runs on `:5173` with a dev proxy to the backend, so it just works. You're welcom docker compose up ``` -...if the images are actually built and pushed, which they will be, because there's a whole CI pipeline for it. I didn't half-ass this. +...if the images are actually built and pushed, which they will be, because there's a whole CI pipeline for it. I didn't half-ass this. ✨ -## Project layout, since you'll get lost otherwise +## 🎀 Project layout, since you'll get lost otherwise ``` src/ Rust backend (axum handlers, roll logic, models) @@ -91,16 +91,16 @@ frontend/ React + TypeScript SPA .gitea/ CI/CD workflow ``` -## A note on the data +## 🌸 A note on the data -Heroes, items, and enchantments are scraped from Liquipedia's Dota 2 wiki, not hand-typed or pulled from memory — patches change too fast for that to stay accurate, and I refuse to ship stale data. The scrapers check each item's actual current status (active / removed / unreleased / hidden) rather than trusting whatever list happens to mention it, because apparently even wikis get this wrong sometimes. +Heroes, items, and enchantments are scraped from Liquipedia's Dota 2 wiki, not hand-typed or pulled from memory — patches change too fast for that to stay accurate, and I refuse to ship stale data. The scrapers check each item's actual current status (active / removed / unreleased / hidden) rather than trusting whatever list happens to mention it, because apparently even wikis get this wrong sometimes. 🧐 -## Disclaimer +## 📎 Disclaimer -Part of this project — the whole frontend, a chunk of the Rust backend, the data scrapers, the CI/CD setup — was written with AI assistance. It's not like every line was hand-crafted by a lone genius at 3am. Mostly. I just don't like writing boilerplate code or code I already know how to write! Baka! +Part of this project — the whole frontend, a chunk of the Rust backend, the data scrapers, the CI/CD setup — was written with AI assistance. It's not like every line was hand-crafted by a lone genius at 3am. Mostly. I just don't like writing boilerplate code or code I already know how to write! Baka! 💢 -## Author +## 🌷 Author **ItzYumeii** -...I guess if you actually enjoy using this, that's... fine. Not that it matters to me or anything. +...I guess if you actually enjoy using this, that's... fine. Not that it matters to me or anything. 🩷