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

Emoji approve based on changes and code owners #254

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

lkm
Copy link

@lkm lkm commented Apr 24, 2020

I followed on from the work done by @FlorianLudwig on #247 and #145 and added parsing of changes set to determine who should be able to approve (using the emoji award thumbup).

At the moment I parse CODEOWNERS and require all matched users to have approved. This is probably far from ideal in practice so either we add it as a command line switch or using the suggested .marge-bot.yml file or add some parsable comment #<MIN_REQUIRED:2> to the codeowners file to avoid having to make too many API calls to gitlab. In any case we should also handle cases where available reviewers < required reviewers.

@lkm
Copy link
Author

lkm commented Apr 25, 2020

Updated to pass linting and also add a comment to the merge request with a list of valid approvers as parsed from codeowners and change set of the MR.

@lkm lkm force-pushed the emoji_approve branch 2 times, most recently from bc8ec6a to 4b95950 Compare April 25, 2020 11:41
README.md Outdated Show resolved Hide resolved
# Multiple codeowners can be specified, separated by spaces or tabs
CODEOWNERS @multiple @code @owners

# Both usernames or email addresses can be used to match
Copy link
Contributor

Choose a reason for hiding this comment

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

Reading the code only usernames not email addresses work.

Copy link
Author

Choose a reason for hiding this comment

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

This might fall into the same category as the group comment, I wonder what would be the best way to support emails or whether it's necessary? AFAIK gitlab only supports @username format in the comments so it would take another lookup to the users api to find username for the comment that gets added to the MR. It might be simpler than it sounds, will have a look at it


# Group names can be used to match groups and nested groups to specify
# them as owners for a file
README @group @group/with-nested/subgroup
Copy link
Contributor

Choose a reason for hiding this comment

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

groups seem not implemented

Copy link
Author

Choose a reason for hiding this comment

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

Good point! I actually just copied the example CODEOWNERS file from the Gitlab documentation to make sure that the file could be parsed correctly for the tests. While support for groups would be amazing I think that's something that should be done in a follow-up MR. I'll remove those references in the test as it's confusing.

@FlorianLudwig
Copy link
Contributor

@lkm this is pretty awesome! Will try it out today. But already left some comments of my first thoughts. I do prefer the CODEOWNERS file over having a new custom format. Do you have an idea how to handle an approver count setting?

@lkm
Copy link
Author

lkm commented Apr 27, 2020

Cheers @FlorianLudwig. I haven't had a chance to test this in prod yet, but will update our marge-bot installation later today and probably update this MR with anything I find.

Re the approver count. We need a per project setting for sure, and I agree that it would be undesirable to have the new file, and while I do prefer the structure of a yaml file. I think it would be very simple to add parsing of a line from CODEOWNERS, e.g.:

# MARGEBOT_MINIMUM_APPROVERS=1

And perhaps default to either 1 or all appropriate (all matches) code owners? Let me know what you think.

@lkm
Copy link
Author

lkm commented Apr 27, 2020

Alright that's been done now. I've also updated the README file to reflect the changes

@FlorianLudwig
Copy link
Contributor

Re the approver count. We need a per project setting for sure, and I agree that it would be undesirable to have the new file, and while I do prefer the structure of a yaml file. I think it would be very simple to add parsing of a line from CODEOWNERS, e.g.:

# MARGEBOT_MINIMUM_APPROVERS=1

And perhaps default to either 1 or all appropriate (all matches) code owners? Let me know what you think.

I was thinking exactly the same.

@carno
Copy link

carno commented Sep 18, 2020

@lkm do You intend to continue work on this pull request?

@lkm
Copy link
Author

lkm commented Sep 22, 2020

@carno I think it's pretty complete as is. The only thing I would say is that since last release Gitlab supports approvals (only optional not required) in the free version which was my main motivations for this MR, so maybe that can be utilised for a better approach than the awards api.

@sysadmiral
Copy link

sysadmiral commented Oct 28, 2020

I would still find this emoji based approach useful on gitlab.com.

Currently since marge cannot impersonate approvers on the hosted version if a branch gets rebased the approval is removed and marge-bot cannot do anything.

With the emoji approach the "approval" remains on the merge request even after a rebase.

This does mean that with the merge request itself there is no longer an actual Gitlab approval attached to the MR but doesn't the reviewed-by footer kind of negate the need for this?

Copy link
Contributor

@nejch nejch left a comment

Choose a reason for hiding this comment

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

@tclh123 just wanted to bring some attention to this PR so I've added my own comments (not sure if @lkm is still interested in this. A lot has changed since April 2020 including Approvals in CE, and a standalone codeowners library is available for python now.

return self._api.call(GET(emoji_url))

def get_codeowners_ce(self):
config_file = self._api.repo_file_get(self.project_id, "CODEOWNERS", "master")
Copy link
Contributor

Choose a reason for hiding this comment

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

This should point to the project's default_branch from the API response instead a hardcoded master IMO (you have develop, development, devel, main, etc)

Copy link
Author

Choose a reason for hiding this comment

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

I agree. I will have a look at this

Comment on lines +96 to +114
for line in config_file['content'].splitlines():
if 'MARGEBOT_' in line:
match = required_regex.match(line)
if match:
required = int(match.group(1))

if line != "" and not line.startswith(' ') and not line.startswith('#'):
elements = shlex.split(line)
glob = elements.pop(0)
owner_globs.setdefault(glob, set([]))

for user in elements:
owner_globs[glob].add(user.strip('@'))
Copy link
Contributor

Choose a reason for hiding this comment

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

The matching order for patterns should be ordered and reversed, see https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners (gitlab has the same):

# Order is important; the last matching pattern takes the most
# precedence. When someone opens a pull request that only
# modifies JS files, only @js-owner and not the global
# owner(s) will be requested for a review.

Maybe use https://github.com/sbdchd/codeowners for this instead and any more issues can be solved upstream?

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for the suggestion. I will have a look at the library

Comment on lines +68 to +101
def call(self, command, sudo=None):
"""call gitlab api and parse response json"""
response = self.call_raw(command, sudo)
return command.extract(response.json()) if command.extract else response.json()

def repo_file_get(self, project_id, file_path, ref):
"""Get file from repository

The function returns a dict similar to the JSON except
that "encoding" is missing as the content is already
provided decoded as bytes.

See: https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository
"""
file_path = urllib.parse.quote(file_path, safe="")
url = '/projects/{id}/repository/files/{file_path}/raw?ref={ref}'
url = url.format(id=project_id, file_path=file_path, ref=ref)

try:
result = self.call_raw(GET(url))
return {
'file_name': result.headers['X-Gitlab-File-Name'],
'file_path': result.headers['X-Gitlab-File-Path'],
'size': result.headers['X-Gitlab-Size'],
'content_sha256': result.headers['X-Gitlab-Content-Sha256'],
'blob_id': result.headers['X-Gitlab-Blob-Id'],
'commit_id': result.headers['X-Gitlab-Commit-Id'],
'last_commit_id': result.headers['X-Gitlab-Last-Commit-Id'],
'content': result.text,
'ref': result.headers['X-Gitlab-Ref'],
}
except NotFound:
return None

Copy link
Contributor

Choose a reason for hiding this comment

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

I would say use https://github.com/python-gitlab/python-gitlab/ for this (disclaimer, I help maintain it so I'm biased here) but I realize the rest of this project doesn't use it and it would take more refactoring for that. But this would be a one-liner if you used a library.

Copy link
Author

Choose a reason for hiding this comment

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

It wouldn't make sense to introduce a new library for this PR, however, it looks like a great idea of another PR

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, you're right, this just needs to get merged :)

@lkm
Copy link
Author

lkm commented Feb 18, 2021

@nejch We are using this in production every single day, so I'm interested yes. I do think that sysadmiral's point is still valid regarding approval removal without impersonating. We use our own instance of Gitlab so no problem for us though. I guess it would be possible to support both models side-by-side. Do you know whether gitlab free edition allows anybody to approve a MR or whether it too parses the CODEOWNERS file?

@FlorianLudwig
Copy link
Contributor

@lkm the free version does not parse the CODEOWNERS file

@lkm
Copy link
Author

lkm commented Feb 18, 2021

I've pushed support for using a combination of awards and approvals in CE edition. Haven't tested much in our production environment yet. This PR has been open for such a long time that I'm not sure whether anybody is interested in merging it...?

@nejch
Copy link
Contributor

nejch commented Feb 18, 2021

I've pushed support for using a combination of awards and approvals in CE edition. Haven't tested much in our production environment yet. This PR has been open for such a long time that I'm not sure whether anybody is interested in merging it...?

Thanks for picking this up again @lkm! Yeah, I wonder as well, there's also @matthiasbalke's PR that's still waiting and would be great. I'll keep poking around this project to see :)

Otherwise I had a look and it seems they've actually introduced this upstream for UI rebases: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/489/diffs so maybe it could be extended for local pushes as well, maybe as a project setting. I'm pretty useless at Ruby but I know some people who could guide me perhaps. Then you'd only need to rely on native approvals.

IMO the approval feature (in marge) would be a big draw for a lot of people on CE, because gitlab have been pretty vocal about not bringing required approvals to Core, ever. So it might be worth it trying to get native approvals to work for everyone here.

@erikseifert
Copy link

I really want to see this feature. Can i help ?

@lkm
Copy link
Author

lkm commented Apr 20, 2021

@erikseifert I would actually suggest that someone fork this project so we can get a proper workflow going, nothing is going to happen here, see #295

I maintain a local fork for my company with these changes and its been running in prod for a year now

@nejch
Copy link
Contributor

nejch commented May 24, 2021

@erikseifert I would actually suggest that someone fork this project so we can get a proper workflow going, nothing is going to happen here, see #295

I maintain a local fork for my company with these changes and its been running in prod for a year now

@lkm if you want to rebase and pick this up again, there's some more activity now, and there's also CI running properly now on this repo.

Thanks for your patience in any case, I'm trying to get this adopted in our company to compensate for EE features but without resorting to forks :)

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.

7 participants