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

Number of open issue probe #353

Open
wants to merge 50 commits into
base: main
Choose a base branch
from

Conversation

Jagrutiti
Copy link
Member

@Jagrutiti Jagrutiti commented Jul 23, 2023

Description

This probe fetches the number of open issues in a plugin.

Steps:

Create IssueTrackerDetectionProbe, this probe will check whether JIRA, GitHub is configured or both is configured.

  • Return a success as long as at least one issue tracker configured.
  • If no issue tracker is configured that is an error
  • more than one error is a success. Stores which ones are configured.

For GitHubOpenIssuesProbe and JiraOpenIssuesProbe:

  • Create an abstract class. That would be the parent for GitHubOpenIssuesProbe and JiraOpenIssuesProbe.
  • Make sure that IssueTrackerDetectionProbe is executed and success is returned.
  • Get the message of the probe and pass it. Try to see which system is used.
  • Return a Map<key, url>

Some code reusing details:

Basically this from your PR:

       return context.getUpdateCenter()
           .issueTrackers().stream()
           .flatMap(map -> map.entrySet().stream())
           .filter(map -> map.getKey().equals(filter))
           .map(map -> map.getValue())
           .collect(Collectors.toList());
   }

Is your entry point for the new probe

IssueTrackerDetectionProbe
| - GitHubOpenIssuesProbe
| - JiraOpemIssuesProbe
"github" - "https://github.com/
"jira" - "https://issues.jenkins.io

Closes #143

Testing done

Submitter checklist

Edit tasklist title
Beta Give feedback Tasklist Submitter checklist, more options

Delete tasklist

Delete tasklist block?
Are you sure? All relationships in this tasklist will be removed.
  1. If an issue exists, it is well described and linked in the description
    Options
  2. The description of this pull request is detailed and explain why this pull request is needed
    Options
  3. The changeset is on a specific branch. Using feature/ for new feature, or improvements ; Using fix/ for bug fixes ; Using docs/ for any documentation changes.
    Options
  4. If required, the documentation has been updated
    Options
  5. There is automated tests to cover the code change / addition or an explanation why there is no tests in the description.
    Options

@Jagrutiti Jagrutiti self-assigned this Jul 23, 2023
@Jagrutiti Jagrutiti changed the title Open issue probe Number of open issue probe Jul 23, 2023
@Jagrutiti Jagrutiti marked this pull request as ready for review July 30, 2023 15:15
Copy link
Collaborator

@aneveux aneveux left a comment

Choose a reason for hiding this comment

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

Did not get time to finish a full review, but already sharing bunch of comments

@Jagrutiti Jagrutiti marked this pull request as draft August 3, 2023 14:23
@Jagrutiti
Copy link
Member Author

Your reviews help me learn how can I do the same thing in a better way. Thank you for your time.

if you'd like me to do it some other way, just let me know.

I am fine with the current method. It helps me clearly see the line that should be improved and fix similar issues.

I read all the reviews twice, took my time, and then tackled them one by one. This way I understood the bigger picture and avoided the mistakes I made in the past.

Copy link
Collaborator

@aneveux aneveux left a comment

Choose a reason for hiding this comment

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

Few comments from a quick review. General remark: adding Javadocs on the classes you write is also interesting to understand the rationale for classes to exist. It is often a nice thing to read as a first discovery of what a class is for.

core/pom.xml Outdated
Comment on lines 105 to 110
<!-- Used to invoke API calls -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's your rationale for using this Apache httpclient instead of the Java HttpClient for example?

Copy link
Member Author

Choose a reason for hiding this comment

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

Apache HTTPClient is an additional dependency. While I can do the same thing using Java HTTPClient. So I shouldn't be using it.

String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().get("jira");

if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) {
LOGGER.info("JIRA issues not found in Update Center for the plugin.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

For consistency, it would be better to use a similar message than the one used for the same situation with GitHub issues:

The plugin does not use GitHub issues to tracker issues.

(talking about Jira of course)


httpRequest = HttpRequest.newBuilder()
.uri(new URI(api))
.timeout(Duration.of(5, SECONDS))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't this too quick? What is the default value?

IMHO, for any decision like this, it is interesting that you leave a simple comment in the source code explaining why you took that decision, so readers can understand if it is a deliberate choice, and what is the rationale for it.

General remark: remember you mostly write code for other humans, so you need to tell them your intention.

Copy link
Member Author

Choose a reason for hiding this comment

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

The JavaDoc says:

The effect of not setting a timeout is the same as setting an infinite Duration, i.e. block forever.

I was not really sure which value to pick. Honestly, the APIs I had tested took less than a second to respond. So I figured 5 seconds is apt.

What should I actually write as the comment?

Copy link
Collaborator

Choose a reason for hiding this comment

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

What should I actually write as the comment?

The general rule to follow while writing source code is that someone reading it should not have to guess why you did certain things, but should find the information written explicitely.

If you thought that 5 seconds was a good timeout value based on your testing, then write it in a simple comment, so it is now our shared understanding.

Basically, imagine reading that piece of source code if you did not write it yourself, and try to see if you understand everything from what you read.

@@ -112,7 +112,7 @@ public void shouldBeInErrorWhenRepositoryIsNotInOrganization() {

when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter(
Map.of(
pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(
pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like a lot of those Plugin objects are the same, with similar values. Maybe extract that in a variable that can be reused everywhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

Here parameters like pluginName, scmLink, defaultBranch are mocked before being passed.

You do not mean creating a constructor in Record like I already did it once?

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's OK like this

Copy link
Collaborator

@aneveux aneveux left a comment

Choose a reason for hiding this comment

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

Very minor comments. Great job Jagruti!

Just few little things to clean-up and we'll be ready to merge.

@Override
Optional<Integer> getCountOfOpenIssues(ProbeContext context) {
/* Stores the GitHub URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues */
String issueTrackerViewUrl = context.getIssueTrackerUrlsByNames().get("github");
Copy link
Collaborator

Choose a reason for hiding this comment

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

context.getIssueTrackerUrlsByNames() cannot be null right?

If you are not sure, you can add a first check to validate that the plugin has an issue tracker configured? (a simple if before trying to .get("github");)

Copy link
Member Author

Choose a reason for hiding this comment

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

IssueTrackerDetectionProbe is the requirement for GitHubOpenIssuesProbe and UpdateCenterPluginPublicationProbe is the requirement for IssueTrackerDetectionProbe that is why a part of my believes that this issue might not occur.

It is better to be safe than sorry.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I like the "better safe than sorry" principal. 👍

String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().get("jira");

if (viewJiraIssuesUrl == null || viewJiraIssuesUrl.isEmpty()) {
LOGGER.info("The plugin does not use JIRA to track issues.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same remark: which plugin?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think this was addressed.

Copy link
Member Author

Choose a reason for hiding this comment

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

This requires the plugin to be passed as a parameter to getCountOfOpenIssues to get plugin.getName() that is why
did not work on this one.

Copy link
Collaborator

Choose a reason for hiding this comment

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

or you could just provide the name of the plugin, rather than the entire plugin.

Copy link
Member Author

Choose a reason for hiding this comment

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

or you could just provide the name of the plugin, rather than the entire plugin.

I did something similar last time. You said we shouldn't pass a parameter just to display in the logs, But if you are cool with it I can do that,

@@ -112,7 +112,7 @@ public void shouldBeInErrorWhenRepositoryIsNotInOrganization() {

when(ctx.getUpdateCenter()).thenReturn(new UpdateCenter(
Map.of(
pluginName, new io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin(
pluginName, io.jenkins.pluginhealth.scoring.model.updatecenter.Plugin.of(
Copy link
Collaborator

Choose a reason for hiding this comment

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

That's OK like this

aneveux
aneveux previously approved these changes Aug 27, 2023
Copy link
Collaborator

@aneveux aneveux left a comment

Choose a reason for hiding this comment

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

LGTM.

I'll let @alecharp have another look at it in case I missed something, and I believe that'll be ready to merge 🚀

Copy link
Collaborator

@alecharp alecharp left a comment

Choose a reason for hiding this comment

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

there are a few things that were not addressed.

I would like to know why you moved the getSpy method implementation on most (if not all) test classes.

@Override
Optional<Integer> getCountOfOpenIssues(ProbeContext context) {
/* Stores the GitHub URL to view all existing issues in the plugin. Ex: https://github.com/jenkinsci/cloudevents-plugin/issues */
String issueTrackerViewUrl = context.getIssueTrackerUrlsByNames().get("github");
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like the "better safe than sorry" principal. 👍

Comment on lines +56 to +57
HttpClient httpClient;
HttpRequest httpRequest;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree here. those fields should be local variables.

*/
@Override
Optional<Integer> getCountOfOpenIssues(ProbeContext context) {
String viewJiraIssuesUrl = context.getIssueTrackerUrlsByNames().get("jira");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same as before, "better safe than sorry".

Comment on lines 53 to 57
@Override
KnownSecurityVulnerabilityProbe getSpy() {
return spy(KnownSecurityVulnerabilityProbe.class);
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Same as before.

Comment on lines 58 to 62
@Override
protected SpotBugsProbe getSpy() {
return spy(SpotBugsProbe.class);
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Again.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is all because of Ctrl + Alt + L. I did not do it manually.

Comment on lines 51 to 55
@Override
UpForAdoptionProbe getSpy() {
return spy(UpForAdoptionProbe.class);
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Again.

Comment on lines 48 to 52
@Override
UpdateCenterPluginPublicationProbe getSpy() {
return spy(UpdateCenterPluginPublicationProbe.class);
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Again.

@Jagrutiti
Copy link
Member Author

there are a few things that were not addressed.

I would like to know why you moved the getSpy method implementation on most (if not all) test classes.

All I did was Ctrl + Alt + L. It moved because of formatting.

@alecharp
Copy link
Collaborator

alecharp commented Apr 2, 2024

Is this still something you want to contribute @Jagrutiti?

@Jagrutiti
Copy link
Member Author

Is this still something you want to contribute @Jagrutiti?

Yes. I am interested.

I remember this PR wasn't merged because of some code structuring thing and variable scope used in the test cases that you wanted to refactor.

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.

Number of open issues
3 participants