DriveStage/CONTRIBUTING.md

272 lines
8.8 KiB
Markdown
Executable File

# Contributing to drivestage
Thanks for your interest in contributing to **drivestage**. This document
covers everything you need to get a local development environment running and
to send changes back upstream.
**Maintainer:** Jeremy Anderson <info@dcos.net> — [dcos.net](https://dcos.net)
> **Architecture context:** read [`BLOG.md`](./BLOG.md) first. It explains the
> ext4 + GRUB2 design, the boot-time auto-discovery model, and the rationale
> behind every non-obvious decision in the codebase. PRs that contradict the
> documented architecture without justification will be asked to motivate the
> change.
---
## How to report bugs
Open a [GitHub Issue](https://git.dcos.net/dcosnet/DriveStage/issues)
and include:
1. **What you did** — exact command line (the full `blkstage.sh ...`
invocation), the GUI button/tab, or the GRUB menu sequence.
2. **What you expected** — the observable outcome you were aiming for.
3. **What happened instead** — the actual output, error message, or panic
backtrace.
4. **Environment** — distro + version, kernel, Rust version (if GUI-related),
target USB device model/capacity, and ISO filenames involved.
5. **Logs** — capture with `sudo blkstage.sh --help`-equivalent verbose
output or `RUST_LOG=debug` for the GUI. Redact sudo passwords — the script
and GUI never log them, but please double-check anything you paste.
**Security issues** are handled separately — see [`SECURITY.md`](./SECURITY.md).
Do **not** open public issues for security vulnerabilities.
---
## How to submit patches
1. **Fork & branch.** Fork the repo, create a feature branch off `main`:
```bash
git clone https://github.com/<your-user>/drivestage.git
cd drivestage
git checkout -b feat/my-feature
```
2. **Make your changes.** Keep commits atomic and focused (see *Commit message
conventions* below).
3. **Run the full local check suite** (see *Running tests*):
```bash
make check test fmt clippy
```
CI runs the same gates — a green `make check test` will almost always mean a
green CI run.
4. **Open a Pull Request** against `main`. Reference any related issue
(`Closes #123`) in the PR body. Explain **why** the change is needed, not
just **what** it does.
5. **Respond to review.** Maintainers may request changes; force-push to the
same branch to update the PR.
All contributions are merged under the project's [MIT license](./LICENSE).
---
## Development setup
### Rust (GUI)
- Rust **1.75+** via [rustup](https://rustup.rs):
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup default stable
```
- Linux GUI build deps (Ubuntu/Debian):
```bash
sudo apt-get install -y \
libgtk-3-dev libssl-dev pkg-config libdbus-1-dev libudev-dev
```
- Build the GUI from the repo root:
```bash
make gui # cargo build --release in gui/
# or directly:
cargo build --release
```
### Bash (engine)
Standard Linux utilities plus `shellcheck` for linting:
```bash
sudo apt-get install -y \
bash parted sfdisk dosfstools e2fsprogs util-linux \
grub-pc-bin grub-efi-amd64-bin tar rsync wipefs shellcheck
```
Optional for non-GRUB bootloaders: `bootctl`, `limine`, `refind-install`.
### Working inside the source tree
The repo is small enough that no special workspace tooling is required:
```
drivestage/
├── scripts/blkstage.sh ← the engine (single bash file)
├── scripts/test_distro_detection.sh
├── gui/ ← Rust + Iced companion app
└── (delivery files: Makefile, CHANGELOG.md, .github/, ...)
```
The bundled copy at `gui/assets/blkstage.sh` must stay byte-identical to
`scripts/blkstage.sh` — run `make sync-assets` (or copy manually) before
committing changes to the script.
---
## Running tests
### Bash distro-detection suite
30 filename → distro-profile assertions, no USB device required:
```bash
make test # runs both bash tests and cargo test
# or directly:
bash scripts/test_distro_detection.sh
```
### Rust unit tests
```bash
cd gui && cargo test --locked
# or from repo root:
make test
```
### Lint gate
```bash
make check # cargo check + shellcheck
make fmt # cargo fmt (writes)
make clippy # cargo clippy -- -D warnings
```
`make fmt` writes; CI runs `cargo fmt --check` (read-only). Run `make fmt`
locally before pushing.
---
## Code style
### Rust (`gui/`)
- **rustfmt** is authoritative. `edition = "2021"`, `max_width = 100` (see
[`rustfmt.toml`](./rustfmt.toml)).
- **clippy** must pass with `-D warnings`. Don't `#[allow(...)]` without a
comment explaining why.
- Core logic lives under `gui/src/core/`; UI pages under `gui/src/ui/`. Don't
put business logic in UI modules or `iced` calls in core modules.
- Public functions get doc comments (`///`). Internal helpers may use `//`.
- Errors flow through `anyhow::Result` at the boundary; `thiserror` types for
typed errors in `core/error.rs`.
### Bash (`scripts/`)
- **shellcheck** must pass. Use `shellcheck -x scripts/blkstage.sh`
locally (`-x` allows following `source` across files).
- `set -euo pipefail` is the script's baseline — every function inherits it.
- Keep the engine as a single file. Don't split into a library tree.
- Prefer `printf` over `echo` for any output that may contain backslashes or
variable interpolation.
- New distro support = one new `case` clause in `detect_distro_profile` **and**
one new test case in `scripts/test_distro_detection.sh`.
---
## Commit message conventions
This project uses [**Conventional Commits**](https://www.conventionalcommits.org/en/v1.0.0/).
Each commit message should look like:
```
<type>(<scope>): <subject>
<optional body>
<optional footer>
```
### Types
| Type | When to use |
|------------|------------------------------------------------------------------------|
| `feat` | New user-facing capability (new subcommand, new GUI tab, new distro) |
| `fix` | Bug fix |
| `docs` | Documentation only (README, BLOG, CHANGELOG) |
| `style` | Formatting, whitespace, rustfmt — no semantic change |
| `refactor` | Code restructure with no behavior change |
| `perf` | Performance improvement |
| `test` | Adding or fixing tests |
| `build` | Build system, Cargo.toml, Makefile, CI workflow |
| `ci` | Changes to `.github/` |
| `chore` | Tooling, repo hygiene, things not user-visible |
### Scopes
Common scopes: `engine`, `gui`, `grub`, `distro`, `ci`, `deps`, `docs`.
### Examples
```
feat(engine): detect LVM/LUKS/mdadm-backed root in guard_root_disk
Walks the lsblk PKNAME chain so the script refuses to operate when
the host root filesystem sits on a layered block device, not just
when /dev/sdX matches the root device directly.
Closes #42.
```
```
fix(grub): use --checkpoint=100 --checkpoint-action=dot
GNU tar's `--checkpoint=.100` was never valid syntax. Corrected to
the documented form so progress dots emit every 100 records during
deploy_payload.
```
```
docs: add CONTRIBUTING.md and SECURITY.md for v0.2.0
```
### Tips
- Keep the **subject** to 50 characters where possible; wrap the body at 72.
- Use the **imperative mood** ("add", "fix", "refactor") — the subject should
complete the sentence *"If applied, this commit will ___."*
- Reference issues in the footer: `Closes #42`, `Refs #17`.
- Breaking changes: append `!` after the type/scope (`feat(engine)!:`) and add
a `BREAKING CHANGE:` footer.
---
## Branch strategy
- **`main`** — always shippable. Tags cut from `main`. Never push directly;
everything goes through PR.
- **Feature branches** — `feat/...`, `fix/...`, `docs/...`, `chore/...`.
Short-lived; delete after merge.
- **Release tags** — `v0.2.0`, `v0.2.1`, ...; follow SemVer. The CI workflow
runs on tags too — a green tag build is the release artifact.
- **Hotfix branches** — `hotfix/...` off `main`, merged straight back; bump
the patch version.
### Merge policy
- Squash-and-merge for single-logical-change PRs (preserves the conventional
commit subject as the merge commit).
- Rebase-and-merge for multi-commit PRs where each commit is meaningful on
`main`.
- Merge commits are reserved for release PRs that pull together many
contributions.
---
## Need help?
- Architecture & design intent: [`BLOG.md`](./BLOG.md)
- Getting started: [`QUICKSTART.md`](./QUICKSTART.md)
- Issues: [git.dcos.net/dcosnet/DriveStage/issues](https://git.dcos.net/dcosnet/DriveStage/issues)
- Author: Jeremy Anderson <info@dcos.net> — [dcos.net](https://dcos.net)
Thanks for helping make drivestage better.