-
Notifications
You must be signed in to change notification settings - Fork 28
Add option to write missing error annotations back to the test file. #202
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?
Conversation
3972c10
to
fd900d8
Compare
I already rejected this in the rustc repo: rust-lang/rust#109080 While it may be convenient, me going through 100+ files individually has usually revealed a lot to me and caused me to do follow-up changes. I guess self-reviewing them could yield similar results, but it just feels wrong ^^. Is this really a recurring large issue? Or a problem for beginners or sth? |
This is different than just regenerating the annotations.
This is more of a way to assist with converting a test suite to use annotations. Not really a thing which would be used afterwards. I do agree that doing it all the time does defeat part of the purpose of having annotations. |
/// Whether to write back missing annotations to the test file. | ||
write_back: Option<WriteBackLevel>, |
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.
I wonder if we can make this a standalone emitter instead. Should have all the information available, and can then be combined with an existing emitter, run on its own, or even turned into a runtime switchable mode, all without affecting the core ui_test engine at all
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.
I've been trying to understand ui_test
and these changes. Based on my current (most likely limited) understanding, I think that the emitter would be the wrong place or at least it would be inconsistent with how the normal "bless" works.
Edit: Never mind the later parts of my comment. I just saw that it was incorrect.
yea makes sense. If it can be done as a standalone emitter, I'll take it in this crate just to avoid it bitrotting across version bumps, but then it could be written entirely outside this repo, which is good for encapsulation. |
ping ^^ |
The current api for emitters would require buffering everything until the end since there's currently no way to tell when all the revisions for a test are completed. Adding an extra trait layer like |
We do have Line 46 in 680bb08
Arc<AtomicU8> that you count up and down when adding a revision and when it finishes. When the last one finishes, do the overwriting action.
|
This can now be written as a custom flag. the entire rustfix logic is a custom flag now, and works similarly, so you should be able to implement it the same way. |
@Jarcho Are there any updates on this implementation? I would really like to have this! :D |
I'll look into continuing this implementation, but no promises though... I'm also on summer break, so my time is a bit all over the place. I also wanted to add to a previous discussion
I want this for newcomers and myself. For newcomers it would be super convenient to give them a comment like I would personally also prefer to have the comments automatically added and then review them when doing the git add. If others have a different preference, they can just ignore this option |
@xFrednet I can get to it this week since I'll be mostly off work for a while. Custom flags won't work with how they're currently exposed. There's currently no access to which messages don't have a corresponding annotation. A status emitter could work, but the implementation would be awkward. Would basically look like:
|
Okay, then I'll leave the implementation to you. I'm happy to help if you need any assistance :D |
Outline of what using an annotator looks like: struct AnnotationEmitter;
impl StatusEmitter for AnnotationEmitter {
fn register_test(&self, path: PathBuf) -> Box<dyn TestStatus> {
Box::new(Annotator {
inner: Arc::new(Mutex::new(AnnotatorImpl {
path,
revisions: HashMap::new(),
failed: false,
})),
revision: String::new(),
})
}
fn finalize(
&self,
_failed: usize,
_succeeded: usize,
_ignored: usize,
_filtered: usize,
) -> Box<dyn Summary> {
Box::new(())
}
}
struct AnnotatorImpl {
path: PathBuf,
revisions: HashMap<String, Vec<Message>>,
failed: bool,
}
impl Drop for AnnotatorImpl {
fn drop(&mut self) {
// same as write_back_annotations
}
}
struct Annotator {
inner: Arc<Mutex<AnnotatorImpl>>,
revision: String,
}
impl TestStatus for Annotator {
fn for_revision(&self, revision: &str) -> Box<dyn TestStatus> {
self.inner
.lock()
.unwrap()
.revisions
.insert(revision.to_owned(), Vec::new());
Box::new(Annotator {
inner: self.inner.clone(),
revision: revision.to_owned(),
})
}
fn for_path(&self, _path: &Path) -> Box<dyn TestStatus> {
// do something here.
panic!()
}
fn failed_test<'a>(
&'a self,
_cmd: &'a Command,
_stderr: &'a [u8],
_stdout: &'a [u8],
) -> Box<dyn Debug + 'a> {
struct S;
impl Debug for S {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
Box::new(S)
}
fn update_status(&self, _msg: String) {}
fn done(&self, result: &TestResult) {
if let Err(e) = result {
match &*e.errors {
[] => {}
[Error::ErrorsWithoutPattern { msgs, .. }] => self
.inner
.lock()
.unwrap()
.revisions
.get_mut(&self.revision)
.unwrap()
.extend(msgs.iter().cloned()),
_ => self.inner.lock().unwrap().failed = true,
}
}
}
fn path(&self) -> &Path {
// actually deal with this
panic!()
}
fn revision(&self) -> &str {
&self.revision
}
} Still a few extra things to add before it works and it's quite awkward, but it would work. |
Yea I like that approach. Can you explain why it's awkward for you? Just because I think this is the better approach doesn't make it the better approach |
// For all other revision's messages, remove the ones that exist in all revisions. | ||
print_msgs.retain(|&(i, _, _, rev)| { | ||
rev.is_empty() || counters.get(i).map_or(true, |&x| x != revs.len()) | ||
}); |
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.
maybe do a filter pass on the full data first, and then just print out everything at once instead of mixing the printing and the filtering
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.
I don't see how this comment matches the lines you're commenting on.
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 filtering out of duplicated messages could be a separate pass before the printing. Here it is in the middle of printing logic
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.
The printing code follows immediately after this, it's not in the middle.
A few problems that it has as a status emitter:
The first two issues can just be ignored and it would be fine-ish. The last one means printing needs to be partially reimplemented since we can't use this with the normal status emitter. |
Isn't that the current behaviour? Or I'm misunderstanding what you're saying
Why that? It fails, the next time it may pass. Your changes should not affect the run in which the changes are happening |
The behaviour in this PR changes that into three option: yolo, annotate and error. Using a status emitter allows four options, one of which (yolo + annotate) doesn't work.
Because not doing so is a terrible interface for the same reason printing error messages when blessing stderr output is a terrible interface. |
Ah I see. We could make the annotating emitter a wrapper around any other emitter and not forward the method calls to the nested emitter if we know we're gonna annotate for this test. Even if we are only collecting the annotations to do at once at the end, we know at each error emission whether we'll be able to annotate (even if the annotations may get aggregated). |
"doesn't work" means "getting no annotations done automatically" right? Maybe we can refactor yolo mode in general (or just get rid of it, wasn't the plan to make clippy fully annotated?) |
That is correct. The annotator uses the unmatched annotations error.
IIRC last time this was discussed we decided on transitioning clippy to require annotations.
The way the PR is currently implemented all revisions must pass the other tests (e.g stderr and rustfix) before the annotations are written. I'm not sure if this part is actually a useful constraint or not. Even if we do remove this constraint it still leaves the emitter not composing at all. I'm not sure if this poses a practical issue or not. |
it is, because we want to avoid modifying the tests while other revisions on the same test may be running. I guess we could refactor emitters to handle revisions less independently.
I don't think it's an issue. This is going to get set up once, and the fact that it needs to wrap other emitters will hopefully make ppl read the documentation 😆 |
We will always have to wait until all revisions are done running to get the full list of annotations (to see if the annotation is per-revision or for all revisions). My comment was about whether we block writing annotations to the file if any revision fails. Which is to say we don't know if the current revision should be considered successful until after all revisions have run. The need to buffer test status here would make the implementation awkward. Also somethings that's not currently handled is insertion around existing comments. e.g. converting
to
Not really the biggest problem, but I don't think status emitters are given any access to the parsed comments, let alone the (never actually constructed) list of all comments independent of their revision. |
can't you just use a |
When wrapping an existing status emitter we can't forward the |
Currently has no tests and it can only write error codes. There's also a problem that this does not take into account other annotations already in the file. e.g.
Gets changed to:
This isn't really a big deal to manually fix up, but it would be better if this didn't happen.
This was successfully used on clippy, minus one file which had the aforementioned problem and a few times where rustfmt moved the added annotation.