-
Notifications
You must be signed in to change notification settings - Fork 14
Stash interface #106
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
base: master
Are you sure you want to change the base?
Stash interface #106
Changes from 4 commits
cd76ea4
25a06b1
68036b9
0a2d7e2
2426128
c2bd991
3437547
900835f
fe86b2a
3383ae7
041d2d0
235eee4
ad9f6c7
f371d36
a01dc54
26a0335
312f33f
3c8a418
d93a308
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| # -*- coding: utf-8 -*- | ||
| from __future__ import absolute_import | ||
|
|
||
| import stashy | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| import unidiff | ||
|
|
||
| from inlineplz.interfaces.base import InterfaceBase | ||
| from inlineplz.util import git | ||
|
|
||
|
|
||
| class StashInterface(InterfaceBase): | ||
| def __init__(self, project, repo, pr, username, password, url=None): | ||
| # TODO: support non-PR runs | ||
| try: | ||
| pr = int(pr) | ||
| except ValueError: | ||
| return | ||
| if not url: | ||
| return | ||
| else: | ||
| self.stash = stashy.connect(url, username=username, password=password, verify=False) | ||
| self.pull_request = self.stash.projects[project].repos[repo].pull_requests[pr] | ||
| self.commits = [c for c in self.pull_request.commits()] | ||
| self.last_sha = self.commits[0]['id'] | ||
| self.first_sha = self.commits[-1]['id'] | ||
| self.parent_sha = self.commits[-1]['parents'][0]['id'] | ||
| self.diff = git.diff(self.parent_sha, self.last_sha) | ||
|
|
||
| def post_messages(self, messages, max_comments): | ||
| # TODO: support non-PR runs | ||
| if not self.stash: | ||
| return | ||
| messages_to_post = 0 | ||
| messages_posted = 0 | ||
| for msg in messages: | ||
| if not msg.comments: | ||
| continue | ||
| msg_position = self.position(msg) | ||
| if msg_position: | ||
| messages_to_post += 1 | ||
| if not self.is_duplicate(msg, msg_position): | ||
| self.pull_request.comment( | ||
| self.format_message(msg), | ||
| srcPath=msg.path, | ||
| fileLine=msg_position, | ||
| lineType='ADDED', | ||
| fileType='TO' | ||
| ) | ||
| messages_posted += 1 | ||
| if max_comments >= 0 and messages_posted > max_comments: | ||
| break | ||
| return messages_to_post | ||
|
|
||
| def is_duplicate(self, message, position): | ||
| for comment in self.pull_request.comments(message.path): | ||
| if ('anchor' in comment and | ||
| 'line' in comment['anchor'] and | ||
| comment['anchor']['line'] == position and | ||
| comment['text'].strip() == self.format_message(message).strip()): | ||
| return True | ||
| return False | ||
|
|
||
| @staticmethod | ||
| def format_message(message): | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i wonder if this should be moved to the parent class or to a utility module. thoughts?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, the implementation here is slightly different from
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah i didn't notice the difference, nevermind |
||
| if not message.comments: | ||
| return '' | ||
| if len(message.comments) > 1: | ||
| return ( | ||
| '```\n' + | ||
| '\n'.join(sorted(list(message.comments))) + | ||
| '\n```' | ||
| ) | ||
| return '`{0}`'.format(list(message.comments)[0].strip()) | ||
|
|
||
| def position(self, message): | ||
| """ | ||
| Determine where the comment should go | ||
| Skips messages outside of the scope of changes we're looking at | ||
| """ | ||
| patch = unidiff.PatchSet(self.diff.split('\n')) | ||
| for patched_file in patch: | ||
| target = patched_file.target_file.lstrip('b/') | ||
| if target == message.path: | ||
| for hunk_no, hunk in enumerate(patched_file): | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| for position, hunk_line in enumerate(hunk): | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if '+' not in hunk_line.line_type: | ||
| continue | ||
| if hunk_line.target_line_no == message.line_number: | ||
| return hunk_line.target_line_no | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,8 @@ def main(): | |
| parser.add_argument('--repo', type=str) | ||
| parser.add_argument('--repo-slug', type=str) | ||
| parser.add_argument('--token', type=str) | ||
| parser.add_argument('--user', type=str) | ||
| parser.add_argument('--password', type=str) | ||
| parser.add_argument('--interface', type=str, choices=interfaces.INTERFACES) | ||
| parser.add_argument('--url', type=str) | ||
| parser.add_argument('--dryrun', action='store_true') | ||
|
|
@@ -103,13 +105,23 @@ def inline(args): | |
| print(str(msg)) | ||
| return 0 | ||
| try: | ||
| my_interface = interfaces.INTERFACES[args.interface]( | ||
| owner, | ||
| repo, | ||
| args.pull_request, | ||
| args.token, | ||
| args.url | ||
| ) | ||
| if args.token: | ||
|
||
| my_interface = interfaces.INTERFACES[args.interface]( | ||
| owner, | ||
| repo, | ||
| args.pull_request, | ||
| args.token, | ||
| args.url | ||
| ) | ||
| else: | ||
| my_interface = interfaces.INTERFACES[args.interface]( | ||
| owner, | ||
| repo, | ||
| args.pull_request, | ||
| args.user, | ||
| args.password, | ||
| args.url | ||
| ) | ||
| if my_interface.post_messages(messages, args.max_comments) and not args.zero_exit: | ||
| return 1 | ||
| except KeyError: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |
| requirements = [ | ||
| 'unidiff', | ||
| 'github3.py', | ||
| 'stashy', | ||
| 'xmltodict', | ||
| 'pyyaml', | ||
| 'scandir' | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prospector: pylint: Import "from inlineplz.interfaces.stash import StashInterface" should be placed at the top of the module (wrong-import-position)