272 lines
8.8 KiB
Markdown
Executable File
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.
|