Skip to content
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

Added bug report template generator #1094

Merged
merged 11 commits into from
Dec 1, 2021
Merged

Added bug report template generator #1094

merged 11 commits into from
Dec 1, 2021

Conversation

Kukovec
Copy link
Contributor

@Kukovec Kukovec commented Nov 12, 2021

  • Tests added for any new code
  • Ran make fmt-fix (or had formatting run automatically on all files edited)
  • Documentation added for any new functionality
  • Entry added to UNRELEASED.md for any new functionality

Part 1 of addressing #943:
A bug report file is now automatically generated on FailureMessage in the run directory.

TODO: Add documentation/unreleased

@shonfeder
Copy link
Contributor

I believe we can construct a URL that will open an issue on GitHub, with a parameterized template, rather than pointing users towards a file. Do you think this would be a nicer UI?

See: https://docs.github.com/en/enterprise-server@3.1/issues/tracking-your-work-with-issues/creating-an-issue#creating-an-issue-from-a-url-query

@Kukovec
Copy link
Contributor Author

Kukovec commented Nov 16, 2021

I believe we can construct a URL that will open an issue on GitHub, with a parameterized template, rather than pointing users towards a file. Do you think this would be a nicer UI?

See: https://docs.github.com/en/enterprise-server@3.1/issues/tracking-your-work-with-issues/creating-an-issue#creating-an-issue-from-a-url-query

We discussed this idea with Igor, and the overall conclusion is that it's beneficial to have an artificial barrier between error and bug report, for the simple reason that some users might now want to, or be allowed to, share their specs, and it'd be dangerous if they could accidentally misclick on a link and post the spec.

Copy link
Contributor

@shonfeder shonfeder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, as far as motive for not using the URL to create an issue (tho I'll note that just following the URL doesn't automatically open an issue, the user would still have the chance to remove any sensitive info they wanted to).

I do have one question about the implementation details, regarding how the file location is threaded through, and one suggestion about the approach that leads us to implement an adhoc templating.

Comment on lines 96 to 107
handleExceptions(injector, runParse(injector, parse))(parse.file)

case Some(check: CheckCmd) =>
val injector = injectorFactory(check)
handleExceptions(injector, runCheck(injector, check))
handleExceptions(injector, runCheck(injector, check))(check.file)

case Some(test: TestCmd) =>
val injector = injectorFactory(test)
handleExceptions(injector, runTest(injector, test))
handleExceptions(injector, runTest(injector, test))(test.file)

case Some(typecheck: TypeCheckCmd) =>
val injector = injectorFactory(typecheck)
handleExceptions(injector, runTypeCheck(injector, typecheck))
handleExceptions(injector, runTypeCheck(injector, typecheck))(typecheck.file)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems strange to me that the file is added as an extra argument in all these. Wouldn't the location of this file be a perfect fit for the OutputManager?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, since this is not an output file, but the input specification file passed by the user. It's used to read the specification string, to copy into the issue body.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True the file is not input, but iiuc, it's only use it to construct output for the user (the report template)!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this file is the example.tla in e.g. check example.tla, which can be anywhere on the filesystem and doesn't get copied into the rundir at any point.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that. But the only reason you need to pass it in here is in order to use it for generating the bug report output, no? Anyhow, this isn’t a critical thing. Just seems a bit off to me to be passing in additional arguments here when we already have access to the data via the output manager, which we need anyhow in the bug report template generator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is, the OutputManager doesn't know about this file, because it's not otherwise related to outputs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't know currently, true :)

My main rationale here is about keeping the dataflow simple. With this change, we get something like the following:

CLIArgs -----------------------------------+
 |                                         |
 |                                         |
 \/                                       \/
OutputManager ---------------> exceptionHandler ------> ReportGenerator

And what I'm advocating for is keeping this flat, mostly because I just don't see a good reason not to:

CLIArgs -----> OutputManager ---------------> exceptionHandler ------> ReportGenerator

The main practical implication being we don't need to extract and thread through the file argument for each subsequent invocation of the exceptionHandler we might add.

But the stakes around this are small, so happy to leave to your discretion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems sensible, but at the same time, probably scope creep for this particular PR. You should make an issue for it though, since I can see it being relevant again with the other part of #943, where the error explainer displays the contents of the input file line where the issue is, for which it will need access to the source file too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should only a take a few lines of code to make the proposed change, but if you'd rather, perhaps leave a note on #1069 that this should be corrected as part of that work, and I can take care of it later this week?

Comment on lines 1 to 12
<!-- Thank you for filing a report! Please ensure you have filled out all -->
<!-- sections, as it help us to address the problem effectively. -->

## Input specification

```
__SPEC
```

## The command line parameters used to run the tool

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any added value to making this a standalone file that has to be included in the resources that you have in mind?

My initial thought is that this adds some unneeded complexity (an additional resource, then adhoc templating logic), but it seems our usecase could be served just as well with a function that has this string in and just uses Scala's string interpolation for templating. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could just have a string, that's true, but the string would be messy to write, and it's easy to edit the .md file as a standalone file to get the desired formatting. I guess string interpolation is better than replacement, so the question is really whether we intend to change the bug report template at all. If the answer is "not really", I suppose we can copy the file into a string.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, it would simplify the code enough to justify, and editing a multiline string in a .scala file is just as easy as editing a multiline string a .md file IMO :) But I won't block on this and am OK leaving it up to whatever you think best.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ambivalent on this, if you'd prefer a string it's easy enough to include.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, the reasons for making it a string, imo, are these:

  • Eliminate an external resource.
  • Eliminate one IO operation.
  • Reduce the logic of this changeset (I think approximately halving it)?

The one advantage I've thought of for keeping this as an external .md file is that could enable us to keep the github issue template and this template in sync. However, that's not currently the case, and it's not immediately clear to me how we'd achieve that synchronization.

So, in my estimation, unless we want to invest in ensuring those two files are kept in sync, I do find the idea of just inlining the string preferable.

But, as I said, this isn't a super hard preference on my side.

Comment on lines 1 to 12
<!-- Thank you for filing a report! Please ensure you have filled out all -->
<!-- sections, as it help us to address the problem effectively. -->

## Input specification

```
__SPEC
```

## The command line parameters used to run the tool

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, it would simplify the code enough to justify, and editing a multiline string in a .scala file is just as easy as editing a multiline string a .md file IMO :) But I won't block on this and am OK leaving it up to whatever you think best.

Comment on lines 96 to 107
handleExceptions(injector, runParse(injector, parse))(parse.file)

case Some(check: CheckCmd) =>
val injector = injectorFactory(check)
handleExceptions(injector, runCheck(injector, check))
handleExceptions(injector, runCheck(injector, check))(check.file)

case Some(test: TestCmd) =>
val injector = injectorFactory(test)
handleExceptions(injector, runTest(injector, test))
handleExceptions(injector, runTest(injector, test))(test.file)

case Some(typecheck: TypeCheckCmd) =>
val injector = injectorFactory(typecheck)
handleExceptions(injector, runTypeCheck(injector, typecheck))
handleExceptions(injector, runTypeCheck(injector, typecheck))(typecheck.file)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True the file is not input, but iiuc, it's only use it to construct output for the user (the report template)!


new File(
OutputManager.runDirPathOpt
.getOrElse(throw new IllegalStateException("run directory is not configured"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using OutputManager.runDir will already check for the state validity, and raise an appropriate error if its not configurd, so think this can OutputManager.runDir.resolve(reportFile).normalize.toString to

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OutputManager.runDir does not exist.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/**
* Accessor for the configured run directory.
*
* @throws IllegalStateException if called before OutputManager is configured: this is considered an implementator error
*/
def runDir: Path = {
runDirOpt.getOrElse(throw new IllegalStateException("run directory does not exist"))
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is from a recent commit merged into unstable that isn't on this branch yet. I guess we can use that after I rebase in unstable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. All our PR's should assume the code available in unstable I think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, but I understand. This was only just slipped in with the latest changes to the OutputManager I think. Make sense it wasn't used initially!

@shonfeder shonfeder self-requested a review November 30, 2021 16:27
Comment on lines 96 to 107
handleExceptions(injector, runParse(injector, parse))(parse.file)

case Some(check: CheckCmd) =>
val injector = injectorFactory(check)
handleExceptions(injector, runCheck(injector, check))
handleExceptions(injector, runCheck(injector, check))(check.file)

case Some(test: TestCmd) =>
val injector = injectorFactory(test)
handleExceptions(injector, runTest(injector, test))
handleExceptions(injector, runTest(injector, test))(test.file)

case Some(typecheck: TypeCheckCmd) =>
val injector = injectorFactory(typecheck)
handleExceptions(injector, runTypeCheck(injector, typecheck))
handleExceptions(injector, runTypeCheck(injector, typecheck))(typecheck.file)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should only a take a few lines of code to make the proposed change, but if you'd rather, perhaps leave a note on #1069 that this should be corrected as part of that work, and I can take care of it later this week?

s"${Version.version} build ${Version.build}"
)
Console.err.println(
s"Please report an issue at $ISSUES_LINK: $e\nA bug report template has been generated at [$absPath]."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
s"Please report an issue at $ISSUES_LINK: $e\nA bug report template has been generated at [$absPath]."
s"Please report an issue at $ISSUES_LINK: $e\nA bug report has been generated at [$absPath]."

Iiuc, we are generating the report using the template?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, the user is still meant to fill in "Expected Behavior". I'll add a prompt to do that in the stdout string.

@shonfeder
Copy link
Contributor

Whenever you're ready for me to have another look, please re-request review by clicking the little recycle symbol by my name in the requested reviewers :)

Copy link
Contributor

@shonfeder shonfeder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two questions, but not all blocking. LGTM!

Nice that we have removed even more IO operations by caching the source file!

Comment on lines +55 to +61
// Should be called only if input is a .tla file
def initSourceLines(file: File): Unit =
if (sourceLinesOpt.isEmpty) {
val src = Source.fromFile(file)
try sourceLinesOpt = Some(src.getLines().toIndexedSeq)
finally src.close()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should it only be called on TLA files? Why not also store the lines from other kinds of input?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because JSON file lines don't correspond to anything sensible (in fact, the location fields in the JSON reference the original spec's line numbers) and tnt isn't implemented yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON file lines would correspond to the JSON source data, at least. Couldn't we get an error that related to some data coming from a bit of bad json?

the location fields in the JSON reference the original spec's line numbers

This makes me wonder whether we are asking for trouble by introducing a new way to count line numbers (outside of the one we are currently using for source mapping.....).

Would the correct logic here not then be to parse the spec from the JSON file that was input and save that in memory here?


// Can't access Version in IO, have to pass at call site
def prepareReportFile(cmdStr: String, versionStr: String): String = {
val specTxt = OutputManager.getAllSrc.getOrElse("")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this perhaps return some message if the spec cannot be loaded? Like unable to read specification or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean as a log/stdout message or as a replacement for "" in getOrElse?
The latter sounds like a good idea, the former not so much. The only scenario where this returns "" is when you call Apalache on a .json file. In that case, there's really no spec to attach to the template (I do not want to encourage people to attach JSON specs in bug reports).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant in the generated bug template, yeah, just so we know what it means if we get an empty string there. Not at all critical. Makes sense about not getting giant json outputs :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, it should now print a <!-- TLA+ specification not found. --> in the else case.

Copy link
Contributor

@shonfeder shonfeder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Still LGTM :)

Copy link
Contributor

@shonfeder shonfeder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry! I’d meant to approve before too.

@Kukovec Kukovec merged commit 6857ddc into unstable Dec 1, 2021
@Kukovec Kukovec deleted the jk/autoBugReport branch December 1, 2021 19:30
This was referenced Dec 6, 2021
shonfeder pushed a commit that referenced this pull request Mar 17, 2022
Closes #1502

Followup to #1094, which added a file read for the debug template that
is outside the scope of our standard error handling.

The fix here is just to ensure the file exists before trying to
initialize the "sourceLines" tracker.
shonfeder pushed a commit that referenced this pull request Mar 17, 2022
Closes #1502

Followup to #1094, which added a file read for the debug template that
is outside the scope of our standard error handling.

The fix here is just to ensure the file exists before trying to
initialize the "sourceLines" tracker.
shonfeder pushed a commit that referenced this pull request Mar 17, 2022
Closes #1502

Followup to #1094, which added a file read for the debug template that
is outside the scope of our standard error handling.

The fix here is just to ensure the file exists before trying to
initialize the "sourceLines" tracker.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants