-
Notifications
You must be signed in to change notification settings - Fork 2
Tolerate recorded violations in strict mode (Part B of #43) #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
e198118
7b22b86
22bc710
bfec99d
03ce358
c131362
7ba0136
f706610
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,33 @@ | |
|
|
||
| ### Breaking Changes | ||
|
|
||
| #### Strict mode tolerates violations already recorded in `package_todo.yml` | ||
|
|
||
| `enforce_privacy: strict` and `enforce_dependencies: strict` now fail only on | ||
| references that are **not** already recorded in a `package_todo.yml`. This matches | ||
| packwerk's `unlisted_strict_mode_violations` (Shopify/packwerk#368). | ||
|
|
||
| **Who is affected:** any project with a strict pack whose existing violations are | ||
| recorded in todo files. Previously `pks check` failed on every one of them, so a | ||
| strict pack could only be green with an empty todo list. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two small corrections here. "whose existing violations are recorded in todo files" points at the wrong pack's file. Entries live in the referencing pack's "could only be green with an empty todo list" overstates it. Green required no strict entries, not an empty file. A strict pack with only non-strict recorded violations was already green on |
||
|
|
||
| **What changes:** pks silently produces different (smaller) results without any | ||
| configuration change. Strict packs that were red because of grandfathered | ||
| violations go green. New references into a strict pack still fail, and `pks update` | ||
| still refuses to record an unrecorded strict violation, so strict mode cannot be | ||
| silenced by running it. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "different (smaller) results" is right for On It is also the strongest justification for the Breaking Changes heading this sits under, which the entry never quite states. Lines 19 to 21 describe the half of |
||
|
|
||
| **Opt out:** there is no config flag, matching packwerk. To see everything the todo | ||
| files are grandfathering, run: | ||
|
|
||
| ``` | ||
| pks check --ignore-recorded-violations | ||
| ``` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The prose is accurate, but under an "Opt out:" heading a reader will try Two mechanical things while you are here. The fence on line 26 is untagged, where the |
||
|
|
||
| ## 0.4.0 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This retitling is correct, and the evidence is stronger than the PR description claims. Agreed on leaving the version bump to a release PR, which matches how #25 and #38 were done. One thing to flag for whoever cuts 0.5.0, since it makes these headings functional rather than bookkeeping: |
||
|
|
||
| ### Breaking Changes | ||
|
|
||
| #### `respect_gitignore` defaults to `true` | ||
|
|
||
| pks now respects `.gitignore` files by default. Files and directories matched by | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,11 @@ enforce_privacy: true | |
|
|
||
| Setting `enforce_privacy` to `true` will make all references to private constants in your package a violation. | ||
|
|
||
| Setting `enforce_privacy` to `strict` will forbid all references to private constants in your package. **This includes violations that have been added to other packages' `package_todo.yml` files.** | ||
| Setting `enforce_privacy` to `strict` will forbid *new* references to private constants in your package. **Violations already recorded in another package's `package_todo.yml` are tolerated**, so strict mode stops the list growing rather than requiring it to be empty. | ||
|
|
||
| Note: You will need to remove all existing privacy violations before setting `enforce_privacy` to `strict`. | ||
| Note: you do not need to remove existing privacy violations before setting `enforce_privacy` to `strict`. Turn it on, and any reference that is not already recorded will fail the check. To see everything the todo files are currently grandfathering, run `pks check --ignore-recorded-violations`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Blocking: this describes the one adoption order that does not work. "Turn it on, and any reference that is not already recorded will fail the check" is true, and the preceding sentence is true, but together they point at a dead end. Tolerance only matches entries that are already in a todo file, and once a pack is strict A user who follows this note lands there, and their only exits are fixing the reference, hand-writing the todo entry, or reverting to That sentence is currently in neither |
||
|
|
||
| Running `pks update` will not silence strict mode either: an unrecorded strict violation is never written to a `package_todo.yml`, so it keeps failing until the reference itself is dealt with. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This promises a bit more than holds. It is true of That matches packwerk, so it is not a bug. But "it keeps failing until the reference itself is dealt with" reads as a guarantee, when in practice the boundary is only as strong as review of |
||
|
|
||
| ### Using public folders | ||
| You may enforce privacy either way mentioned above and still expose a public API for your package by placing constants in the public folder, which by default is `app/public`. The constants in the public folder will be made available for use by the rest of the application. | ||
|
|
@@ -99,8 +101,7 @@ end => Ideal solution. No exceptions from rubocop and very low risk of the magic | |
| Sometimes it is desirable to only enforce privacy on a subset of constants in a package. You can do so by defining a `private_constants` list in your package.yml. Note that `enforce_privacy` must be set to `true` or `'strict'` for this to work. | ||
|
|
||
| ### Ignore strict mode for violation coming from specific path patterns | ||
| If you want to activate `'strict'` mode on your package but have a few privacy violations you know you will deal with later, | ||
| you can set a list of patterns to exclude. | ||
| You do not need this to adopt `'strict'` mode on a package that already has violations you will deal with later: violations recorded in a `package_todo.yml` are tolerated by default. Reach for these patterns when you want to exempt a **path** instead of a recorded list. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sentence and the one at line 114 now actively steer people toward
The pks equivalent is The dead yaml block predates this PR, but the PR is what turns it into a recommendation, so it would be good to either repoint these two sentences at |
||
|
|
||
| ```yaml | ||
| enforce_privacy: strict | ||
|
|
@@ -110,6 +111,8 @@ strict_privacy_ignored_patterns: | |
|
|
||
| In this example, violations on constants of your engine referenced in those files `engines/another_engine/test/**/*` will not fail Packwerk checks. | ||
|
|
||
| The difference matters. A `package_todo.yml` entry grandfathers one `(constant, file)` pair, so a *new* reference from the same file still fails. A pattern here exempts the path outright, so anything those files reference later is ignored too. Prefer the todo file unless you genuinely want the whole path exempt. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "so a new reference from the same file still fails" is false as written. I added a second Your own doc comment at The stated unit is also narrower than the real one. One word fixes the conclusion:
That is also exactly what |
||
|
|
||
| ### Package Privacy violation | ||
| Packwerk thinks something is a privacy violation if you're referencing a constant, class, or module defined in the private implementation (i.e. not the public folder) of another package. We care about these because we want to make sure we only use parts of a package that have been exposed as public API. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,20 @@ pub struct ViolationIdentifier { | |
| pub referencing_pack_name: String, | ||
| pub defining_pack_name: String, | ||
| } | ||
|
|
||
| impl ViolationIdentifier { | ||
| /// `strict` describes how a violation should be treated, not which violation | ||
| /// it is, and `package_todo.yml` has nowhere to record it, so recorded | ||
| /// violations are always rebuilt with `strict: false`. Compare through this | ||
| /// so a violation in a strict pack can still match its recorded entry. | ||
| pub fn recorded_key(&self) -> Self { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two small things on this method, neither blocking.
On the allocations I raised last round, I measured instead of guessing, and your call to leave it was right. When someone does pick it up, a borrowed |
||
| Self { | ||
| strict: false, | ||
| ..self.clone() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// A violation combines an identifier with display metadata. | ||
| /// | ||
| /// `source_location` is intentionally separate from `ViolationIdentifier` because: | ||
|
|
@@ -124,7 +138,7 @@ impl<'a> CheckAllBuilder<'a> { | |
| .cloned() | ||
| .collect(), | ||
| strict_mode_violations: self | ||
| .build_strict_mode_violations() | ||
| .build_strict_mode_violations(recorded_violations) | ||
| .into_iter() | ||
| .collect(), | ||
| }) | ||
|
|
@@ -142,7 +156,10 @@ impl<'a> CheckAllBuilder<'a> { | |
| self.found_violations | ||
| .violations | ||
| .iter() | ||
| .filter(|v| !recorded_violations.contains(&v.identifier)) | ||
| .filter(|v| { | ||
| !recorded_violations | ||
| .contains(&v.identifier.recorded_key()) | ||
| }) | ||
| .collect() | ||
| }; | ||
| reportable_violations | ||
|
|
@@ -152,11 +169,11 @@ impl<'a> CheckAllBuilder<'a> { | |
| &mut self, | ||
| recorded_violations: &'a HashSet<ViolationIdentifier>, | ||
| ) -> anyhow::Result<Vec<&'a ViolationIdentifier>> { | ||
| let found_violation_identifiers: HashSet<&ViolationIdentifier> = self | ||
| let found_violation_identifiers: HashSet<ViolationIdentifier> = self | ||
| .found_violations | ||
| .violations | ||
| .par_iter() | ||
| .map(|v| &v.identifier) | ||
| .map(|v| v.identifier.recorded_key()) | ||
| .collect(); | ||
| let relative_files = self | ||
| .found_violations | ||
|
|
@@ -196,9 +213,13 @@ impl<'a> CheckAllBuilder<'a> { | |
| Ok(stale_violations) | ||
| } | ||
|
|
||
| /// `found_violation_identifiers` is keyed by [`ViolationIdentifier::recorded_key`]. | ||
| /// `todo_violation_identifier` needs no such normalization: it comes from | ||
| /// `pack_set.all_violations`, which rebuilds every recorded violation with | ||
| /// `strict: false` already, so it is its own recorded key. | ||
| fn is_stale_violation( | ||
| relative_files: &HashSet<&str>, | ||
| found_violation_identifiers: &HashSet<&ViolationIdentifier>, | ||
| found_violation_identifiers: &HashSet<ViolationIdentifier>, | ||
| todo_violation_identifier: &ViolationIdentifier, | ||
| ) -> bool { | ||
| let violation_path_exists = | ||
|
|
@@ -210,11 +231,23 @@ impl<'a> CheckAllBuilder<'a> { | |
| } | ||
| } | ||
|
|
||
| fn build_strict_mode_violations(&self) -> Vec<Violation> { | ||
| /// Strict mode reports violations that are not already recorded in a | ||
| /// `package_todo.yml`, matching packwerk's `unlisted_strict_mode_violations` | ||
| /// (Shopify/packwerk#368). Turning strict on therefore blocks new violations | ||
| /// without also requiring every recorded one to be fixed first. | ||
| fn build_strict_mode_violations( | ||
| &self, | ||
| recorded_violations: &HashSet<ViolationIdentifier>, | ||
| ) -> Vec<Violation> { | ||
| self.found_violations | ||
| .violations | ||
| .iter() | ||
| .filter(|v| v.identifier.strict) | ||
| .filter(|v| { | ||
| self.configuration.ignore_recorded_violations | ||
| || !recorded_violations | ||
| .contains(&v.identifier.recorded_key()) | ||
| }) | ||
| .cloned() | ||
| .collect() | ||
| } | ||
|
|
@@ -302,22 +335,33 @@ pub(crate) fn update(configuration: &Configuration) -> anyhow::Result<()> { | |
| &checkers, | ||
| )?; | ||
|
|
||
| let strict_violations = &violations | ||
| let recorded_violations = &configuration.pack_set.all_violations; | ||
|
|
||
| // Only *unlisted* strict violations make `check` fail, so only those are | ||
| // worth reporting here. Reporting recorded ones too claimed `check` would | ||
| // fail when it succeeds. Same filter as `build_strict_mode_violations`, and | ||
| // as packwerk's `unlisted_strict_mode_violations`. | ||
| let unlisted_strict_violations = &violations | ||
| .iter() | ||
| .filter(|v| v.identifier.strict) | ||
| .filter(|v| !recorded_violations.contains(&v.identifier.recorded_key())) | ||
| .collect::<Vec<&Violation>>(); | ||
| if !strict_violations.is_empty() { | ||
| for violation in strict_violations { | ||
| if !unlisted_strict_violations.is_empty() { | ||
| for violation in unlisted_strict_violations { | ||
| let strict_message = | ||
| build_strict_violation_message(&violation.identifier); | ||
| println!("{}", strict_message); | ||
| } | ||
| println!( | ||
| "{} strict mode violation(s) detected. These violations must be fixed for `check` to succeed.", | ||
| &strict_violations.len() | ||
| &unlisted_strict_violations.len() | ||
| ); | ||
| } | ||
| package_todo::write_violations_to_disk(configuration, violations); | ||
| package_todo::write_violations_to_disk( | ||
| configuration, | ||
| violations, | ||
| recorded_violations, | ||
| ); | ||
| println!("Successfully updated package_todo.yml files!"); | ||
|
Comment on lines
+365
to
370
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still pre-existing and still not yours to fix. Raising it once more only because this PR edits this block and adds a comment asserting the filter matches packwerk's packwerk treats this state as a failure and pks reports success. A follow-up issue or a one-line note that it is out of scope would settle it either way. |
||
|
|
||
| Ok(()) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer}; | |
| use std::collections::{BTreeMap, HashMap, HashSet}; | ||
| use tracing::debug; | ||
|
|
||
| use super::checker::ViolationIdentifier; | ||
| use super::{pack::Pack, Configuration, Violation}; | ||
|
|
||
| #[derive(PartialEq, Debug, Eq, Deserialize, Serialize, Default, Clone)] | ||
|
|
@@ -133,6 +134,7 @@ pub fn package_todos_for_pack_name( | |
| pub fn write_violations_to_disk( | ||
| configuration: &Configuration, | ||
| violations: HashSet<Violation>, | ||
| recorded_violations: &HashSet<ViolationIdentifier>, | ||
| ) { | ||
| debug!("Starting writing violations to disk"); | ||
| // First we need to group the violations by the responsible pack, which today is always the referencing pack | ||
|
|
@@ -141,7 +143,18 @@ pub fn write_violations_to_disk( | |
| let mut violations_by_responsible_pack: HashMap<String, Vec<Violation>> = | ||
| HashMap::new(); | ||
| for violation in violations { | ||
| if violation.identifier.strict { | ||
| // An *unlisted* strict violation is never recorded, so `update` cannot | ||
| // be used to silence strict mode. An already-recorded one has to be | ||
| // re-written, because `check` now tolerates recorded violations in | ||
| // strict packs and `PackageTodo` is dumped wholesale from these | ||
| // entries — dropping it here would delete the record that made the | ||
| // build green and fail the next `check` with no source change in | ||
| // between. packwerk keeps the entry for the same reason, in | ||
| // `OffenseCollection#add_offense`. | ||
| if violation.identifier.strict | ||
| && !recorded_violations | ||
| .contains(&violation.identifier.recorded_key()) | ||
| { | ||
| continue; | ||
|
Comment on lines
+146
to
158
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is right, and the comment explaining why is welcome. The gap is on the other side of it: nothing pins that Behavior is correct today, I checked. Deleting the recorded reference gets "There were stale violations found" from But the comment says an already-recorded strict violation "has to be re-written", and the natural over-correction to that is to union That is the highest-value test this PR is missing. A |
||
| } | ||
| let referencing_pack_name = | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -320,12 +320,34 @@ fn test_check_without_stale_violations() -> Result<(), Box<dyn Error>> { | |
| } | ||
|
|
||
| #[test] | ||
| fn test_check_with_strict_mode() -> Result<(), Box<dyn Error>> { | ||
| fn test_check_with_recorded_strict_mode_violation() -> Result<(), Box<dyn Error>> | ||
| { | ||
| // The violation is already recorded in packs/foo/package_todo.yml, so strict | ||
| // mode tolerates it and only blocks new ones. Matches packwerk's | ||
| // `unlisted_strict_mode_violations` (Shopify/packwerk#368). | ||
| cargo_bin_cmd!("pks") | ||
| .arg("--project-root") | ||
| .arg("tests/fixtures/uses_strict_mode") | ||
| .arg("check") | ||
| .assert() | ||
| .code(0) | ||
| .stdout(predicate::str::contains("No violations detected!")); | ||
|
|
||
| common::teardown(); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_check_with_recorded_strict_mode_violation_ignoring_todo( | ||
| ) -> Result<(), Box<dyn Error>> { | ||
| // `--ignore-recorded-violations` is the escape hatch: it still surfaces | ||
| // everything the todo file is grandfathering. | ||
| cargo_bin_cmd!("pks") | ||
| .arg("--project-root") | ||
| .arg("tests/fixtures/uses_strict_mode") | ||
| .arg("check") | ||
| .arg("--ignore-recorded-violations") | ||
| .assert() | ||
| .code(1) | ||
| .stdout(predicate::str::contains( | ||
| "packs/foo cannot have privacy violations on packs/bar because strict mode is enabled for privacy violations in the enforcing pack's package.yml file", | ||
|
|
@@ -338,18 +360,74 @@ fn test_check_with_strict_mode() -> Result<(), Box<dyn Error>> { | |
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_check_with_unrecorded_strict_mode_violation( | ||
| ) -> Result<(), Box<dyn Error>> { | ||
| // No package_todo.yml entry for this one, so strict mode must still fail. | ||
| cargo_bin_cmd!("pks") | ||
| .arg("--project-root") | ||
| .arg("tests/fixtures/contains_strict_violations") | ||
| .arg("check") | ||
| .assert() | ||
| .code(1) | ||
| .stdout(predicate::str::contains( | ||
| "packs/foo cannot have privacy violations on packs/bar because strict mode is enabled for privacy violations in the enforcing pack's package.yml file", | ||
| )); | ||
|
|
||
| common::teardown(); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_check_with_partially_recorded_strict_mode_violations( | ||
| ) -> Result<(), Box<dyn Error>> { | ||
| // The case that makes strict mode adoptable, and the one nothing else | ||
| // covers: one recorded violation (::Bar) and one unrecorded (::Baz) in the | ||
| // same strict pack, in the same run. Only the unrecorded one is reported, | ||
| // and the run still fails because of it. | ||
| cargo_bin_cmd!("pks") | ||
| .arg("--project-root") | ||
| .arg("tests/fixtures/uses_strict_mode_partially_recorded") | ||
| .arg("check") | ||
| .assert() | ||
| .code(1) | ||
| .stdout(predicate::str::contains( | ||
| "packs/foo cannot have privacy violations on packs/baz because strict mode is enabled for privacy violations in the enforcing pack's package.yml file", | ||
| )) | ||
| .stdout(predicate::str::contains( | ||
| "packs/foo cannot have dependency violations on packs/baz because strict mode is enabled for dependency violations in the enforcing pack's package.yml file", | ||
| )) | ||
| .stdout(predicate::str::contains("::Baz")) | ||
| // The recorded one stays silent: no strict message, no new-violation | ||
| // report, no stale-todo line. | ||
| .stdout(predicate::str::contains("packs/bar").not()) | ||
| .stdout(predicate::str::contains("::Bar").not()) | ||
| .stdout( | ||
| predicate::str::contains( | ||
| "There were stale violations found, please run `packs update`", | ||
| ) | ||
| .not(), | ||
| ); | ||
|
|
||
| common::teardown(); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_check_with_strict_mode_output_csv() -> Result<(), Box<dyn Error>> { | ||
| // Uses `contains_strict_violations` rather than `uses_strict_mode`: the | ||
| // latter's violation is recorded, so there is nothing left to assert against | ||
| // in the CSV. The duplicate assertion this used to carry was byte-identical | ||
| // to the one below it, so nothing is lost by dropping it. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second half of this comment is right, the duplicate assertion really was byte-identical. The first half claims more than the test now delivers. After the fixture swap this test no longer exercises strict tolerance at all. It passes on That is fine, a CSV format test is worth having. Just worth toning the comment down, or adding a recorded entry to the fixture so the CSV test actually distinguishes the recorded and unrecorded buckets. |
||
| cargo_bin_cmd!("pks") | ||
| .arg("--project-root") | ||
| .arg("tests/fixtures/uses_strict_mode") | ||
| .arg("tests/fixtures/contains_strict_violations") | ||
| .arg("check") | ||
| .arg("-o") | ||
| .arg("csv") | ||
| .assert() | ||
| .code(1) | ||
| .stdout(predicate::str::contains("Violation,Strict?,File,Constant,Referencing Pack,Defining Pack,Message")) | ||
| .stdout(predicate::str::contains("privacy,true,packs/foo/app/services/foo.rb,::Bar,packs/foo,packs/bar,packs/foo cannot have privacy violations on packs/bar because strict mode is enabled for privacy violations in the enforcing pack\'s package.yml file")) | ||
| .stdout(predicate::str::contains( | ||
| "privacy,true,packs/foo/app/services/foo.rb,::Bar,packs/foo,packs/bar,packs/foo cannot have privacy violations on packs/bar because strict mode is enabled for privacy violations in the enforcing pack\'s package.yml file", | ||
| )); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,6 +55,38 @@ pub fn delete_foobar_app_with_custom_readme() { | |
| } | ||
| } | ||
|
|
||
| // Restores the round-trip strict-mode fixture. Its todo file records a strict | ||
| // violation, which is the state `check` tolerance depends on, so any test that | ||
| // runs `update` against it has to put it back. | ||
| #[allow(dead_code)] | ||
| pub fn set_up_uses_strict_mode_round_trip_fixture() { | ||
| let package_todo = String::from( | ||
| "\ | ||
| # This file contains a list of dependencies that are not part of the long term plan for the | ||
| # 'packs/foo' package. | ||
| # We should generally work to reduce this list over time. | ||
| # | ||
| # You can regenerate this file using the following command: | ||
| # | ||
| # bin/packwerk update-todo | ||
| --- | ||
| packs/bar: | ||
| \"::Bar\": | ||
| violations: | ||
| - privacy | ||
| - dependency | ||
|
Comment on lines
+162
to
+163
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This helper hand-writes Harmless at runtime, since the reader collects into a set. The cost is that the round-trip test never compares the file against what Separately, and not about this helper: no fixture anywhere records a single violation type in a strict pack. Both |
||
| files: | ||
| - packs/foo/app/services/foo.rb | ||
| ", | ||
| ); | ||
|
|
||
| fs::write( | ||
| "tests/fixtures/uses_strict_mode_round_trip/packs/foo/package_todo.yml", | ||
| package_todo, | ||
| ) | ||
| .unwrap(); | ||
| } | ||
|
|
||
| // In case we want our tests to call `update` or otherwise mutate the file system | ||
| #[allow(dead_code)] | ||
| pub fn set_up_fixtures() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| enforce_privacy: strict | ||
| enforce_dependencies: strict |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| module Bar | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| enforce_privacy: strict | ||
| enforce_dependencies: strict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This scopes the change to 2 of the 5 checkers, but the filter is checker-agnostic.
checker.rs:245isfilter(|v| v.identifier.strict), and all five arms ofrules_checker_setting()(pack_checker.rs:85-101) can returnCheckerSetting::Strict. Soenforce_layers: strict,enforce_visibility: strict, andenforce_folder_privacy()are all affected too.Confirmed on the layer case, using
layer_violationswithenforce_layers: strictonpacks/feature_flagsand the layer violation recorded in its todo file:Anyone using
enforce_layers: strictto hold a layer boundary hard gets the same silent relaxation, and the entry does not warn them. One line of prose.