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

Allow to skip a build on commit messages #3457

Closed
wants to merge 24 commits into from

Conversation

stsewd
Copy link
Member

@stsewd stsewd commented Dec 28, 2017

This implements a feature discussed here #871

When a webhook is called, its receive the last commit after the push event,
the following marks are searched in the commit message:

  • [skip doc]
  • [skip docs]
  • [docs skip]
  • [doc skip]

If one is found, the build process is skipped.

Still wip, this is what I have so far:

  • Change GitHub webhook
  • Change GitLab webhook
  • Change BitBucket webhook
  • Change Generic webhook (backwards compatible)
  • fix tests
  • Add tests
  • Update docs

@@ -159,7 +167,13 @@ def handle_webhook(self):
# Handle push events and trigger builds
if event == GITHUB_PUSH:
try:
branches = [self.data['ref'].replace('refs/heads/', '')]
branch = {
Copy link
Member Author

Choose a reason for hiding this comment

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

I change branch to be a dict with name and last_commit as elements.
last_commit must have an id and message.

branch = {
'name': self.request.data['ref'].replace('refs/heads/', ''),
# Assuming the first element is the last commit.
'commit': self.request.data['commits'][0],
Copy link
Member Author

@stsewd stsewd Dec 28, 2017

Choose a reason for hiding this comment

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

Not sure about this, didn't found much documentation about this on gitlab.

}
}]
}

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 is what I proposed for the general webhook, maintaining the backwards compatibility.

version.slug
for version in versions
}
return (to_build, not_building)
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 is the logic for skipping the build, not sure if this is the correct place

Copy link
Member

Choose a reason for hiding this comment

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

So, if the last commit contains the mark we don't build any version?

I'm confused here since the next few lines there is a logic that can build some version but not some others comming in the same webhook, right? Shouldn't we apply a similar logic here also?

That to_build and not_building rely on the function _build_version. So, this logic shouldn't be in that method? (I don't know, but is has the logging integrated and returns what it needs. On the other hand, it seems that we shouldn't call that method if we already know that we need to skip the version but there are some logic to skip versions inside that function too :/

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm confused here since the next few lines there is a logic that can build some version but not some others comming in the same webhook, right? Shouldn't we apply a similar logic here also?

Of what I understand, a branch/tag/commit can be tied to various versions so there is only one commit message for all versions, this means that all versions from this branch aren't going to be built. And also is about what you mention, we already know if the version isn't going to be built.

...
}

See full payload here:
https://developer.github.com/v3/activity/events/types/#pushevent
Copy link
Member Author

Choose a reason for hiding this comment

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

Are we using the v3 of the gh api?

Copy link
Member

Choose a reason for hiding this comment

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

It seems, https://developer.github.com/v3/#current-version, since we are not sending the Accept header and v3 is the default.

Copy link
Member Author

@stsewd stsewd Feb 18, 2018

Choose a reason for hiding this comment

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

And also v4 is using GraphQL, this will break everything.

Tests from generic aren't updated for now
Json and urlencoded test case
@@ -62,15 +71,17 @@ def test_exchange_form_request_body(self):
integration = fixture.get(Integration, project=project,
integration_type=Integration.GITHUB_WEBHOOK,
provider_data='')
resp = client.post(
payload_decode = '{"head_commit": {"id": "3eea78b2", "message": "Update README.md"}, "ref": "exchange_form"}'
payload_encode = '%7B%22head_commit%22%3A%20%7B%22id%22%3A%20%223eea78b2%22%2C%20%22message%22%3A%20%22Update%20README.md%22%7D%2C%20%22ref%22%3A%20%22exchange_form%22%7D'
Copy link
Member Author

Choose a reason for hiding this comment

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

I use this tool for encode/decode https://meyerweb.com/eric/tools/dencoder/

Note: the order matters!

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 do this with a Python function to encode a JSON into an URL query string? (it should be there one in the standard library)

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, I think that's cleaner, just wanted to keep to the current tests style.

@stsewd
Copy link
Member Author

stsewd commented Dec 29, 2017

While updating some tests, I found that there is some old webhook code (https://github.com/rtfd/readthedocs.org/blob/master/readthedocs/core/views/hooks.py#L158) that is marked as deprecated, should we remove this code? (another PR?) o should we still support the v1 webhooks?

@humitos humitos added the PR: work in progress Pull request is not ready for full review label Dec 29, 2017
@humitos
Copy link
Member

humitos commented Feb 15, 2018

that is marked as deprecated, should we remove this code? (another PR?) o should we still support the v1 webhooks?

Hehe, I asked the same to Eric and he checked the logs: many people still use this so we can't remove this endpoint :(

@@ -66,6 +66,23 @@ def _build_version(project, slug, already_built=()):
return None


def _contains_skip_mark(commit):
Copy link
Member

Choose a reason for hiding this comment

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

Receive the message itself, instead of relying on a commit object.

to_build = set()
not_building = set()
if _contains_skip_mark(commit):
log.info('(Branch Build) Skip build %s', project.slug)
Copy link
Member

Choose a reason for hiding this comment

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

Add the reason of the skip, like "because contains skip mark" or something better :)

Copy link
Member

@humitos humitos left a comment

Choose a reason for hiding this comment

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

I like the addition of this new feature.

Although, I think it needs more work and make some decision on the logic/flow followed when a webhook is received. It's still kind of complex to me how the path is and "where this code should live" (the skip you wrote).

Please, take a look at my comments and let's keep discussing where and how :)

version.slug
for version in versions
}
return (to_build, not_building)
Copy link
Member

Choose a reason for hiding this comment

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

So, if the last commit contains the mark we don't build any version?

I'm confused here since the next few lines there is a logic that can build some version but not some others comming in the same webhook, right? Shouldn't we apply a similar logic here also?

That to_build and not_building rely on the function _build_version. So, this logic shouldn't be in that method? (I don't know, but is has the logging integrated and returns what it needs. On the other hand, it seems that we shouldn't call that method if we already know that we need to skip the version but there are some logic to skip versions inside that function too :/

...
}

See full payload here:
https://developer.github.com/v3/activity/events/types/#pushevent
Copy link
Member

Choose a reason for hiding this comment

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

It seems, https://developer.github.com/v3/#current-version, since we are not sending the Accept header and v3 is the default.

@@ -75,9 +92,17 @@ def build_branches(project, branch_list):
not_building - a list of branches that we won't build
"""
for branch in branch_list:
versions = project.versions_from_branch_name(branch)
commit = branch['last_commit']
versions = project.versions_from_branch_name(branch['name'])
Copy link
Member

Choose a reason for hiding this comment

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

Why did you change branch by branch['name'] here?

Copy link
Member Author

Choose a reason for hiding this comment

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

branches = [self.request.data['ref'].replace('refs/heads/', '')]
# GitLab only returns one branch.
branch = {
'name': self.request.data['ref'].replace('refs/heads/', ''),
Copy link
Member

Choose a reason for hiding this comment

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

Won't this interferes with your other PR at #3546?

Copy link
Member Author

Choose a reason for hiding this comment

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

Just when merging/rebasing, on the logic everything would work as expected :)

# Assuming the first element is the last commit.
'last_commit': self.request.data['commits'][0],
}
branches = [branch]
Copy link
Member

Choose a reason for hiding this comment

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

Another thought here... If we already know at this point the last commit message, shouldn't skip here the call to self.get_response_push instead of going deeper in the path?

Copy link
Member Author

Choose a reason for hiding this comment

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

We need the (buid, not_building) from the build_branches function to make the response.

@@ -62,15 +71,17 @@ def test_exchange_form_request_body(self):
integration = fixture.get(Integration, project=project,
integration_type=Integration.GITHUB_WEBHOOK,
provider_data='')
resp = client.post(
payload_decode = '{"head_commit": {"id": "3eea78b2", "message": "Update README.md"}, "ref": "exchange_form"}'
payload_encode = '%7B%22head_commit%22%3A%20%7B%22id%22%3A%20%223eea78b2%22%2C%20%22message%22%3A%20%22Update%20README.md%22%7D%2C%20%22ref%22%3A%20%22exchange_form%22%7D'
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 do this with a Python function to encode a JSON into an URL query string? (it should be there one in the standard library)

@humitos
Copy link
Member

humitos commented Feb 15, 2018

Also, if you can, please add test cases for this specific feature so we can be sure that it works and then we are safe while refactoring/restructuring the code.

@stsewd
Copy link
Member Author

stsewd commented Feb 18, 2018

@humitos thanks for the feedback, I have improve the log and added some tests, I also made sure to keep the changes backwards compatible with the old webhooks and with the generic webhook.

@stsewd
Copy link
Member Author

stsewd commented Apr 11, 2018

Some previous tests were wrong and pass unnoticed because of the old mock library. Everything is correct now (I think).

@stsewd stsewd added PR: ready for review and removed PR: work in progress Pull request is not ready for full review labels Apr 11, 2018
@ericholscher
Copy link
Member

Feels like this has a larger refactor in it. Is this still something useful that we should try and get in?

@stsewd
Copy link
Member Author

stsewd commented Nov 2, 2018

Feels like this has a larger refactor in it. Is this still something useful that we should try and get in?

Hmm, not sure. This will allow users to help us to save some resources, but I don't know how much.

@humitos
Copy link
Member

humitos commented Nov 6, 2018

This is "nice to have" but I'm not sure that it worth to add this complexity to the code. Also, I'm not sure how many people will use this feature in the end since it's something manually that also could "mess/dirty" the commit messages from the repo.

@stsewd stsewd added the Needed: design decision A core team decision is required label Nov 21, 2018
@humitos
Copy link
Member

humitos commented Jan 9, 2019

I'm closing this PR here because it was off our roadmap and we consider that adding this complexity to the code base for a feature that will affect more our servers than the user itself does not worth it.

Thanks a lot for this code and I'm sorry that it's not going to be merged 😞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needed: design decision A core team decision is required
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants