From 6f5c8634892cc2d80ec90437f0c6f86a65acb5f6 Mon Sep 17 00:00:00 2001 From: Ryan Davis Date: Tue, 14 Jul 2026 21:50:48 -0700 Subject: [PATCH] feat(devcont): #365 mise task runner for dev Introduce mise as a shared task layer (restore/build/test/run/watch) so VS Code, terminal-based editors, and CI all use the same commands against Redux.slnx. The devcontainer now uses the official devcontainers/dotnet image and a post-create script installs mise, trusts the repo config, and warms the NuGet cache automatically. Publish port 27000 so the API is reachable from the host without relying on VS Code's port forwarding, enabling terminal-only editors like neovim to work with the container via the devcontainer CLI. Update Readme and CONTRIBUTING to document the dev container as the recommended setup path, reducing onboarding friction and keeping local environments consistent with CI. --- .devcontainer/devcontainer.json | 23 ++++++--------- .devcontainer/post-create.sh | 21 ++++++++++++++ CONTRIBUTING.md | 13 ++++++++- Readme.md | 51 +++++++++++++++++++++++++++++++++ mise.toml | 35 ++++++++++++++++++++++ 5 files changed, 128 insertions(+), 15 deletions(-) create mode 100755 .devcontainer/post-create.sh create mode 100644 mise.toml 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"