Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion inlineplz/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from __future__ import absolute_import

from inlineplz.interfaces.github import GitHubInterface
from inlineplz.interfaces.stash import StashInterface

Copy link
Owner

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)

INTERFACES = {
'github': GitHubInterface
'github': GitHubInterface,
'stash': StashInterface
}
90 changes: 90 additions & 0 deletions inlineplz/interfaces/stash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import

import stashy
Copy link
Owner

Choose a reason for hiding this comment

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

prospector: pylint: Unable to import 'stashy' (import-error)

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):
Copy link
Owner

Choose a reason for hiding this comment

The 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?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well, the implementation here is slightly different from github.py because the structure of comments in the stash API is different. I couldn't think of a good way to extract the shared logic from what is unique to each interface. Any suggestions?

Copy link
Owner

Choose a reason for hiding this comment

The 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):
Copy link
Owner

Choose a reason for hiding this comment

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

prospector: pylint: Unused variable 'hunk_no' (unused-variable)

for position, hunk_line in enumerate(hunk):
Copy link
Owner

Choose a reason for hiding this comment

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

prospector: pylint: Unused variable 'position' (unused-variable)

if '+' not in hunk_line.line_type:
continue
if hunk_line.target_line_no == message.line_number:
return hunk_line.target_line_no
26 changes: 19 additions & 7 deletions inlineplz/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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:
Copy link
Owner

Choose a reason for hiding this comment

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

this seems maybe a little awkward. maybe we could just pass an auth dict?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree. I'll revise this.

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:
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
requirements = [
'unidiff',
'github3.py',
'stashy',
'xmltodict',
'pyyaml',
'scandir'
Expand Down