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

GitHub Status API Integration #412

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

europ
Copy link
Member

@europ europ commented Mar 7, 2018

This feature will allow miq-bot to mark the latest commit with a status which depends from the offence(s).

Commits are marked with success or error state based on offence(s) detection via create_status. If there are any offences in the code, the latest commit is marked with error state, otherwise with success state. It is reflected at the end of pull request in the checks section. The status also involves a reference (URL) to the comment which has the description about the offences.

Detailed description about the creation of a commit status.

The commit state is stated in rubocop_checker.rb which will be used as a marking state for the last commit. This state is passed to the replace_comments method in github_service.rb as an optional parameter also with the hash (sha) of the last commit which is going to be marked with this state. In replace_comments the comment(s) writing is firstly proceed as it was originally. After writing the comment(s) about the offence(s) the id of each comment is preserved due to the missing URL which will be used in the commit status as a reference to the comment including the commit status description including the offence(s). The first comment id is selected and a payload is created which is required for the create_status. Obtaining these information, the last commit is marked with the adequate state, a little state description and link to the comment including detailed description.

\cc
@skateman
@romanblanco


Preview

  • success

good_status

  • error

bad_status

NOTE: The Details refers to the comment shown above.

@europ europ changed the title Integration of GitHub Status API GitHub Status API Integration Mar 7, 2018
@europ europ force-pushed the commit_status branch 3 times, most recently from 0f24fbc to cfe0348 Compare March 7, 2018 17:58
Copy link
Member

@skateman skateman left a comment

Choose a reason for hiding this comment

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

Looks good, but some things can be simplified and logically reorganized. Also please add some tests.

@@ -34,12 +34,14 @@ def process_branch
end

def rubocop_comments
MessageBuilder.new(results, branch).comments
message_builder = MessageBuilder.new(results, branch)
@status = message_builder.commit_status
Copy link
Member

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 is The Right Way™ to pass the information, the rubocop_comments method is being used just in the replace_rubocop_comments method, so it's safe to move its content there. This way you don't need the instance variable at all. Then you can refactor or even rename the method and maybe break it into small(er) chunk.

end

def replace_rubocop_comments
logger.info("Updating PR #{pr_number} with rubocop comment.")
GithubService.replace_comments(fq_repo_name, pr_number, rubocop_comments) do |old_comment|
GithubService.replace_comments(fq_repo_name, pr_number, rubocop_comments, @status) do |old_comment|
Copy link
Member

Choose a reason for hiding this comment

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

See my comment above...


unless commit_status.nil?
commit_status["options"]["target_url"] = retval["html_url"]
add_status(commit_status)
Copy link
Member

Choose a reason for hiding this comment

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

Adding the status is depending on the comment's ID, however, it is an operation on the same level so this method call doesn't belong here, but AFTER the add_comments is called.

raise "no block given" unless block_given?

to_delete = issue_comments(fq_repo_name, issue_number).select { |c| yield c }
delete_comments(fq_repo_name, to_delete.map(&:id))
add_comments(fq_repo_name, issue_number, new_comments)
add_comments(fq_repo_name, issue_number, new_comments, commit_status)
Copy link
Member

Choose a reason for hiding this comment

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

I think you should put the add_status call after this line, see above...

Gemfile.lock Outdated
@@ -396,4 +396,4 @@ DEPENDENCIES
webmock

BUNDLED WITH
1.15.4
1.16.1
Copy link
Member

Choose a reason for hiding this comment

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

Don't forget to change this back please...

@europ europ force-pushed the commit_status branch 3 times, most recently from ef1f877 to bb0aee2 Compare March 8, 2018 09:21
GithubService.replace_comments(fq_repo_name, pr_number, rubocop_comments) do |old_comment|
msg_builder_result = rubocop_comments

GithubService.replace_comments(fq_repo_name, pr_number, msg_builder_result[:comments], msg_builder_result[:status]) do |old_comment|
Copy link
Member

Choose a reason for hiding this comment

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

Do you really need the 2 arguments if you're taking them from the same hash? Send the whole hash instead!

@@ -14,6 +14,20 @@ def comments
message_builder.comments
end

# requirements to "create_status(repo, sha, state, options)"
def commit_status
Copy link
Member

Choose a reason for hiding this comment

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

Why is this method under the MessageBuilder? Maybe this can be moved to a better place.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed. This feels like it should live somewhere else.

Copy link
Member Author

Choose a reason for hiding this comment

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

@skateman @Fryguy The commit_status method is now in the MessageBuilder.

first_comment = add_comments(fq_repo_name, issue_number, new_comments)

# add_status creates a commit status pointing to the first comment URL
add_status(commit_status, first_comment)
Copy link
Member

Choose a reason for hiding this comment

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

add_status(commit_status, first_comment) unless first_comment.nil?

Then you don't need the condition in the add_status.

def add_status(comstat, comment)
unless comstat.nil?
comstat["options"]["target_url"] = comment["html_url"]
create_status(comstat["repo"], comstat["sha"], comstat["state"], comstat["options"])
Copy link
Member

Choose a reason for hiding this comment

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

Again, you're sending arguments from a single hash, these things can be simplified.

@europ europ force-pushed the commit_status branch 2 times, most recently from 4395636 to d59d903 Compare March 8, 2018 10:31
add_comment(fq_repo_name, issue_number, comment)
end
end.first
Copy link
Member

Choose a reason for hiding this comment

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

I like the idea of returning the comments, but from a clean standpoint, this method should just return all of the comments. If the caller only needs the first one, they should be the one to call .first. This way you also don't need the comment describing why you need the .first.

@europ europ force-pushed the commit_status branch 2 times, most recently from 9f39949 to 85b2f5a Compare March 12, 2018 12:42
"state" => state ? "success" : "error",
"options" => {
"context" => "miq-bot", # TODO: it should be user name variable
"target_url" => nil,
Copy link
Member

Choose a reason for hiding this comment

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

Why is this nil? Can't be this parametrized as state?

Copy link
Member Author

Choose a reason for hiding this comment

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

@skateman The key is required and the value is added when the URL of the comment is obtained.

Copy link
Member

Choose a reason for hiding this comment

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

OK, what about the 2nd part of the question? 😉

@europ europ force-pushed the commit_status branch 4 times, most recently from 42e8f34 to 9699f2d Compare March 12, 2018 14:09
@skateman
Copy link
Member

@europ please don't mark this as ready until you have tests.

@miq-bot add_label wip

@miq-bot miq-bot changed the title GitHub Status API Integration [WIP] GitHub Status API Integration Mar 19, 2018
@miq-bot miq-bot added the wip label Mar 19, 2018
@europ europ force-pushed the commit_status branch 3 times, most recently from 56fc858 to 20a574f Compare March 21, 2018 12:06
@europ
Copy link
Member Author

europ commented Mar 21, 2018

@miq-bot remove_label wip

@europ europ changed the title [WIP] GitHub Status API Integration GitHub Status API Integration Mar 21, 2018
@miq-bot miq-bot removed the wip label Mar 21, 2018
@europ europ force-pushed the commit_status branch 2 times, most recently from caad3ad to b0e6911 Compare March 21, 2018 14:09
@@ -39,7 +39,10 @@ def rubocop_comments

def replace_rubocop_comments
logger.info("Updating PR #{pr_number} with rubocop comment.")
GithubService.replace_comments(fq_repo_name, pr_number, rubocop_comments) do |old_comment|

status = results["files"].select { |f| f["offenses"].any? }.empty?
Copy link
Member

Choose a reason for hiding this comment

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

Can you just do status = results["files"].any? { |f| f["offenses"].any? } ?

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 works exactly the opposite. I will have to negate it as

status = !results["files"].any? { |f| f["offenses"].any? }

otherwise I will have to remake the rest of the code. Do you agree with the negation?

Copy link
Member

Choose a reason for hiding this comment

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

if you're looking for the negation, then you can also do

results["files"].none? { |f| f["offenses"].any? }

first_comment = add_comments(fq_repo_name, issue_number, new_comments).first

# add_status creates a commit status pointing to the first comment URL
unless first_comment.nil? && status.nil?
Copy link
Member

Choose a reason for hiding this comment

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

unless nil && nil is melting my head with triple-negatives. This would be much easier to read in the positive. I think it's

if first_comment && status
  add_status(...)
end

Copy link
Member Author

Choose a reason for hiding this comment

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

@Fryguy Can it be like this?

if first_comment && !status.nil?
  add_status(...)
end

The status variable contain a boolean value so your example will not work in case of status has False value.

Copy link
Member

Choose a reason for hiding this comment

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

Ah ok, then yes, first_comment && !status.nil? is good.


RSpec.describe GithubService do
let(:repo) { "owner/repository" }
let(:sha) { "cd16q9z48b3b0xbb91wb311" }
Copy link
Member

Choose a reason for hiding this comment

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

Pretty sure a SHA only has hexidecimal digits ;)

@Fryguy
Copy link
Member

Fryguy commented Mar 26, 2018

high level I like the ability to use the github api status, but I'm not sure I want to block the PR expect in specific cases (like 💣 💥 🔥 🚒)

@skateman
Copy link
Member

@Fryguy by block do you mean red status? AFAIK we don't block PRs based on any status...

@Fryguy
Copy link
Member

Fryguy commented Mar 26, 2018

Sorry, yes, red status. If too many PRs go "red" then it's harder for reviewers to differentiate between actual failed PRs (i.e. travis didn't pass) vs not actually failed PRs (like how when code climate goes red on 1 new issue).

@skateman
Copy link
Member

@Fryguy this makes sense, so let's add a green status when all is good and a red when 💣 💥 🔥 🚒 happens. For other cases I would just simply not set the status...what do you think?

@europ
Copy link
Member Author

europ commented Apr 24, 2018

Based on the pull request review from @skateman and @Fryguy this feature was a little bit changed.

There are now 3 types of statuses:

  • Green "success" status (zero offenses)

    status_green

  • Red "error" status (at least one fatal or error offense)

    status_red

  • No status (other offense types such as warning, informing, etc.)

    status_none

@Fryguy
Copy link
Member

Fryguy commented May 8, 2018

@europ I'm thinking the third case

No status (other offense types such as warning, informing, etc.)

should still show the status API entry, but it should be a) green and b) say something like "Changes requested"

@europ
Copy link
Member Author

europ commented May 8, 2018

@Fryguy There is a possibility to use "yellow" status - the pending status.

There are 4 available statuses:

  • failure - this means an internal error (red) - this will not be used
  • error - at leas one 💣 💥 🔥 🚒 offense (red)
  • pending - detected offenses required to fix (yellow)
  • success - no offense detected (green)

Would you like to use the "yellow" one (pending status) for this case with a message "detected offenses required to fix"?

@Fryguy
Copy link
Member

Fryguy commented May 8, 2018

The problem there is that when PR reviewers see "yellow" they think "the CI for this PR is still running", which is not what we want. I'm thinking just use green.

Commits are marked with [success/error] state depending on offence detection. If there are any offences in the code, the commit is marked with error state otherwise with success state. It is reflected at the end of PR in the check conclusion part.
@europ
Copy link
Member Author

europ commented May 16, 2018

@Fryguy The commits are from now marked every time depending of the detected offences as you requested.

There are 3 types of commit marking:

  1. zero offences:
    "success" status + "Everything looks fine."
  2. one or more warning offences excluding 💣 💥 🔥 🚒 offences:
    "success" status + "Some offenses detected."
  3. at least one 💣 💥 🔥 🚒 offence:
    "error" status + "Something went wrong."

@miq-bot
Copy link
Member

miq-bot commented May 16, 2018

Checked commit europ@1354dd8 with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0
4 files checked, 0 offenses detected
Everything looks fine. 🍪

@miq-bot
Copy link
Member

miq-bot commented Mar 16, 2020

This pull request is not mergeable. Please rebase and repush.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants