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
22 changes: 16 additions & 6 deletions .anvil.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version = 1
tool = "anvil"
tool_version = "0.11.1"
catalog_checksum = "sha256:50ec8969dd7f576cef150439b044e29cef03a1c72c0f1838197cd5bb6d8a6b9e"
tool_version = "0.12.0"
catalog_checksum = "sha256:b097d6ce3927a9bf4acb84ec0d17f18d32a4fc0fd46ea999ea14feab96634dd9"

[[file]]
path = ".anvil/container/Dockerfile.dockerignore"
Expand Down Expand Up @@ -141,7 +141,7 @@ checksum = "sha256:bab029c5ca3be78fcea2d6af02763a0e0640722dfe1431a0eaa541801a981

[[file]]
path = "justfiles/anvil/checks/miri-tree-borrows.just"
checksum = "sha256:ea3349941fd3cf3811bce48a679490fe466dddafdb6d0955c1f5471155669f79"
checksum = "sha256:65f7a333394fc9ce48a54c281b6b87b28cc622710fb5c985cdd5292921da490e"

[[file]]
path = "justfiles/anvil/checks/miri.just"
Expand Down Expand Up @@ -288,8 +288,18 @@ checksum = "sha256:b91854c7f0e6d14c74751f607d2c0e3dfcefef55f5178bbafae59d47e577a

[[region]]
host = "Cargo.toml"
id = "anvil-workspace-lints"
checksum = "sha256:c0d399b21c665de0831143a3d78715ceb38f1d22511d8705f164aeb62e12f174"
id = "anvil-workspace-clippy-lints"
checksum = "sha256:cf78b123235b694a8222e499e7ba91729de9325d1de3f5275e58a85880fabc4e"

[[region]]
host = "Cargo.toml"
id = "anvil-workspace-rust-lints"
checksum = "sha256:ade16a15a1ecfbe6a8f98aca044266f570a7e658bef51f4b3f6e23d8ebd14798"

[[region]]
host = "Cargo.toml"
id = "anvil-workspace-rustdoc-lints"
checksum = "sha256:5040c38d64a80ddedc2c51d25881841a1670de77e68bbd14b67ac66fd0062091"

[[region]]
host = "Justfile"
Expand All @@ -299,7 +309,7 @@ checksum = "sha256:f8affd59b69c7083c2f3b6f593c63672116dda974c1e661dcb66a4412eb3e
[[region]]
host = "clippy.toml"
id = "anvil-clippy"
checksum = "sha256:aba0733632eac4cb54c4768db578fe1f7b7cfe730aa0d7dc13e2828c9062d67d"
checksum = "sha256:0c37975f24d538358d792626e32d67a043c3a892d076ddf90267ce6757b3245b"

[[region]]
host = "crates/automation/Cargo.toml"
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

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

146 changes: 68 additions & 78 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -122,104 +122,94 @@ wiremock = { version = "0.6.5", default-features = false }
yaml_serde = { version = "0.10.7", default-features = false }
zstd = { version = "0.14.0", default-features = false }

# >>> anvil-managed: anvil-workspace-lints
[workspace.lints]
# Catalog of opinionated lints, in dotted-key form so users can extend the
# same scope (`[workspace.lints]` or `[lints]`) outside the sentinels.
# The host-specific table header (`[workspace.lints]` or `[lints]`) is
# prepended by cargo-anvil based on whether the manifest is a workspace
# root or a single-crate Cargo.toml.

# --- rust ------------------------------------------------------------------
rust.ambiguous_negative_literals = "warn"
rust.missing_debug_implementations = "warn"
rust.redundant_imports = "warn"
rust.redundant_lifetimes = "warn"
rust.trivial_numeric_casts = "warn"
rust.unsafe_op_in_unsafe_fn = "warn"
rust.unused_lifetimes = "warn"
# >>> anvil-managed: anvil-workspace-rust-lints
[workspace.lints.rust]
# Rust compiler lint policy. Repository-specific Rust lints can follow this
# region as bare keys in the same table.
ambiguous_negative_literals = "warn"
missing_debug_implementations = "warn"
redundant_imports = "warn"
redundant_lifetimes = "warn"
trivial_numeric_casts = "warn"
unsafe_op_in_unsafe_fn = "warn"
unused_lifetimes = "warn"
# `unexpected_cfgs` is on-by-default at warn since Rust 1.80; combined
# with the catalog's `-D warnings` cloud-workflow policy, any custom cfg name
# becomes a hard build failure. Pre-declare the cfgs that
# `cargo llvm-cov` sets so the recommended coverage-exclusion pattern
# `#[cfg_attr(coverage_nightly, coverage(off))]` works out of the box.
# Adopters who need additional cfg names take ownership of this one
# line (edit the check-cfg array); anvil's drift detector will
# assignment (edit the check-cfg array); anvil's drift detector will
# emit a `.anvil-proposed` sibling on future catalog bumps so the
# customization is preserved.
rust.unexpected_cfgs = { level = "warn", check-cfg = [
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(coverage,coverage_nightly)',
'cfg(loom)',
'cfg(miri_race_coverage)',
'cfg(miri_strict_provenance)',
'cfg(miri_tree_borrows)',
] }

# --- rustdoc ---------------------------------------------------------------
rustdoc.broken_intra_doc_links = "warn"
rustdoc.missing_crate_level_docs = "warn"
rustdoc.unescaped_backticks = "warn"

# --- clippy: category gates (priority -1 so per-lint allows can override) --
clippy.cargo = { level = "warn", priority = -1 }
clippy.complexity = { level = "warn", priority = -1 }
clippy.correctness = { level = "warn", priority = -1 }
clippy.nursery = { level = "warn", priority = -1 }
clippy.pedantic = { level = "warn", priority = -1 }
clippy.perf = { level = "warn", priority = -1 }
clippy.style = { level = "warn", priority = -1 }
clippy.suspicious = { level = "warn", priority = -1 }

# --- clippy: opinionated additions -----------------------------------------
# <<< anvil-managed: anvil-workspace-rust-lints

# >>> anvil-managed: anvil-workspace-rustdoc-lints
[workspace.lints.rustdoc]
# Rustdoc lint policy. Repository-specific rustdoc lints can follow this
# region as bare keys in the same table.
broken_intra_doc_links = "warn"
missing_crate_level_docs = "warn"
unescaped_backticks = "warn"
# <<< anvil-managed: anvil-workspace-rustdoc-lints

# >>> anvil-managed: anvil-workspace-clippy-lints
[workspace.lints.clippy]
# Clippy category gates use priority -1 so per-lint allows can override them.
cargo = { level = "warn", priority = -1 }
complexity = { level = "warn", priority = -1 }
correctness = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
perf = { level = "warn", priority = -1 }
style = { level = "warn", priority = -1 }
suspicious = { level = "warn", priority = -1 }
# Two-repo consensus (oxidizer + oxidizer-github). Restriction-group
# lints that catch real code-smell cases. Adding a workspace-wide lint
# means adopters can only opt out per-crate or by taking ownership of
# this region; only enable when the consensus is strong enough to
# justify that cost.
clippy.allow_attributes = "warn"
clippy.allow_attributes_without_reason = "warn"
clippy.as_pointer_underscore = "warn"
clippy.assertions_on_result_states = "warn"
clippy.clone_on_ref_ptr = "warn"
clippy.deref_by_slicing = "warn"
clippy.disallowed_script_idents = "warn"
clippy.empty_drop = "warn"
clippy.empty_enum_variants_with_brackets = "warn"
clippy.fn_to_numeric_cast_any = "warn"
clippy.if_then_some_else_none = "warn"
clippy.map_err_ignore = "warn"
clippy.multiple_unsafe_ops_per_block = "warn"
clippy.redundant_type_annotations = "warn"
clippy.renamed_function_params = "warn"
clippy.semicolon_outside_block = "warn"
clippy.undocumented_unsafe_blocks = "warn"
clippy.unnecessary_safety_comment = "warn"
clippy.unnecessary_safety_doc = "warn"
clippy.unneeded_field_pattern = "warn"
clippy.unused_result_ok = "warn"
clippy.unwrap_used = "warn"

# --- clippy: opinionated suppressions of category-enabled lints ------------
clippy.missing_const_for_fn = "allow"
clippy.multiple_crate_versions = "allow"
clippy.option_if_let_else = "allow"
clippy.redundant_pub_crate = "allow"
clippy.should_panic_without_expect = "allow"
clippy.significant_drop_tightening = "allow"
allow_attributes = "warn"
allow_attributes_without_reason = "warn"
as_pointer_underscore = "warn"
assertions_on_result_states = "warn"
clone_on_ref_ptr = "warn"
deref_by_slicing = "warn"
disallowed_script_idents = "warn"
empty_drop = "warn"
empty_enum_variants_with_brackets = "warn"
empty_structs_with_brackets = "warn"
fn_to_numeric_cast_any = "warn"
if_then_some_else_none = "warn"
map_err_ignore = "warn"
multiple_unsafe_ops_per_block = "warn"
redundant_type_annotations = "warn"
renamed_function_params = "warn"
semicolon_outside_block = "warn"
undocumented_unsafe_blocks = "warn"
unnecessary_safety_comment = "warn"
unnecessary_safety_doc = "warn"
unneeded_field_pattern = "warn"
unused_result_ok = "warn"
unwrap_used = "warn"
# Literal braces are valid data in templates and structured-logging messages.
literal_string_with_formatting_args = "allow"
missing_const_for_fn = "allow"
multiple_crate_versions = "allow"
option_if_let_else = "allow"
redundant_pub_crate = "allow"
should_panic_without_expect = "allow"
significant_drop_tightening = "allow"
# Blocked by Clippy bug: https://github.com/rust-lang/rust-clippy/issues/15036
clippy.wildcard_imports = "allow"
# <<< anvil-managed: anvil-workspace-lints

# --- clippy: catalog entries this project adds outside the managed region ---
# The dotted-key form above keeps `[workspace.lints]` open, so these extend the
# same scope without editing the anvil-managed block and provoking its drift
# detector. They complete the `M-STATIC-VERIFICATION` catalog, which names all
# three: https://microsoft.github.io/rust-guidelines/guidelines/universal/#M-STATIC-VERIFICATION
clippy.empty_structs_with_brackets = "warn"
clippy.too_long_first_doc_paragraph = "warn"
# The guideline's own opt-out: a structured-logging call site legitimately
# passes a literal holding `{field}` placeholders for the logger to expand.
clippy.literal_string_with_formatting_args = "allow"
wildcard_imports = "allow"
# <<< anvil-managed: anvil-workspace-clippy-lints

# A bit of debugging support for release builds.
[profile.release]
Expand Down
2 changes: 1 addition & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ allow-panic-in-tests = true
allow-unwrap-in-tests = true

# Aspirational: when clippy.wildcard_imports is re-enabled (currently
# allowed in cargo-lints-body.toml due to upstream bug rust-clippy#15036),
# allowed in cargo-clippy-lints.toml due to upstream bug rust-clippy#15036),
# we want the stricter variant that warns on ALL wildcard imports
# including prelude. Setting it now means flipping the lint level to
# warn later is a one-line change with no tuning afterthought.
Expand Down
19 changes: 19 additions & 0 deletions crates/cargo-anvil/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

## [Unreleased]

## [0.12.0] - 2026-09-18

- ✨ Features

- split managed lint regions
- lint empty braced structs

- 🐛 Bug Fixes

- scope coverage reports to affected packages ([#190](https://github.com/microsoft/ox-tools/pull/190))

- ♻️ Code Refactoring

- centralize lint overrides

- 🧩 Miscellaneous

- Merge origin/main into feat/anvil-empty-struct-lint

## [0.11.1] - 2026-09-21

- 🐛 Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion crates/cargo-anvil/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[package]
name = "cargo-anvil"
version = "0.11.1"
version = "0.12.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
Expand Down
8 changes: 4 additions & 4 deletions crates/cargo-anvil/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ More detailed design and operational guidance is available in the
This crate was developed as part of <a href="../..">The Oxidizer Project</a>. Browse this crate's <a href="https://github.com/microsoft/ox-tools/tree/main/crates/cargo-anvil">source code</a>.
</sub>

[__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQblRYhli3L8qob_NSi_WYo69wbWnMVqZw3jJwb3u56HnT6RDphYvRhcoQbBALu36V1VAYbFUDdfp-8dCobobFjKbRep8AbYNMPgi_aMhFhZIGDa2NhcmdvLWFudmlsZjAuMTEuMWtjYXJnb19hbnZpbA
[__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQblRYhli3L8qob_NSi_WYo69wbWnMVqZw3jJwb3u56HnT6RDphYvRhcoQbBALu36V1VAYbFUDdfp-8dCobobFjKbRep8AbYNMPgi_aMhFhZIGDa2NhcmdvLWFudmlsZjAuMTIuMGtjYXJnb19hbnZpbA
[__link0]: https://github.com/casey/just
[__link1]: https://rust-lang.github.io/rustfmt/
[__link10]: https://embarkstudios.github.io/cargo-deny/
Expand All @@ -419,9 +419,9 @@ This crate was developed as part of <a href="../..">The Oxidizer Project</a>. Br
[__link22]: https://mutants.rs/
[__link23]: https://crates.io/crates/cargo-hack
[__link24]: https://crates.io/crates/cargo-coverage-gate
[__link25]: https://docs.rs/cargo-anvil/0.11.1/cargo_anvil/?search=Catalog::anvil
[__link26]: https://docs.rs/cargo-anvil/0.11.1/cargo_anvil/?search=Artifact
[__link27]: https://docs.rs/cargo-anvil/0.11.1/cargo_anvil/fn.run_app.html
[__link25]: https://docs.rs/cargo-anvil/0.12.0/cargo_anvil/?search=Catalog::anvil
[__link26]: https://docs.rs/cargo-anvil/0.12.0/cargo_anvil/?search=Artifact
[__link27]: https://docs.rs/cargo-anvil/0.12.0/cargo_anvil/fn.run_app.html
[__link3]: https://crates.io/crates/cargo-sort
[__link4]: https://crates.io/crates/cargo-heather
[__link5]: https://crates.io/crates/cargo-ensure-no-cyclic-deps
Expand Down
49 changes: 28 additions & 21 deletions crates/cargo-anvil/docs/design/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,9 @@ Corollaries that drive every section below:
- Drift detection lives inside the files themselves (per-file checksums and per-managed-region
checksums). There is no parallel metadata file. See [updates.md](./updates.md).
- The tool inserts managed sections into the user's `Justfile` and into a small set of shared
config files (`deny.toml`, `[workspace.lints]` in the workspace `Cargo.toml`, and `[lints]`
in each crate's `Cargo.toml`, plus `.delta.toml` and `rustfmt.toml`). Outside those sections,
config files (`deny.toml`, separate `[workspace.lints.<namespace>]` regions in the workspace
`Cargo.toml`, and `[lints]` in each member crate's `Cargo.toml`, plus `.delta.toml` and
`rustfmt.toml`). Outside those sections,
the user's content is preserved verbatim. Everything else is in tool-owned files under
`justfiles/anvil/` and the backend-specific cloud workflows directories.

Expand Down Expand Up @@ -255,7 +256,7 @@ repo/
├── Justfile managed-region: anvil-imports
├── justfiles/anvil/ owned (see local.md)
├── .anvil/container/ owned — the container image definition (see containers.md)
├── Cargo.toml managed-region: anvil-workspace-lints (or anvil-lints in single-crate)
├── Cargo.toml managed-regions: anvil-{workspace-,}{rust,rustdoc,clippy}-lints
├── crates/<member>/Cargo.toml managed-region: anvil-lints (one per workspace member)
├── deny.toml managed-regions: anvil-deny-{advisories,licenses,bans,sources}
├── rustfmt.toml managed-region: anvil-rustfmt
Expand Down Expand Up @@ -296,19 +297,25 @@ Detail on each host:
credentials. `justfiles/` holds `.just` recipes and nothing else, so these
live in a tool-owned directory of their own; see
[containers.md](./containers.md).
- **`Cargo.toml` lints regions** — workspace `Cargo.toml` carries the
`anvil-workspace-lints` region containing a single `[workspace.lints]` table whose
rust/clippy/rustdoc entries are written in dotted-key form
(`rust.unsafe_op_in_unsafe_fn = "warn"`, `clippy.unwrap_used = "warn"`, etc.). This
form is chosen because TOML forbids re-declaring a table header — if anvil wrote
`[workspace.lints.clippy]` inside the region, users couldn't add another
`[workspace.lints.clippy]` block elsewhere in the file. With dotted keys, users
append new lints in the same scope right after the closing sentinel; see §7. Each
member `Cargo.toml` carries an `anvil-lints` region with exactly
- **`Cargo.toml` lints regions** — workspace `Cargo.toml` carries separate
`anvil-workspace-rust-lints`, `anvil-workspace-rustdoc-lints`, and
`anvil-workspace-clippy-lints` regions. Each opens its explicit
`[workspace.lints.<namespace>]` table and contains bare lint names. Users append
repository-specific bare lint keys immediately after the corresponding closing
sentinel, before the next table header. This gives `cargo sort --grouped` a stable
Comment thread
Copilot marked this conversation as resolved.
sorting unit for each namespace without mixing managed and repository-owned keys.
Each member `Cargo.toml` carries an `anvil-lints` region with exactly
`[lints]\nworkspace = true`. The emitter uses `toml-edit` for round-trip-safe
manipulation. In a single-crate repo (no `[workspace]` table), the workspace region
becomes `anvil-lints` and contains a single `[lints]` table with the same
dotted-key layout.
manipulation. In a single-crate repo (no `[workspace]` table), the root manifest
instead carries `anvil-rust-lints`, `anvil-rustdoc-lints`, and
`anvil-clippy-lints` regions under `[lints.<namespace>]`. The catalog favors broadly
applicable, low-false-positive diagnostics. It warns on empty braced structs whose unit form is clearer
(`empty_structs_with_brackets`) and allows literal strings with formatting-like
braces because templates and structured-logging messages legitimately carry such
text. Documentation completeness, whether production code may panic, and whether
crate-internal APIs may use `pub` remain repository policy: `missing_docs`,
`clippy::panic`, and `unreachable_pub` are not catalog defaults and adopters can
add them outside the managed region.
- **`deny.toml`** — one managed region per top-level section (`[advisories]`, `[licenses]`,
`[bans]`, `[sources]`) carrying the tool's baseline license/advisory rules. The bans baseline
rejects wildcard registry requirements while allowing versionless path or Git
Expand Down Expand Up @@ -356,12 +363,12 @@ Four escape valves, in increasing severity:
The path of least resistance and the recommended approach for project-specific checks.
2. **Edit a managed-region host file outside the sentinels**: extra recipes in your
`Justfile`, extra rules in `deny.toml` outside the managed regions (or in the gaps
between its per-section regions), extra clippy
lints written in dotted-key form after the closing sentinel (e.g. `clippy.pedantic = "warn"`
in the `[workspace.lints]` scope). The tool preserves everything outside the
sentinels verbatim. Note that TOML forbids redeclaring a table header (`[workspace.lints.clippy]`
etc.), so user extensions must use dotted-key form or sit in a different parent
table. Repeating a managed key is invalid TOML; editing it inside the block
between its per-section regions), and extra lint keys written in bare form immediately
after the matching namespace sentinel (for example, `pedantic = "warn"` after
`anvil-workspace-clippy-lints`). The tool preserves everything outside the
sentinels verbatim. Note that TOML forbids redeclaring a table header
(`[workspace.lints.clippy]` etc.), so user extensions continue the table opened by
the managed region. Repeating a managed key is invalid TOML; editing it inside the block
causes a refusal, even if the template has not changed.
3. **Disable an owned file by emptying it.** An unchanged template leaves it alone;
a changed template can produce a `.anvil-proposed` sibling. Emptying a managed
Expand Down
Loading
Loading