142 lines
5.8 KiB
Markdown
142 lines
5.8 KiB
Markdown
## Blessed dependencies maintenance and `loco doctor`
|
||
|
||
Loco contain a few major and "blessed" dependencies, these appear **both** in an app that was generated at the surface level in their `Cargo.toml` and in the core Loco framework.
|
||
|
||
If stale, may require an upgrade as a must.
|
||
|
||
Example for such dependencies:
|
||
|
||
* The `sea-orm-cli` - while Loco uses `SeaORM`, it uses the `SeaORM` CLI to generate entities, and so there may be an incompatibility if `SeaORM` has a too large breaking change between their CLI (which ships separately) and their framework.
|
||
* `axum`
|
||
* etc.
|
||
|
||
This is why we are checking these automatically as part of `loco doctor`.
|
||
|
||
We keep minimal version requirements for these. As a maintainer, you can update these **minimal** versions, only if required in [`doctor.rs`](src/doctor.rs).
|
||
|
||
|
||
|
||
## Running Tests
|
||
|
||
Before running tests make sure that:
|
||
|
||
[ ] redis is running
|
||
[ ] starters/saas frontend package is built:
|
||
|
||
```
|
||
$ cd starters/saas/frontend
|
||
$ npm i -g pnpm
|
||
$ pnpm i && pnpm build
|
||
```
|
||
|
||
Running all tests should be done with:
|
||
|
||
```
|
||
$ cargo xtask test
|
||
```
|
||
|
||
### Docker / testcontainers
|
||
|
||
Database and Redis tests use [testcontainers](https://crates.io/crates/testcontainers),
|
||
which spin up their own Postgres/Redis containers on demand — so you need a
|
||
running Docker daemon, but you do **not** need to start Postgres/Redis yourself.
|
||
|
||
If you use a non–Docker Desktop runtime (Colima, OrbStack, Podman, ...), the
|
||
Docker socket is not at the default `/var/run/docker.sock` and testcontainers
|
||
will fail with `SocketNotFoundError("/var/run/docker.sock")`. Point it at your
|
||
socket, e.g. for Colima:
|
||
|
||
```
|
||
$ export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock"
|
||
```
|
||
|
||
## Rebuilding your database and local generated entities
|
||
|
||
This should write out a fresh DB structure (drops and migrates):
|
||
|
||
```
|
||
$ cargo loco db reset
|
||
```
|
||
|
||
And then, the entities generators connect to that newly minted DB, to generate a corresponding entities code:
|
||
|
||
```
|
||
$ cargo loco db entities
|
||
```
|
||
|
||
## Publishing a new version
|
||
|
||
**Test your changes**
|
||
|
||
* [ ] Ensure you have the necessary local resources, such as `DB`/`Redis`, by executing the command `cargo loco doctor --environment test`. In case you don't have them, refer to the relevant documentation section for guidance.
|
||
* [ ] run `cargo test` on the root to test Loco itself
|
||
* [ ] cd `examples/demo` and run `cargo test` to test our "driver app" which exercises the framework in various ways
|
||
* [ ] push your changes to Github to get the CI running and testing in various additional configurations that you don't have
|
||
* [ ] CI should pass. Take note that all `starters-*` CI are using a **fixed version** of Loco and are not seeing your changes yet
|
||
|
||
|
||
**Actually bump version + test and align starters**
|
||
|
||
* [ ] in project root, run `cargo xtask bump-version` and give it the next version. Versions are without `v` prefix. Example: `0.1.3`.
|
||
* [ ] Did the xtask testing workflow fail?
|
||
* [ ] YES: fix errors, and re-run `cargo xtask bump-version` **with the same version as before**.
|
||
* [ ] NO: great, move to publishing
|
||
* [ ] Your repo may be dirty with fixes. Now that tests are passing locally commit the changes. Then run `cargo publish` to publish the next Loco version (remember: the starters at this point are pointing to the **next version already**, so we don't want to push until publish finished)
|
||
* [ ] When publish finished successfully, push your changes to github
|
||
* [ ] Wait for CI to finish. You want to be focusing more at the starters CI, because they will now pull the new version.
|
||
* [ ] Did CI fail?
|
||
* [ ] YES: This means you had a circumstance that's not predictable (e.g. some operating system issue). Fix the issue and **repeat the bumping process, advance a new version**.
|
||
* [ ] NO: all good! you're done.
|
||
|
||
**Book keeping**
|
||
|
||
* [ ] Update changelog: (1) move vnext to be that new version of yours, (2) create a blank vnext
|
||
* [ ] Think about if any of the items in the new version needs new documentation or update to the documentation -- and do it
|
||
## Errors
|
||
|
||
Errors are done with `thiserror`. We adopt a minimalistic approach to errors.
|
||
|
||
* We try to have _one error kind_ for the entirety of Loco.
|
||
* Errors that cannot be handled, are _informative_ and so can be opaque (we don't offer deep matching on those)
|
||
* Errors that can be handled and reasoned upon should be able to be matched and extract good knowledge from
|
||
* To users, error should _not be cryptic_, and should indicate how to fix issues as much as possible, or point to the issue precisely
|
||
|
||
|
||
### Auto conversions
|
||
|
||
When possible use `from` conversions.
|
||
|
||
```rust
|
||
#[error(transparent)]
|
||
JSON(#[from] serde_json::Error),
|
||
```
|
||
|
||
When complicated, implement a `From` trait yourself. This is done to _centralize_ errors into one place and not litter needless `map_err` code which holds error conversion logic (an exception is Context, see below).
|
||
|
||
|
||
### Context
|
||
|
||
When you know a user might need context, resort to manually shaping the error with extra information. First, define the error:
|
||
|
||
```rust
|
||
#[error("cannot parse `{1}`: {0}")]
|
||
YAMLFile(#[source] serde_yaml::Error, String),
|
||
```
|
||
|
||
Then, shape it:
|
||
|
||
```rust
|
||
serde_yaml::from_str(&rendered)
|
||
.map_err(|err| Error::YAMLFile(err, selected_path.to_string_lossy().to_string()))
|
||
```
|
||
|
||
In this example, the information about where `rendered` came from was long lost at the `serde_yaml::from_str` callsite. Which is why errors were cryptic indicating bad YAML format, but not where it comes from (which file).
|
||
|
||
In this case, we duplicate the YAML error type, leave one of those for auto conversions with `from`, where we don't have a file, and create a new specialized error type with the file information: `YAMLFile`.
|
||
|
||
## The `CONTRIBUTORS` comment
|
||
|
||
Some files contain a special `CONTRIBUTORS` comment. This comment should
|
||
contain context, special notes for that module, and a checklist if needed, so please make sure to follow it.
|
||
|