diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6fd72f8b..0793d192 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,21 +1,16 @@ { "name": "Redux .NET Dev Container", - "image": "mcr.microsoft.com/dotnet/sdk:10.0", - "features": { - "ghcr.io/devcontainers/features/common-utils:2": { - "username": "vscode", - "installZsh": false, - "upgradePackages": false - } + "image": "mcr.microsoft.com/devcontainers/dotnet:10.0", + "//appPort": "Publishes 27000 to the host via `docker -p`, so it works from a plain terminal (devcontainer CLI), not just VS Code forwarding. The API binds 0.0.0.0 (see the mise `run` task).", + "appPort": [27000], + "portsAttributes": { + "27000": { "label": "Redux API", "onAutoForward": "notify" } }, + "postCreateCommand": "bash .devcontainer/post-create.sh", "remoteUser": "vscode", "customizations": { "vscode": { - "extensions": [ - "ms-dotnettools.csharp" - ] + "extensions": ["ms-dotnettools.csharp"] } - }, - "postStartCommand": "if [ \"$(stat -c %U /workspaces/Redux)\" != \"vscode\" ]; then sudo chown -R vscode:vscode /workspaces/Redux; fi", - "postCreateCommand": "dotnet --list-sdks" -} \ No newline at end of file + } +} diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh new file mode 100755 index 00000000..6b7cbcd0 --- /dev/null +++ b/.devcontainer/post-create.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Post-create for the Redux devcontainer. +# +# The .NET 10 runtime comes from the base image. This script only layers in mise +# (the unified task runner) and restores NuGet packages so the container is ready +# to `mise run build|test|run`. See CLAUDE.md "Toolchain layering (DECIDED)". +set -euo pipefail + +# 1. Install mise if the base image doesn't already provide it. +if ! command -v mise >/dev/null 2>&1; then + curl -fsSL https://mise.run | sh +fi +MISE="${HOME}/.local/bin/mise" + +# 2. Activate mise for future interactive shells. +ACTIVATE="eval \"\$(${MISE} activate bash)\"" +grep -qF "${ACTIVATE}" "${HOME}/.bashrc" 2>/dev/null || echo "${ACTIVATE}" >> "${HOME}/.bashrc" + +# 3. Trust this repo's mise.toml, then warm the NuGet cache via the shared task. +"${MISE}" trust +"${MISE}" run restore diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index effb35ce..25ed83a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,6 +27,17 @@ By submitting a contribution (pull request, patch, or code submission), you conf ## How to Contribute +### Development environment + +The easiest way to develop is the **dev container**: it provides the correct .NET 10 toolchain +and a shared `mise run ` command set, so you install nothing on your host and your +environment matches CI. Open the repo in VS Code (**Reopen in Container**) or run +`devcontainer up` from a terminal. See **Quick Start → Recommended: Dev Container** in the +[README](./Readme.md) for full setup. + +Inside the container: `mise run run` starts the API on `http://localhost:27000`, and +`mise run test` runs the full test suite. + ### 1. Fork the repository Create your own fork of the project. @@ -40,7 +51,7 @@ Use a descriptive branch name: ### 4. Test your changes - Ensure the project builds successfully -- Run any existing tests +- Run any existing tests (`mise run test` in the dev container) - Add tests if applicable ### 5. Submit a Pull Request (PR) diff --git a/Readme.md b/Readme.md index c1b533fd..31d64c20 100644 --- a/Readme.md +++ b/Readme.md @@ -34,6 +34,57 @@ The backend is designed to be adaptable and can work with different frontends. T ## Quick Start +The recommended path is the **dev container** (below): it needs only a container runtime and +gives everyone the same .NET 10 toolchain. Prefer to install toolchains on your host instead? +Skip to [Prerequisites](#prerequisites). + +### Recommended: Dev Container + +The dev container pins the .NET 10 SDK and a shared task runner ([mise](https://mise.jdx.dev/)) +so VS Code, a plain terminal, and CI all build and test the same way. **No local .NET SDK or +Node.js is required for backend work** — the container provides them. + +**Dependencies** + +- [Docker](https://docs.docker.com/get-docker/) (or a compatible container runtime), and +- one of: + - **VS Code** + the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) (or a [GitHub Codespace](https://github.com/features/codespaces)), or + - the [`@devcontainers/cli`](https://github.com/devcontainers/cli) for terminal-based editors (neovim, etc.): `npm install -g @devcontainers/cli` (needs Node.js on your host). + +**VS Code / Codespaces** + +Open the repo and choose **Reopen in Container**. The first build restores packages +automatically; then use the tasks below from the integrated terminal. + +**Terminal (devcontainer CLI)** + +```bash +# create/start the container (first run pulls the image + restores packages) +devcontainer up --workspace-folder . + +# run tasks inside it +devcontainer exec --workspace-folder . mise run test # restore -> build -> test +devcontainer exec --workspace-folder . mise run run # API on http://localhost:27000 +``` + +**Tasks** — the same `mise run ` names work in VS Code, the terminal, and CI: + +| Task | What it does | +|------|--------------| +| `mise run restore` | Restore NuGet packages | +| `mise run build` | Build the solution (Release) | +| `mise run test` | Restore → build → test (mirrors CI) | +| `mise run run` | Run the API on http://localhost:27000 (Swagger at `/swagger/index.html`) | +| `mise run watch` | Run the API with hot reload | + +Port **27000** is published to your host, so a browser or the +[Redux_GUI](https://github.com/ReduxISU/Redux_GUI) frontend can reach the API at +`http://localhost:27000` while you develop. + +> **Working on the GUI too (e.g. a reduction)?** Run this backend container, then start the +> frontend separately and point its `REDUX_BASE_URL` at `http://localhost:27000/`. The two are +> independent containers wired over HTTP — you do not need both in one container. + ### Prerequisites - [.NET 10 SDK](https://dotnet.microsoft.com/en-us/download) diff --git a/mise.toml b/mise.toml new file mode 100644 index 00000000..fe6c29fd --- /dev/null +++ b/mise.toml @@ -0,0 +1,35 @@ +# mise — one task vocabulary across the Redux repos (`mise run build|test|run|watch`), +# so C#, Python, and JS repos share the same commands. +# +# There is intentionally NO [tools] section: the .NET 10 runtime is provided by the +# devcontainer base image, not mise. mise is the task layer only. See CLAUDE.md +# "Toolchain layering (DECIDED)". +# +# Every task names Redux.slnx explicitly — a bare `dotnet` at the repo root errors +# MSB1011 because API.csproj and Redux.slnx sit side by side (same reason CI does). + +[tasks.restore] +description = "Restore NuGet packages" +run = "dotnet restore Redux.slnx" + +[tasks.build] +description = "Build the solution (Release)" +depends = ["restore"] +run = "dotnet build Redux.slnx --no-restore --configuration Release" + +[tasks.test] +description = "Run unit tests (restore -> build -> test, matching CI)" +depends = ["build"] +run = "dotnet test Redux.slnx --no-restore --no-build --configuration Release" + +[tasks.run] +description = "Run the API on http://localhost:27000 (Development + Swagger)" +# Bind via ASPNETCORE_URLS, NOT `--urls`: `dotnet run` treats `--urls` as an unknown +# run option and exits before the app starts. 0.0.0.0 so the published port is reachable. +env = { ASPNETCORE_URLS = "http://0.0.0.0:27000" } +run = "dotnet run --project API.csproj" + +[tasks.watch] +description = "Run the API with hot reload on :27000" +env = { ASPNETCORE_URLS = "http://0.0.0.0:27000" } +run = "dotnet watch --project API.csproj run"