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

WIP: Implement 'Links' functionality #337

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
12 changes: 10 additions & 2 deletions pyup/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
class Bot(object):
def __init__(self, repo, user_token, bot_token=None,
provider=GithubProvider, bundle=RequirementsBundle, config=Config,
integration=False, provider_url=None):
integration=False, provider_url=None, dryrun=False):
self.req_bundle = bundle()
self.provider = provider(self.req_bundle, integration, provider_url)
self.provider = provider(self.req_bundle, integration, provider_url, dryrun)
self.user_token = user_token
self.bot_token = bot_token
self.fetched_files = []
Expand All @@ -31,6 +31,7 @@ def __init__(self, repo, user_token, bot_token=None,
self._fetched_prs = False

self.integration = integration
self.dryrun = dryrun

@property
def user_repo(self):
Expand Down Expand Up @@ -228,6 +229,8 @@ def close_stale_prs(self, update, pull_request, scheduled):
:param update:
:param pull_request:
"""
if self.dryrun:
return
closed = []
if self.bot_token and not pull_request.is_initial:
for pr in self.pull_requests:
Expand Down Expand Up @@ -328,6 +331,8 @@ def create_branch(self, new_branch, delete_empty=False):
:return: bool -- True if successfull
"""
logger.info("Preparing to create branch {} from {}".format(new_branch, self.config.branch))
if self.dryrun:
return True
try:
# create new branch
self.provider.create_branch(
Expand Down Expand Up @@ -405,6 +410,7 @@ def pull_config(self, new_config): # pragma: no cover

def commit_and_pull(self, initial, new_branch, title, body, updates):
logger.info("Preparing commit {}".format(title))

if self.create_branch(new_branch, delete_empty=False):
updated_files = {}
for update in self.iter_changes(initial, updates):
Expand Down Expand Up @@ -450,6 +456,8 @@ def commit_and_pull(self, initial, new_branch, title, body, updates):
return None

def create_issue(self, title, body):
if self.dryrun:
return
return self.provider.create_issue(
repo=self.bot_repo if self.bot_token else self.user_repo,
title=title,
Expand Down
9 changes: 6 additions & 3 deletions pyup/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
@click.option('--branch', help='Set the branch the bot should use', default='master')
@click.option('--initial', help='Set this to bundle all PRs into a large one',
default=False, is_flag=True)
@click.option('--dryrun', help='Dry run, creates no new artifacts',
default=False, is_flag=True)
@click.option('--log', help='Set the log level', default="ERROR")
def main(repo, user_token, bot_token, key, provider, provider_url, branch, initial, log):
def main(repo, user_token, bot_token, key, provider, provider_url, dryrun, branch, initial, log):
logging.basicConfig(level=getattr(logging, log.upper(), None))

settings.configure(key=key)
Expand All @@ -42,6 +44,7 @@ def main(repo, user_token, bot_token, key, provider, provider_url, branch, initi
bot_token=bot_token,
provider=ProviderClass,
provider_url=provider_url,
dryrun=dryrun,
)

bot.update(branch=branch, initial=initial)
Expand All @@ -54,9 +57,9 @@ def main(repo, user_token, bot_token, key, provider, provider_url, branch, initi
class CLIBot(Bot):

def __init__(self, repo, user_token, bot_token=None,
provider=GithubProvider, bundle=RequirementsBundle, provider_url=None):
provider=GithubProvider, bundle=RequirementsBundle, provider_url=None, dryrun=False):
bundle = CLIBundle
super(CLIBot, self).__init__(repo, user_token, bot_token, provider, bundle, provider_url=provider_url)
super(CLIBot, self).__init__(repo, user_token, bot_token, provider, bundle, provider_url=provider_url, dryrun=dryrun)

def iter_updates(self, initial, scheduled):

Expand Down
36 changes: 35 additions & 1 deletion pyup/providers/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@


class Provider(object):
def __init__(self, bundle, integration=False, url=None):
name = 'github'

def __init__(self, bundle, integration=False, url=None, dryrun=False):
self.bundle = bundle
self.integration = integration
self.dryrun = dryrun
self.url = url

@classmethod
Expand Down Expand Up @@ -88,6 +91,9 @@ def get_file(self, repo, path, branch):
def create_and_commit_file(self, repo, path, branch, content, commit_message, committer):
# integrations don't support committer data being set. Add this as extra kwarg
# if we're not dealing with an integration token
if self.dryrun:
return

extra_kwargs = {}
if not self.integration:
extra_kwargs["committer"] = self.get_committer_data(committer)
Expand All @@ -111,6 +117,9 @@ def get_requirement_file(self, repo, path, branch):
return None

def create_branch(self, repo, base_branch, new_branch):
if self.dryrun:
return

try:
ref = repo.get_git_ref("/".join(["heads", base_branch]))
repo.create_git_ref(ref="refs/heads/" + new_branch, sha=ref.object.sha)
Expand Down Expand Up @@ -143,6 +152,9 @@ def delete_branch(self, repo, branch, prefix):
:param repo: github.Repository
:param branch: string name of the branch to delete
"""
if self.dryrun:
return

# extra safeguard to make sure we are handling a bot branch here
assert branch.startswith(prefix)
ref = repo.get_git_ref("/".join(["heads", branch]))
Expand All @@ -156,6 +168,9 @@ def create_commit(self, path, branch, commit_message, content, sha, repo, commit

# integrations don't support committer data being set. Add this as extra kwarg
# if we're not dealing with an integration token
if self.dryrun:
return

extra_kwargs = {}
if not self.integration:
extra_kwargs["committer"] = self.get_committer_data(committer)
Expand Down Expand Up @@ -207,6 +222,9 @@ def get_pull_request_committer(self, repo, pull_request):
return []

def close_pull_request(self, bot_repo, user_repo, pull_request, comment, prefix):
if self.dryrun:
return True

try:
pull_request = bot_repo.get_pull(pull_request.number)
pull_request.create_issue_comment(comment)
Expand All @@ -219,6 +237,16 @@ def close_pull_request(self, bot_repo, user_repo, pull_request, comment, prefix)
return False

def create_pull_request(self, repo, title, body, base_branch, new_branch, pr_label, assignees, **kwargs):
if self.dryrun:
return self.bundle.get_pull_request_class()(
state='',
title=title,
url='',
created_at=0,
number=0,
issue=False
)

try:
if len(body) >= 65536:
logger.warning("PR body exceeds maximum length of 65536 chars, reducing")
Expand Down Expand Up @@ -254,6 +282,9 @@ def create_pull_request(self, repo, title, body, base_branch, new_branch, pr_lab
"Unable to create pull request on {repo}".format(repo=repo))

def get_or_create_label(self, repo, name):
if self.dryrun:
return ''

try:
label = repo.get_label(name=name)
except UnknownObjectException:
Expand All @@ -267,6 +298,9 @@ def get_or_create_label(self, repo, name):
return label

def create_issue(self, repo, title, body):
if self.dryrun:
return

try:
return repo.create_issue(
title=title,
Expand Down
34 changes: 32 additions & 2 deletions pyup/providers/gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ class Committer(object):
def __init__(self, login):
self.login = login

def __init__(self, bundle, intergration=False, url=None):
def __init__(self, bundle, intergration=False, url=None, dryrun=False):
self.bundle = bundle
self.url = url
self.dryrun = dryrun
if intergration:
raise NotImplementedError(
'Gitlab provider does not support integration mode')
Expand Down Expand Up @@ -83,8 +84,10 @@ def get_file(self, repo, path, branch):
return contentfile.decode().decode("utf-8"), contentfile

def create_and_commit_file(self, repo, path, branch, content, commit_message, committer):

# TODO: committer
if self.dryrun:
return

return repo.files.create({
'file_path': path,
'branch': branch,
Expand All @@ -102,6 +105,9 @@ def get_requirement_file(self, repo, path, branch):
return None

def create_branch(self, repo, base_branch, new_branch):
if self.dryrun:
return

try:
repo.branches.create({"branch": new_branch,
"ref": base_branch})
Expand Down Expand Up @@ -134,13 +140,18 @@ def delete_branch(self, repo, branch, prefix):
:param repo: github.Repository
:param branch: string name of the branch to delete
"""
if self.dryrun:
return

# make sure that the name of the branch begins with pyup.
assert branch.startswith(prefix)
obj = repo.branches.get(branch)
obj.delete()

def create_commit(self, path, branch, commit_message, content, sha, repo, committer):
# TODO: committer
if self.dryrun:
return

f = repo.files.get(file_path=path, ref=branch)
# Gitlab supports a plaintext encoding, which is when the encoding
Expand All @@ -158,6 +169,9 @@ def get_pull_request_committer(self, repo, pull_request):
]

def close_pull_request(self, bot_repo, user_repo, pull_request, comment, prefix):
if self.dryrun:
return True

mr = user_repo.mergerequests.get(pull_request.number)
mr.state_event = 'close'
mr.save()
Expand All @@ -168,11 +182,24 @@ def close_pull_request(self, bot_repo, user_repo, pull_request, comment, prefix)
self.delete_branch(user_repo, source_branch, prefix)

def _merge_merge_request(self, mr, config):
if self.dryrun:
return

mr.merge(should_remove_source_branch=config.gitlab.should_remove_source_branch,
merge_when_pipeline_succeeds=True)

def create_pull_request(self, repo, title, body, base_branch, new_branch, pr_label, assignees, config):
# TODO: Check permissions
if self.dryrun:
return self.bundle.get_pull_request_class()(
state='',
title=title,
url='',
created_at=0,
number=0,
issue=False
)

try:
if len(body) >= 65536:
logger.warning("PR body exceeds maximum length of 65536 chars, reducing")
Expand Down Expand Up @@ -223,6 +250,9 @@ def create_pull_request(self, repo, title, body, base_branch, new_branch, pr_lab
)

def create_issue(self, repo, title, body):
if self.dryrun:
return

return repo.issues.create({
'title': title,
'description': body
Expand Down
20 changes: 20 additions & 0 deletions pyup/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ def __init__(self, name, specs, line, lineno, extras, file_type):

self._is_insecure = None
self._changelog = None
self._package_metadata = None

def __eq__(self, other):
return (
Expand Down Expand Up @@ -441,6 +442,25 @@ def changelog(self):
self._changelog[version] = log
return self._changelog

@property
def package_metadata(self):
if self._package_metadata is None:
self._package_metadata = OrderedDict()
if settings.api_key:
r = requests.get(
"https://pyup.io/api/v1/package_metadata/{}/".format(self.key),
headers={"X-Api-Key": settings.api_key}
)
if r.status_code == 403:
raise InvalidKeyError
if r.status_code == 200:
data = r.json()
if data and 'links' in data:
self._package_metadata = OrderedDict(
(source, link) for source, link in data['links']
)
return self._package_metadata

@property
def is_outdated(self):
if self.version and self.latest_version_within_specs:
Expand Down
10 changes: 10 additions & 0 deletions pyup/templates/_links.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<details>
<summary>Links</summary>
{% for source, link in package_metadata.items() %}
{% if link %}
- {{ source }}: {{ link }}
{% endif %}
{% endfor %}
</details>


8 changes: 8 additions & 0 deletions pyup/templates/sequential_update_body.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ This PR pins [{{ requirement.full_name }}](https://pypi.org/project/{{ requireme
*The bot wasn't able to find a changelog for this release. [Got an idea?](https://github.com/pyupio/changelogs/issues/new)*
{% endif %}

{% if requirement.package_metadata %}
{% with package_metadata=requirement.package_metadata %}
{% include "_links.md" %}
{% endwith %}
{% elif api_key %}
*The bot wasn't able to find the links for this package. [Got an idea?](https://github.com/pyupio/changelogs/issues/new)*
{% endif %}

{% include "_api_key.md" %}