Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/scripts/release/smoke/smoke.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ try {
New-Item -ItemType Directory -Force -Path $env:FLAVOR_INSTALL_ROOT, $env:FLAVOR_LOCAL_BIN_DIR | Out-Null
& (Join-Path $root 'manage.ps1') install --channel $channel --version $version --retain=false
& (Join-Path $env:FLAVOR_LOCAL_BIN_DIR 'flavor.exe') --version
& (Join-Path $env:FLAVOR_LOCAL_BIN_DIR 'flavor.exe') check --root $root --config (Join-Path $root 'flavor.json')
& (Join-Path $env:FLAVOR_LOCAL_BIN_DIR 'flavor.exe') check --root $root --config (Join-Path $root 'flavor.toml')
& (Join-Path $root 'manage.ps1') uninstall --version $version
if (Test-Path (Join-Path $env:FLAVOR_INSTALL_ROOT $version)) {
throw "version uninstall left $(Join-Path $env:FLAVOR_INSTALL_ROOT $version)"
Expand All @@ -24,7 +24,7 @@ try {
$env:FLAVOR_INSTALL_ROOT = Join-Path $tmpdir 'latest-smoke'
& (Join-Path $root 'manage.ps1') install --channel $channel --retain=false
& (Join-Path $env:FLAVOR_LOCAL_BIN_DIR 'flavor.exe') --version
& (Join-Path $env:FLAVOR_LOCAL_BIN_DIR 'flavor.exe') check --root $root --config (Join-Path $root 'flavor.json')
& (Join-Path $env:FLAVOR_LOCAL_BIN_DIR 'flavor.exe') check --root $root --config (Join-Path $root 'flavor.toml')
& (Join-Path $root 'manage.ps1') uninstall --install-root $env:FLAVOR_INSTALL_ROOT
if (Test-Path $env:FLAVOR_INSTALL_ROOT) {
throw "full uninstall left $env:FLAVOR_INSTALL_ROOT"
Expand Down
4 changes: 2 additions & 2 deletions .github/scripts/release/smoke/smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mkdir -p "$HOME" "$FLAVOR_INSTALL_ROOT" "$FLAVOR_LOCAL_BIN_DIR"

sh "$ROOT/manage.sh" install --channel "$CHANNEL" --version "$VERSION" --retain=false
"$FLAVOR_LOCAL_BIN_DIR/flavor" --version
"$FLAVOR_LOCAL_BIN_DIR/flavor" check --root "$ROOT" --config "$ROOT/flavor.json"
"$FLAVOR_LOCAL_BIN_DIR/flavor" check --root "$ROOT" --config "$ROOT/flavor.toml"
sh "$ROOT/manage.sh" uninstall --version "$VERSION"
[ ! -e "$FLAVOR_INSTALL_ROOT/$VERSION" ] || { printf '%s\n' "version uninstall left $FLAVOR_INSTALL_ROOT/$VERSION" >&2; exit 1; }

Expand All @@ -26,7 +26,7 @@ if [ "${SMOKE_LATEST:-}" = "1" ]; then
rm -rf "$FLAVOR_INSTALL_ROOT/latest-smoke"
sh "$ROOT/manage.sh" install --channel "$CHANNEL" --install-root "$FLAVOR_INSTALL_ROOT/latest-smoke" --retain=false
"$FLAVOR_LOCAL_BIN_DIR/flavor" --version
"$FLAVOR_LOCAL_BIN_DIR/flavor" check --root "$ROOT" --config "$ROOT/flavor.json"
"$FLAVOR_LOCAL_BIN_DIR/flavor" check --root "$ROOT" --config "$ROOT/flavor.toml"
sh "$ROOT/manage.sh" uninstall --install-root "$FLAVOR_INSTALL_ROOT/latest-smoke"
[ ! -e "$FLAVOR_INSTALL_ROOT/latest-smoke" ] || { printf '%s\n' "full uninstall left $FLAVOR_INSTALL_ROOT/latest-smoke" >&2; exit 1; }
fi
2 changes: 1 addition & 1 deletion .github/workflows/guard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ jobs:
run: cargo test --locked --workspace

- name: Flavor self-check
run: cargo run --locked -p flavor-cli -- check --root . --config flavor.json
run: cargo run --locked -p flavor-cli -- check --root . --config flavor.toml
2 changes: 1 addition & 1 deletion .github/workflows/release-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
run: cargo clippy --locked --workspace --all-targets -- -D warnings

- name: Flavor self-check
run: cargo run --locked -p flavor-cli -- check --root . --config flavor.json
run: cargo run --locked -p flavor-cli -- check --root . --config flavor.toml

build:
needs: [metadata, verify]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ jobs:
run: cargo clippy --locked --workspace --all-targets -- -D warnings

- name: Flavor self-check
run: cargo run --locked -p flavor-cli -- check --root . --config flavor.json
run: cargo run --locked -p flavor-cli -- check --root . --config flavor.toml

build:
needs: [metadata, verify]
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ python3 scripts/init.py
cargo fmt --all --check
cargo clippy --locked --workspace --all-targets -- -D warnings
cargo test --locked --workspace
cargo run --locked -p flavor-cli -- check --root . --config flavor.json
cargo run --locked -p flavor-cli -- check --root . --config flavor.toml
python3 scripts/dev/antlr.py check
runseal :pr --help
```
Expand Down Expand Up @@ -165,7 +165,7 @@ Every PR must pass these commands before review:
cargo fmt --all --check
cargo clippy --locked --workspace --all-targets -- -D warnings
cargo test --locked --workspace
cargo run --locked -p flavor-cli -- check --root . --config flavor.json
cargo run --locked -p flavor-cli -- check --root . --config flavor.toml
```

CI reruns them across Linux, Windows, and macOS.
Expand Down
88 changes: 87 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ curl -fsSL https://flavor.perish.uk/manage.sh | sh -s -- uninstall --version v0.
## Usage

```bash
flavor check # auto-discovers flavor.json at --root
flavor check --config flavor.json # explicit path
flavor check # auto-discovers flavor.* at --root
flavor check --config flavor.toml # explicit path
flavor check --format json
flavor check --strict-warnings
flavor rules # browse the built-in rule catalog
Expand All @@ -71,9 +71,9 @@ Run `flavor help` for the product boundary and `flavor rules` for the full rule

## Config

A `flavor.json` has one required top-level key, `scan`. Optional `preferences`
expand named rule sets over consumer paths, and `overrides` remain the final
rule adjustment layer.
A `flavor.json`, `flavor.toml`, `flavor.yaml`, or `flavor.yml` has one required
top-level key, `scan`. Optional `preferences` expand named rule sets over
consumer paths, and `overrides` remain the final rule adjustment layer.

```json
{
Expand Down Expand Up @@ -162,7 +162,7 @@ Use `flavor rules` to browse rule ids, default severity, and payload keys withou
`flavor check` resolves the config in this order:

1. The `--config <path>` argument if provided. Missing or malformed → error.
2. `<root>/flavor.json` if it exists. flavor prints `flavor: using config <path>` on stderr so a stray file at the scan root never silently changes the check.
2. The first supported config under `<root>` if it exists. Format priority is `flavor.toml`, `flavor.yaml`, `flavor.yml`, then `flavor.json`. flavor prints `flavor: using config <path>` on stderr so a stray file at the scan root never silently changes the check.
3. Built-in defaults. In user repos these match nothing; the empty-scan warning will flag that.

## Workspace
Expand All @@ -188,7 +188,7 @@ python3 scripts/init.py # initialize hooks and verify loca
cargo fmt --all --check
cargo clippy --locked --workspace --all-targets -- -D warnings
cargo test --locked --workspace
cargo run --locked -p flavor-cli -- check --root . --config flavor.json
cargo run --locked -p flavor-cli -- check --root . --config flavor.toml
python3 scripts/dev/antlr.py check # optional Dockerized G4 validation
```

Expand Down
2 changes: 1 addition & 1 deletion crates/flavor-cli/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ repository orchestration, or runtime management here.
```bash
cargo test --locked -p flavor-cli --test unit
cargo run --locked -p flavor-cli -- rules
cargo run --locked -p flavor-cli -- check --root . --config flavor.json
cargo run --locked -p flavor-cli -- check --root . --config flavor.toml
```

## Standard Workflow
Expand Down
4 changes: 3 additions & 1 deletion crates/flavor-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "flavor-cli"
version = "0.3.1"
version = "0.3.2"
edition = "2021"
license = "MIT"
description = "Personal check-only AST-backed code flavor lint CLI."
Expand All @@ -17,6 +17,8 @@ flavor-plugin-vue = { path = "../flavor-plugin-vue" }
rayon = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
toml = "0.8"
tracing = "0.1"
tracing-subscriber = "0.3"
walkdir = "2"
Expand Down
14 changes: 7 additions & 7 deletions crates/flavor-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,19 +155,19 @@ Commands:
version

Config:
--config <path> Load this JSON config. The file's directory becomes the
--config <path> Load this JSON, TOML, or YAML config. The file's directory becomes the
project root for scan patterns.
(no --config) Walk ancestors of --root (default: cwd) looking for a
flavor.json. The nearest match wins; its directory
becomes the project root. Falls back to built-in
include/exclude patterns if none is found before the
filesystem root.
flavor.toml, flavor.yaml, flavor.yml, or flavor.json.
The nearest match wins; its directory becomes the project
root. Falls back to built-in include/exclude patterns if
none is found before the filesystem root.

Optional flavor.json field:
Optional config field:
allowEmptyScan Suppress the "0 files matched" warning + exit 1.
Reserved for workspace-root configs that intentionally
exclude every submodule and delegate to per-submodule
flavor.json files via walk-up.
flavor.* files via walk-up.

Scope:
The check covers handwritten Python, Rust, TypeScript, TSX, Vue, and Svelte source
Expand Down
43 changes: 43 additions & 0 deletions crates/flavor-cli/src/config/formats.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::{fs, path::Path};

use super::{GuardConfigFile, DEFAULT_CONFIG_FILENAME};

pub(super) const CONFIG_FILENAMES: &[&str] = &[
"flavor.toml",
"flavor.yaml",
"flavor.yml",
DEFAULT_CONFIG_FILENAME,
];

pub(super) fn parse_config_file(config_path: &Path) -> Result<GuardConfigFile, String> {
let source = fs::read_to_string(config_path)
.map_err(|error| format!("failed to read config {}: {error}", config_path.display()))?;
let extension = config_path
.extension()
.and_then(|value| value.to_str())
.unwrap_or_default();
match extension {
"json" => serde_json::from_str(&source).map_err(|error| {
format!(
"failed to parse JSON config {}: {error}",
config_path.display()
)
}),
"toml" => toml::from_str(&source).map_err(|error| {
format!(
"failed to parse TOML config {}: {error}",
config_path.display()
)
}),
"yaml" | "yml" => serde_yaml::from_str(&source).map_err(|error| {
format!(
"failed to parse YAML config {}: {error}",
config_path.display()
)
}),
_ => Err(format!(
"unsupported config format for {}: expected .json, .toml, .yaml, or .yml",
config_path.display()
)),
}
}
Loading