Commit e8dec524 authored by Jochen Sprickerhof's avatar Jochen Sprickerhof

New upstream version 0.6.4

parent 39ca0531
0.6.4 (2018-03-20 13:15:00 -0800)
---------------------------------
- Fixed use of non-dependency library. `#468 <https://github.com/ros-infrastructure/bloom/pull/468>`_
0.6.3 (2018-03-09 11:05:00 -0800)
---------------------------------
- Released for Debian buster. `#457 <https://github.com/ros-infrastructure/bloom/pull/457>`_
- Updated bloom-release: The --track/-t argument is now optional and defaults to the rosdistro. `#459 <https://github.com/ros-infrastructure/bloom/pull/459>`_
- Added bouncy to the list of ROS 2 rosdistros. `#462 <https://github.com/ros-infrastructure/bloom/pull/462>`_
- Added melodic to the list of rosdistros. `#463 <https://github.com/ros-infrastructure/bloom/pull/463>`_
- Added support for releasing repositories with submodules. `#461 <https://github.com/ros-infrastructure/bloom/pull/461>`_
- Improved release repository discovery with optional environment variable. `#460 <https://github.com/ros-infrastructure/bloom/pull/460>`_
- Fixed python3 encoding issue when processing rpm templates. `#464 <https://github.com/ros-infrastructure/bloom/pull/464>`_
0.6.2 (2018-01-08 13:45:00 -0800)
---------------------------------
- Removed test.* subpackages from installation. `#444 <https://github.com/ros-infrastructure/bloom/pull/444>`_
- Prepared for release supporting Ubuntu Bionic Beaver. `#452 <https://github.com/ros-infrastructure/bloom/pull/452>`_
- Fixed error message when GitHub Multi-Factor auth is enabled. `#451 <https://github.com/ros-infrastructure/bloom/pull/451>`_
- Added support for ROS 2 Ardent Apalone. `#453 <https://github.com/ros-infrastructure/bloom/pull/453>`_
- Fixed an HTTP/JSON encoding issue in bloom-release for Python 3. `#445 <https://github.com/ros-infrastructure/bloom/pull/445>`_
0.6.1 (2017-10-20 13:45:00 -0800)
---------------------------------
- Switched to PyPI JSON API for online updates check. `#438 <https://github.com/ros-infrastructure/bloom/pull/438>`_
......
......@@ -51,7 +51,6 @@ from bloom.logging import warning
from bloom.git import branch_exists
from bloom.git import get_root
from bloom.git import has_submodules
from bloom.git import tag_exists
from bloom.util import add_global_arguments
......@@ -121,14 +120,6 @@ def export_upstream(uri, tag, vcs_type, output_dir, show_uri, name):
error("Failed to clone repository at '{0}'".format(uri) +
(" to reference '{0}'.".format(tag) if tag else '.'),
exit=True)
if get_root() is not None and has_submodules(upstream_repo.get_path()):
error("""\
bloom does not support exporting git repositories with submodules, see:
- https://github.com/ros-infrastructure/bloom/issues/202
- https://github.com/ros-infrastructure/bloom/issues/217
- https://github.com/vcstools/vcstools/issues/84
""", exit=True)
tarball_prefix = '{0}-{1}'.format(name, tag) if tag else name
tarball_path = os.path.join(output_dir, tarball_prefix)
full_tarball_path = tarball_path + '.tar.gz'
......
......@@ -56,8 +56,11 @@ from pkg_resources import parse_version
# python2/3 compatibility
try:
from urllib.error import HTTPError, URLError
from urllib.parse import urlparse
from urllib.request import Request, urlopen
except ImportError:
from urllib2 import HTTPError, Request, URLError, urlopen
from urlparse import urlparse
import bloom
......@@ -77,6 +80,7 @@ from bloom.github import auth_header_from_basic_auth
from bloom.github import auth_header_from_oauth_token
from bloom.github import Github
from bloom.github import GithubException
from bloom.github import GitHubAuthException
from bloom.logging import debug
from bloom.logging import error
......@@ -295,6 +299,27 @@ def validate_github_url(url, url_type):
return True
def infer_release_repo_from_env(repository):
"""
Generate a release repo url from a hint variable.
If the environment var BLOOM_RELEASE_REPO_BASE exists, and
BLOOM_RELEASE_REPO_BASE + repository + '-release.git' exists online, then
this function will return the newly composed url
"""
base = os.environ.get('BLOOM_RELEASE_REPO_BASE', None)
if base is None:
return None
url = base + repository + '-release.git'
try:
urlopen(Request(url))
except URLError:
return None
except HTTPError:
return None
return url
def get_repo_uri(repository, distro):
url = None
# Fetch the distro file
......@@ -308,6 +333,8 @@ def get_repo_uri(repository, distro):
matches = difflib.get_close_matches(repository, distribution_file.repositories)
if matches:
info(fmt("@{yf}Did you mean one of these: '" + "', '".join([m for m in matches]) + "'?"))
if url is None:
url = infer_release_repo_from_env(repository)
if url is None:
info("Could not determine release repository url for repository '{0}' of distro '{1}'"
.format(repository, distro))
......@@ -638,6 +665,19 @@ _gh = None
def get_github_interface(quiet=False):
def mfa_prompt(oauth_config_path, username):
"""Explain how to create a token for users with Multi-Factor Authentication configured."""
warning("Receiving 401 when trying to create an oauth token can be caused by the user "
"having two-factor authentication enabled.")
warning("If 2FA is enabled, the user will have to create an oauth token manually.")
warning("A token can be created at https://github.com/settings/applications")
warning("The resulting token can be placed in the '{oauth_config_path}' file as such:"
.format(**locals()))
info("")
warning('{{"github_user": "{username}", "oauth_token": "TOKEN_GOES_HERE"}}'
.format(**locals()))
info("")
global _gh
if _gh is not None:
return _gh
......@@ -686,20 +726,14 @@ def get_github_interface(quiet=False):
f.write(json.dumps(config))
info("The token '{token}' was created and stored in the bloom config file: '{oauth_config_path}'"
.format(**locals()))
except GitHubAuthException as exc:
error("{0}".format(exc))
mfa_prompt(oauth_config_path, username)
except GithubException as exc:
error("{0}".format(exc))
info("")
if '{0}'.format(exc.resp.status) in ['401']:
warning("Receiving 401 when trying to create an oauth token can be caused by the user "
"having two-factor authentication enabled.")
warning("If 2FA is enabled, the user will have to create an oauth token manually.")
warning("A token can be created at https://github.com/settings/applications")
warning("The resulting token can be placed in the '{oauth_config_path}' file as such:"
.format(**locals()))
info("")
warning('{{"github_user": "{username}", "oauth_token": "TOKEN_GOES_HERE"}}'
.format(**locals()))
info("")
if hasattr(exc, 'resp') and '{0}'.format(exc.resp.status) in ['401']:
mfa_prompt(oauth_config_path, username)
warning("This sometimes fails when the username or password are incorrect, try again?")
if not maybe_continue():
return None
......@@ -1258,7 +1292,7 @@ def get_argument_parser():
add('repository', help="repository to run bloom on")
add('--list-tracks', '-l', action='store_true', default=False,
help="list available tracks for repository")
add('--track', '-t', required=True, help="track to run")
add('--track', '-t', required=False, help="track to run; defaults to rosdistro name")
add('--non-interactive', '-y', action='store_true', default=False)
add('--ros-distro', '--rosdistro', '-r', required=True,
help="determines the ROS distro file used")
......@@ -1285,6 +1319,8 @@ def main(sysargs=None):
parser = get_argument_parser()
parser = add_global_arguments(parser)
args = parser.parse_args(sysargs)
if args.track is None:
args.track = args.ros_distro
handle_global_arguments(args)
if args.list_tracks:
......
......@@ -88,7 +88,7 @@ class RosDebianGenerator(DebianGenerator):
subs['Package'] = rosify_package_name(subs['Package'], self.rosdistro)
# XXX Add workspace package to runtime and buildtime dependencies for ROS 2 only.
if self.rosdistro in ['r2b2', 'r2b3'] and \
if self.rosdistro in ['r2b2', 'r2b3', 'ardent', 'bouncy'] and \
package.name not in ['ament_cmake_core', 'ament_package', 'ros_workspace']:
workspace_pkg_name = rosify_package_name('ros-workspace', self.rosdistro)
subs['BuildDepends'].append(workspace_pkg_name)
......
......@@ -34,6 +34,7 @@ from __future__ import print_function
import collections
import datetime
import io
import json
import os
import pkg_resources
......@@ -374,7 +375,9 @@ def __process_template_folder(path, subs):
os.path.relpath(template_path)))
result = em.expand(template, **subs)
# Write the result
with open(template_path, 'w') as f:
with io.open(template_path, 'w', encoding='utf-8') as f:
if sys.version_info.major == 2:
result = result.decode('utf-8')
f.write(result)
# Copy the permissions
shutil.copymode(item, template_path)
......
......@@ -708,26 +708,6 @@ def get_last_tag_by_date(directory=None):
return output[-1]
def has_submodules(directory=None):
"""
Returns True if the git repository at this directory has submodules
:param directory: directory to check for submodules in
:returns: True if there are submodules, False otherwise
:raises: RuntimeError if directory is not a git repository
"""
root = get_root(directory)
checked_dir = directory or os.getcwd()
if root is None:
raise RuntimeError("Directory '{0}' is not in a git repository.".format(checked_dir))
cmd = "git submodule status"
output = check_output(cmd, shell=True, cwd=root, stderr=PIPE)
if not output.strip():
return False
return True
def get_remotes(directory=None):
"""
Returns a list of remote names.
......
......@@ -92,13 +92,27 @@ def do_github_post_req(path, data=None, auth=None, site='api.github.com'):
try:
response = urlopen(request, timeout=120)
except HTTPError as e:
raise GithubException(str(e) + ' (%s)' % url)
if e.code in [401]:
raise GitHubAuthException(str(e) + ' (%s)' % url)
else:
raise GithubException(str(e) + ' (%s)' % url)
except URLError as e:
raise GithubException(str(e) + ' (%s)' % url)
return response
def json_loads(resp):
"""Handle parsing json from an HTTP response for both Python 2 and Python 3."""
try:
charset = resp.headers.getparam('charset')
charset = 'utf8' if not charset else charset
except AttributeError:
charset = resp.headers.get_content_charset()
return json.loads(resp.read().decode(charset))
class GithubException(Exception):
def __init__(self, msg, resp=None):
if resp:
......@@ -110,6 +124,11 @@ class GithubException(Exception):
self.resp = resp
class GitHubAuthException(GithubException):
def __init__(self, msg):
super(GithubException, self).__init__(msg)
class Github(object):
def __init__(self, username, auth, token=None):
self.username = username
......@@ -126,7 +145,7 @@ class Github(object):
"note_url": 'http://bloom.readthedocs.org/' if note_url is None else note_url
}
resp = do_github_post_req('/authorizations', payload, self.auth)
resp_data = json.loads(resp.read())
resp_data = json_loads(resp)
resp_code = '{0}'.format(resp.getcode())
if resp_code not in ['201', '202'] or 'token' not in resp_data:
raise GithubException("Failed to create a new oauth authorization", resp)
......@@ -141,7 +160,7 @@ class Github(object):
if '{0}'.format(resp.getcode()) not in ['200']:
raise GithubException(
"Failed to get information for repository '{owner}/{repo}'".format(**locals()), resp)
resp_data = json.loads(resp.read())
resp_data = json_loads(resp)
return resp_data
def list_repos(self, user, start_page=None):
......@@ -153,7 +172,7 @@ class Github(object):
if '{0}'.format(resp.getcode()) not in ['200']:
raise GithubException(
"Failed to list repositories for user '{user}' using url '{url}'".format(**locals()), resp)
new_repos = json.loads(resp.read())
new_repos = json_loads(resp)
if not new_repos:
return repos
repos.extend(new_repos)
......@@ -166,7 +185,7 @@ class Github(object):
raise GithubException("Failed to get branch information for '{branch}' on '{owner}/{repo}' using '{url}'"
.format(**locals()),
resp)
return json.loads(resp.read())
return json_loads(resp)
def list_branches(self, owner, repo, start_page=None):
page = start_page or 1
......@@ -177,7 +196,7 @@ class Github(object):
if '{0}'.format(resp.getcode()) not in ['200']:
raise GithubException(
"Failed to list branches for '{owner}/{repo}' using url '{url}'".format(**locals()), resp)
new_branches = json.loads(resp.read())
new_branches = json_loads(resp)
if not new_branches:
return branches
branches.extend(new_branches)
......@@ -188,7 +207,7 @@ class Github(object):
if '{0}'.format(resp.getcode()) not in ['200', '202']:
raise GithubException(
"Failed to create a fork of '{parent_org}/{parent_repo}'".format(**locals()), resp)
return json.loads(resp.read())
return json_loads(resp)
def list_forks(self, org, repo, start_page=None):
page = start_page or 1
......@@ -199,7 +218,7 @@ class Github(object):
if '{0}'.format(resp.getcode()) not in ['200', '202']:
raise GithubException(
"Failed to list forks of '{org}/{repo}'".format(**locals()), resp)
new_forks = json.loads(resp.read())
new_forks = json_loads(resp)
if not new_forks:
return forks
forks.extend(new_forks)
......@@ -215,5 +234,5 @@ class Github(object):
resp = do_github_post_req('/repos/{org}/{repo}/pulls'.format(**locals()), data, self.auth)
if '{0}'.format(resp.getcode()) not in ['200', '201']:
raise GithubException("Failed to create pull request", resp)
resp_json = json.loads(resp.read())
resp_json = json_loads(resp)
return resp_json['html_url']
......@@ -266,6 +266,7 @@ _distro_list_prompt = [
'indigo',
'kinetic',
'lunar',
'melodic',
]
......
......@@ -22,8 +22,8 @@ if sys.version_info[0] == 2 and sys.version_info[1] <= 6:
setup(
name='bloom',
version='0.6.1',
packages=find_packages(exclude=['test']),
version='0.6.4',
packages=find_packages(exclude=['test', 'test.*']),
package_data={
'bloom.generators.debian': [
'bloom/generators/debian/templates/*',
......
......@@ -3,5 +3,5 @@ Depends: python-yaml, python-empy, python-argparse, python-rosdep (>= 0.10.25),
Depends3: python3-yaml, python3-empy, python3-rosdep (>= 0.10.25), python3-rosdistro (>= 0.4.0), python3-vcstools (>= 0.1.22), python3-setuptools, python3-catkin-pkg (>= 0.3.8)
Conflicts: python3-bloom
Conflicts3: python-bloom
Suite: oneiric precise quantal raring saucy trusty utopic vivid wily xenial yakkety zesty artful wheezy jessie stretch
Suite: oneiric precise quantal raring saucy trusty utopic vivid wily xenial yakkety zesty artful bionic wheezy jessie stretch buster
X-Python3-Version: >= 3.2
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment