diff -Nru silver-platter-0.4.0/debian/changelog silver-platter-0.4.1/debian/changelog --- silver-platter-0.4.0/debian/changelog 2021-02-01 23:34:24.000000000 +0000 +++ silver-platter-0.4.1/debian/changelog 2021-02-18 13:05:11.000000000 +0000 @@ -1,3 +1,17 @@ +silver-platter (0.4.1-2) unstable; urgency=medium + + * Bump minimum breezy-debian version to something that supports + debcommit. Closes: #983008 + + -- Jelmer Vernooij Thu, 18 Feb 2021 13:05:11 +0000 + +silver-platter (0.4.1-1) unstable; urgency=medium + + * New upstream release. + + Depend on upstream ontologist for upstream metadata. Closes: #982994 + + -- Jelmer Vernooij Wed, 17 Feb 2021 22:47:59 +0000 + silver-platter (0.4.0-1) unstable; urgency=medium * New upstream release. diff -Nru silver-platter-0.4.0/debian/control silver-platter-0.4.1/debian/control --- silver-platter-0.4.0/debian/control 2021-02-01 23:34:24.000000000 +0000 +++ silver-platter-0.4.1/debian/control 2021-02-18 13:05:11.000000000 +0000 @@ -5,13 +5,14 @@ Build-Depends: dh-python, brz-debian (>= 2.8.41), python3-all, - python3-breezy (>= 3.1.0), + python3-breezy (>= 2.8.50), python3-breezy.tests, python3-distro-info, python3-dulwich (>= 0.19.7), python3-launchpadlib, python3-yaml, python3-testtools, + python3-upstream-ontologist, lintian-brush (>= 0.70), debhelper-compat (= 13) Standards-Version: 4.5.0 @@ -23,12 +24,13 @@ Package: silver-platter Architecture: all Depends: devscripts, - brz-debian (>= 2.8.41), + brz-debian (>= 2.8.50), python3-breezy (>= 3.1.0), python3-dulwich (>= 0.19.7), python3-distro-info, python3-launchpadlib, python3-yaml, + python3-upstream-ontologist, ${misc:Depends}, ${python3:Depends} Conflicts: lintian-brush (<< 0.40) diff -Nru silver-platter-0.4.0/.flake8 silver-platter-0.4.1/.flake8 --- silver-platter-0.4.0/.flake8 1970-01-01 00:00:00.000000000 +0000 +++ silver-platter-0.4.1/.flake8 2021-02-17 22:45:01.000000000 +0000 @@ -0,0 +1,5 @@ +[flake8] +extend-ignore = E203, E266, E501, W293, W291 +max-line-length = 88 +max-complexity = 18 +select = B,C,E,F,W,T4,B9 diff -Nru silver-platter-0.4.0/.github/workflows/pythonpackage.yml silver-platter-0.4.1/.github/workflows/pythonpackage.yml --- silver-platter-0.4.0/.github/workflows/pythonpackage.yml 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/.github/workflows/pythonpackage.yml 2021-02-17 22:45:01.000000000 +0000 @@ -23,10 +23,12 @@ sudo apt install devscripts cython3 bzr python -m pip install --upgrade pip pip install -U pip setuptools flake8 mypy debmutate pyyaml testtools - python setup.py develop mkdir $HOME/.config/breezy/plugins -p bzr branch lp:brz-debian ~/.config/breezy/plugins/debian - pip install -U git+https://salsa.debian.org/python-debian-team/python-debian + pip install -U git+https://salsa.debian.org/python-debian-team/python-debian \ + git+https://salsa.debian.org/jelmer/lintian-brush \ + "git+https://salsa.debian.org/debian/distro-info#egg=distro-info&subdirectory=python" + python setup.py develop - name: Style checks run: | python -m flake8 @@ -35,6 +37,6 @@ python -m mypy silver_platter - name: Test suite run run: | - python -m unittest silver_platter.tests.test_suite + python setup.py test env: PYTHONHASHSEED: random diff -Nru silver-platter-0.4.0/PKG-INFO silver-platter-0.4.1/PKG-INFO --- silver-platter-0.4.0/PKG-INFO 2021-02-01 23:30:19.579928400 +0000 +++ silver-platter-0.4.1/PKG-INFO 2021-02-17 22:45:13.295229700 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: silver-platter -Version: 0.4.0 +Version: 0.4.1 Summary: Automatic merge proposal creeator Home-page: https://jelmer.uk/code/silver-platter Author: Jelmer Vernooij diff -Nru silver-platter-0.4.0/README.rst silver-platter-0.4.1/README.rst --- silver-platter-0.4.0/README.rst 2021-02-01 23:22:43.000000000 +0000 +++ silver-platter-0.4.1/README.rst 2021-02-17 22:45:01.000000000 +0000 @@ -35,10 +35,10 @@ At the moment, the following code hosters are supported: - * `GitHub `_ - * `Launchpad `_ - * `GitLab `_ instances, such as Debian's - `Salsa `_ +* `GitHub `_ +* `Launchpad `_ +* `GitLab `_ instances, such as Debian's + `Salsa `_ Working with Debian packages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -50,15 +50,15 @@ Subcommands that are available include: - * *lintian-brush*: Run the `lintian-brush - `_ command on the branch. - * *upload-pending*: Build and upload a package and push/propose the - changelog updates. - * *new-upstream*: Merge in a new upstream release or snapshot. - * *apply-multi-arch-hints*: Apply multi-arch hints. - * *orphan*: Mark a package as orphaned, update its Maintainer - field and move it to the common Debian salsa group. - * *rules-requires-root*: Mark a package as "Rules-Requires-Root: no" +* *lintian-brush*: Run the `lintian-brush + `_ command on the branch. +* *upload-pending*: Build and upload a package and push/propose the + changelog updates. +* *new-upstream*: Merge in a new upstream release or snapshot. +* *apply-multi-arch-hints*: Apply multi-arch hints. +* *orphan*: Mark a package as orphaned, update its Maintainer + field and move it to the common Debian salsa group. +* *rules-requires-root*: Mark a package as "Rules-Requires-Root: no" *debian-svp run* takes package name arguments that will be resolved to repository locations from the *Vcs-Git* field in the package. diff -Nru silver-platter-0.4.0/releaser.conf silver-platter-0.4.1/releaser.conf --- silver-platter-0.4.0/releaser.conf 1970-01-01 00:00:00.000000000 +0000 +++ silver-platter-0.4.1/releaser.conf 2021-02-17 22:45:01.000000000 +0000 @@ -0,0 +1,19 @@ +# How to use this file: +# - Install silver-platter (apt install silver-platter / pip install silver-platter) +# - Run: svp releaser git+ssh://git@github.com/jelmer/silver-platter +# - Done! + +name: "silver-platter" +timeout_days: 5 +tag_name: "$VERSION" +verify_command: "make check" +update_version { + path: "setup.py" + match: "^ version=\"(.*)\",$" + new_line: " version='$VERSION'," +} +update_version { + path: "silver_platter/__init__.py" + match: "^__version__ = \((.*)\)$" + new_line: "__version__ = $TUPLED_VERSION" +} diff -Nru silver-platter-0.4.0/setup.py silver-platter-0.4.1/setup.py --- silver-platter-0.4.0/setup.py 2021-02-01 23:29:51.000000000 +0000 +++ silver-platter-0.4.1/setup.py 2021-02-17 22:45:11.000000000 +0000 @@ -17,13 +17,23 @@ from setuptools import setup +debian_deps = [ + 'pyyaml', # For reading debian/upstream/metadata + 'debmutate>=0.3', + 'lintian-brush>=0.50', + 'python_debian', + 'distro-info', + 'upstream-ontologist', +] + + setup( name='silver-platter', author="Jelmer Vernooij", author_email="jelmer@jelmer.uk", url="https://jelmer.uk/code/silver-platter", description="Automatic merge proposal creeator", - version="0.4.0", + version='0.4.1', license='GNU GPL v2 or later', project_urls={ "Bug Tracker": "https://github.com/jelmer/silver-platter/issues", @@ -63,12 +73,7 @@ 'dulwich', ], extras_require={ - 'debian': [ - 'pyyaml', # For reading debian/upstream/metadata - 'debmutate>=0.3', - 'lintian-brush>=0.50', - 'python_debian', - ], + 'debian': debian_deps, }, - tests_require=['testtools'], + tests_require=['testtools', 'lintian-brush'] + debian_deps, ) diff -Nru silver-platter-0.4.0/silver_platter/debian/backport.py silver-platter-0.4.1/silver_platter/debian/backport.py --- silver-platter-0.4.0/silver_platter/debian/backport.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/backport.py 2021-02-17 22:45:01.000000000 +0000 @@ -17,24 +17,24 @@ from distro_info import DebianDistroInfo +import logging import os import re import tempfile from . import ( DEFAULT_BUILDER, - ) +) from .changer import ( run_mutator, DebianChanger, ChangerResult, - ) +) from breezy.plugins.debian.cmds import _build_helper from breezy.plugins.debian.util import ( dput_changes, debsign, - ) -from breezy.trace import note +) from debian.changelog import format_date, get_maintainer from debmutate.changelog import ChangelogEditor, changeblock_add_line @@ -44,7 +44,6 @@ class BackportResult(object): - def __init__(self, target_release): self.target_release = target_release @@ -52,28 +51,28 @@ def backport_suffix(release): distro_info = DebianDistroInfo() version = distro_info.version(release) - return 'bpo%s' % version + return "bpo%s" % version def backport_distribution(release): distro_info = DebianDistroInfo() - if distro_info.codename('stable') == release: - return '%s-backports' % release - elif distro_info.codename('oldstable') == release: - return '%s-backports-sloppy' % release + if distro_info.codename("stable") == release: + return "%s-backports" % release + elif distro_info.codename("oldstable") == release: + return "%s-backports-sloppy" % release else: - raise Exception('unable to determine target suite for %s' % release) + raise Exception("unable to determine target suite for %s" % release) def create_bpo_version(orig_version, bpo_suffix): - m = re.fullmatch(r'(.*)\~' + bpo_suffix + r'\+([0-9]+)', str(orig_version)) + m = re.fullmatch(r"(.*)\~" + bpo_suffix + r"\+([0-9]+)", str(orig_version)) if m: base = m.group(1) buildno = int(m.group(2)) + 1 else: base = str(orig_version) buildno = 1 - return '%s~%s+%d' % (base, bpo_suffix, buildno) + return "%s~%s+%d" % (base, bpo_suffix, buildno) def backport_package(local_tree, subpath, target_release, author=None): @@ -85,12 +84,15 @@ # TODO(jelmer): Update Vcs-Git/Vcs-Browser header? target_distribution = backport_distribution(target_release) version_suffix = backport_suffix(target_release) - note('Using target distribution %s, version suffix %s', - target_distribution, version_suffix) - clp = local_tree.abspath(os.path.join(subpath, 'debian/changelog')) + logging.info( + "Using target distribution %s, version suffix %s", + target_distribution, + version_suffix, + ) + clp = local_tree.abspath(os.path.join(subpath, "debian/changelog")) if author is None: - author = '%s <%s>' % get_maintainer() + author = "%s <%s>" % get_maintainer() with ChangelogEditor(clp) as cl: # TODO(jelmer): If there was an existing backport, use that version @@ -98,22 +100,23 @@ cl.new_block( package=cl[0].package, distributions=target_distribution, - urgency='low', + urgency="low", author=author, date=format_date(), - version=create_bpo_version(since_version, version_suffix)) + version=create_bpo_version(since_version, version_suffix), + ) block = cl[0] changeblock_add_line( block, - ['Backport to %s.' % target_release] + - [' +' + line for line in changes]) + ["Backport to %s." % target_release] + [" +" + line for line in changes], + ) return since_version class BackportChanger(DebianChanger): - name = 'backport' + name = "backport" def __init__(self, dry_run=False, target_release=None, builder=None): self.dry_run = dry_run @@ -124,70 +127,88 @@ def setup_parser(cls, parser): distro_info = DebianDistroInfo() parser.add_argument( - '--target-release', type=str, - help='Target release', default=distro_info.stable()) - parser.add_argument( - '--dry-run', action='store_true', - help='Do a dry run.') + "--target-release", + type=str, + help="Target release", + default=distro_info.stable(), + ) + parser.add_argument("--dry-run", action="store_true", help="Do a dry run.") parser.add_argument( - '--builder', + "--builder", type=str, - help='Build command', - default=(DEFAULT_BUILDER + ' --source --source-only-changes ' - '--debbuildopt=-v${LAST_VERSION}')) + help="Build command", + default=( + DEFAULT_BUILDER + " --source --source-only-changes " + "--debbuildopt=-v${LAST_VERSION}" + ), + ) @classmethod def from_args(cls, args): - return cls(target_release=args.target_release, dry_run=args.dry_run, - builder=args.builder) + return cls( + target_release=args.target_release, + dry_run=args.dry_run, + builder=args.builder, + ) def suggest_branch_name(self): return backport_distribution(self.target_release) - def make_changes(self, local_tree, subpath, update_changelog, reporter, - committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revision = local_tree.last_revision() since_version = backport_package( - local_tree, subpath, self.target_release, author=committer) + local_tree, subpath, self.target_release, author=committer + ) with tempfile.TemporaryDirectory() as td: - builder = self.builder.replace( - "${LAST_VERSION}", str(since_version)) + builder = self.builder.replace("${LAST_VERSION}", str(since_version)) target_changes = _build_helper( - local_tree, subpath, local_tree.branch, td, builder=builder) + local_tree, subpath, local_tree.branch, td, builder=builder + ) debsign(target_changes) if not self.dry_run: dput_changes(target_changes) - branches = [ - ('main', None, base_revision, - local_tree.last_revision())] + branches = [("main", None, base_revision, local_tree.last_revision())] # TODO(jelmer): Add debian/... tag tags = [] return ChangerResult( - description=None, mutator=None, branches=branches, + description=None, + mutator=None, + branches=branches, tags=tags, - proposed_commit_message='Backport to %s.' % self.target_release, - sufficient_for_proposal=True) + proposed_commit_message="Backport to %s." % self.target_release, + sufficient_for_proposal=True, + ) - def get_proposal_description( - self, applied, description_format, existing_proposal): - return 'Backport to %s.' % self.target_release + def get_proposal_description(self, applied, description_format, existing_proposal): + return "Backport to %s." % self.target_release def describe(self, result, publish_result): if publish_result.is_new: - note('Proposed backportg to %s: %s', - result.target_release, - publish_result.proposal.url) + logging.info( + "Proposed backportg to %s: %s", + result.target_release, + publish_result.proposal.url, + ) else: - note('No changes for package %s', result.package_name) + logging.info("No changes for package %s", result.package_name) -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(run_mutator(BackportChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/changer.py silver-platter-0.4.1/silver_platter/debian/changer.py --- silver-platter-0.4.0/silver_platter/debian/changer.py 2021-01-25 18:36:03.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/changer.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,10 +15,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -__all__ = ['iter_conflicted'] +__all__ = ["iter_conflicted"] import argparse from functools import partial +import logging import pkg_resources import sys from typing import Any, List, Optional, Dict, Iterable, Tuple, Type @@ -26,7 +27,6 @@ from breezy import version_info as breezy_version_info from breezy.branch import Branch from breezy.propose import Hoster, MergeProposal -from breezy.trace import note, warning, show_error from breezy.transport import Transport from breezy.workingtree import WorkingTree @@ -36,7 +36,7 @@ NoSuchPackage, NoAptSources, DEFAULT_BUILDER, - ) +) from ..proposal import ( HosterLoginRequired, UnsupportedHoster, @@ -45,12 +45,12 @@ find_existing_proposed, get_hoster, iter_conflicted, - ) +) from ..publish import ( PublishResult, SUPPORTED_MODES, - ) +) from ..utils import ( BranchMissing, BranchUnavailable, @@ -59,20 +59,29 @@ run_post_check, PostCheckFailed, full_branch_url, - ) +) -def get_package(package: str, branch_name: str, - overwrite_unrelated: bool = False, - refresh: bool = False, - possible_transports: Optional[List[Transport]] = None, - possible_hosters: Optional[List[Hoster]] = None, - owner: Optional[str] = None - ) -> Tuple[str, Branch, str, Optional[Branch], - Optional[Hoster], Optional[MergeProposal], - Optional[bool]]: +def get_package( + package: str, + branch_name: str, + overwrite_unrelated: bool = False, + refresh: bool = False, + possible_transports: Optional[List[Transport]] = None, + possible_hosters: Optional[List[Hoster]] = None, + owner: Optional[str] = None, +) -> Tuple[ + str, + Branch, + str, + Optional[Branch], + Optional[Hoster], + Optional[MergeProposal], + Optional[bool], +]: main_branch, subpath = open_packaging_branch( - package, possible_transports=possible_transports) + package, possible_transports=possible_transports + ) overwrite: Optional[bool] = False @@ -85,23 +94,35 @@ existing_proposal = None hoster = None else: - (resume_branch, overwrite, existing_proposal) = ( - find_existing_proposed( - main_branch, hoster, branch_name, owner=owner, - overwrite_unrelated=overwrite_unrelated)) + (resume_branch, overwrite, existing_proposal) = find_existing_proposed( + main_branch, + hoster, + branch_name, + owner=owner, + overwrite_unrelated=overwrite_unrelated, + ) if refresh: overwrite = True resume_branch = None return ( - package, main_branch, subpath, resume_branch, hoster, - existing_proposal, overwrite) + package, + main_branch, + subpath, + resume_branch, + hoster, + existing_proposal, + overwrite, + ) -def iter_packages(packages: Iterable[str], branch_name: str, - overwrite_unrelated: bool = False, - refresh: bool = False, - derived_owner: Optional[str] = None): +def iter_packages( + packages: Iterable[str], + branch_name: str, + overwrite_unrelated: bool = False, + refresh: bool = False, + derived_owner: Optional[str] = None, +): """Iterate over relevant branches for a set of packages. Args: @@ -119,20 +140,38 @@ possible_hosters: List[Hoster] = [] for pkg in packages: - note('Processing: %s', pkg) + logging.info("Processing: %s", pkg) - (pkg, main_branch, subpath, resume_branch, hoster, existing_proposal, - overwrite) = get_package( - pkg, branch_name, overwrite_unrelated=overwrite_unrelated, - refresh=refresh, possible_transports=possible_transports, - possible_hosters=possible_hosters, owner=derived_owner) + ( + pkg, + main_branch, + subpath, + resume_branch, + hoster, + existing_proposal, + overwrite, + ) = get_package( + pkg, + branch_name, + overwrite_unrelated=overwrite_unrelated, + refresh=refresh, + possible_transports=possible_transports, + possible_hosters=possible_hosters, + owner=derived_owner, + ) - yield (pkg, main_branch, subpath, resume_branch, hoster, - existing_proposal, overwrite) + yield ( + pkg, + main_branch, + subpath, + resume_branch, + hoster, + existing_proposal, + overwrite, + ) class ChangerReporter(object): - def report_context(self, context): raise NotImplementedError(self.report_context) @@ -144,24 +183,27 @@ class ChangerError(Exception): - - def __init__(self, category: str, summary: str, - original: Optional[Exception] = None): + def __init__( + self, category: str, summary: str, original: Optional[Exception] = None + ): self.category = category self.summary = summary self.original = original class ChangerResult(object): - - def __init__(self, description: Optional[str], mutator: Any, - branches: Optional[List[Tuple[str, str, bytes, bytes]]] = [], - tags: Optional[Dict[str, bytes]] = None, - value: Optional[int] = None, - proposed_commit_message: Optional[str] = None, - title: Optional[str] = None, - labels: Optional[List[str]] = None, - sufficient_for_proposal: bool = True): + def __init__( + self, + description: Optional[str], + mutator: Any, + branches: Optional[List[Tuple[str, str, bytes, bytes]]] = [], + tags: Optional[Dict[str, bytes]] = None, + value: Optional[int] = None, + proposed_commit_message: Optional[str] = None, + title: Optional[str] = None, + labels: Optional[List[str]] = None, + sufficient_for_proposal: bool = True, + ): self.description = description self.mutator = mutator self.branches = branches or [] @@ -172,9 +214,16 @@ self.labels = labels self.sufficient_for_proposal = sufficient_for_proposal - def show_diff(self, repository, outf, role='main', - old_label: str = 'old/', new_label: str = 'new/') -> None: + def show_diff( + self, + repository, + outf, + role="main", + old_label: str = "old/", + new_label: str = "new/", + ) -> None: from breezy.diff import show_diff_trees + for (brole, name, base_revision, revision) in self.branches: if role == brole: break @@ -183,73 +232,88 @@ old_tree = repository.revision_tree(base_revision) new_tree = repository.revision_tree(revision) show_diff_trees( - old_tree, new_tree, outf, - old_label=old_label, new_label=new_label) + old_tree, new_tree, outf, old_label=old_label, new_label=new_label + ) def setup_parser_common(parser: argparse.ArgumentParser) -> None: parser.add_argument( "--dry-run", help="Create branches but don't push or propose anything.", - action="store_true", default=False) - parser.add_argument( - '--build-verify', - help='Build package to verify it.', - dest='build_verify', - action='store_true') - parser.add_argument( - '--pre-check', - help='Command to run to check whether to process package.', - type=str) + action="store_true", + default=False, + ) parser.add_argument( - '--post-check', - help='Command to run to check package before pushing.', - type=str) + "--build-verify", + help="Build package to verify it.", + dest="build_verify", + action="store_true", + ) parser.add_argument( - '--builder', default=DEFAULT_BUILDER, type=str, - help='Build command to use when verifying build.') + "--pre-check", + help="Command to run to check whether to process package.", + type=str, + ) parser.add_argument( - '--refresh', - help='Discard old branch and apply fixers from scratch.', - action='store_true') + "--post-check", help="Command to run to check package before pushing.", type=str + ) parser.add_argument( - '--committer', - help='Committer identity', - type=str) + "--builder", + default=DEFAULT_BUILDER, + type=str, + help="Build command to use when verifying build.", + ) parser.add_argument( - '--mode', - help='Mode for pushing', choices=SUPPORTED_MODES, - default="propose", type=str) + "--refresh", + help="Discard old branch and apply fixers from scratch.", + action="store_true", + ) + parser.add_argument("--committer", help="Committer identity", type=str) parser.add_argument( - '--no-update-changelog', action="store_false", default=None, - dest="update_changelog", help="do not update the changelog") + "--mode", + help="Mode for pushing", + choices=SUPPORTED_MODES, + default="propose", + type=str, + ) parser.add_argument( - '--update-changelog', action="store_true", dest="update_changelog", - help="force updating of the changelog", default=None) + "--no-update-changelog", + action="store_false", + default=None, + dest="update_changelog", + help="do not update the changelog", + ) parser.add_argument( - '--diff', action="store_true", - help="Output diff of created merge proposal.") + "--update-changelog", + action="store_true", + dest="update_changelog", + help="force updating of the changelog", + default=None, + ) parser.add_argument( - '--build-target-dir', type=str, - help=("Store built Debian files in specified directory " - "(with --build-verify)")) + "--diff", action="store_true", help="Output diff of created merge proposal." + ) parser.add_argument( - '--overwrite', action='store_true', - help='Overwrite existing branches.') + "--build-target-dir", + type=str, + help=( + "Store built Debian files in specified directory " "(with --build-verify)" + ), + ) parser.add_argument( - '--name', type=str, - help='Proposed branch name', default=None) + "--overwrite", action="store_true", help="Overwrite existing branches." + ) + parser.add_argument("--name", type=str, help="Proposed branch name", default=None) parser.add_argument( - '--derived-owner', type=str, default=None, - help='Owner for derived branches.') + "--derived-owner", type=str, default=None, help="Owner for derived branches." + ) parser.add_argument( - '--label', type=str, - help='Label to attach', action="append", default=[]) + "--label", type=str, help="Label to attach", action="append", default=[] + ) class DebianChanger(object): - """A class which can make and explain changes to a Debian package in VCS. - """ + """A class which can make and explain changes to a Debian package in VCS.""" name: str @@ -258,26 +322,26 @@ raise NotImplementedError(cls.setup_parser) @classmethod - def from_args(cls, args: List[str]) -> 'DebianChanger': + def from_args(cls, args: List[str]) -> "DebianChanger": raise NotImplementedError(cls.from_args) def suggest_branch_name(self) -> str: raise NotImplementedError(self.suggest_branch_name) - def make_changes(self, - local_tree: WorkingTree, - subpath: str, - update_changelog: bool, - reporter: ChangerReporter, - committer: Optional[str], - base_proposal: Optional[MergeProposal] = None, - ) -> ChangerResult: + def make_changes( + self, + local_tree: WorkingTree, + subpath: str, + update_changelog: bool, + reporter: ChangerReporter, + committer: Optional[str], + base_proposal: Optional[MergeProposal] = None, + ) -> ChangerResult: raise NotImplementedError(self.make_changes) def get_proposal_description( - self, applied: Any, - description_format: str, - existing_proposal: MergeProposal) -> str: + self, applied: Any, description_format: str, existing_proposal: MergeProposal + ) -> str: raise NotImplementedError(self.get_proposal_description) def describe(self, applied: Any, publish_result: PublishResult) -> None: @@ -289,7 +353,6 @@ class DummyChangerReporter(ChangerReporter): - def report_context(self, context): pass @@ -300,117 +363,137 @@ return None -def _run_single_changer( - changer: DebianChanger, - pkg: str, - main_branch: Branch, - subpath: str, - resume_branch: Optional[Branch], - hoster: Optional[Hoster], - existing_proposal: Optional[MergeProposal], - overwrite: Optional[bool], mode: str, branch_name: str, - diff: bool = False, - committer: Optional[str] = None, build_verify: bool = False, - pre_check: Optional[str] = None, post_check: Optional[str] = None, - builder: str = DEFAULT_BUILDER, dry_run: bool = False, - update_changelog: Optional[bool] = None, - label: Optional[List[str]] = None, - derived_owner: Optional[str] = None, - build_target_dir: Optional[str] = None) -> Optional[bool]: +def _run_single_changer( # noqa: C901 + changer: DebianChanger, + pkg: str, + main_branch: Branch, + subpath: str, + resume_branch: Optional[Branch], + hoster: Optional[Hoster], + existing_proposal: Optional[MergeProposal], + overwrite: Optional[bool], + mode: str, + branch_name: str, + diff: bool = False, + committer: Optional[str] = None, + build_verify: bool = False, + pre_check: Optional[str] = None, + post_check: Optional[str] = None, + builder: str = DEFAULT_BUILDER, + dry_run: bool = False, + update_changelog: Optional[bool] = None, + label: Optional[List[str]] = None, + derived_owner: Optional[str] = None, + build_target_dir: Optional[str] = None, +) -> Optional[bool]: from breezy import errors from . import ( BuildFailedError, MissingUpstreamTarball, Workspace, - ) + ) - if hoster is None and mode == 'attempt-push': - warning('Unsupported hoster; will attempt to push to %s', - full_branch_url(main_branch)) - mode = 'push' - with Workspace(main_branch, resume_branch=resume_branch) as ws, \ - ws.local_tree.lock_write(): + if hoster is None and mode == "attempt-push": + logging.warn( + "Unsupported hoster; will attempt to push to %s", + full_branch_url(main_branch), + ) + mode = "push" + with Workspace( + main_branch, resume_branch=resume_branch + ) as ws, ws.local_tree.lock_write(): if ws.refreshed: overwrite = True run_pre_check(ws.local_tree, pre_check) if update_changelog is None: dch_guess = guess_update_changelog(ws.local_tree) if dch_guess: - note(dch_guess[1]) + logging.info(dch_guess[1]) update_changelog = dch_guess[0] else: # Assume yes. update_changelog = True try: changer_result = changer.make_changes( - ws.local_tree, subpath=subpath, + ws.local_tree, + subpath=subpath, update_changelog=update_changelog, - committer=committer, reporter=DummyChangerReporter()) + committer=committer, + reporter=DummyChangerReporter(), + ) except ChangerError as e: - show_error(e.summary) + logging.exception(e.summary) return False if not ws.changes_since_main(): if existing_proposal: - note('%s: nothing left to do. Closing proposal.', pkg) + logging.info("%s: nothing left to do. Closing proposal.", pkg) existing_proposal.close() else: - note('%s: nothing to do', pkg) + logging.info("%s: nothing to do", pkg) return None try: run_post_check(ws.local_tree, post_check, ws.orig_revid) except PostCheckFailed as e: - note('%s: %s', pkg, e) + logging.info("%s: %s", pkg, e) return False if build_verify: try: ws.build(builder=builder, result_dir=build_target_dir) except BuildFailedError: - note('%s: build failed', pkg) + logging.info("%s: build failed", pkg) return False except MissingUpstreamTarball: - note('%s: unable to find upstream source', pkg) + logging.info("%s: unable to find upstream source", pkg) return False enable_tag_pushing(ws.local_tree.branch) kwargs: Dict[str, Any] = {} if breezy_version_info >= (3, 1): - kwargs['tags'] = changer_result.tags + kwargs["tags"] = changer_result.tags try: publish_result = ws.publish_changes( - mode, branch_name, + mode, + branch_name, get_proposal_description=partial( - changer.get_proposal_description, changer_result.mutator), + changer.get_proposal_description, changer_result.mutator + ), get_proposal_commit_message=( - lambda oldmp: changer_result.proposed_commit_message), - dry_run=dry_run, hoster=hoster, + lambda oldmp: changer_result.proposed_commit_message + ), + dry_run=dry_run, + hoster=hoster, allow_create_proposal=changer_result.sufficient_for_proposal, overwrite_existing=overwrite, existing_proposal=existing_proposal, - derived_owner=derived_owner, labels=label, - **kwargs) + derived_owner=derived_owner, + labels=label, + **kwargs + ) except UnsupportedHoster as e: - show_error( - '%s: No known supported hoster for %s. Run \'svp login\'?', - pkg, full_branch_url(e.branch)) + logging.exception( + "%s: No known supported hoster for %s. Run 'svp login'?", + pkg, + full_branch_url(e.branch), + ) return False except NoSuchProject as e: - note('%s: project %s was not found', pkg, e.project) + logging.info("%s: project %s was not found", pkg, e.project) return False except errors.PermissionDenied as e: - note('%s: %s', pkg, e) + logging.info("%s: %s", pkg, e) return False except errors.DivergedBranches: - note('%s: a branch exists. Use --overwrite to discard it.', - pkg) + logging.info("%s: a branch exists. Use --overwrite to discard it.", pkg) return False except HosterLoginRequired as e: - show_error( - 'Credentials for hosting site at %r missing. ' - 'Run \'svp login\'?', e.hoster.base_url) + logging.exception( + "Credentials for hosting site at %r missing. " "Run 'svp login'?", + e.hoster.base_url, + ) return False if publish_result.proposal: @@ -419,21 +502,20 @@ for entry in changer_result.branches: role = entry[0] if len(changer_result.branches) > 1: - sys.stdout.write('%s\n' % role) - sys.stdout.write(('-' * len(role)) + '\n') + sys.stdout.write("%s\n" % role) + sys.stdout.write(("-" * len(role)) + "\n") sys.stdout.flush() changer_result.show_diff( - ws.local_tree.branch.repository, sys.stdout.buffer, - role=role) + ws.local_tree.branch.repository, sys.stdout.buffer, role=role + ) if len(changer_result.branches) > 1: - sys.stdout.write('\n') + sys.stdout.write("\n") return True -def run_single_changer( - changer: DebianChanger, args: argparse.Namespace) -> int: - import silver_platter # noqa: F401 +def run_single_changer(changer: DebianChanger, args: argparse.Namespace) -> int: + import silver_platter # noqa: F401 if args.name: branch_name = args.name @@ -441,34 +523,63 @@ branch_name = changer.suggest_branch_name() try: - (pkg, main_branch, subpath, resume_branch, hoster, existing_proposal, - overwrite) = get_package( - args.package, branch_name, overwrite_unrelated=args.overwrite, - refresh=args.refresh, owner=args.derived_owner) + ( + pkg, + main_branch, + subpath, + resume_branch, + hoster, + existing_proposal, + overwrite, + ) = get_package( + args.package, + branch_name, + overwrite_unrelated=args.overwrite, + refresh=args.refresh, + owner=args.derived_owner, + ) except NoSuchPackage: - note('%s: no such package', args.package) + logging.info("%s: no such package", args.package) return 1 except NoSuchProject as e: - note('%s: unable to find project: %s', args.package, e.project) + logging.info("%s: unable to find project: %s", args.package, e.project) return 1 except (BranchMissing, BranchUnavailable, BranchUnsupported) as e: - note('%s: ignoring: %s', args.package, e) + logging.info("%s: ignoring: %s", args.package, e) return 1 except NoAptSources: - note('%s: no apt sources configured, unable to get package metadata.', - args.package) + logging.info( + "%s: no apt sources configured, unable to get package metadata.", + args.package, + ) return 1 - if _run_single_changer( - changer, pkg, main_branch, subpath, resume_branch, hoster, - existing_proposal, overwrite, args.mode, branch_name, - diff=args.diff, committer=args.committer, + if ( + _run_single_changer( + changer, + pkg, + main_branch, + subpath, + resume_branch, + hoster, + existing_proposal, + overwrite, + args.mode, + branch_name, + diff=args.diff, + committer=args.committer, build_verify=args.build_verify, - pre_check=args.pre_check, builder=args.builder, - post_check=args.post_check, dry_run=args.dry_run, + pre_check=args.pre_check, + builder=args.builder, + post_check=args.post_check, + dry_run=args.dry_run, update_changelog=args.update_changelog, - label=args.label, derived_owner=args.derived_owner, - build_target_dir=args.build_target_dir) is False: + label=args.label, + derived_owner=args.derived_owner, + build_target_dir=args.build_target_dir, + ) + is False + ): return 1 else: return 0 @@ -476,44 +587,49 @@ BUILTIN_ENTRYPOINTS = [ pkg_resources.EntryPoint( - 'run', 'silver_platter.debian.run', attrs=('ScriptChanger', )), - pkg_resources.EntryPoint( - 'lintian-brush', 'silver_platter.debian.lintian', - attrs=('LintianBrushChanger', )), - pkg_resources.EntryPoint( - 'tidy', 'silver_platter.debian.tidy', - attrs=('TidyChanger', )), - pkg_resources.EntryPoint( - 'new-upstream', 'silver_platter.debian.upstream', - attrs=('NewUpstreamChanger', )), + "run", "silver_platter.debian.run", attrs=("ScriptChanger",) + ), pkg_resources.EntryPoint( - 'cme', 'silver_platter.debian.cme', - attrs=('CMEChanger', )), + "lintian-brush", "silver_platter.debian.lintian", attrs=("LintianBrushChanger",) + ), pkg_resources.EntryPoint( - 'apply-multiarch-hints', - 'silver_platter.debian.multiarch', attrs=('MultiArchHintsChanger', )), + "tidy", "silver_platter.debian.tidy", attrs=("TidyChanger",) + ), pkg_resources.EntryPoint( - 'rules-requires-root', - 'silver_platter.debian.rrr', attrs=('RulesRequiresRootChanger', )), + "new-upstream", "silver_platter.debian.upstream", attrs=("NewUpstreamChanger",) + ), + pkg_resources.EntryPoint("cme-fix", "silver_platter.debian.cme", attrs=("CMEFixChanger",)), + pkg_resources.EntryPoint( + "apply-multiarch-hints", + "silver_platter.debian.multiarch", + attrs=("MultiArchHintsChanger",), + ), + pkg_resources.EntryPoint( + "rules-requires-root", + "silver_platter.debian.rrr", + attrs=("RulesRequiresRootChanger",), + ), + pkg_resources.EntryPoint( + "orphan", "silver_platter.debian.orphan", attrs=("OrphanChanger",) + ), + pkg_resources.EntryPoint( + "import-upload", + "silver_platter.debian.uncommitted", + attrs=("UncommittedChanger",), + ), + pkg_resources.EntryPoint( + "scrub-obsolete", + "silver_platter.debian.scrub_obsolete", + attrs=("ScrubObsoleteChanger",), + ), pkg_resources.EntryPoint( - 'orphan', - 'silver_platter.debian.orphan', attrs=('OrphanChanger', )), - pkg_resources.EntryPoint( - 'import-upload', - 'silver_platter.debian.uncommitted', attrs=('UncommittedChanger', )), - pkg_resources.EntryPoint( - 'scrub-obsolete', - 'silver_platter.debian.scrub_obsolete', - attrs=('ScrubObsoleteChanger', )), - pkg_resources.EntryPoint( - 'debianize', 'silver_platter.debian.debianize', - attrs=('DebianizeChanger', )), + "debianize", "silver_platter.debian.debianize", attrs=("DebianizeChanger",) + ), ] def changer_subcommands() -> List[str]: - endpoints = pkg_resources.iter_entry_points( - 'silver_platter.debian.changer') + endpoints = pkg_resources.iter_entry_points("silver_platter.debian.changer") ret = [] for ep in BUILTIN_ENTRYPOINTS + list(endpoints): ret.append(ep.name) @@ -524,8 +640,7 @@ for ep in BUILTIN_ENTRYPOINTS: if ep.name == name: return ep.resolve() - endpoints = pkg_resources.iter_entry_points( - 'silver_platter.debian.changer', name) + endpoints = pkg_resources.iter_entry_points("silver_platter.debian.changer", name) for ep in endpoints: return ep.load() raise KeyError(name) @@ -536,76 +651,81 @@ import argparse import os from breezy.workingtree import WorkingTree + parser = argparse.ArgumentParser() changer_cls.setup_parser(parser) args = parser.parse_args(argv) - wt, subpath = WorkingTree.open_containing('.') + wt, subpath = WorkingTree.open_containing(".") changer = changer_cls.from_args(args) try: - update_changelog_str = os.environ['UPDATE_CHANGELOG'], + update_changelog_str = (os.environ["UPDATE_CHANGELOG"],) except KeyError: update_changelog = None else: - if update_changelog_str == 'leave_changelog': + if update_changelog_str == "leave_changelog": update_changelog = False - elif update_changelog_str == 'update_changelog': + elif update_changelog_str == "update_changelog": update_changelog = True else: # TODO(jelmer): Warn update_changelog = None try: - base_metadata_path = os.environ['BASE_METADATA'] + base_metadata_path = os.environ["BASE_METADATA"] except KeyError: existing_proposal = None else: - with open(base_metadata_path, 'r') as f: + with open(base_metadata_path, "r") as f: base_metadata = json.load(f) class PreviousProposal(MergeProposal): - def __init__(self, metadata): self.metadata = metadata def get_description(self): - return self.metadata.get('description') + return self.metadata.get("description") def get_commit_message(self): - return self.metadata.get('commit-message') + return self.metadata.get("commit-message") - existing_proposal = PreviousProposal(base_metadata['merge-proposal']) + existing_proposal = PreviousProposal(base_metadata["merge-proposal"]) mutator_metadata = {} try: result = changer.make_changes( - wt, subpath, update_changelog=update_changelog, - committer=os.environ.get('COMMITTER'), + wt, + subpath, + update_changelog=update_changelog, + committer=os.environ.get("COMMITTER"), base_proposal=existing_proposal, - reporter=DummyChangerReporter()) + reporter=DummyChangerReporter(), + ) except ChangerError as e: result_json = { - 'result-code': e.category, - 'description': e.summary, + "result-code": e.category, + "description": e.summary, } else: result_json = { - 'result-code': None, - 'description': result.description, - 'suggested-branch-name': changer.suggest_branch_name(), - 'tags': result.tags, - 'branches': result.branches, - 'value': result.value, - 'mutator': mutator_metadata, - 'merge-proposal': { - 'sufficient': changer.sufficient_for_proposal, - 'commit-message': result.proposed_commit_message, - 'title': result.title, - 'labels': result.labels, - 'description-plain': changer.get_proposal_description( - result.mutator, 'plain', existing_proposal), - 'description-markdown': changer.get_proposal_description( - result.mutator, 'markdown', existing_proposal), - } + "result-code": None, + "description": result.description, + "suggested-branch-name": changer.suggest_branch_name(), + "tags": result.tags, + "branches": result.branches, + "value": result.value, + "mutator": mutator_metadata, + "merge-proposal": { + "sufficient": changer.sufficient_for_proposal, + "commit-message": result.proposed_commit_message, + "title": result.title, + "labels": result.labels, + "description-plain": changer.get_proposal_description( + result.mutator, "plain", existing_proposal + ), + "description-markdown": changer.get_proposal_description( + result.mutator, "markdown", existing_proposal + ), + }, } json.dump(result_json, sys.stdout, indent=4) return 0 diff -Nru silver-platter-0.4.0/silver_platter/debian/cme.py silver-platter-0.4.1/silver_platter/debian/cme.py --- silver-platter-0.4.0/silver_platter/debian/cme.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/cme.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,28 +15,27 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +import logging import subprocess from .changer import ( run_mutator, DebianChanger, ChangerResult, - ) -from breezy.trace import note +) -BRANCH_NAME = 'cme' +BRANCH_NAME = "cme" class CMEResult(object): - def __init__(self): pass -class CMEChanger(DebianChanger): +class CMEFixChanger(DebianChanger): - name = 'cme' + name = "cme-fix" def __init__(self, dry_run=False): self.dry_run = dry_run @@ -52,40 +51,51 @@ def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, reporter, - committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revid = local_tree.last_revision() - cwd = local_tree.abspath(subpath or '') - subprocess.check_call( - ['/usr/bin/cme', 'modify', 'dpkg', '-save'], - cwd=cwd) - local_tree.commit('Reformat for cme.') - subprocess.check_call( - ['/usr/bin/cme', 'fix', 'dpkg'], cwd=cwd) - revid = local_tree.commit('Run cme.') - branches = [('main', None, base_revid, revid)] + cwd = local_tree.abspath(subpath or "") + subprocess.check_call(["/usr/bin/cme", "modify", "dpkg", "-save"], cwd=cwd) + local_tree.commit("Reformat for cme.") + subprocess.check_call(["/usr/bin/cme", "fix", "dpkg"], cwd=cwd) + revid = local_tree.commit("Run cme.") + branches = [("main", None, base_revid, revid)] tags = [] return ChangerResult( - description=None, mutator=None, branches=branches, - tags=tags, proposed_commit_message='Run cme.', - sufficient_for_proposal=True) - - def get_proposal_description( - self, applied, description_format, existing_proposal): - return 'Run cme.' + description=None, + mutator=None, + branches=branches, + tags=tags, + proposed_commit_message="Run cme.", + sufficient_for_proposal=True, + ) + + def get_proposal_description(self, applied, description_format, existing_proposal): + return "Run cme." def describe(self, result, publish_result): if publish_result.is_new: - note('Proposed change from \'cme fix dpkg\': %s', - publish_result.proposal.url) + logging.info( + "Proposed change from 'cme fix dpkg': %s", + publish_result.proposal.url) else: - note('No changes for package %s', result.package_name) + logging.info( + "No changes for package %s", + result.package_name) @classmethod def describe_command(cls, command): return "Apply Configuration Model Editor (CME) fixes" -if __name__ == '__main__': +if __name__ == "__main__": import sys - sys.exit(run_mutator(CMEChanger)) + + sys.exit(run_mutator(CMEFixChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/debianize.py silver-platter-0.4.1/silver_platter/debian/debianize.py --- silver-platter-0.4.0/silver_platter/debian/debianize.py 2021-02-01 23:26:44.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/debianize.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,30 +15,27 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import argparse +import logging import sys import breezy -from breezy.trace import note +from breezy.revision import NULL_REVISION from lintian_brush import ( version_string as lintian_brush_version_string, - ) +) from lintian_brush.debianize import ( debianize, - ) +) from lintian_brush.config import Config import silver_platter -from . import ( - control_files_in_root, - ) from .changer import ( DebianChanger, - ChangerResult, run_mutator, - ChangerError, - ) + ChangerResult, +) BRANCH_NAME = "debianize" @@ -46,15 +43,14 @@ class DebianizeChanger(DebianChanger): - name = 'debianize' + name = "debianize" def __init__(self, compat_release=None): self.compat_release = compat_release @classmethod def setup_parser(cls, parser): - parser.add_argument( - '--compat-release', type=str, help=argparse.SUPPRESS) + parser.add_argument("--compat-release", type=str, help=argparse.SUPPRESS) @classmethod def from_args(cls, args): @@ -63,17 +59,29 @@ def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, - reporter, committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revid = local_tree.last_revision() + upstream_base_revid = NULL_REVISION - reporter.report_metadata('versions', { - 'lintian-brush': lintian_brush_version_string, - 'silver-platter': silver_platter.version_string, - 'breezy': breezy.version_string, - }) + reporter.report_metadata( + "versions", + { + "lintian-brush": lintian_brush_version_string, + "silver-platter": silver_platter.version_string, + "breezy": breezy.version_string, + }, + ) import distro_info + debian_info = distro_info.DebianDistroInfo() compat_release = self.compat_release @@ -85,39 +93,40 @@ compat_release = cfg.compat_release() if compat_release: compat_release = debian_info.codename( - compat_release, default=compat_release) + compat_release, default=compat_release + ) if compat_release is None: compat_release = debian_info.stable() with local_tree.lock_write(): - if control_files_in_root(local_tree, subpath): - raise ChangerError( - 'control-files-in-root', - 'control files live in root rather than debian/ ' - '(LarstIQ mode)') - - debianize( - local_tree, subpath=subpath, - compat_release=self.compat_release) + debianize(local_tree, subpath=subpath, compat_release=self.compat_release) + # TODO(jelmer): Pristine tar branch? branches = [ - ('main', None, base_revid, - local_tree.last_revision())] + ("main", None, base_revid, local_tree.last_revision()), + ( + "upstream", + "upstream", + upstream_base_revid, + local_tree.controldir.open_branch("upstream").last_revision(), + ), + ] return ChangerResult( - description='Debianized package.', + description="Debianized package.", mutator=None, - branches=branches, tags=[], + branches=branches, + tags=[], value=None, - sufficient_for_proposal=True) + sufficient_for_proposal=True, + ) - def get_proposal_description( - self, applied, description_format, existing_proposal): + def get_proposal_description(self, applied, description_format, existing_proposal): return "Debianize package." def describe(self, applied, publish_result): - note('Created Debian package.') + logging.info("Created Debian package.") -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(run_mutator(DebianizeChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/__init__.py silver-platter-0.4.1/silver_platter/debian/__init__.py --- silver-platter-0.4.0/silver_platter/debian/__init__.py 2021-02-01 20:49:25.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/__init__.py 2021-02-17 22:45:01.000000000 +0000 @@ -32,19 +32,16 @@ from breezy.plugins.debian.directory import ( source_package_vcs, vcs_field_to_bzr_url_converters, - ) +) from breezy.tree import Tree from breezy.urlutils import InvalidURL from breezy.workingtree import WorkingTree -from breezy.plugins.debian.changelog import ( - changelog_commit_message, - ) from breezy.plugins.debian.builder import BuildFailedError from breezy.plugins.debian.upstream import ( MissingUpstreamTarball, - ) +) from lintian_brush.detect_gbp_dch import guess_update_changelog from lintian_brush.changelog import add_changelog_entry @@ -52,33 +49,35 @@ from .. import proposal as _mod_proposal from ..utils import ( open_branch, - ) +) __all__ = [ - 'add_changelog_entry', - 'changelog_add_line', - 'apt_get_source_package', - 'guess_update_changelog', - 'source_package_vcs', - 'build', - 'BuildFailedError', - 'MissingUpstreamTarball', - 'vcs_field_to_bzr_url_converters', - ] + "add_changelog_entry", + "changelog_add_line", + "apt_get_source_package", + "guess_update_changelog", + "source_package_vcs", + "build", + "BuildFailedError", + "MissingUpstreamTarball", + "vcs_field_to_bzr_url_converters", +] -DEFAULT_BUILDER = 'sbuild --no-clean-source' +DEFAULT_BUILDER = "sbuild --no-clean-source" class NoSuchPackage(Exception): """No such package.""" -def build(tree: Tree, - subpath: str = '', - builder: Optional[str] = None, - result_dir: Optional[str] = None) -> None: +def build( + tree: Tree, + subpath: str = "", + builder: Optional[str] = None, + result_dir: Optional[str] = None, +) -> None: """Build a debian package in a directory. Args: @@ -92,8 +91,7 @@ # TODO(jelmer): Refactor brz-debian so it's not necessary # to call out to cmd_builddeb, but to lower-level # functions instead. - cmd_builddeb().run( - [tree.abspath(subpath)], builder=builder, result_dir=result_dir) + cmd_builddeb().run([tree.abspath(subpath)], builder=builder, result_dir=result_dir) class NoAptSources(Exception): @@ -109,13 +107,13 @@ A `Deb822` object """ import apt_pkg + apt_pkg.init() try: sources = apt_pkg.SourceRecords() except apt_pkg.Error as e: - if e.args[0] == ( - 'E:You must put some \'deb-src\' URIs in your sources.list'): + if e.args[0] == ("E:You must put some 'deb-src' URIs in your sources.list"): raise NoAptSources() raise @@ -137,9 +135,9 @@ try: return converters[vcs_type](vcs_url) except KeyError: - raise ValueError('unknown vcs %s' % vcs_type) + raise ValueError("unknown vcs %s" % vcs_type) except InvalidURL as e: - raise ValueError('invalid URL: %s' % e) + raise ValueError("invalid URL: %s" % e) def open_packaging_branch(location, possible_transports=None, vcs_type=None): @@ -147,74 +145,62 @@ location can either be a package name or a full URL """ - if '/' not in location and ':' not in location: + if "/" not in location and ":" not in location: pkg_source = apt_get_source_package(location) try: (vcs_type, vcs_url) = source_package_vcs(pkg_source) except KeyError: - raise Exception( - 'Package %s does not have any VCS information' % location) + raise Exception("Package %s does not have any VCS information" % location) (url, branch_name, subpath) = split_vcs_url(vcs_url) else: url, params = urlutils.split_segment_parameters(location) - branch_name = params.get('branch') - subpath = '' + branch_name = params.get("branch") + subpath = "" probers = select_probers(vcs_type) branch = open_branch( - url, possible_transports=possible_transports, probers=probers, - name=branch_name) - return branch, subpath or '' + url, possible_transports=possible_transports, probers=probers, name=branch_name + ) + return branch, subpath or "" def pick_additional_colocated_branches(main_branch): ret = ["pristine-tar", "pristine-lfs", "upstream"] - ret.append('patch-queue/' + main_branch.name) - if main_branch.name.startswith('debian/'): - parts = main_branch.name.split('/') - parts[0] = 'upstream' - ret.append('/'.join(parts)) + ret.append("patch-queue/" + main_branch.name) + if main_branch.name.startswith("debian/"): + parts = main_branch.name.split("/") + parts[0] = "upstream" + ret.append("/".join(parts)) return ret class Workspace(_mod_proposal.Workspace): - def __init__(self, main_branch: Branch, *args, **kwargs) -> None: if isinstance(main_branch.repository, GitRepository): - kwargs['additional_colocated_branches'] = ( - kwargs.get('additional_colocated_branches', []) + - pick_additional_colocated_branches(main_branch)) + kwargs["additional_colocated_branches"] = kwargs.get( + "additional_colocated_branches", [] + ) + pick_additional_colocated_branches(main_branch) super(Workspace, self).__init__(main_branch, *args, **kwargs) - def build(self, builder: Optional[str] = None, - result_dir: Optional[str] = None, subpath: str = '') -> None: - return build(tree=self.local_tree, subpath=subpath, builder=builder, - result_dir=result_dir) - - -def debcommit(tree, committer=None, subpath='', paths=None): - message = changelog_commit_message( - tree, tree.basis_tree(), - path=os.path.join(subpath, 'debian/changelog')) - if paths: - specific_files = [os.path.join(subpath, p) for p in paths] - elif subpath: - specific_files = [subpath] - else: - specific_files = None - tree.commit( - committer=committer, - message=message, - specific_files=specific_files) + def build( + self, + builder: Optional[str] = None, + result_dir: Optional[str] = None, + subpath: str = "", + ) -> None: + return build( + tree=self.local_tree, + subpath=subpath, + builder=builder, + result_dir=result_dir, + ) class UnsupportedVCSProber(Prober): - def __init__(self, vcs_type): self.vcs_type = vcs_type def __eq__(self, other): - return (isinstance(other, type(self)) and - other.vcs_type == self.vcs_type) + return isinstance(other, type(self)) and other.vcs_type == self.vcs_type def __call__(self): # The prober expects to be registered as a class. @@ -225,8 +211,8 @@ def probe_transport(self, transport): raise UnsupportedFormatError( - 'This VCS %s is not currently supported.' % - self.vcs_type) + "This VCS %s is not currently supported." % self.vcs_type + ) @classmethod def known_formats(klass): @@ -234,8 +220,8 @@ prober_registry = { - 'bzr': RemoteBzrProber, - 'git': RemoteGitProber, + "bzr": RemoteBzrProber, + "git": RemoteGitProber, } try: @@ -243,35 +229,35 @@ except ImportError: pass else: - prober_registry['fossil'] = RemoteFossilProber + prober_registry["fossil"] = RemoteFossilProber try: from breezy.plugins.svn import SvnRepositoryProber except ImportError: pass else: - prober_registry['svn'] = SvnRepositoryProber + prober_registry["svn"] = SvnRepositoryProber try: from breezy.plugins.hg import SmartHgProber except ImportError: pass else: - prober_registry['hg'] = SmartHgProber + prober_registry["hg"] = SmartHgProber try: from breezy.plugins.darcs import DarcsProber except ImportError: pass else: - prober_registry['darcs'] = DarcsProber + prober_registry["darcs"] = DarcsProber try: from breezy.plugins.cvs import CVSProber except ImportError: pass else: - prober_registry['cvs'] = CVSProber + prober_registry["cvs"] = CVSProber def select_probers(vcs_type=None): @@ -294,35 +280,32 @@ def changelog_add_line( - tree: WorkingTree, - subpath: str, - line: str, - email: Optional[str] = None) -> None: + tree: WorkingTree, subpath: str, line: str, email: Optional[str] = None +) -> None: env = {} if email: - env['DEBEMAIL'] = email - subprocess.check_call( - ['dch', '--', line], cwd=tree.abspath(subpath), env=env) + env["DEBEMAIL"] = email + subprocess.check_call(["dch", "--", line], cwd=tree.abspath(subpath), env=env) def is_debcargo_package(tree: Tree, subpath: str) -> bool: - debian_path = os.path.join(subpath, 'debian') + debian_path = os.path.join(subpath, "debian") if tree.has_filename(debian_path): return False - control_path = os.path.join(subpath, 'debcargo.toml') + control_path = os.path.join(subpath, "debcargo.toml") if tree.has_filename(control_path): return True return False def control_files_in_root(tree: Tree, subpath: str) -> bool: - debian_path = os.path.join(subpath, 'debian') + debian_path = os.path.join(subpath, "debian") if tree.has_filename(debian_path): return False - control_path = os.path.join(subpath, 'control') + control_path = os.path.join(subpath, "control") if tree.has_filename(control_path): return True - if tree.has_filename(control_path + '.in'): + if tree.has_filename(control_path + ".in"): return True return False @@ -336,8 +319,7 @@ Returns: whether control file is present """ - for name in ['debian/control', 'debian/control.in', 'control', - 'control.in']: + for name in ["debian/control", "debian/control.in", "control", "control.in"]: name = os.path.join(subpath, name) if tree.has_filename(name): return True diff -Nru silver-platter-0.4.0/silver_platter/debian/lintian.py silver-platter-0.4.1/silver_platter/debian/lintian.py --- silver-platter-0.4.0/silver_platter/debian/lintian.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/lintian.py 2021-02-17 22:45:01.000000000 +0000 @@ -16,14 +16,13 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import argparse +import logging import sys from typing import List, Set from debian.changelog import ChangelogCreateError import breezy -from breezy.errors import BzrError -from breezy.trace import note from lintian_brush import ( available_lintian_fixers, @@ -32,55 +31,54 @@ SUPPORTED_CERTAINTIES, NotDebianPackage, version_string as lintian_brush_version_string, - ) +) from lintian_brush.config import Config import silver_platter from . import ( control_files_in_root, - ) +) from .changer import ( DebianChanger, ChangerResult, run_mutator, ChangerError, - ) +) __all__ = [ - 'available_lintian_fixers', - 'calculate_value', - ] + "available_lintian_fixers", + "calculate_value", +] DEFAULT_ADDON_FIXERS = [ - 'debian-changelog-line-too-long', - 'file-contains-trailing-whitespace', - 'out-of-date-standards-version', - 'package-uses-old-debhelper-compat-version', - 'public-upstream-key-not-minimal', - 'no-dh-sequencer', - ] + "debian-changelog-line-too-long", + "file-contains-trailing-whitespace", + "out-of-date-standards-version", + "package-uses-old-debhelper-compat-version", + "public-upstream-key-not-minimal", + "no-dh-sequencer", +] DEFAULT_VALUE_LINTIAN_BRUSH_ADDON_ONLY = 10 DEFAULT_VALUE_LINTIAN_BRUSH = 50 # Base these scores on the importance as set in Debian? LINTIAN_BRUSH_TAG_VALUES = { - 'file-contains-trailing-whitespace': 0, - } + "file-contains-trailing-whitespace": 0, +} LINTIAN_BRUSH_TAG_DEFAULT_VALUE = 5 BRANCH_NAME = "lintian-fixes" -class UnknownFixer(BzrError): +class UnknownFixer(Exception): """The specified fixer is unknown.""" - _fmt = "No such fixer: %s." - def __init__(self, fixer): - super(UnknownFixer, self).__init__(fixer=fixer) + self.fixer = fixer + super(UnknownFixer, self).__init__("No such fixer: %s." % fixer) def calculate_value(tags: Set[str]) -> int: @@ -89,8 +87,7 @@ else: value = DEFAULT_VALUE_LINTIAN_BRUSH for tag in tags: - value += LINTIAN_BRUSH_TAG_VALUES.get( - tag, LINTIAN_BRUSH_TAG_DEFAULT_VALUE) + value += LINTIAN_BRUSH_TAG_VALUES.get(tag, LINTIAN_BRUSH_TAG_DEFAULT_VALUE) return value @@ -106,8 +103,9 @@ if len(existing_lines) == 1: return existing_lines else: - return [line[2:].rstrip('\n') - for line in existing_lines if line.startswith('* ')] + return [ + line[2:].rstrip("\n") for line in existing_lines if line.startswith("* ") + ] def create_mp_description(description_format: str, lines: List[str]) -> str: @@ -126,46 +124,58 @@ mp_description.append(line) else: mp_description = [lines[0]] - return ''.join(mp_description) + return "".join(mp_description) def applied_entry_as_line(description_format, fixed_lintian_tags, line): if not fixed_lintian_tags: return line - if description_format == 'markdown': - return '%s (%s)' % (line, ', '.join( - ['[%s](https://lintian.debian.org/tags/%s.html)' % (tag, tag) - for tag in fixed_lintian_tags])) - return '%s (%s)' % (line, ', '.join(fixed_lintian_tags)) + if description_format == "markdown": + return "%s (%s)" % ( + line, + ", ".join( + [ + "[%s](https://lintian.debian.org/tags/%s.html)" % (tag, tag) + for tag in fixed_lintian_tags + ] + ), + ) + return "%s (%s)" % (line, ", ".join(fixed_lintian_tags)) -def update_proposal_description( - description_format, existing_proposal, applied): +def update_proposal_description(description_format, existing_proposal, applied): if existing_proposal: existing_description = existing_proposal.get_description() existing_lines = parse_mp_description(existing_description) else: existing_lines = [] return create_mp_description( - description_format, existing_lines + - [applied_entry_as_line(description_format, r.fixed_lintian_tags, l) - for r, l in applied]) + description_format, + existing_lines + + [ + applied_entry_as_line(description_format, r.fixed_lintian_tags, l) + for r, l in applied + ], + ) def update_proposal_commit_message(existing_proposal, applied): existing_commit_message = getattr( - existing_proposal, 'get_commit_message', lambda: None)() + existing_proposal, "get_commit_message", lambda: None + )() if existing_commit_message and not existing_commit_message.startswith( - 'Fix lintian issues: '): + "Fix lintian issues: " + ): # The commit message is something we haven't set - let's leave it # alone. return if existing_commit_message: - existing_applied = existing_commit_message.split(':', 1)[1] + existing_applied = existing_commit_message.split(":", 1)[1] else: existing_applied = [] return "Fix lintian issues: " + ( - ', '.join(sorted(existing_applied + [l for r, l in applied]))) + ", ".join(sorted(existing_applied + [l for r, l in applied])) + ) def has_nontrivial_changes(applied, propose_addon_only: Set[str]) -> bool: @@ -214,16 +224,24 @@ class LintianBrushChanger(DebianChanger): - name = 'lintian-brush' + name = "lintian-brush" def __init__( - self, names=None, exclude=None, propose_addon_only=None, - compat_release=None, allow_reformatting=None, - minimum_certainty=None, tags=None, - opinionated=False, trust_package=False, diligence=0): + self, + names=None, + exclude=None, + propose_addon_only=None, + compat_release=None, + allow_reformatting=None, + minimum_certainty=None, + tags=None, + opinionated=False, + trust_package=False, + diligence=0, + ): self.fixers = get_fixers( - available_lintian_fixers(), names=names, - tags=tags, exclude=exclude) + available_lintian_fixers(), names=names, tags=tags, exclude=exclude + ) self.propose_addon_only = propose_addon_only or [] self.compat_release = compat_release self.allow_reformatting = allow_reformatting @@ -235,64 +253,86 @@ @classmethod def setup_parser(cls, parser): parser.add_argument( - "--fixers", - help="Fixers to run.", type=str, action='append') + "--fixers", help="Fixers to run.", type=str, action="append" + ) parser.add_argument( - '--exclude', - help='Fixers to exclude.', type=str, action='append') + "--exclude", help="Fixers to exclude.", type=str, action="append" + ) parser.add_argument( - '--propose-addon-only', - help='Fixers that should be considered add-on-only.', - type=str, action='append', - default=DEFAULT_ADDON_FIXERS) + "--propose-addon-only", + help="Fixers that should be considered add-on-only.", + type=str, + action="append", + default=DEFAULT_ADDON_FIXERS, + ) parser.add_argument( - '--compat-release', type=str, default=None, - help='Oldest Debian release to be compatible with.') + "--compat-release", + type=str, + default=None, + help="Oldest Debian release to be compatible with.", + ) parser.add_argument( - '--allow-reformatting', default=None, action='store_true', - help='Whether to allow reformatting.') + "--allow-reformatting", + default=None, + action="store_true", + help="Whether to allow reformatting.", + ) parser.add_argument( - '--minimum-certainty', + "--minimum-certainty", type=str, choices=SUPPORTED_CERTAINTIES, default=None, - help=argparse.SUPPRESS) - parser.add_argument( - '--opinionated', action='store_true', - help='Make opinionated changes') + help=argparse.SUPPRESS, + ) parser.add_argument( - '--diligence', type=int, default=10, - help=argparse.SUPPRESS) + "--opinionated", action="store_true", help="Make opinionated changes" + ) + parser.add_argument("--diligence", type=int, default=10, help=argparse.SUPPRESS) parser.add_argument( - '--trust-package', action='store_true', - help='Trust package.') - parser.add_argument("tags", nargs='*') + "--trust-package", action="store_true", help="Trust package." + ) + parser.add_argument("tags", nargs="*") @classmethod def from_args(cls, args): - return cls(names=args.fixers, exclude=args.exclude, - propose_addon_only=args.propose_addon_only, - compat_release=args.compat_release, - allow_reformatting=args.allow_reformatting, - minimum_certainty=args.minimum_certainty, - tags=args.tags, opinionated=args.opinionated, - diligence=args.diligence, - trust_package=args.trust_package) + return cls( + names=args.fixers, + exclude=args.exclude, + propose_addon_only=args.propose_addon_only, + compat_release=args.compat_release, + allow_reformatting=args.allow_reformatting, + minimum_certainty=args.minimum_certainty, + tags=args.tags, + opinionated=args.opinionated, + diligence=args.diligence, + trust_package=args.trust_package, + ) def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, - reporter, committer, base_proposal=None): + def make_changes( # noqa: C901 + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revid = local_tree.last_revision() - reporter.report_metadata('versions', { - 'lintian-brush': lintian_brush_version_string, - 'silver-platter': silver_platter.version_string, - 'breezy': breezy.version_string, - }) + reporter.report_metadata( + "versions", + { + "lintian-brush": lintian_brush_version_string, + "silver-platter": silver_platter.version_string, + "breezy": breezy.version_string, + }, + ) import distro_info + debian_info = distro_info.DebianDistroInfo() compat_release = self.compat_release @@ -306,7 +346,8 @@ compat_release = cfg.compat_release() if compat_release: compat_release = debian_info.codename( - compat_release, default=compat_release) + compat_release, default=compat_release + ) allow_reformatting = cfg.allow_reformatting() minimum_certainty = cfg.minimum_certainty() if compat_release is None: @@ -319,103 +360,112 @@ with local_tree.lock_write(): if control_files_in_root(local_tree, subpath): raise ChangerError( - 'control-files-in-root', - 'control files live in root rather than debian/ ' - '(LarstIQ mode)') + "control-files-in-root", + "control files live in root rather than debian/ " "(LarstIQ mode)", + ) try: overall_result = run_lintian_fixers( - local_tree, self.fixers, - committer=committer, - update_changelog=update_changelog, - compat_release=compat_release, - allow_reformatting=allow_reformatting, - minimum_certainty=minimum_certainty, - subpath=subpath, diligence=self.diligence, - opinionated=self.opinionated, - trust_package=self.trust_package) + local_tree, + self.fixers, + committer=committer, + update_changelog=update_changelog, + compat_release=compat_release, + allow_reformatting=allow_reformatting, + minimum_certainty=minimum_certainty, + subpath=subpath, + diligence=self.diligence, + opinionated=self.opinionated, + trust_package=self.trust_package, + ) except NotDebianPackage: - raise ChangerError( - 'not-debian-package', 'Not a Debian package') + raise ChangerError("not-debian-package", "Not a Debian package") except ChangelogCreateError as e: raise ChangerError( - 'changelog-create-error', - 'Error creating changelog entry: %s' % e) + "changelog-create-error", "Error creating changelog entry: %s" % e + ) applied = [] - base_applied = reporter.get_base_metadata('applied', []) + base_applied = reporter.get_base_metadata("applied", []) if base_applied: applied.extend(base_applied) for result, summary in overall_result.success: - applied.append({ - 'summary': summary, - 'description': result.description, - 'fixed_lintian_tags': result.fixed_lintian_tags, - 'revision_id': result.revision_id.decode('utf-8'), - 'certainty': result.certainty}) - reporter.report_metadata('applied', applied) + applied.append( + { + "summary": summary, + "description": result.description, + "fixed_lintian_tags": result.fixed_lintian_tags, + "revision_id": result.revision_id.decode("utf-8"), + "certainty": result.certainty, + } + ) + reporter.report_metadata("applied", applied) if overall_result.failed_fixers: for fixer_name, failure in overall_result.failed_fixers.items(): - note('Fixer %r failed to run:', fixer_name) + logging.info("Fixer %r failed to run:", fixer_name) sys.stderr.write(str(failure)) reporter.report_metadata( - 'failed', { - name: str(e) - for (name, e) in overall_result.failed_fixers.items()}) + "failed", + {name: str(e) for (name, e) in overall_result.failed_fixers.items()}, + ) if not overall_result.success: - raise ChangerError('nothing-to-do', 'no fixers to apply') + raise ChangerError("nothing-to-do", "no fixers to apply") fixed_lintian_tags = set() for result, summary in overall_result.success: fixed_lintian_tags.update(result.fixed_lintian_tags) add_on_only = not has_nontrivial_changes( - overall_result.success, self.propose_addon_only) + overall_result.success, self.propose_addon_only + ) - if not reporter.get_base_metadata('add_on_only', False): + if not reporter.get_base_metadata("add_on_only", False): add_on_only = False if not add_on_only: if overall_result.success: - note('only add-on fixers found') + logging.info("only add-on fixers found") sufficient_for_proposal = False - reporter.report_metadata('add_on_only', True) + reporter.report_metadata("add_on_only", True) else: sufficient_for_proposal = True - reporter.report_metadata('add_on_only', False) + reporter.report_metadata("add_on_only", False) - branches = [ - ('main', None, base_revid, - local_tree.last_revision())] + branches = [("main", None, base_revid, local_tree.last_revision())] return ChangerResult( - description='Applied fixes for %r' % fixed_lintian_tags, + description="Applied fixes for %r" % fixed_lintian_tags, mutator=overall_result.success, - branches=branches, tags=[], + branches=branches, + tags=[], value=calculate_value(fixed_lintian_tags), sufficient_for_proposal=sufficient_for_proposal, proposed_commit_message=update_proposal_commit_message( - base_proposal, overall_result.success)) + base_proposal, overall_result.success + ), + ) - def get_proposal_description( - self, applied, description_format, existing_proposal): + def get_proposal_description(self, applied, description_format, existing_proposal): return update_proposal_description( - description_format, existing_proposal, applied) + description_format, existing_proposal, applied + ) def describe(self, applied, publish_result): tags = set() for brush_result, unused_summary in applied: tags.update(brush_result.fixed_lintian_tags) if publish_result.is_new: - note('Proposed fixes %r: %s', tags, publish_result.proposal.url) + logging.info( + "Proposed fixes %r: %s", tags, publish_result.proposal.url) elif tags: - note('Updated proposal %s with fixes %r', - publish_result.proposal.url, tags) + logging.info( + "Updated proposal %s with fixes %r", publish_result.proposal.url, tags) else: - note('No new fixes for proposal %s', publish_result.proposal.url) + logging.info( + "No new fixes for proposal %s", publish_result.proposal.url) -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(run_mutator(LintianBrushChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/__main__.py silver-platter-0.4.1/silver_platter/debian/__main__.py --- silver-platter-0.4.0/silver_platter/debian/__main__.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/__main__.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +import logging from typing import Optional, Dict, List, Callable import silver_platter # noqa: F401 @@ -27,15 +28,15 @@ run_single_changer, changer_subcommands, changer_subcommand, - ) +) from . import uploader as debian_uploader def run_changer_subcommand(name, changer_cls, argv): - parser = argparse.ArgumentParser(prog='debian-svp %s URL|package' % name) + parser = argparse.ArgumentParser(prog="debian-svp %s URL|package" % name) setup_parser_common(parser) - parser.add_argument('package', type=str, nargs='?') + parser.add_argument("package", type=str, nargs="?") changer_cls.setup_parser(parser) args = parser.parse_args(argv) if args.package is None: @@ -47,38 +48,40 @@ def main(argv: Optional[List[str]] = None) -> Optional[int]: import breezy + breezy.initialize() from ..__main__ import subcommands as main_subcommands - subcommands: Dict[ - str, Callable[[List[str]], Optional[int]]] = { - 'upload-pending': debian_uploader.main, - } + subcommands: Dict[str, Callable[[List[str]], Optional[int]]] = { + "upload-pending": debian_uploader.main, + } - parser = argparse.ArgumentParser(prog='debian-svp', add_help=False) + parser = argparse.ArgumentParser(prog="debian-svp", add_help=False) parser.add_argument( - '--version', action='version', - version='%(prog)s ' + silver_platter.version_string) + "--version", + action="version", + version="%(prog)s " + silver_platter.version_string, + ) parser.add_argument( - '--help', action='store_true', - help='show this help message and exit') + "--help", action="store_true", help="show this help message and exit" + ) subcommands.update(main_subcommands.items()) # We have a debian-specific run command - del subcommands['run'] + del subcommands["run"] parser.add_argument( - 'subcommand', type=str, - choices=list(subcommands.keys()) + changer_subcommands()) + "subcommand", type=str, choices=list(subcommands.keys()) + changer_subcommands() + ) args, rest = parser.parse_known_args() if args.help: if args.subcommand is None: parser.print_help() parser.exit() else: - rest.append('--help') + rest.append("--help") if args.subcommand is None: parser.print_usage() @@ -90,10 +93,11 @@ except KeyError: pass else: + logging.basicConfig(level=logging.INFO) return run_changer_subcommand(args.subcommand, subcmd, rest) parser.print_usage() return 1 -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main()) diff -Nru silver-platter-0.4.0/silver_platter/debian/multiarch.py silver-platter-0.4.1/silver_platter/debian/multiarch.py --- silver-platter-0.4.0/silver_platter/debian/multiarch.py 2021-01-21 17:09:37.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/multiarch.py 2021-02-17 22:45:01.000000000 +0000 @@ -18,6 +18,7 @@ """Support for integration multi-arch hints.""" import argparse +import logging import silver_platter # noqa: F401 @@ -32,45 +33,48 @@ ChangerResult, ChangerError, run_mutator, - ) - -from breezy.trace import note +) -BRANCH_NAME = 'multi-arch-fixes' +BRANCH_NAME = "multi-arch-fixes" DEFAULT_VALUE_MULTIARCH_HINT = 50 MULTIARCH_HINTS_VALUE = { - 'ma-foreign': 20, - 'file-conflict': 50, - 'ma-foreign-library': 20, - 'dep-any': 20, - 'ma-same': 20, - 'arch-all': 20, + "ma-foreign": 20, + "file-conflict": 50, + "ma-foreign-library": 20, + "dep-any": 20, + "ma-same": 20, + "arch-all": 20, } def calculate_value(hints): return sum(map(MULTIARCH_HINTS_VALUE.__getitem__, hints)) + ( - DEFAULT_VALUE_MULTIARCH_HINT) + DEFAULT_VALUE_MULTIARCH_HINT + ) class MultiArchHintsChanger(DebianChanger): - name: str = 'apply-multiarch-hints' + name: str = "apply-multiarch-hints" @classmethod def setup_parser(cls, parser: argparse.ArgumentParser) -> None: # Hide the minimum-certainty option for the moment. parser.add_argument( - '--minimum-certainty', + "--minimum-certainty", type=str, choices=SUPPORTED_CERTAINTIES, default=None, - help=argparse.SUPPRESS) + help=argparse.SUPPRESS, + ) parser.add_argument( - '--allow-reformatting', default=None, action='store_true', - help=argparse.SUPPRESS) + "--allow-reformatting", + default=None, + action="store_true", + help=argparse.SUPPRESS, + ) @classmethod def from_args(cls, args): @@ -81,7 +85,8 @@ cache_download_multiarch_hints, multiarch_hints_by_binary, parse_multiarch_hints, - ) + ) + with cache_download_multiarch_hints() as f: self.hints = multiarch_hints_by_binary(parse_multiarch_hints(f)) self.minimum_certainty = minimum_certainty @@ -90,12 +95,20 @@ def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, reporter, - committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): from lintian_brush import NoChanges from lintian_brush.multiarch_hints import ( MultiArchHintFixer, - ) + ) + base_revid = local_tree.last_revision() minimum_certainty = self.minimum_certainty allow_reformatting = self.allow_reformatting @@ -113,80 +126,84 @@ if control_files_in_root(local_tree, subpath): raise ChangerError( - 'control-files-in-root', - 'control files live in root rather than debian/ ' - '(LarstIQ mode)') + "control-files-in-root", + "control files live in root rather than debian/ " "(LarstIQ mode)", + ) if not control_file_present(local_tree, subpath): if is_debcargo_package(local_tree, subpath): - raise ChangerError( - 'debcargo-package', 'Package uses debcargo') - raise ChangerError( - 'missing-control-file', 'Unable to find debian/control') + raise ChangerError("debcargo-package", "Package uses debcargo") + raise ChangerError("missing-control-file", "Unable to find debian/control") try: with local_tree.lock_write(): result, summary = run_lintian_fixer( - local_tree, MultiArchHintFixer(self.hints), + local_tree, + MultiArchHintFixer(self.hints), update_changelog=update_changelog, minimum_certainty=minimum_certainty, - subpath=subpath, allow_reformatting=allow_reformatting, - net_access=True, committer=committer, - changes_by='apply-multiarch-hints') + subpath=subpath, + allow_reformatting=allow_reformatting, + net_access=True, + committer=committer, + changes_by="apply-multiarch-hints", + ) except NoChanges: - raise ChangerError('nothing-to-do', 'no hints to apply') + raise ChangerError("nothing-to-do", "no hints to apply") except FormattingUnpreservable as e: raise ChangerError( - 'formatting-unpreservable', - 'unable to preserve formatting while editing %s' % e.path) + "formatting-unpreservable", + "unable to preserve formatting while editing %s" % e.path, + ) except GeneratedFile as e: raise ChangerError( - 'generated-file', - 'unable to edit generated file: %r' % e) + "generated-file", "unable to edit generated file: %r" % e + ) applied_hints = [] hint_names = [] for (binary, hint, description, certainty) in result.changes: - hint_names.append(hint['link'].split('#')[-1]) + hint_names.append(hint["link"].split("#")[-1]) entry = dict(hint.items()) - hint_names.append(entry['link'].split('#')[-1]) - entry['action'] = description - entry['certainty'] = certainty + hint_names.append(entry["link"].split("#")[-1]) + entry["action"] = description + entry["certainty"] = certainty applied_hints.append(entry) - note('%s: %s' % (binary['Package'], description)) + logging.info("%s: %s" % (binary["Package"], description)) - reporter.report_metadata('applied-hints', applied_hints) + reporter.report_metadata("applied-hints", applied_hints) - branches = [ - ('main', None, base_revid, - local_tree.last_revision())] + branches = [("main", None, base_revid, local_tree.last_revision())] tags = [] return ChangerResult( - description="Applied multi-arch hints.", mutator=result, - branches=branches, tags=tags, + description="Applied multi-arch hints.", + mutator=result, + branches=branches, + tags=tags, value=calculate_value(hint_names), sufficient_for_proposal=True, - proposed_commit_message='Apply multi-arch hints.') + proposed_commit_message="Apply multi-arch hints.", + ) - def get_proposal_description( - self, applied, description_format, existing_proposal): - ret = ['Apply multi-arch hints.\n'] + def get_proposal_description(self, applied, description_format, existing_proposal): + ret = ["Apply multi-arch hints.\n"] for binary, hint, description, certainty in applied.changes: - ret.append('* %s: %s\n' % (binary['Package'], description)) - return ''.join(ret) + ret.append("* %s: %s\n" % (binary["Package"], description)) + return "".join(ret) def describe(self, applied, publish_result): - note('Applied multi-arch hints.') + logging.info("Applied multi-arch hints.") for binary, hint, description, certainty in applied.changes: - note('* %s: %s', binary['Package'], description) + logging.info("* %s: %s", binary["Package"], description) @classmethod def describe_command(cls, command): return "Apply multi-arch hints" -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(run_mutator(MultiArchHintsChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/orphan.py silver-platter-0.4.1/silver_platter/debian/orphan.py --- silver-platter-0.4.0/silver_platter/debian/orphan.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/orphan.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,53 +15,60 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +import logging from urllib.parse import urlparse +from breezy import osutils + +from debmutate.control import ControlEditor +from debmutate.reformatting import GeneratedFile, FormattingUnpreservable + + from . import ( pick_additional_colocated_branches, add_changelog_entry, - ) +) from .changer import ( run_mutator, DebianChanger, ChangerError, ChangerResult, - ) +) from ..proposal import push_changes -from breezy import osutils -from breezy.trace import note - -from debmutate.control import ControlEditor -from debmutate.reformatting import GeneratedFile, FormattingUnpreservable -BRANCH_NAME = 'orphan' +BRANCH_NAME = "orphan" def push_to_salsa(local_tree, user, name, dry_run=False): from breezy.branch import Branch - from breezy.plugins.propose.gitlabs import GitLab - salsa = GitLab.probe_from_url('https://salsa.debian.org/') + from breezy.plugins.gitlab.hoster import GitLab + + salsa = GitLab.probe_from_url("https://salsa.debian.org/") # TODO(jelmer): Fork if the old branch was hosted on salsa if dry_run: - note('Creating and pushing to salsa project %s/%s', - user, name) + logging.info("Creating and pushing to salsa project %s/%s", user, name) return - salsa.create_project('%s/%s' % (user, name)) + salsa.create_project("%s/%s" % (user, name)) target_branch = Branch.open( - 'git+ssh://git@salsa.debian.org/%s/%s.git' % (user, name)) + "git+ssh://git@salsa.debian.org/%s/%s.git" % (user, name) + ) additional_colocated_branches = pick_additional_colocated_branches( - local_tree.branch) + local_tree.branch + ) return push_changes( - local_tree.branch, target_branch, hoster=salsa, + local_tree.branch, + target_branch, + hoster=salsa, additional_colocated_branches=additional_colocated_branches, - dry_run=dry_run) + dry_run=dry_run, + ) class OrphanResult(object): - - def __init__(self, package=None, old_vcs_url=None, new_vcs_url=None, - salsa_user=None): + def __init__( + self, package=None, old_vcs_url=None, new_vcs_url=None, salsa_user=None + ): self.package = package self.old_vcs_url = old_vcs_url self.new_vcs_url = new_vcs_url @@ -71,10 +78,11 @@ class OrphanChanger(DebianChanger): - name = 'orphan' + name = "orphan" - def __init__(self, update_vcs=True, salsa_push=True, - salsa_user='debian', dry_run=False): + def __init__( + self, update_vcs=True, salsa_push=True, salsa_user="debian", dry_run=False + ): self.update_vcs = update_vcs self.salsa_push = salsa_push self.salsa_user = salsa_user @@ -83,15 +91,23 @@ @classmethod def setup_parser(cls, parser): parser.add_argument( - '--no-update-vcs', action='store_true', - help='Do not move the VCS repository to the Debian team on Salsa.') + "--no-update-vcs", + action="store_true", + help="Do not move the VCS repository to the Debian team on Salsa.", + ) parser.add_argument( - '--salsa-user', type=str, default='debian', - help='Salsa user to push repository to.') + "--salsa-user", + type=str, + default="debian", + help="Salsa user to push repository to.", + ) parser.add_argument( - '--just-update-headers', action='store_true', - help='Update the VCS-* headers, but don\'t actually ' - 'clone the repository.') + "--just-update-headers", + action="store_true", + help="Update the VCS-* headers, but don't actually " + "clone the repository.", + ) + parser.add_argument("--dry-run", action="store_true", help="Dry run changes.") @classmethod def from_args(cls, args): @@ -99,22 +115,28 @@ update_vcs=not args.no_update_vcs, dry_run=args.dry_run, salsa_user=args.salsa_user, - salsa_push=not args.just_update_headers) + salsa_push=not args.just_update_headers, + ) def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, - reporter, committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revid = local_tree.last_revision() - control_path = local_tree.abspath( - osutils.pathjoin(subpath, 'debian/control')) + control_path = local_tree.abspath(osutils.pathjoin(subpath, "debian/control")) try: with ControlEditor(path=control_path) as editor: - editor.source[ - 'Maintainer'] = 'Debian QA Group ' + editor.source["Maintainer"] = "Debian QA Group " try: - del editor.source['Uploaders'] + del editor.source["Uploaders"] except KeyError: pass @@ -122,74 +144,84 @@ if self.update_vcs: with ControlEditor(path=control_path) as editor: - result.package_name = editor.source['Source'] - result.old_vcs_url = editor.source.get('Vcs-Git') - editor.source['Vcs-Git'] = ( - 'https://salsa.debian.org/%s/%s.git' % ( - self.salsa_user, result.package_name)) - result.new_vcs_url = editor.source['Vcs-Git'] - editor.source['Vcs-Browser'] = ( - 'https://salsa.debian.org/%s/%s' % ( - self.salsa_user, result.package_name)) + result.package_name = editor.source["Source"] + result.old_vcs_url = editor.source.get("Vcs-Git") + editor.source["Vcs-Git"] = "https://salsa.debian.org/%s/%s.git" % ( + self.salsa_user, + result.package_name, + ) + result.new_vcs_url = editor.source["Vcs-Git"] + editor.source["Vcs-Browser"] = "https://salsa.debian.org/%s/%s" % ( + self.salsa_user, + result.package_name, + ) result.salsa_user = self.salsa_user if result.old_vcs_url == result.new_vcs_url: result.old_vcs_url = result.new_vcs_url = None if update_changelog in (True, None): add_changelog_entry( local_tree, - osutils.pathjoin(subpath, 'debian/changelog'), - ['QA Upload.', 'Move package to QA team.']) + osutils.pathjoin(subpath, "debian/changelog"), + ["QA Upload.", "Move package to QA team."], + ) local_tree.commit( - 'Move package to QA team.', committer=committer, - allow_pointless=False) + "Move package to QA team.", committer=committer, allow_pointless=False + ) except FormattingUnpreservable as e: raise ChangerError( - 'formatting-unpreservable', - 'unable to preserve formatting while editing %s' % e.path) + "formatting-unpreservable", + "unable to preserve formatting while editing %s" % e.path, + ) except GeneratedFile as e: raise ChangerError( - 'generated-file', - 'unable to edit generated file: %r' % e) + "generated-file", "unable to edit generated file: %r" % e + ) if self.update_vcs and self.salsa_push and result.new_vcs_url: push_to_salsa( - local_tree, self.salsa_user, result.package_name, - dry_run=self.dry_run) + local_tree, self.salsa_user, result.package_name, dry_run=self.dry_run + ) result.pushed = True - reporter.report_metadata('old_vcs_url', result.old_vcs_url) - reporter.report_metadata('new_vcs_url', result.new_vcs_url) - reporter.report_metadata('pushed', result.pushed) - - branches = [ - ('main', None, base_revid, - local_tree.last_revision())] + reporter.report_metadata("old_vcs_url", result.old_vcs_url) + reporter.report_metadata("new_vcs_url", result.new_vcs_url) + reporter.report_metadata("pushed", result.pushed) + + branches = [("main", None, base_revid, local_tree.last_revision())] tags = [] return ChangerResult( - description='Move package to QA team.', - mutator=result, branches=branches, tags=tags, + description="Move package to QA team.", + mutator=result, + branches=branches, + tags=tags, sufficient_for_proposal=True, - proposed_commit_message=( - 'Set the package maintainer to the QA team.')) + proposed_commit_message=("Set the package maintainer to the QA team."), + ) - def get_proposal_description( - self, applied, description_format, existing_proposal): - return 'Set the package maintainer to the QA team.' + def get_proposal_description(self, applied, description_format, existing_proposal): + return "Set the package maintainer to the QA team." def describe(self, result, publish_result): if publish_result.is_new: - note('Proposed change of maintainer to QA team: %s', - publish_result.proposal.url) + logging.info( + "Proposed change of maintainer to QA team: %s", + publish_result.proposal.url, + ) else: - note('No changes for orphaned package %s', result.package_name) + logging.info( + "No changes for orphaned package %s", + result.package_name) if result.pushed: - note('Pushed new package to %s.', result.new_vcs_url) + logging.info("Pushed new package to %s.", result.new_vcs_url) elif result.new_vcs_url: for line in move_instructions( - result.package_name, result.salsa_user, result.old_vcs_url, - result.new_vcs_url): - note('%s', line) + result.package_name, + result.salsa_user, + result.old_vcs_url, + result.new_vcs_url, + ): + logging.info("%s", line) @classmethod def describe_command(cls, command): @@ -197,23 +229,22 @@ def move_instructions(package_name, salsa_user, old_vcs_url, new_vcs_url): - yield 'Please move the repository from %s to %s.' % ( - old_vcs_url, new_vcs_url) - if urlparse(old_vcs_url).hostname == 'salsa.debian.org': + yield "Please move the repository from %s to %s." % (old_vcs_url, new_vcs_url) + if urlparse(old_vcs_url).hostname == "salsa.debian.org": path = urlparse(old_vcs_url).path - if path.endswith('.git'): + if path.endswith(".git"): path = path[:-4] - yield 'If you have the salsa(1) tool installed, run: ' - yield '' - yield ' salsa fork --group=%s %s' % ( - salsa_user, path) + yield "If you have the salsa(1) tool installed, run: " + yield "" + yield " salsa fork --group=%s %s" % (salsa_user, path) else: - yield 'If you have the salsa(1) tool installed, run: ' - yield '' - yield ' git clone %s %s' % (old_vcs_url, package_name) - yield ' salsa --group=%s push_repo %s' % (salsa_user, package_name) + yield "If you have the salsa(1) tool installed, run: " + yield "" + yield " git clone %s %s" % (old_vcs_url, package_name) + yield " salsa --group=%s push_repo %s" % (salsa_user, package_name) -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(run_mutator(OrphanChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/rrr.py silver-platter-0.4.1/silver_platter/debian/rrr.py --- silver-platter-0.4.0/silver_platter/debian/rrr.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/rrr.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,30 +15,30 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -from .changer import ( - run_mutator, - DebianChanger, - ChangerResult, - ) +import logging + from breezy import osutils -from breezy.trace import note -from . import add_changelog_entry from debmutate.control import ControlEditor +from . import add_changelog_entry +from .changer import ( + run_mutator, + DebianChanger, + ChangerResult, +) -BRANCH_NAME = 'rules-requires-root' +BRANCH_NAME = "rules-requires-root" class RulesRequiresRootResult(object): - def __init__(self, package=None): self.package = package class RulesRequiresRootChanger(DebianChanger): - name = 'rules-requires-root' + name = "rules-requires-root" def __init__(self, dry_run=False): self.dry_run = dry_run @@ -54,48 +54,60 @@ def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, - reporter, committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revid = local_tree.last_revision() with ControlEditor.from_tree(local_tree, subpath) as updater: - updater.source['Rules-Requires-Root'] = 'no' - result = RulesRequiresRootResult(updater.source['Source']) + updater.source["Rules-Requires-Root"] = "no" + result = RulesRequiresRootResult(updater.source["Source"]) if update_changelog in (True, None): add_changelog_entry( local_tree, - osutils.pathjoin(subpath, 'debian/changelog'), - ['Set Rules-Requires-Root: no.']) + osutils.pathjoin(subpath, "debian/changelog"), + ["Set Rules-Requires-Root: no."], + ) revid = local_tree.commit( - 'Set Rules-Requires-Root.', committer=committer, - allow_pointless=False) + "Set Rules-Requires-Root.", committer=committer, allow_pointless=False + ) - branches = [ - ('main', None, base_revid, revid)] + branches = [("main", None, base_revid, revid)] tags = [] return ChangerResult( - description='Set Rules-Requires-Root', - mutator=result, branches=branches, tags=tags, + description="Set Rules-Requires-Root", + mutator=result, + branches=branches, + tags=tags, sufficient_for_proposal=True, - proposed_commit_message='Set Rules-Requires-Root.') + proposed_commit_message="Set Rules-Requires-Root.", + ) - def get_proposal_description( - self, applied, description_format, existing_proposal): - return 'Set Rules-Requires-Root.' + def get_proposal_description(self, applied, description_format, existing_proposal): + return "Set Rules-Requires-Root." def describe(self, result, publish_result): if publish_result.is_new: - note('Proposed change to enable Rules-Requires-Root: %s', - publish_result.proposal.url) + logging.info( + "Proposed change to enable Rules-Requires-Root: %s", + publish_result.proposal.url, + ) else: - note('No changes for package %s', result.package_name) + logging.info("No changes for package %s", result.package_name) @classmethod def describe_command(cls, command): return "Set rules-requires-root" -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(run_mutator(RulesRequiresRootChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/run.py silver-platter-0.4.1/silver_platter/debian/run.py --- silver-platter-0.4.0/silver_platter/debian/run.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/run.py 2021-02-17 22:45:01.000000000 +0000 @@ -17,23 +17,23 @@ """Support for updating with a script.""" -from breezy.trace import note +import logging from .changer import ( ChangerError, ChangerResult, DebianChanger, - ) +) from ..run import ( ScriptMadeNoChanges, derived_branch_name, script_runner, - ) +) class ScriptChanger(DebianChanger): - name = 'run' + name = "run" def _init__(self, script, commit_pending=None): self.script = script @@ -41,46 +41,54 @@ @classmethod def setup_parser(cls, parser): + parser.add_argument("script", help="Path to script to run.", type=str) parser.add_argument( - 'script', help='Path to script to run.', type=str) - parser.add_argument( - '--commit-pending', - help='Commit pending changes after script.', - choices=['yes', 'no', 'auto'], - default='auto', type=str) + "--commit-pending", + help="Commit pending changes after script.", + choices=["yes", "no", "auto"], + default="auto", + type=str, + ) @classmethod def from_args(cls, args): - commit_pending = {'auto': None, 'yes': True, 'no': False}[ - args.commit_pending] + commit_pending = {"auto": None, "yes": True, "no": False}[args.commit_pending] return cls(script=args.script, commit_pending=commit_pending) - def make_changes(self, local_tree, subpath, update_changelog, reporter, - committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revid = local_tree.last_revision() try: - description = script_runner( - local_tree, self.script, self.commit_pending) + description = script_runner(local_tree, self.script, self.commit_pending) except ScriptMadeNoChanges as e: - raise ChangerError( - 'nothing-to-do', 'Script did not make any changes.', e) + raise ChangerError("nothing-to-do", "Script did not make any changes.", e) - branches = [ - ('main', None, base_revid, - local_tree.last_revision())] + branches = [("main", None, base_revid, local_tree.last_revision())] tags = [] # TODO(jelmer): Compare old and new tags/branches? return ChangerResult( - description=description, mutator=description, - sufficient_for_proposal=True, branches=branches, tags=tags, - proposed_commit_message=None) + description=description, + mutator=description, + sufficient_for_proposal=True, + branches=branches, + tags=tags, + proposed_commit_message=None, + ) def get_proposal_description( - self, description, description_format, existing_proposal): + self, description, description_format, existing_proposal + ): if description is not None: return description if existing_proposal is not None: @@ -88,7 +96,7 @@ raise ValueError("No description available") def describe(self, description, publish_result): - note('%s', description) + logging.info("%s", description) def suggest_branch_name(self): return derived_branch_name(self.script) diff -Nru silver-platter-0.4.0/silver_platter/debian/scrub_obsolete.py silver-platter-0.4.1/silver_platter/debian/scrub_obsolete.py --- silver-platter-0.4.0/silver_platter/debian/scrub_obsolete.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/scrub_obsolete.py 2021-02-17 22:45:01.000000000 +0000 @@ -18,6 +18,7 @@ """Support for scrubbing obsolete settings.""" import argparse +import logging from debmutate.reformatting import GeneratedFile, FormattingUnpreservable @@ -30,11 +31,10 @@ ChangerError, ChangerResult, run_mutator, - ) +) -from breezy.trace import note -BRANCH_NAME = 'scrub-obsolete' +BRANCH_NAME = "scrub-obsolete" DEFAULT_VALUE_MULTIARCH_HINT = 30 @@ -50,25 +50,32 @@ class ScrubObsoleteChanger(DebianChanger): - name: str = 'scrub-obsolete' + name: str = "scrub-obsolete" @classmethod def setup_parser(cls, parser: argparse.ArgumentParser) -> None: parser.add_argument( - '--allow-reformatting', default=None, action='store_true', - help=argparse.SUPPRESS) + "--allow-reformatting", + default=None, + action="store_true", + help=argparse.SUPPRESS, + ) parser.add_argument( - '--upgrade-release', metavar='UPGRADE-RELEASE', - help='Release to allow upgrading from.', default='oldstable') + "--upgrade-release", + metavar="UPGRADE-RELEASE", + help="Release to allow upgrading from.", + default="oldstable", + ) @classmethod def from_args(cls, args): import distro_info + debian_info = distro_info.DebianDistroInfo() upgrade_release = debian_info.codename(args.upgrade_release) return cls( - allow_reformatting=args.allow_reformatting, - upgrade_release=upgrade_release) + allow_reformatting=args.allow_reformatting, upgrade_release=upgrade_release + ) def __init__(self, upgrade_release, allow_reformatting=None): self.allow_reformatting = allow_reformatting @@ -77,9 +84,17 @@ def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, - reporter, committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): from lintian_brush.scrub_obsolete import scrub_obsolete + base_revid = local_tree.last_revision() allow_reformatting = self.allow_reformatting try: @@ -94,50 +109,56 @@ try: result = scrub_obsolete( - local_tree, subpath, self.upgrade_release, - update_changelog=update_changelog) + local_tree, + subpath, + self.upgrade_release, + update_changelog=update_changelog, + ) except FormattingUnpreservable as e: raise ChangerError( - 'formatting-unpreservable', - 'unable to preserve formatting while editing %s' % e.path) + "formatting-unpreservable", + "unable to preserve formatting while editing %s" % e.path, + ) except GeneratedFile as e: raise ChangerError( - 'generated-file', - 'unable to edit generated file: %r' % e) + "generated-file", "unable to edit generated file: %r" % e + ) if not result: - raise ChangerError('nothing-to-do', 'no obsolete constraints') + raise ChangerError("nothing-to-do", "no obsolete constraints") - branches = [ - ('main', None, base_revid, - local_tree.last_revision())] + branches = [("main", None, base_revid, local_tree.last_revision())] tags = [] return ChangerResult( - description="Scrub obsolete settings.", mutator=result, - branches=branches, tags=tags, + description="Scrub obsolete settings.", + mutator=result, + branches=branches, + tags=tags, value=calculate_value(result), sufficient_for_proposal=True, - proposed_commit_message='Scrub obsolete settings.') + proposed_commit_message="Scrub obsolete settings.", + ) - def get_proposal_description( - self, result, description_format, existing_proposal): + def get_proposal_description(self, result, description_format, existing_proposal): ret = [ - 'Remove constraints unnecessary since %s.' % self.upgrade_release, - ''] + ['* ' + line for line in result.itemized()] - return ''.join(ret) + "Remove constraints unnecessary since %s." % self.upgrade_release, + "", + ] + ["* " + line for line in result.itemized()] + return "".join(ret) def describe(self, applied, publish_result): - note('Scrub obsolete settings.') + logging.info("Scrub obsolete settings.") for line in applied.itemized(): - note('* %s', line) + logging.info("* %s", line) @classmethod def describe_command(cls, command): return "Remove obsolete dependencies" -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(run_mutator(ScrubObsoleteChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/tidy.py silver-platter-0.4.1/silver_platter/debian/tidy.py --- silver-platter-0.4.0/silver_platter/debian/tidy.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/tidy.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,29 +15,29 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -from breezy.trace import note +import logging from .changer import ( run_mutator, DebianChanger, ChangerResult, - ) +) from .lintian import LintianBrushChanger from .multiarch import MultiArchHintsChanger -BRANCH_NAME = 'tidy' +BRANCH_NAME = "tidy" class TidyChanger(DebianChanger): - name = 'tidy' + name = "tidy" SUBCHANGERS = [ LintianBrushChanger, MultiArchHintsChanger, - ] + ] def __init__(self) -> None: self.subchangers = [kls() for kls in self.SUBCHANGERS] @@ -53,17 +53,24 @@ def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, - reporter, committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revid = local_tree.last_revision() result = {} tags = [] sufficient_for_proposal = False branches = [] for subchanger in self.subchangers: - subresult = ( - subchanger.make_changes( - local_tree, subpath, update_changelog, committer)) + subresult = subchanger.make_changes( + local_tree, subpath, update_changelog, committer + ) result[subchanger] = subresult.mutator if subresult.sufficient_for_proposal: sufficient_for_proposal = True @@ -71,46 +78,52 @@ tags.extend(subresult.tags) if subresult.branches: branches.extend( - [entry for entry in subresult.branches - if entry[0] != 'main']) + [entry for entry in subresult.branches if entry[0] != "main"] + ) commit_items = [] for subchanger in result: if isinstance(subchanger, LintianBrushChanger): - commit_items.append('fix some lintian tags') + commit_items.append("fix some lintian tags") if isinstance(subchanger, MultiArchHintsChanger): - commit_items.append('apply multi-arch hints') - proposed_commit_message = (', '.join(commit_items) + '.').capitalize() + commit_items.append("apply multi-arch hints") + proposed_commit_message = (", ".join(commit_items) + ".").capitalize() - branches.insert( - 0, ('main', None, base_revid, - local_tree.last_revision())) + branches.insert(0, ("main", None, base_revid, local_tree.last_revision())) return ChangerResult( mutator=result, - description='Fix various small issues.', - tags=tags, branches=branches, + description="Fix various small issues.", + tags=tags, + branches=branches, sufficient_for_proposal=sufficient_for_proposal, - proposed_commit_message=proposed_commit_message) + proposed_commit_message=proposed_commit_message, + ) - def get_proposal_description( - self, result, description_format, existing_proposal): + def get_proposal_description(self, result, description_format, existing_proposal): entries = [] for subchanger, memo in result.items(): # TODO(jelmer): Does passing existing proposal in here work? - entries.append(subchanger.get_proposal_description( - memo, description_format, existing_proposal)) - return '\n'.join(entries) + entries.append( + subchanger.get_proposal_description( + memo, description_format, existing_proposal + ) + ) + return "\n".join(entries) def describe(self, result, publish_result): if publish_result.is_new: - note('Create merge proposal: %s', publish_result.proposal.url) + logging.info( + "Create merge proposal: %s", publish_result.proposal.url) elif result: - note('Updated proposal %s', publish_result.proposal.url) + logging.info( + "Updated proposal %s", publish_result.proposal.url) else: - note('No new fixes for proposal %s', publish_result.proposal.url) + logging.info( + "No new fixes for proposal %s", publish_result.proposal.url) -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(run_mutator(TidyChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/uncommitted.py silver-platter-0.4.1/silver_platter/debian/uncommitted.py --- silver-platter-0.4.0/silver_platter/debian/uncommitted.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/uncommitted.py 2021-02-17 22:45:01.000000000 +0000 @@ -17,6 +17,7 @@ import contextlib import json +import logging import os import subprocess import tempfile @@ -31,12 +32,11 @@ DebianChanger, ChangerResult, ChangerError, - ) -from breezy.trace import note +) from breezy.plugins.debian.upstream import PackageVersionNotPresent -BRANCH_NAME = 'missing-commits' +BRANCH_NAME = "missing-commits" class AptSourceError(Exception): @@ -48,11 +48,13 @@ def select_vcswatch_packages(): import psycopg2 + conn = psycopg2.connect( database="udd", user="udd-mirror", password="udd-mirror", - host="udd-mirror.debian.net") + host="udd-mirror.debian.net", + ) cursor = conn.cursor() args = [] query = """\ @@ -70,87 +72,92 @@ def download_snapshot(package, version, output_dir, no_preparation=False): - note('Downloading %s %s', package, version) - srcfiles_url = ('https://snapshot.debian.org/mr/package/%s/%s/' - 'srcfiles?fileinfo=1' % (package, version)) + logging.info("Downloading %s %s", package, version) + srcfiles_url = ( + "https://snapshot.debian.org/mr/package/%s/%s/" + "srcfiles?fileinfo=1" % (package, version) + ) files = {} - for hsh, entries in json.load(urlopen(srcfiles_url))['fileinfo'].items(): + for hsh, entries in json.load(urlopen(srcfiles_url))["fileinfo"].items(): for entry in entries: - files[entry['name']] = hsh + files[entry["name"]] = hsh for filename, hsh in files.items(): local_path = os.path.join(output_dir, os.path.basename(filename)) - with open(local_path, 'wb') as f: - url = 'https://snapshot.debian.org/file/%s' % hsh + with open(local_path, "wb") as f: + url = "https://snapshot.debian.org/file/%s" % hsh with urlopen(url) as g: f.write(g.read()) args = [] if no_preparation: - args.append('--no-preparation') + args.append("--no-preparation") subprocess.check_call( - ['dpkg-source'] + args + ['-x', '%s_%s.dsc' % (package, version)], - cwd=output_dir) + ["dpkg-source"] + args + ["-x", "%s_%s.dsc" % (package, version)], + cwd=output_dir, + ) class NoMissingVersions(Exception): - def __init__(self, vcs_version, archive_version): self.vcs_version = vcs_version self.archive_version = archive_version super(NoMissingVersions, self).__init__( - 'No missing versions after all. Archive has %s, VCS has %s' % ( - archive_version, vcs_version)) + "No missing versions after all. Archive has %s, VCS has %s" + % (archive_version, vcs_version) + ) class TreeVersionNotInArchiveChangelog(Exception): - def __init__(self, tree_version): self.tree_version = tree_version super(TreeVersionNotInArchiveChangelog, self).__init__( - 'tree version %s does not appear in archive changelog' % - tree_version) + "tree version %s does not appear in archive changelog" % tree_version + ) class TreeUpstreamVersionMissing(Exception): - def __init__(self, upstream_version): self.upstream_version = upstream_version super(TreeUpstreamVersionMissing, self).__init__( - 'unable to find upstream version %r' % upstream_version) + "unable to find upstream version %r" % upstream_version + ) def retrieve_source(package_name, target): try: subprocess.run( - ['apt', 'source', package_name], cwd=target, + ["apt", "source", package_name], + cwd=target, check=True, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + ) except subprocess.CalledProcessError as e: stderr = e.stderr.splitlines() if stderr[-1] == ( - b'E: You must put some \'source\' URIs in your ' - b'sources.list'): + b"E: You must put some 'source' URIs in your " b"sources.list" + ): raise NoAptSources() CS = b"\x1b[1;31mE: \x1b[0m" CE = b"\x1b[0m" if stderr[-1] == ( - CS + - b"You must put some 'deb-src' URIs in your sources.list" + - CE): + CS + b"You must put some 'deb-src' URIs in your sources.list" + CE + ): raise NoAptSources() - if stderr[-1].startswith(b'E: '): + if stderr[-1].startswith(b"E: "): raise AptSourceError(stderr[-1][3:].decode()) if stderr[-1].startswith(CS): - raise AptSourceError(stderr[-1][len(CS):-len(CE)]) + raise AptSourceError(stderr[-1][len(CS) : -len(CE)]) raise AptSourceError( - [line.decode('utf-8', 'surrogateescape') for line in stderr]) + [line.decode("utf-8", "surrogateescape") for line in stderr] + ) def import_uncommitted(tree, subpath): from breezy.plugins.debian.import_dsc import ( DistributionBranch, DistributionBranchSet, - ) - cl_path = os.path.join(subpath, 'debian/changelog') + ) + + cl_path = os.path.join(subpath, "debian/changelog") with tree.get_file(cl_path) as f: tree_cl = Changelog(f) package_name = tree_cl.package @@ -163,14 +170,13 @@ reason = e.reason[-1] else: reason = e.reason - raise ChangerError('apt-source-error', reason) + raise ChangerError("apt-source-error", reason) except NoAptSources: raise ChangerError( - 'no-apt-sources', - 'No sources configured in /etc/apt/sources.list') - [subdir] = [ - e.path for e in os.scandir(archive_source) if e.is_dir()] - with open(os.path.join(subdir, 'debian', 'changelog'), 'r') as f: + "no-apt-sources", "No sources configured in /etc/apt/sources.list" + ) + [subdir] = [e.path for e in os.scandir(archive_source) if e.is_dir()] + with open(os.path.join(subdir, "debian", "changelog"), "r") as f: archive_cl = Changelog(f) missing_versions = [] for block in archive_cl: @@ -181,37 +187,34 @@ raise TreeVersionNotInArchiveChangelog(tree_cl.version) if len(missing_versions) == 0: raise NoMissingVersions(tree_cl.version, archive_cl.version) - note('Missing versions: %s', ', '.join(map(str, missing_versions))) + logging.info("Missing versions: %s", ", ".join(map(str, missing_versions))) ret = [] dbs = DistributionBranchSet() db = DistributionBranch(tree.branch, tree.branch, tree=tree) dbs.add_branch(db) if tree_cl.version.debian_revision: - note('Extracting upstream version %s.', - tree_cl.version.upstream_version) + logging.info("Extracting upstream version %s.", tree_cl.version.upstream_version) upstream_dir = es.enter_context(tempfile.TemporaryDirectory()) try: - upstream_tips = db.pristine_upstream_source\ - .version_as_revisions( - tree_cl.package, - tree_cl.version.upstream_version) + upstream_tips = db.pristine_upstream_source.version_as_revisions( + tree_cl.package, tree_cl.version.upstream_version + ) except PackageVersionNotPresent: - raise TreeUpstreamVersionMissing( - tree_cl.version.upstream_version) + raise TreeUpstreamVersionMissing(tree_cl.version.upstream_version) db.extract_upstream_tree(upstream_tips, upstream_dir) - no_preparation = not tree.has_filename('.pc/applied-patches') + no_preparation = not tree.has_filename(".pc/applied-patches") version_path = {} for version in missing_versions: output_dir = es.enter_context(tempfile.TemporaryDirectory()) download_snapshot( - package_name, version, output_dir, - no_preparation=no_preparation) + package_name, version, output_dir, no_preparation=no_preparation + ) version_path[version] = output_dir for version in reversed(missing_versions): - note('Importing %s', version) + logging.info("Importing %s", version) dsc_path = os.path.join( - version_path[version], - '%s_%s.dsc' % (package_name, version)) + version_path[version], "%s_%s.dsc" % (package_name, version) + ) tag_name = db.import_package(dsc_path) revision = db.version_as_revisions(version) ret.append((tag_name, version, revision)) @@ -220,7 +223,7 @@ class UncommittedChanger(DebianChanger): - name = 'import-upload' + name = "import-upload" @classmethod def setup_parser(cls, parser): @@ -233,60 +236,73 @@ def suggest_branch_name(self): return BRANCH_NAME - def make_changes(self, local_tree, subpath, update_changelog, reporter, - committer, base_proposal=None): + def make_changes( + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revid = local_tree.last_revision() try: ret = import_uncommitted(local_tree, subpath) except TreeUpstreamVersionMissing as e: - raise ChangerError('tree-upstream-version-missing', str(e)) + raise ChangerError("tree-upstream-version-missing", str(e)) except TreeVersionNotInArchiveChangelog as e: - raise ChangerError( - 'tree-version-not-in-archive-changelog', str(e)) + raise ChangerError("tree-version-not-in-archive-changelog", str(e)) except NoMissingVersions as e: - raise ChangerError('nothing-to-do', str(e)) + raise ChangerError("nothing-to-do", str(e)) tags = [(None, tag_name, revid) for (tag_name, version, revid) in ret] # TODO(jelmer): Include upstream tags proposed_commit_message = "Import missing uploads: %s." % ( - ', '.join([str(v) for t, v in ret])) - reporter.report_metadata('tags', [ - (tag_name, str(version)) for (tag_name, version, revid) in ret]) - - branches = [ - ('main', None, base_revid, - local_tree.last_revision())] + ", ".join([str(v) for t, v in ret]) + ) + reporter.report_metadata( + "tags", [(tag_name, str(version)) for (tag_name, version, revid) in ret] + ) + + branches = [("main", None, base_revid, local_tree.last_revision())] # TODO(jelmer): Include branches for upstream/pristine-tar return ChangerResult( - description='Import archive changes missing from the VCS.', - branches=branches, mutator=ret, tags=tags, + description="Import archive changes missing from the VCS.", + branches=branches, + mutator=ret, + tags=tags, sufficient_for_proposal=True, - proposed_commit_message=proposed_commit_message) + proposed_commit_message=proposed_commit_message, + ) - def get_proposal_description( - self, applied, description_format, existing_proposal): - return "Import missing uploads: %s." % ( - ', '.join([str(v) for t, v in applied])) + def get_proposal_description(self, applied, description_format, existing_proposal): + return "Import missing uploads: %s." % (", ".join([str(v) for t, v in applied])) def describe(self, applied, publish_result): if publish_result.is_new: - note('Proposed import of versions %s: %s', - ', '.join([str(v) for t, v in applied]), - publish_result.proposal.url) + logging.info( + "Proposed import of versions %s: %s", + ", ".join([str(v) for t, v in applied]), + publish_result.proposal.url, + ) elif applied: - note('Updated proposal %s with versions %s.', - publish_result.proposal.url, - ', '.join([str(v) for t, v in applied])) + logging.info( + "Updated proposal %s with versions %s.", + publish_result.proposal.url, + ", ".join([str(v) for t, v in applied]), + ) else: - note('No new versions imported for proposal %s', - publish_result.proposal.url) + logging.info( + "No new versions imported for proposal %s", publish_result.proposal.url + ) @classmethod def describe_command(cls, command): return "Import archive changes missing from VCS" -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(run_mutator(UncommittedChanger)) diff -Nru silver-platter-0.4.0/silver_platter/debian/uploader.py silver-platter-0.4.1/silver_platter/debian/uploader.py --- silver-platter-0.4.0/silver_platter/debian/uploader.py 2021-02-01 23:26:31.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/uploader.py 2021-02-17 22:45:01.000000000 +0000 @@ -17,10 +17,11 @@ """Support for uploading packages.""" -import silver_platter # noqa: F401 +import silver_platter # noqa: F401 import datetime from email.utils import parseaddr +import logging import os import subprocess import sys @@ -30,27 +31,28 @@ from debmutate.changelog import ( ChangelogEditor, changeblock_ensure_first_line, - ) +) from debmutate.control import ControlEditor from breezy import gpg -from breezy.errors import NoSuchTag +from breezy.config import extract_email_address +from breezy.errors import NoSuchTag, PermissionDenied from breezy.commit import NullCommitReporter from breezy.plugins.debian.builder import BuildFailedError from breezy.plugins.debian.cmds import _build_helper from breezy.plugins.debian.import_dsc import ( DistributionBranch, - ) +) from breezy.plugins.debian.release import ( release, - ) +) from breezy.plugins.debian.util import ( changelog_find_previous_upload, dput_changes, find_changelog, debsign, - ) -from breezy.trace import note, show_error, warning + MissingChangelogError, +) from debian.changelog import get_maintainer @@ -61,13 +63,26 @@ Workspace, DEFAULT_BUILDER, select_probers, - ) + NoSuchPackage, +) from ..utils import ( open_branch, BranchUnavailable, BranchMissing, BranchUnsupported, - ) +) + + +class LastUploadMoreRecent(Exception): + """Last version in archive is newer than vcs version.""" + + def __init__(self, archive_version, vcs_version): + self.archive_version = archive_version + self.vcs_version = vcs_version + super(LastUploadMoreRecent, self).__init__( + "last upload (%s) is more recent than vcs (%s)" + % (archive_version, vcs_version) + ) class NoUnuploadedChanges(Exception): @@ -76,8 +91,8 @@ def __init__(self, archive_version): self.archive_version = archive_version super(NoUnuploadedChanges, self).__init__( - "nothing to upload, latest version is in archive: %s" % - archive_version) + "nothing to upload, latest version is in archive: %s" % archive_version + ) class NoUnreleasedChanges(Exception): @@ -86,8 +101,8 @@ def __init__(self, version): self.version = version super(NoUnreleasedChanges, self).__init__( - "nothing to upload, latest version in vcs is not unreleased: %s" % - version) + "nothing to upload, latest version in vcs is not unreleased: %s" % version + ) class RecentCommits(Exception): @@ -97,8 +112,21 @@ self.commit_age = commit_age self.min_commit_age = min_commit_age super(RecentCommits, self).__init__( - "Last commit is only %d days old (< %d)" % ( - self.commit_age, self.min_commit_age)) + "Last commit is only %d days old (< %d)" + % (self.commit_age, self.min_commit_age) + ) + + +class CommitterNotAllowed(Exception): + """Specified committer is not allowed.""" + + def __init__(self, committer, allowed_committers): + self.committer = committer + self.allowed_committers = allowed_committers + super(CommitterNotAllowed, self).__init__( + "Committer %s not in allowed committers: %r" + % (self.committer, self.allowed_committers) + ) class LastReleaseRevisionNotFound(Exception): @@ -108,16 +136,17 @@ self.package = package self.version = version super(LastReleaseRevisionNotFound, self).__init__( - "Unable to find revision matching version %r for %s" % ( - version, package)) + "Unable to find revision matching version %r for %s" % (version, package) + ) -def check_revision(rev, min_commit_age): +def check_revision(rev, min_commit_age, allowed_committers): """Check whether a revision can be included in an upload. Args: rev: revision to check min_commit_age: Minimum age for revisions + allowed_committers: List of allowed committers Raises: RecentCommits: When there are commits younger than min_commit_age """ @@ -128,6 +157,9 @@ if time_delta.days < min_commit_age: raise RecentCommits(time_delta.days, min_commit_age) # TODO(jelmer): Allow tag to prevent automatic uploads + committer_email = extract_email_address(rev.committer) + if allowed_committers and committer_email not in allowed_committers: + raise CommitterNotAllowed(committer_email, allowed_committers) def find_last_release_revid(branch, version): @@ -136,86 +168,92 @@ def get_maintainer_keys(context): - for key in context.keylist( - source='/usr/share/keyrings/debian-keyring.gpg'): + for key in context.keylist(source="/usr/share/keyrings/debian-keyring.gpg"): yield key.fpr for subkey in key.subkeys: yield subkey.keyid def prepare_upload_package( - local_tree, subpath, pkg, last_uploaded_version, builder, - gpg_strategy=None, min_commit_age=None): - if local_tree.has_filename(os.path.join(subpath, 'debian/gbp.conf')): + local_tree, + subpath, + pkg, + last_uploaded_version, + builder, + gpg_strategy=None, + min_commit_age=None, + allowed_committers=None, +): + if local_tree.has_filename(os.path.join(subpath, "debian/gbp.conf")): subprocess.check_call( - ['gbp', 'dch', '--ignore-branch'], - cwd=local_tree.abspath('.')) + ["gbp", "dch", "--ignore-branch"], cwd=local_tree.abspath(".") + ) cl, top_level = find_changelog(local_tree, merge=False, max_blocks=None) if cl.version == last_uploaded_version: raise NoUnuploadedChanges(cl.version) previous_version_in_branch = changelog_find_previous_upload(cl) if last_uploaded_version > previous_version_in_branch: - raise Exception( - "last uploaded version more recent than previous " - "version in branch: %r > %r" % ( - last_uploaded_version, previous_version_in_branch)) + raise LastUploadMoreRecent(last_uploaded_version, previous_version_in_branch) - note("Checking revisions since %s" % last_uploaded_version) + logging.info("Checking revisions since %s" % last_uploaded_version) with local_tree.lock_read(): try: last_release_revid = find_last_release_revid( - local_tree.branch, last_uploaded_version) + local_tree.branch, last_uploaded_version + ) except NoSuchTag: raise LastReleaseRevisionNotFound(pkg, last_uploaded_version) graph = local_tree.branch.repository.get_graph() - revids = list(graph.iter_lefthand_ancestry( - local_tree.branch.last_revision(), [last_release_revid])) + revids = list( + graph.iter_lefthand_ancestry( + local_tree.branch.last_revision(), [last_release_revid] + ) + ) if not revids: - note("No pending changes") + logging.info("No pending changes") return if gpg_strategy: - note('Verifying GPG signatures...') + logging.info("Verifying GPG signatures...") count, result, all_verifiables = gpg.bulk_verify_signatures( - local_tree.branch.repository, revids, - gpg_strategy) + local_tree.branch.repository, revids, gpg_strategy + ) for revid, code, key in result: if code != gpg.SIGNATURE_VALID: - raise Exception( - "No valid GPG signature on %r: %d" % - (revid, code)) - for revid, rev in local_tree.branch.repository.iter_revisions( - revids): - check_revision(rev, min_commit_age) + raise Exception("No valid GPG signature on %r: %d" % (revid, code)) + for revid, rev in local_tree.branch.repository.iter_revisions(revids): + if rev is not None: + check_revision(rev, min_commit_age, allowed_committers) if cl.distributions != "UNRELEASED": raise NoUnreleasedChanges(cl.version) qa_upload = False team_upload = False - control_path = local_tree.abspath(os.path.join(subpath, 'debian/control')) + control_path = local_tree.abspath(os.path.join(subpath, "debian/control")) with ControlEditor(control_path) as e: - maintainer = parseaddr(e.source['Maintainer']) - if maintainer[1] == 'packages@qa.debian.org': + maintainer = parseaddr(e.source["Maintainer"]) + if maintainer[1] == "packages@qa.debian.org": qa_upload = True # TODO(jelmer): Check whether this is a team upload # TODO(jelmer): determine whether this is a NMU upload if qa_upload or team_upload: - changelog_path = local_tree.abspath( - os.path.join(subpath, 'debian/changelog')) + changelog_path = local_tree.abspath(os.path.join(subpath, "debian/changelog")) with ChangelogEditor(changelog_path) as e: if qa_upload: - changeblock_ensure_first_line(e[0], 'QA upload.') + changeblock_ensure_first_line(e[0], "QA upload.") elif team_upload: - changeblock_ensure_first_line(e[0], 'Team upload.') + changeblock_ensure_first_line(e[0], "Team upload.") local_tree.commit( - specific_files=[os.path.join(subpath, 'debian/changelog')], - message='Mention QA Upload.', + specific_files=[os.path.join(subpath, "debian/changelog")], + message="Mention QA Upload.", allow_pointless=False, - reporter=NullCommitReporter()) + reporter=NullCommitReporter(), + ) tag_name = release(local_tree, subpath) target_dir = tempfile.mkdtemp() builder = builder.replace("${LAST_VERSION}", last_uploaded_version) target_changes = _build_helper( - local_tree, subpath, local_tree.branch, target_dir, builder=builder) + local_tree, subpath, local_tree.branch, target_dir, builder=builder + ) debsign(target_changes) return target_changes, tag_name @@ -223,6 +261,7 @@ def select_apt_packages(package_names, maintainer): packages = [] import apt_pkg + apt_pkg.init() sources = apt_pkg.SourceRecords() while sources.step(): @@ -239,13 +278,17 @@ return packages -def select_vcswatch_packages(packages: List[str], maintainer: List[str]): +def select_vcswatch_packages( + packages: List[str], maintainer: List[str], autopkgtest_only: bool +): import psycopg2 + conn = psycopg2.connect( database="udd", user="udd-mirror", password="udd-mirror", - host="udd-mirror.debian.net") + host="udd-mirror.debian.net", + ) cursor = conn.cursor() args = [] query = """\ @@ -255,6 +298,8 @@ vcswatch.status IN ('COMMITS', 'NEW') AND sources.release = 'sid' """ + if autopkgtest_only: + query += " AND sources.testsuite != '' " if maintainer: query += " AND sources.maintainer_email IN (%s)" args.append(tuple(maintainer)) @@ -270,48 +315,66 @@ return packages -def main(argv): +def main(argv): # noqa: C901 import argparse - parser = argparse.ArgumentParser(prog='upload-pending-commits') - parser.add_argument("packages", nargs='*') - parser.add_argument( - '--dry-run', action='store_true', - help='Dry run changes.') - parser.add_argument( - '--acceptable-keys', - help='List of acceptable GPG keys', - action='append', default=[], type=str) + + parser = argparse.ArgumentParser(prog="upload-pending-commits") + parser.add_argument("packages", nargs="*") + parser.add_argument("--dry-run", action="store_true", help="Dry run changes.") parser.add_argument( - '--gpg-verification', - help='Verify GPG signatures on commits', action='store_true') + "--acceptable-keys", + help="List of acceptable GPG keys", + action="append", + default=[], + type=str, + ) parser.add_argument( - '--min-commit-age', - help='Minimum age of the last commit, in days', - type=int, default=0) + "--gpg-verification", + help="Verify GPG signatures on commits", + action="store_true", + ) parser.add_argument( - '--diff', - action='store_true', - help='Show diff.') + "--min-commit-age", + help="Minimum age of the last commit, in days", + type=int, + default=0, + ) + parser.add_argument("--diff", action="store_true", help="Show diff.") parser.add_argument( - '--builder', + "--builder", type=str, - help='Build command', - default=(DEFAULT_BUILDER + ' --source --source-only-changes ' - '--debbuildopt=-v${LAST_VERSION}')) + help="Build command", + default=( + DEFAULT_BUILDER + " --source --source-only-changes " + "--debbuildopt=-v${LAST_VERSION}" + ), + ) parser.add_argument( - '--maintainer', + "--maintainer", type=str, - action='append', - help='Select all packages maintainer by specified maintainer.') + action="append", + help="Select all packages maintainer by specified maintainer.", + ) parser.add_argument( - '--vcswatch', - action='store_true', + "--vcswatch", + action="store_true", default=False, - help='Use vcswatch to determine what packages need uploading.') + help="Use vcswatch to determine what packages need uploading.", + ) parser.add_argument( - '--autopkgtest-only', - action='store_true', - help='Only process packages with autopkgtests.') + "--exclude", type=str, action="append", default=[], help="Ignore source package" + ) + parser.add_argument( + "--autopkgtest-only", + action="store_true", + help="Only process packages with autopkgtests.", + ) + parser.add_argument( + "--allowed-committer", + type=str, + action="append", + help="Require that all new commits are from specified committers", + ) args = parser.parse_args(argv) ret = 0 @@ -319,7 +382,7 @@ if not args.packages and not args.maintainer: (name, email) = get_maintainer() if email: - note('Processing packages maintained by %s', email) + logging.info("Processing packages maintained by %s", email) args.maintainer = [email] else: parser.print_usage() @@ -327,18 +390,20 @@ if args.vcswatch: packages = select_vcswatch_packages( - args.packages, args.maintainer) + args.packages, args.maintainer, args.autopkgtest_only + ) else: - note('Use --vcswatch to only process packages for which ' - 'vcswatch found pending commits.') + logging.info( + "Use --vcswatch to only process packages for which " + "vcswatch found pending commits." + ) if args.maintainer: - packages = select_apt_packages( - args.packages, args.maintainer) + packages = select_apt_packages(args.packages, args.maintainer) else: packages = args.packages if not packages: - note('No packages found.') + logging.info("No packages found.") parser.print_usage() sys.exit(1) @@ -346,24 +411,30 @@ # commits are more likely to be successful. if len(packages) > 1: - note('Uploading packages: %s', ', '.join(packages)) + logging.info("Uploading packages: %s", ", ".join(packages)) for package in packages: - note('Processing %s', package) + logging.info("Processing %s", package) # Can't use open_packaging_branch here, since we want to use pkg_source # later on. - if '/' not in package: - pkg_source = apt_get_source_package(package) + if "/" not in package: + try: + pkg_source = apt_get_source_package(package) + except NoSuchPackage: + logging.info("%s: package not found in apt", package) + ret = 1 + continue try: vcs_type, vcs_url = source_package_vcs(pkg_source) except KeyError: - note('%s: no declared vcs location, skipping', - pkg_source['Package']) + logging.info("%s: no declared vcs location, skipping", pkg_source["Package"]) ret = 1 continue - source_name = pkg_source['Package'] - source_version = pkg_source['Version'] - has_testsuite = 'Testsuite' in pkg_source + source_name = pkg_source["Package"] + if source_name in args.exclude: + continue + source_version = pkg_source["Version"] + has_testsuite = "Testsuite" in pkg_source else: vcs_url = package vcs_type = None @@ -372,34 +443,36 @@ has_testsuite = None (location, branch_name, subpath) = split_vcs_url(vcs_url) if subpath is None: - subpath = '' + subpath = "" probers = select_probers(vcs_type) try: - main_branch = open_branch( - location, probers=probers, name=branch_name) + main_branch = open_branch(location, probers=probers, name=branch_name) except (BranchUnavailable, BranchMissing, BranchUnsupported) as e: - show_error('%s: %s', vcs_url, e) + logging.exception("%s: %s", vcs_url, e) ret = 1 continue with Workspace(main_branch) as ws: if source_name is None: with ControlEditor( - ws.local_tree.abspath( - os.path.join(subpath, 'debian/control')) - ) as ce: - source_name = ce.source['Source'] + ws.local_tree.abspath(os.path.join(subpath, "debian/control")) + ) as ce: + source_name = ce.source["Source"] with ChangelogEditor( - ws.local_tree.abspath( - os.path.join(subpath, 'debian/changelog')) - ) as cle: + ws.local_tree.abspath(os.path.join(subpath, "debian/changelog")) + ) as cle: source_version = cle[0].version - has_testsuite = 'Testsuite' in ce.source - if (args.autopkgtest_only and - not has_testsuite and - not ws.local_tree.has_filename( - os.path.join(subpath, 'debian/tests/control'))): - note('%s: Skipping, package has no autopkgtest.', - source_name) + has_testsuite = "Testsuite" in ce.source + if source_name in args.exclude: + continue + if ( + args.autopkgtest_only + and not has_testsuite + and not ws.local_tree.has_filename( + os.path.join(subpath, "debian/tests/control") + ) + ): + logging.info( + "%s: Skipping, package has no autopkgtest.", source_name) continue branch_config = ws.local_tree.branch.get_config_stack() if args.gpg_verification: @@ -407,48 +480,83 @@ if args.acceptable_keys: acceptable_keys = args.acceptable_keys else: - acceptable_keys = list(get_maintainer_keys( - gpg_strategy.context)) - gpg_strategy.set_acceptable_keys(','.join(acceptable_keys)) + acceptable_keys = list(get_maintainer_keys(gpg_strategy.context)) + gpg_strategy.set_acceptable_keys(",".join(acceptable_keys)) else: gpg_strategy = None try: target_changes, tag_name = prepare_upload_package( - ws.local_tree, subpath, - source_name, source_version, - builder=args.builder, gpg_strategy=gpg_strategy, - min_commit_age=args.min_commit_age) + ws.local_tree, + subpath, + source_name, + source_version, + builder=args.builder, + gpg_strategy=gpg_strategy, + min_commit_age=args.min_commit_age, + allowed_committers=args.allowed_committer, + ) + except CommitterNotAllowed as e: + logging.warn( + "%s: committer %s not in allowed list: %r", + source_name, + e.committer, + e.allowed_committers, + ) + continue except BuildFailedError as e: - warning( - '%s: package failed to build: %s', - source_name, e) + logging.warn("%s: package failed to build: %s", source_name, e) ret = 1 continue except LastReleaseRevisionNotFound as e: - warning( - '%s: Unable to find revision matching last release ' - '%s, skipping.', source_name, e.version) + logging.warn( + "%s: Unable to find revision matching last release " + "%s, skipping.", + source_name, + e.version, + ) + ret = 1 + continue + except LastUploadMoreRecent as e: + logging.warn( + "%s: Last upload (%s) was more recent than VCS (%s)", + source_name, + e.archive_version, + e.vcs_version, + ) + ret = 1 + continue + except MissingChangelogError: + logging.info("%s: No changelog found, skipping.", source_name) ret = 1 continue except RecentCommits as e: - note('%s: Recent commits (%d days), skipping.', - source_name, e.commit_age) + logging.info( + "%s: Recent commits (%d days), skipping.", + source_name, e.commit_age + ) continue except NoUnuploadedChanges: - note('%s: No unuploaded changes, skipping.', - source_name) + logging.info( + "%s: No unuploaded changes, skipping.", source_name) continue except NoUnreleasedChanges: - note('%s: No unreleased changes, skipping.', - source_name) + logging.info( + "%s: No unreleased changes, skipping.", source_name) continue tags = [] if tag_name is not None: - note('Pushing tag %s', tag_name) + logging.info("Pushing tag %s", tag_name) tags.append(tag_name) - ws.push(dry_run=args.dry_run, tags=tags) + try: + ws.push(dry_run=args.dry_run, tags=tags) + except PermissionDenied: + logging.info( + "%s: Permission denied pushing to branch, skipping.", + source_name) + ret = 1 + continue if not args.dry_run: dput_changes(target_changes) if args.diff: @@ -459,5 +567,5 @@ return ret -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main(sys.argv)) diff -Nru silver-platter-0.4.0/silver_platter/debian/upstream.py silver-platter-0.4.1/silver_platter/debian/upstream.py --- silver-platter-0.4.0/silver_platter/debian/upstream.py 2021-01-29 15:13:25.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/debian/upstream.py 2021-02-17 22:45:01.000000000 +0000 @@ -21,7 +21,7 @@ import argparse import errno -from debian.changelog import Version, ChangelogParseError +import logging import os import re import ssl @@ -29,28 +29,29 @@ import traceback from typing import List, Optional, Callable, Union +from debian.changelog import Version, ChangelogParseError + from ..utils import ( full_branch_url, open_branch, BranchMissing, BranchUnavailable, BranchUnsupported, - ) +) from . import ( changelog_add_line, - debcommit, control_files_in_root, - ) +) from .changer import ( run_mutator, ChangerError, DebianChanger, ChangerResult, - ) +) from breezy.commit import ( PointlessCommit, - ) +) from breezy.errors import ( FileExists, InvalidNormalization, @@ -59,20 +60,18 @@ PointlessMerge, InvalidHttpResponse, NoRoundtrippingSupport, - ) +) from breezy.revision import NULL_REVISION -from breezy.plugins.debian.config import ( - UpstreamMetadataSyntaxError - ) +from breezy.plugins.debian.config import UpstreamMetadataSyntaxError from breezy.plugins.debian.util import ( InconsistentSourceFormatError, - ) +) from breezy.plugins.debian.import_dsc import ( UpstreamAlreadyImported, UpstreamBranchAlreadyMerged, - ) +) +from breezy.plugins.debian.changelog import debcommit -from breezy.trace import note, warning from breezy.transform import MalformedTransform from breezy.plugins.debian.merge_upstream import ( @@ -81,19 +80,19 @@ do_merge, get_tarballs, PreviousVersionTagMissing, - ) +) from breezy.plugins.debian.repack_tarball import ( UnsupportedRepackFormat, - ) +) from breezy.plugins.debian.upstream.pristinetar import ( PristineTarError, get_pristine_tar_source, - ) +) from breezy.plugins.quilt.quilt import ( QuiltError, QuiltPatches, - ) +) from breezy.plugins.debian.util import ( debuild_config, @@ -110,51 +109,48 @@ TarfileSource, MissingUpstreamTarball, PackageVersionNotPresent, - ) +) from breezy.plugins.debian.upstream.uscan import ( UScanSource, UScanError, NoWatchFile, WatchLineWithoutMatches, WatchLineWithoutMatchingHrefs, - ) +) from breezy.plugins.debian.upstream.branch import ( UpstreamBranchSource, DistCommandFailed, run_dist_command, - ) +) from breezy.tree import Tree from lintian_brush.vcs import sanitize_url as sanitize_vcs_url -from lintian_brush.upstream_metadata import ( - guess_upstream_metadata, - ) __all__ = [ - 'PreviousVersionTagMissing', - 'merge_upstream', - 'InvalidFormatUpstreamVersion', - 'DistCommandFailed', - 'MissingChangelogError', - 'MissingUpstreamTarball', - 'NewUpstreamMissing', - 'UpstreamBranchUnavailable', - 'UnsupportedRepackFormat', - 'UpstreamAlreadyMerged', - 'UpstreamAlreadyImported', - 'UpstreamMergeConflicted', - 'NewUpstreamTarballMissing', - 'QuiltError', - 'NoUpstreamLocationsKnown', - 'UpstreamVersionMissingInUpstreamBranch', - 'UpstreamBranchUnknown', - 'PackageIsNative', - 'ChangelogParseError', - 'UScanError', - 'UpstreamMetadataSyntaxError', - 'QuiltPatchPushFailure', - 'WatchLineWithoutMatches', + "PreviousVersionTagMissing", + "merge_upstream", + "InvalidFormatUpstreamVersion", + "DistCommandFailed", + "MissingChangelogError", + "MissingUpstreamTarball", + "NewUpstreamMissing", + "UpstreamBranchUnavailable", + "UnsupportedRepackFormat", + "UpstreamAlreadyMerged", + "UpstreamAlreadyImported", + "UpstreamMergeConflicted", + "NewUpstreamTarballMissing", + "QuiltError", + "NoUpstreamLocationsKnown", + "UpstreamVersionMissingInUpstreamBranch", + "UpstreamBranchUnknown", + "PackageIsNative", + "ChangelogParseError", + "UScanError", + "UpstreamMetadataSyntaxError", + "QuiltPatchPushFailure", + "WatchLineWithoutMatches", ] @@ -174,7 +170,6 @@ class QuiltPatchPushFailure(Exception): - def __init__(self, patch_name, actual_error): self.patch_name = patch_name self.actual_error = actual_error @@ -228,7 +223,6 @@ class NewUpstreamTarballMissing(Exception): - def __init__(self, package, version, upstream): self.package = package self.version = version @@ -252,28 +246,29 @@ RELEASE_BRANCH_NAME = "new-upstream-release" SNAPSHOT_BRANCH_NAME = "new-upstream-snapshot" -DEFAULT_DISTRIBUTION = 'unstable' +DEFAULT_DISTRIBUTION = "unstable" def get_upstream_branch_location(tree, subpath, config, trust_package=False): if config.upstream_branch is not None: - note("Using upstream branch %s (from configuration)", - config.upstream_branch) + logging.info("Using upstream branch %s (from configuration)", config.upstream_branch) # TODO(jelmer): Make brz-debian sanitize the URL? upstream_branch_location = sanitize_vcs_url(config.upstream_branch) - upstream_branch_browse = getattr( - config, 'upstream_branch_browse', None) + upstream_branch_browse = getattr(config, "upstream_branch_browse", None) else: + from upstream_ontologist.guess import ( + guess_upstream_metadata, + ) guessed_upstream_metadata = guess_upstream_metadata( - tree.abspath(subpath), trust_package=trust_package, - net_access=True, consult_external_directory=False) - upstream_branch_location = guessed_upstream_metadata.get( - 'Repository') - upstream_branch_browse = guessed_upstream_metadata.get( - 'Repository-Browse') + tree.abspath(subpath), + trust_package=trust_package, + net_access=True, + consult_external_directory=False, + ) + upstream_branch_location = guessed_upstream_metadata.get("Repository") + upstream_branch_browse = guessed_upstream_metadata.get("Repository-Browse") if upstream_branch_location: - note("Using upstream branch %s (guessed)", - upstream_branch_location) + logging.info("Using upstream branch %s (guessed)", upstream_branch_location) if upstream_branch_browse is None and upstream_branch_location is not None: try: from lintian_brush.vcs import determine_browser_url @@ -281,47 +276,58 @@ pass else: upstream_branch_browse = determine_browser_url( - None, upstream_branch_location) + None, upstream_branch_location + ) return (upstream_branch_location, upstream_branch_browse) def refresh_quilt_patches( - local_tree: Tree, old_version: Version, new_version: Version, - committer: Optional[str] = None, subpath: str = '') -> None: + local_tree: Tree, + old_version: Version, + new_version: Version, + committer: Optional[str] = None, + subpath: str = "", +) -> None: # TODO(jelmer): # Find patch base branch. # If it exists, rebase it onto the new upstream. # And then run 'gbp pqm export' or similar # If not: # Refresh patches against the new upstream revision - patches = QuiltPatches(local_tree, os.path.join(subpath, 'debian/patches')) + patches = QuiltPatches(local_tree, os.path.join(subpath, "debian/patches")) patches.upgrade() for name in patches.unapplied(): try: patches.push(name, refresh=True) except QuiltError as e: lines = e.stdout.splitlines() - m = re.match( - 'Patch debian/patches/(.*) can be reverse-applied', lines[-1]) - if m and getattr(patches, 'delete', None): + m = re.match("Patch debian/patches/(.*) can be reverse-applied", lines[-1]) + if m and getattr(patches, "delete", None): assert m.group(1) == name patches.delete(name, remove=True) changelog_add_line( - local_tree, subpath, - 'Drop patch %s, present upstream.' % name, - email=committer) + local_tree, + subpath, + "Drop patch %s, present upstream." % name, + email=committer, + ) debcommit( - local_tree, committer=committer, + local_tree, + committer=committer, subpath=subpath, paths=[ - 'debian/patches/series', 'debian/patches/' + name, - 'debian/changelog']) + "debian/patches/series", + "debian/patches/" + name, + "debian/changelog", + ], + ) else: raise QuiltPatchPushFailure(name, e) patches.pop_all() try: local_tree.commit( - 'Refresh patches.', committer=committer, allow_pointless=False) + "Refresh patches.", committer=committer, allow_pointless=False + ) except PointlessCommit: pass @@ -330,19 +336,25 @@ """Object representing the result of an import_upstream operation.""" __slots__ = [ - 'old_upstream_version', - 'new_upstream_version', - 'upstream_branch', - 'upstream_branch_browse', - 'upstream_revisions', - 'imported_revisions', - 'include_upstream_history', - ] - - def __init__(self, include_upstream_history, - old_upstream_version, new_upstream_version, - upstream_branch, upstream_branch_browse, - upstream_revisions, imported_revisions): + "old_upstream_version", + "new_upstream_version", + "upstream_branch", + "upstream_branch_browse", + "upstream_revisions", + "imported_revisions", + "include_upstream_history", + ] + + def __init__( + self, + include_upstream_history, + old_upstream_version, + new_upstream_version, + upstream_branch, + upstream_branch_browse, + upstream_revisions, + imported_revisions, + ): self.old_upstream_version = old_upstream_version self.new_upstream_version = new_upstream_version self.upstream_branch = upstream_branch @@ -353,30 +365,38 @@ def detect_include_upstream_history( - tree, upstream_branch_source, package, old_upstream_version): + tree, upstream_branch_source, package, old_upstream_version +): # Simple heuristic: Find the old upstream version and see if it's present # in the history of the packaging branch try: revision = upstream_branch_source.version_as_revision( - package, old_upstream_version) + package, old_upstream_version + ) except PackageVersionNotPresent: - warning( - 'Old upstream version %r is not present in upstream ' - 'branch %r. Unable to determine whether upstream history ' - 'is normally included. Assuming no.', old_upstream_version, - upstream_branch_source) + logging.warn( + "Old upstream version %r is not present in upstream " + "branch %r. Unable to determine whether upstream history " + "is normally included. Assuming no.", + old_upstream_version, + upstream_branch_source, + ) return False graph = tree.branch.repository.get_graph() ret = graph.is_ancestor(revision, tree.last_revision()) if ret: - note('Including upstream history, since previous upstream version ' - '(%s) is present in packaging branch history.', - old_upstream_version) + logging.info( + "Including upstream history, since previous upstream version " + "(%s) is present in packaging branch history.", + old_upstream_version, + ) else: - note('Not including upstream history, since previous upstream version ' - '(%s) is not present in packaging branch history.', - old_upstream_version) + logging.info( + "Not including upstream history, since previous upstream version " + "(%s) is not present in packaging branch history.", + old_upstream_version, + ) return ret @@ -384,36 +404,48 @@ def matches_release(upstream_version: str, release_version: str): release_version = release_version.lower() upstream_version = upstream_version.lower() - m = re.match('(.*)([~+-])(dfsg|git|bzr|svn|hg).*', upstream_version) + m = re.match("(.*)([~+-])(dfsg|git|bzr|svn|hg).*", upstream_version) if m and m.group(1) == release_version: return True - m = re.match('(.*)([~+-]).*', upstream_version) + m = re.match("(.*)([~+-]).*", upstream_version) if m and m.group(1) == release_version: return True return False -def find_new_upstream( - tree, subpath, config, package, location=None, - old_upstream_version=None, new_upstream_version=None, - trust_package=False, snapshot=False, - allow_ignore_upstream_branch=False, top_level=False, - create_dist=None, include_upstream_history: Optional[bool] = None): +def find_new_upstream( # noqa: C901 + tree, + subpath, + config, + package, + location=None, + old_upstream_version=None, + new_upstream_version=None, + trust_package=False, + snapshot=False, + allow_ignore_upstream_branch=False, + top_level=False, + create_dist=None, + include_upstream_history: Optional[bool] = None, +): # TODO(jelmer): Find the lastest upstream present in the upstream branch # rather than what's in the changelog. - upstream_branch_location, upstream_branch_browse = ( - get_upstream_branch_location( - tree, subpath, config, trust_package=trust_package)) + upstream_branch_location, upstream_branch_browse = get_upstream_branch_location( + tree, subpath, config, trust_package=trust_package + ) if upstream_branch_location: try: upstream_branch = open_branch(upstream_branch_location) except (BranchUnavailable, BranchMissing, BranchUnsupported) as e: if not snapshot and allow_ignore_upstream_branch: - warning('Upstream branch %s inaccessible; ignoring. %s', - upstream_branch_location, e) + logging.warn( + "Upstream branch %s inaccessible; ignoring. %s", + upstream_branch_location, + e, + ) else: raise UpstreamBranchUnavailable(upstream_branch_location, e) upstream_branch = None @@ -424,8 +456,12 @@ if upstream_branch is not None: try: upstream_branch_source = UpstreamBranchSource.from_branch( - upstream_branch, config=config, local_dir=tree.controldir, - create_dist=create_dist, snapshot=snapshot) + upstream_branch, + config=config, + local_dir=tree.controldir, + create_dist=create_dist, + snapshot=snapshot, + ) except InvalidHttpResponse as e: raise UpstreamBranchUnavailable(upstream_branch_location, str(e)) except ssl.SSLError as e: @@ -437,13 +473,15 @@ try: branch = open_branch(location) except (BranchUnavailable, BranchMissing, BranchUnsupported): - primary_upstream_source = TarfileSource( - location, new_upstream_version) + primary_upstream_source = TarfileSource(location, new_upstream_version) else: primary_upstream_source = UpstreamBranchSource.from_branch( - branch, config=config, - local_dir=tree.controldir, create_dist=create_dist, - snapshot=snapshot) + branch, + config=config, + local_dir=tree.controldir, + create_dist=create_dist, + snapshot=snapshot, + ) else: if snapshot: if upstream_branch_source is None: @@ -452,7 +490,8 @@ else: try: primary_upstream_source = UScanSource.from_tree( - tree, subpath, top_level) + tree, subpath, top_level + ) except NoWatchFile: # TODO(jelmer): Call out to lintian_brush.watch to generate a # watch file. @@ -462,7 +501,8 @@ if new_upstream_version is None and primary_upstream_source is not None: new_upstream_version = primary_upstream_source.get_latest_version( - package, old_upstream_version) + package, old_upstream_version + ) if new_upstream_version is None: raise NewUpstreamMissing() @@ -471,25 +511,29 @@ new_upstream_version = Version(new_upstream_version) except ValueError: raise InvalidFormatUpstreamVersion( - new_upstream_version, primary_upstream_source) + new_upstream_version, primary_upstream_source + ) if old_upstream_version: if old_upstream_version == new_upstream_version: raise UpstreamAlreadyImported(new_upstream_version) if old_upstream_version > new_upstream_version: if not snapshot and matches_release( - str(old_upstream_version), str(new_upstream_version)): + str(old_upstream_version), str(new_upstream_version) + ): raise UpstreamAlreadyImported(new_upstream_version) raise NewerUpstreamAlreadyImported( - old_upstream_version, new_upstream_version) + old_upstream_version, new_upstream_version + ) # TODO(jelmer): Check if new_upstream_version is already imported - note("Using version string %s.", new_upstream_version) + logging.info("Using version string %s.", new_upstream_version) if include_upstream_history is None and upstream_branch_source is not None: include_upstream_history = detect_include_upstream_history( - tree, upstream_branch_source, package, old_upstream_version) + tree, upstream_branch_source, package, old_upstream_version + ) if include_upstream_history is False: upstream_branch_source = None @@ -498,24 +542,26 @@ if upstream_branch_source is not None: try: upstream_revisions = upstream_branch_source.version_as_revisions( - package, str(new_upstream_version)) + package, str(new_upstream_version) + ) except PackageVersionNotPresent: if upstream_branch_source is primary_upstream_source: # The branch is our primary upstream source, so if it can't # find the version then there's nothing we can do. raise UpstreamVersionMissingInUpstreamBranch( - upstream_branch_source.upstream_branch, - new_upstream_version) + upstream_branch_source.upstream_branch, new_upstream_version + ) elif not allow_ignore_upstream_branch: raise UpstreamVersionMissingInUpstreamBranch( - upstream_branch_source.upstream_branch, - new_upstream_version) + upstream_branch_source.upstream_branch, new_upstream_version + ) else: - warning( - 'Upstream version %s is not in upstream branch %s. ' - 'Not merging from upstream branch. ', + logging.warn( + "Upstream version %s is not in upstream branch %s. " + "Not merging from upstream branch. ", new_upstream_version, - upstream_branch_source.upstream_branch) + upstream_branch_source.upstream_branch, + ) upstream_revisions = None upstream_branch_source = None else: @@ -534,22 +580,24 @@ upstream_branch, upstream_branch_browse, files_excluded, - include_upstream_history) + include_upstream_history, + ) def import_upstream( - tree: Tree, snapshot: bool = False, - location: Optional[str] = None, - new_upstream_version: Optional[Union[Version, str]] = None, - force: bool = False, distribution_name: str = DEFAULT_DISTRIBUTION, - allow_ignore_upstream_branch: bool = True, - trust_package: bool = False, - committer: Optional[str] = None, - subpath: str = '', - include_upstream_history: Optional[bool] = None, - create_dist: Optional[ - Callable[[Tree, str, Version, str], Optional[str]]] = None - ) -> ImportUpstreamResult: + tree: Tree, + snapshot: bool = False, + location: Optional[str] = None, + new_upstream_version: Optional[Union[Version, str]] = None, + force: bool = False, + distribution_name: str = DEFAULT_DISTRIBUTION, + allow_ignore_upstream_branch: bool = True, + trust_package: bool = False, + committer: Optional[str] = None, + subpath: str = "", + include_upstream_history: Optional[bool] = None, + create_dist: Optional[Callable[[Tree, str, Version, str], Optional[str]]] = None, +) -> ImportUpstreamResult: """Import a new upstream version into a tree. Raises: @@ -578,72 +626,94 @@ ImportUpstreamResult object """ if subpath is None: - subpath = '' + subpath = "" config = debuild_config(tree, subpath) - (changelog, top_level) = find_changelog( - tree, subpath, merge=False, max_blocks=2) + (changelog, top_level) = find_changelog(tree, subpath, merge=False, max_blocks=2) old_upstream_version = changelog.version.upstream_version package = changelog.package contains_upstream_source = tree_contains_upstream_source(tree, subpath) build_type = config.build_type if build_type is None: build_type = guess_build_type( - tree, changelog.version, subpath, - contains_upstream_source=contains_upstream_source) + tree, + changelog.version, + subpath, + contains_upstream_source=contains_upstream_source, + ) if build_type == BUILD_TYPE_MERGE: raise UpstreamNotBundled(changelog.package) if build_type == BUILD_TYPE_NATIVE: raise PackageIsNative(changelog.package, changelog.version) - (primary_upstream_source, - new_upstream_version, - upstream_revisions, - upstream_branch_source, - upstream_branch, - upstream_branch_browse, - files_excluded, include_upstream_history) = find_new_upstream( - tree, subpath, config, package, location=location, + ( + primary_upstream_source, + new_upstream_version, + upstream_revisions, + upstream_branch_source, + upstream_branch, + upstream_branch_browse, + files_excluded, + include_upstream_history, + ) = find_new_upstream( + tree, + subpath, + config, + package, + location=location, old_upstream_version=old_upstream_version, - new_upstream_version=new_upstream_version, trust_package=trust_package, + new_upstream_version=new_upstream_version, + trust_package=trust_package, snapshot=snapshot, allow_ignore_upstream_branch=allow_ignore_upstream_branch, - top_level=top_level, include_upstream_history=include_upstream_history, - create_dist=create_dist) + top_level=top_level, + include_upstream_history=include_upstream_history, + create_dist=create_dist, + ) with tempfile.TemporaryDirectory() as target_dir: - initial_path = os.path.join(target_dir, 'initial') + initial_path = os.path.join(target_dir, "initial") os.mkdir(initial_path) try: locations = primary_upstream_source.fetch_tarballs( - package, str(new_upstream_version), target_dir, - components=[None]) + package, str(new_upstream_version), target_dir, components=[None] + ) except (PackageVersionNotPresent, WatchLineWithoutMatchingHrefs): if upstream_revisions is not None: locations = upstream_branch_source.fetch_tarballs( - package, str(new_upstream_version), initial_path, - components=[None], revisions=upstream_revisions) + package, + str(new_upstream_version), + initial_path, + components=[None], + revisions=upstream_revisions, + ) else: raise - orig_path = os.path.join(target_dir, 'orig') + orig_path = os.path.join(target_dir, "orig") try: tarball_filenames = get_tarballs( - orig_path, tree, package, new_upstream_version, - locations) + orig_path, tree, package, new_upstream_version, locations + ) except FileExists as e: raise AssertionError( "The target file %s already exists, and is either " "different to the new upstream tarball, or they " "are of different formats. Either delete the target " - "file, or use it as the argument to import." - % e.path) + "file, or use it as the argument to import." % e.path + ) imported_revisions = do_import( - tree, subpath, tarball_filenames, package, - str(new_upstream_version), str(old_upstream_version), - upstream_branch_source.upstream_branch - if upstream_branch_source else None, - upstream_revisions, merge_type=None, - force=force, committer=committer, - files_excluded=files_excluded) + tree, + subpath, + tarball_filenames, + package, + str(new_upstream_version), + str(old_upstream_version), + upstream_branch_source.upstream_branch if upstream_branch_source else None, + upstream_revisions, + merge_type=None, + force=force, + committer=committer, + files_excluded=files_excluded, + ) return ImportUpstreamResult( include_upstream_history=include_upstream_history, @@ -652,29 +722,37 @@ upstream_branch=upstream_branch, upstream_branch_browse=upstream_branch_browse, upstream_revisions=upstream_revisions, - imported_revisions=imported_revisions) + imported_revisions=imported_revisions, + ) class MergeUpstreamResult(object): """Object representing the result of a merge_upstream operation.""" __slots__ = [ - 'old_upstream_version', - 'new_upstream_version', - 'upstream_branch', - 'upstream_branch_browse', - 'upstream_revisions', - 'old_revision', - 'new_revision', - 'imported_revisions', - 'include_upstream_history', - ] - - def __init__(self, include_upstream_history, old_upstream_version, - new_upstream_version, - upstream_branch, upstream_branch_browse, - upstream_revisions, old_revision, - new_revision, imported_revisions): + "old_upstream_version", + "new_upstream_version", + "upstream_branch", + "upstream_branch_browse", + "upstream_revisions", + "old_revision", + "new_revision", + "imported_revisions", + "include_upstream_history", + ] + + def __init__( + self, + include_upstream_history, + old_upstream_version, + new_upstream_version, + upstream_branch, + upstream_branch_browse, + upstream_revisions, + old_revision, + new_revision, + imported_revisions, + ): self.include_upstream_history = include_upstream_history self.old_upstream_version = old_upstream_version self.new_upstream_version = new_upstream_version @@ -690,20 +768,21 @@ return (self.old_upstream_version, self.new_upstream_version) -def merge_upstream(tree: Tree, snapshot: bool = False, - location: Optional[str] = None, - new_upstream_version: Optional[str] = None, - force: bool = False, - distribution_name: str = DEFAULT_DISTRIBUTION, - allow_ignore_upstream_branch: bool = True, - trust_package: bool = False, - committer: Optional[str] = None, - update_changelog: bool = True, - subpath: str = '', - include_upstream_history: Optional[bool] = None, - create_dist: Optional[Callable[ - [Tree, str, Version, str], - Optional[str]]] = None) -> MergeUpstreamResult: +def merge_upstream( # noqa: C901 + tree: Tree, + snapshot: bool = False, + location: Optional[str] = None, + new_upstream_version: Optional[str] = None, + force: bool = False, + distribution_name: str = DEFAULT_DISTRIBUTION, + allow_ignore_upstream_branch: bool = True, + trust_package: bool = False, + committer: Optional[str] = None, + update_changelog: bool = True, + subpath: str = "", + include_upstream_history: Optional[bool] = None, + create_dist: Optional[Callable[[Tree, str, Version, str], Optional[str]]] = None, +) -> MergeUpstreamResult: """Merge a new upstream version into a tree. Raises: @@ -732,10 +811,9 @@ MergeUpstreamResult object """ if subpath is None: - subpath = '' + subpath = "" config = debuild_config(tree, subpath) - (changelog, top_level) = find_changelog( - tree, subpath, merge=False, max_blocks=2) + (changelog, top_level) = find_changelog(tree, subpath, merge=False, max_blocks=2) old_upstream_version = changelog.version.upstream_version old_revision = tree.last_revision() package = changelog.package @@ -743,88 +821,111 @@ build_type = config.build_type if build_type is None: build_type = guess_build_type( - tree, changelog.version, subpath, - contains_upstream_source=contains_upstream_source) - need_upstream_tarball = (build_type != BUILD_TYPE_MERGE) + tree, + changelog.version, + subpath, + contains_upstream_source=contains_upstream_source, + ) + need_upstream_tarball = build_type != BUILD_TYPE_MERGE if build_type == BUILD_TYPE_NATIVE: raise PackageIsNative(changelog.package, changelog.version) - (primary_upstream_source, - new_upstream_version, - upstream_revisions, - upstream_branch_source, - upstream_branch, - upstream_branch_browse, - files_excluded, include_upstream_history) = find_new_upstream( - tree, subpath, config, package, location=location, + ( + primary_upstream_source, + new_upstream_version, + upstream_revisions, + upstream_branch_source, + upstream_branch, + upstream_branch_browse, + files_excluded, + include_upstream_history, + ) = find_new_upstream( + tree, + subpath, + config, + package, + location=location, old_upstream_version=old_upstream_version, - new_upstream_version=new_upstream_version, trust_package=trust_package, + new_upstream_version=new_upstream_version, + trust_package=trust_package, snapshot=snapshot, allow_ignore_upstream_branch=allow_ignore_upstream_branch, - top_level=top_level, include_upstream_history=include_upstream_history, - create_dist=create_dist) + top_level=top_level, + include_upstream_history=include_upstream_history, + create_dist=create_dist, + ) if need_upstream_tarball: with tempfile.TemporaryDirectory() as target_dir: - initial_path = os.path.join(target_dir, 'initial') + initial_path = os.path.join(target_dir, "initial") os.mkdir(initial_path) try: locations = primary_upstream_source.fetch_tarballs( - package, str(new_upstream_version), initial_path, - components=[None]) + package, str(new_upstream_version), initial_path, components=[None] + ) except PackageVersionNotPresent as e: if upstream_revisions is not None: locations = upstream_branch_source.fetch_tarballs( - package, str(new_upstream_version), initial_path, - components=[None], revisions=upstream_revisions) + package, + str(new_upstream_version), + initial_path, + components=[None], + revisions=upstream_revisions, + ) else: - raise NewUpstreamTarballMissing( - e.package, e.version, e.upstream) + raise NewUpstreamTarballMissing(e.package, e.version, e.upstream) - orig_path = os.path.join(target_dir, 'orig') + orig_path = os.path.join(target_dir, "orig") os.mkdir(orig_path) try: tarball_filenames = get_tarballs( - orig_path, tree, package, new_upstream_version, - locations) + orig_path, tree, package, new_upstream_version, locations + ) except FileExists as e: raise AssertionError( "The target file %s already exists, and is either " "different to the new upstream tarball, or they " "are of different formats. Either delete the target " - "file, or use it as the argument to import." - % e.path) + "file, or use it as the argument to import." % e.path + ) try: conflicts, imported_revids = do_merge( - tree, subpath, tarball_filenames, package, - str(new_upstream_version), str(old_upstream_version), + tree, + subpath, + tarball_filenames, + package, + str(new_upstream_version), + str(old_upstream_version), upstream_branch_source.upstream_branch - if upstream_branch_source else None, - upstream_revisions, merge_type=None, - force=force, committer=committer, - files_excluded=files_excluded) + if upstream_branch_source + else None, + upstream_revisions, + merge_type=None, + force=force, + committer=committer, + files_excluded=files_excluded, + ) except UpstreamBranchAlreadyMerged: # TODO(jelmer): Perhaps reconcile these two exceptions? raise UpstreamAlreadyMerged(new_upstream_version) except UpstreamAlreadyImported: - pristine_tar_source = get_pristine_tar_source( - tree, tree.branch) + pristine_tar_source = get_pristine_tar_source(tree, tree.branch) upstream_revid = None imported_revids = [] - for component, revid in ( - pristine_tar_source.version_as_revisions( - package, new_upstream_version).items()): + for component, revid in pristine_tar_source.version_as_revisions( + package, new_upstream_version + ).items(): if component is None: upstream_revid = revid upstream_tag = pristine_tar_source.tag_name( - new_upstream_version, component) - imported_revids.append( - (component, upstream_tag, revid, None)) + new_upstream_version, component + ) + imported_revids.append((component, upstream_tag, revid, None)) try: conflicts = tree.merge_from_branch( - pristine_tar_source.branch, - to_revision=upstream_revid) + pristine_tar_source.branch, to_revision=upstream_revid + ) except PointlessMerge: raise UpstreamAlreadyMerged(new_upstream_version) else: @@ -842,11 +943,12 @@ raise UpstreamAlreadyMerged(new_upstream_version) if update_changelog: changelog_add_new_version( - tree, subpath, new_upstream_version, distribution_name, changelog, - package) + tree, subpath, new_upstream_version, distribution_name, changelog, package + ) if not need_upstream_tarball: - note("An entry for the new upstream version has been " - "added to the changelog.") + logging.info( + "An entry for the new upstream version has been " "added to the changelog." + ) else: if conflicts: raise UpstreamMergeConflicted(new_upstream_version, conflicts) @@ -856,9 +958,9 @@ else: tree.commit( committer=committer, - message='Merge new upstream release %s.' % new_upstream_version, - specific_files=( - [subpath] if len(tree.get_parent_ids()) <= 1 else None)) + message="Merge new upstream release %s." % new_upstream_version, + specific_files=([subpath] if len(tree.get_parent_ids()) <= 1 else None), + ) return MergeUpstreamResult( include_upstream_history=include_upstream_history, @@ -869,36 +971,37 @@ upstream_branch=upstream_branch, upstream_branch_browse=upstream_branch_browse, upstream_revisions=upstream_revisions, - imported_revisions=imported_revids) + imported_revisions=imported_revids, + ) def override_dh_autoreconf_add_arguments(basedir: str, args): - from lintian_brush.rules import update_rules + from debmutate._rules import update_rules # TODO(jelmer): Make sure dh-autoreconf is installed, # or debhelper version is >= 10 def update_makefile(mf): - for rule in mf.iter_rules(b'override_dh_autoreconf'): - command = rule.commands()[0].split(b' ') - if command[0] != b'dh_autoreconf': + for rule in mf.iter_rules(b"override_dh_autoreconf"): + command = rule.commands()[0].split(b" ") + if command[0] != b"dh_autoreconf": return rule.lines = [rule.lines[0]] command += args break else: - rule = mf.add_rule(b'override_dh_autoreconf') - command = [b'dh_autoreconf'] + args - rule.append_command(b' '.join(command)) + rule = mf.add_rule(b"override_dh_autoreconf") + command = [b"dh_autoreconf"] + args + rule.append_command(b" ".join(command)) return update_rules( - makefile_cb=update_makefile, - path=os.path.join(basedir, 'debian', 'rules')) + makefile_cb=update_makefile, path=os.path.join(basedir, "debian", "rules") + ) def update_packaging( - tree: Tree, old_tree: Tree, subpath: str = '', - committer: Optional[str] = None) -> List[str]: + tree: Tree, old_tree: Tree, subpath: str = "", committer: Optional[str] = None +) -> List[str]: """Update packaging to take in changes between upstream trees. Args: @@ -914,32 +1017,41 @@ continue if not path.startswith(subpath): continue - path = path[len(subpath):] - if path == 'autogen.sh': - if override_dh_autoreconf_add_arguments( - tree.basedir, [b'./autogen.sh']): - note('Modifying debian/rules: ' - 'Invoke autogen.sh from dh_autoreconf.') + path = path[len(subpath) :] + if path == "autogen.sh": + if override_dh_autoreconf_add_arguments(tree.basedir, [b"./autogen.sh"]): + logging.info("Modifying debian/rules: " "Invoke autogen.sh from dh_autoreconf.") changelog_add_line( - tree, subpath, 'Invoke autogen.sh from dh_autoreconf.', - email=committer) + tree, + subpath, + "Invoke autogen.sh from dh_autoreconf.", + email=committer, + ) debcommit( - tree, committer=committer, + tree, + committer=committer, subpath=subpath, - paths=['debian/changelog', 'debian/rules']) - elif path.startswith('LICENSE') or path.startswith('COPYING'): - notes.append( - 'License file %s has changed.' % os.path.join(subpath, path)) + paths=["debian/changelog", "debian/rules"], + ) + elif path.startswith("LICENSE") or path.startswith("COPYING"): + notes.append("License file %s has changed." % os.path.join(subpath, path)) return notes class NewUpstreamChanger(DebianChanger): - name = 'new-upstream' + name = "new-upstream" - def __init__(self, snapshot, trust_package, refresh_patches, - update_packaging, dist_command, import_only=False, - include_upstream_history=None): + def __init__( + self, + snapshot, + trust_package, + refresh_patches, + update_packaging, + dist_command, + import_only=False, + include_upstream_history=None, + ): self.snapshot = snapshot self.trust_package = trust_package self.refresh_patches = refresh_patches @@ -951,37 +1063,57 @@ @classmethod def setup_parser(cls, parser): parser.add_argument( - '--chroot', type=str, help="Name of chroot", - default=os.environ.get('CHROOT')) + "--chroot", + type=str, + help="Name of chroot", + default=os.environ.get("CHROOT"), + ) parser.add_argument( - '--trust-package', action='store_true', + "--trust-package", + action="store_true", default=False, - help=argparse.SUPPRESS) + help=argparse.SUPPRESS, + ) parser.add_argument( - '--import-only', action='store_true', - help='Only import a new version, do not merge.') + "--import-only", + action="store_true", + help="Only import a new version, do not merge.", + ) parser.add_argument( - '--update-packaging', action='store_true', + "--update-packaging", + action="store_true", default=False, - help='Attempt to update packaging to upstream changes.') + help="Attempt to update packaging to upstream changes.", + ) parser.add_argument( - '--snapshot', - help='Merge a new upstream snapshot rather than a release', - action='store_true') + "--snapshot", + help="Merge a new upstream snapshot rather than a release", + action="store_true", + ) parser.add_argument( - '--refresh-patches', action="store_true", - help="Refresh quilt patches after upstream merge.") + "--refresh-patches", + action="store_true", + help="Refresh quilt patches after upstream merge.", + ) parser.add_argument( - '--dist-command', type=str, - help="Command to run to create tarball from source tree.") + "--dist-command", + type=str, + help="Command to run to create tarball from source tree.", + ) parser.add_argument( - '--no-include-upstream-history', action="store_false", - default=None, dest="include_upstream_history", - help="do not include upstream branch history") + "--no-include-upstream-history", + action="store_false", + default=None, + dest="include_upstream_history", + help="do not include upstream branch history", + ) parser.add_argument( - '--include-upstream-history', action="store_true", + "--include-upstream-history", + action="store_true", dest="include_upstream_history", - help="force inclusion of upstream history", default=None) + help="force inclusion of upstream history", + default=None, + ) def suggest_branch_name(self): if self.snapshot: @@ -991,30 +1123,38 @@ @classmethod def from_args(cls, args): - return cls(snapshot=args.snapshot, - trust_package=args.trust_package, - refresh_patches=args.refresh_patches, - update_packaging=args.update_packaging, - dist_command=args.dist_command, - import_only=args.import_only, - include_upstream_history=args.include_upstream_history) + return cls( + snapshot=args.snapshot, + trust_package=args.trust_package, + refresh_patches=args.refresh_patches, + update_packaging=args.update_packaging, + dist_command=args.dist_command, + import_only=args.import_only, + include_upstream_history=args.include_upstream_history, + ) def create_dist_from_command(self, tree, package, version, target_dir): - return run_dist_command( - tree, package, version, target_dir, self.dist_command) + return run_dist_command(tree, package, version, target_dir, self.dist_command) - def make_changes(self, local_tree, subpath, update_changelog, reporter, - committer, base_proposal=None): + def make_changes( # noqa: C901 + self, + local_tree, + subpath, + update_changelog, + reporter, + committer, + base_proposal=None, + ): base_revids = { - b.name: b.last_revision() - for b in local_tree.controldir.list_branches()} + b.name: b.last_revision() for b in local_tree.controldir.list_branches() + } if control_files_in_root(local_tree, subpath): raise ChangerError( - 'control-files-in-root', - 'control files live in root rather than debian/ ' - '(LarstIQ mode)') + "control-files-in-root", + "control files live in root rather than debian/ " "(LarstIQ mode)", + ) if self.dist_command: create_dist = self.create_dist_from_command @@ -1025,304 +1165,349 @@ if not self.import_only: try: result = merge_upstream( - tree=local_tree, snapshot=self.snapshot, + tree=local_tree, + snapshot=self.snapshot, trust_package=self.trust_package, update_changelog=update_changelog, - subpath=subpath, committer=committer, + subpath=subpath, + committer=committer, include_upstream_history=self.include_upstream_history, - create_dist=create_dist) + create_dist=create_dist, + ) except MalformedTransform: traceback.print_exc() error_description = ( - 'Malformed tree transform during new upstream merge') - error_code = 'malformed-transform' + "Malformed tree transform during new upstream merge" + ) + error_code = "malformed-transform" raise ChangerError(error_code, error_description) else: result = import_upstream( - tree=local_tree, snapshot=self.snapshot, + tree=local_tree, + snapshot=self.snapshot, trust_package=self.trust_package, - subpath=subpath, committer=committer, + subpath=subpath, + committer=committer, include_upstream_history=self.include_upstream_history, - create_dist=create_dist) + create_dist=create_dist, + ) except UpstreamAlreadyImported as e: reporter.report_context(str(e.version)) - reporter.report_metadata('upstream_version', str(e.version)) + reporter.report_metadata("upstream_version", str(e.version)) raise ChangerError( - 'nothing-to-do', - 'Last upstream version %s already imported.' % e.version, e) + "nothing-to-do", + "Last upstream version %s already imported." % e.version, + e, + ) except UnsupportedRepackFormat as e: error_description = ( - 'Unable to repack file %s to supported tarball format.' % ( - os.path.basename(e.location))) - raise ChangerError( - 'unsupported-repack-format', error_description) + "Unable to repack file %s to supported tarball format." + % (os.path.basename(e.location)) + ) + raise ChangerError("unsupported-repack-format", error_description) except NewUpstreamMissing as e: raise ChangerError( - 'new-upstream-missing', - 'Unable to find new upstream source.', e) + "new-upstream-missing", "Unable to find new upstream source.", e + ) except UpstreamAlreadyMerged as e: reporter.report_context(str(e.version)) - reporter.report_metadata('upstream_version', str(e.version)) + reporter.report_metadata("upstream_version", str(e.version)) raise ChangerError( - 'nothing-to-do', - 'Last upstream version %s already merged.' % e.version, e) + "nothing-to-do", + "Last upstream version %s already merged." % e.version, + e, + ) except PreviousVersionTagMissing as e: raise ChangerError( - 'previous-upstream-missing', - 'Previous upstream version %s missing (tag: %s).' % ( - e.version, e.tag_name), e) + "previous-upstream-missing", + "Previous upstream version %s missing (tag: %s)." + % (e.version, e.tag_name), + e, + ) except InvalidFormatUpstreamVersion as e: raise ChangerError( - 'invalid-upstream-version-format', - '%r reported invalid format version string %s.' % ( - e.source, e.version), e) + "invalid-upstream-version-format", + "%r reported invalid format version string %s." % (e.source, e.version), + e, + ) except PristineTarError as e: - raise ChangerError( - 'pristine-tar-error', 'Pristine tar error: %s' % e, e) + raise ChangerError("pristine-tar-error", "Pristine tar error: %s" % e, e) except UpstreamBranchUnavailable as e: - error_description = ( - "The upstream branch at %s was unavailable: %s" % ( - e.location, e.error)) - error_code = 'upstream-branch-unavailable' - if 'Fossil branches are not yet supported' in str(e.error): - error_code = 'upstream-unsupported-vcs-fossil' - if 'Mercurial branches are not yet supported.' in str(e.error): - error_code = 'upstream-unsupported-vcs-hg' - if 'Subversion branches are not yet supported.' in str( - e.error): - error_code = 'upstream-unsupported-vcs-svn' - if 'Darcs branches are not yet supported' in str(e.error): - error_code = 'upstream-unsupported-vcs-darcs' - if 'Unsupported protocol for url' in str(e.error): - if 'svn://' in str(e.error): - error_code = 'upstream-unsupported-vcs-svn' - elif 'cvs+pserver://' in str(e.error): - error_code = 'upstream-unsupported-vcs-cvs' + error_description = "The upstream branch at %s was unavailable: %s" % ( + e.location, + e.error, + ) + error_code = "upstream-branch-unavailable" + if "Fossil branches are not yet supported" in str(e.error): + error_code = "upstream-unsupported-vcs-fossil" + if "Mercurial branches are not yet supported." in str(e.error): + error_code = "upstream-unsupported-vcs-hg" + if "Subversion branches are not yet supported." in str(e.error): + error_code = "upstream-unsupported-vcs-svn" + if "Darcs branches are not yet supported" in str(e.error): + error_code = "upstream-unsupported-vcs-darcs" + if "Unsupported protocol for url" in str(e.error): + if "svn://" in str(e.error): + error_code = "upstream-unsupported-vcs-svn" + elif "cvs+pserver://" in str(e.error): + error_code = "upstream-unsupported-vcs-cvs" else: - error_code = 'upstream-unsupported-vcs' + error_code = "upstream-unsupported-vcs" raise ChangerError(error_code, error_description, e) except UpstreamBranchUnknown as e: raise ChangerError( - 'upstream-branch-unknown', - 'Upstream branch location unknown. ' - 'Set \'Repository\' field in debian/upstream/metadata?', e) + "upstream-branch-unknown", + "Upstream branch location unknown. " + "Set 'Repository' field in debian/upstream/metadata?", + e, + ) except UpstreamMergeConflicted as e: reporter.report_context(str(e.version)) - reporter.report_metadata('upstream_version', str(e.version)) - reporter.report_metadata('conflicts', e.conflicts) + reporter.report_metadata("upstream_version", str(e.version)) + reporter.report_metadata("conflicts", e.conflicts) raise ChangerError( - 'upstream-merged-conflicts', - 'Merging upstream version %s resulted in conflicts.' - % e.version, e) + "upstream-merged-conflicts", + "Merging upstream version %s resulted in conflicts." % e.version, + e, + ) except PackageIsNative as e: raise ChangerError( - 'native-package', - 'Package %s is native; unable to merge new upstream.' % ( - e.package, ), e) + "native-package", + "Package %s is native; unable to merge new upstream." % (e.package,), + e, + ) except ChangelogParseError as e: error_description = str(e) - error_code = 'unparseable-changelog' + error_code = "unparseable-changelog" raise ChangerError(error_code, error_description, e) except UpstreamVersionMissingInUpstreamBranch as e: - error_description = ( - 'Upstream version %s not in upstream branch %r' % ( - e.version, e.branch)) - error_code = 'upstream-version-missing-in-upstream-branch' + error_description = "Upstream version %s not in upstream branch %r" % ( + e.version, + e.branch, + ) + error_code = "upstream-version-missing-in-upstream-branch" raise ChangerError(error_code, error_description, e) except InconsistentSourceFormatError as e: raise ChangerError( - 'inconsistent-source-format', - 'Inconsistencies in type of package: %s' % e, e) + "inconsistent-source-format", + "Inconsistencies in type of package: %s" % e, + e, + ) except WatchLineWithoutMatches as e: raise ChangerError( - 'uscan-watch-line-without-matches', - 'UScan did not find matches for line: %s' % e.line.strip()) + "uscan-watch-line-without-matches", + "UScan did not find matches for line: %s" % e.line.strip(), + ) except NoRoundtrippingSupport: error_description = ( - 'Unable to import upstream repository into ' - 'packaging repository.') - error_code = 'roundtripping-error' + "Unable to import upstream repository into " "packaging repository." + ) + error_code = "roundtripping-error" raise ChangerError(error_code, error_description) except UScanError as e: error_description = str(e) - if e.errors == 'OpenPGP signature did not verify.': - error_code = 'upstream-pgp-signature-verification-failed' + if e.errors == "OpenPGP signature did not verify.": + error_code = "upstream-pgp-signature-verification-failed" else: - error_code = 'uscan-error' + error_code = "uscan-error" raise ChangerError(error_code, error_description, e) except UpstreamMetadataSyntaxError as e: raise ChangerError( - 'upstream-metadata-syntax-error', - 'Unable to parse %s: %s' % (e.path, e.error), e) + "upstream-metadata-syntax-error", + "Unable to parse %s: %s" % (e.path, e.error), + e, + ) except InvalidNormalization as e: error_description = str(e) - error_code = 'invalid-path-normalization' + error_code = "invalid-path-normalization" raise ChangerError(error_code, error_description) except MissingChangelogError as e: - raise ChangerError( - 'missing-changelog', 'Missing changelog %s' % e, e) + raise ChangerError("missing-changelog", "Missing changelog %s" % e, e) except DistCommandFailed as e: - raise ChangerError( - 'dist-command-failed', 'Dist command failed: %s' % e, e) + raise ChangerError("dist-command-failed", "Dist command failed: %s" % e, e) except MissingUpstreamTarball as e: raise ChangerError( - 'missing-upstream-tarball', - 'Missing upstream tarball: %s' % e, e) + "missing-upstream-tarball", "Missing upstream tarball: %s" % e, e + ) except NewUpstreamTarballMissing as e: reporter.report_context(str(e.version)) - reporter.report_metadata('upstream_version', str(e.version)) + reporter.report_metadata("upstream_version", str(e.version)) raise ChangerError( - 'new-upstream-tarball-missing', - 'New upstream version (%s/%s) found, but was missing ' - 'when retrieved as tarball from %r.' % ( - e.package, e.version, e.upstream)) + "new-upstream-tarball-missing", + "New upstream version (%s/%s) found, but was missing " + "when retrieved as tarball from %r." + % (e.package, e.version, e.upstream), + ) except NoUpstreamLocationsKnown as e: raise ChangerError( - 'no-upstream-locations-known', - 'No debian/watch file or Repository in ' - 'debian/upstream/metadata to retrieve new upstream version' - 'from.', e) + "no-upstream-locations-known", + "No debian/watch file or Repository in " + "debian/upstream/metadata to retrieve new upstream version" + "from.", + e, + ) except NewerUpstreamAlreadyImported as e: reporter.report_context(str(e.new_upstream_version)) raise ChangerError( - 'newer-upstream-version-already-imported', - 'A newer upstream release (%s) has already been imported. ' - 'Found: %s' % (e.old_upstream_version, e.new_upstream_version)) + "newer-upstream-version-already-imported", + "A newer upstream release (%s) has already been imported. " + "Found: %s" % (e.old_upstream_version, e.new_upstream_version), + ) except OSError as e: if e.errno == errno.ENOSPC: - raise ChangerError('no-space-on-device', str(e)) + raise ChangerError("no-space-on-device", str(e)) raise reporter.report_metadata( - 'old_upstream_version', - str(result.old_upstream_version) - if result.old_upstream_version else None) - reporter.report_metadata( - 'upstream_version', str(result.new_upstream_version)) + "old_upstream_version", + str(result.old_upstream_version) if result.old_upstream_version else None, + ) + reporter.report_metadata("upstream_version", str(result.new_upstream_version)) if result.upstream_branch: reporter.report_metadata( - 'upstream_branch_url', - full_branch_url(result.upstream_branch)) + "upstream_branch_url", full_branch_url(result.upstream_branch) + ) reporter.report_metadata( - 'upstream_branch_browse', - result.upstream_branch_browse) + "upstream_branch_browse", result.upstream_branch_browse + ) reporter.report_metadata( - 'include_upstream_history', result.include_upstream_history) + "include_upstream_history", result.include_upstream_history + ) reporter.report_context(str(result.new_upstream_version)) tags = [ - (('upstream', str(result.new_upstream_version), component), - tag, revid) - for (component, tag, revid, - pristine_tar_imported) in result.imported_revisions] + (("upstream", str(result.new_upstream_version), component), tag, revid) + for ( + component, + tag, + revid, + pristine_tar_imported, + ) in result.imported_revisions + ] branches = [] try: - pristine_tar_branch = local_tree.controldir.open_branch( - 'pristine-tar') + pristine_tar_branch = local_tree.controldir.open_branch("pristine-tar") except NotBranchError: pass else: - base_revision = base_revids.get('pristine-tar', NULL_REVISION) + base_revision = base_revids.get("pristine-tar", NULL_REVISION) new_revision = pristine_tar_branch.last_revision() if base_revision != new_revision: - branches.append(( - 'pristine-tar', 'pristine-tar', - base_revision, new_revision)) + branches.append( + ("pristine-tar", "pristine-tar", base_revision, new_revision) + ) # TODO(jelmer): ideally, the branch name would be provided by do_merge # / do_import try: - upstream_branch = local_tree.controldir.open_branch('upstream') + upstream_branch = local_tree.controldir.open_branch("upstream") except NotBranchError: pass else: - base_revision = base_revids.get('upstream', NULL_REVISION) + base_revision = base_revids.get("upstream", NULL_REVISION) new_revision = upstream_branch.last_revision() if base_revision != new_revision: - branches.append( - ('upstream', 'upstream', base_revision, new_revision)) + branches.append(("upstream", "upstream", base_revision, new_revision)) if self.import_only: - note('Imported new upstream version %s (previous: %s)', - result.new_upstream_version, - result.old_upstream_version) + logging.info( + "Imported new upstream version %s (previous: %s)", + result.new_upstream_version, + result.old_upstream_version, + ) return ChangerResult( - description="Imported new upstream version %s" % ( - result.new_upstream_version), - mutator=result, tags=tags, branches=branches, - sufficient_for_proposal=True) + description="Imported new upstream version %s" + % (result.new_upstream_version), + mutator=result, + tags=tags, + branches=branches, + sufficient_for_proposal=True, + ) else: - note('Merged new upstream version %s (previous: %s)', - result.new_upstream_version, result.old_upstream_version) + logging.info( + "Merged new upstream version %s (previous: %s)", + result.new_upstream_version, + result.old_upstream_version, + ) if self.update_packaging: old_tree = local_tree.branch.repository.revision_tree( - result.old_revision) + result.old_revision + ) notes = update_packaging(local_tree, old_tree) - reporter.report_metadata('notes', notes) + reporter.report_metadata("notes", notes) for n in notes: - note('%s', n) + logging.info("%s", n) - patch_series_path = os.path.join( - subpath, 'debian/patches/series') - if self.refresh_patches and \ - local_tree.has_filename(patch_series_path): - note('Refresh quilt patches.') + patch_series_path = os.path.join(subpath, "debian/patches/series") + if self.refresh_patches and local_tree.has_filename(patch_series_path): + logging.info("Refresh quilt patches.") try: refresh_quilt_patches( local_tree, old_version=result.old_upstream_version, new_version=result.new_upstream_version, committer=committer, - subpath=subpath) + subpath=subpath, + ) except QuiltError as e: error_description = ( "An error (%d) occurred refreshing quilt patches: " - "%s%s" % (e.retcode, e.stderr, e.extra)) - error_code = 'quilt-refresh-error' + "%s%s" % (e.retcode, e.stderr, e.extra) + ) + error_code = "quilt-refresh-error" raise ChangerError(error_code, error_description, e) except QuiltPatchPushFailure as e: error_description = ( "An error occurred refreshing quilt patch %s: %s" - % (e.patch_name, e.actual_error.extra)) - error_code = 'quilt-refresh-error' + % (e.patch_name, e.actual_error.extra) + ) + error_code = "quilt-refresh-error" raise ChangerError(error_code, error_description, e) branches.append( - ('main', None, - base_revids[local_tree.branch.name], - local_tree.last_revision())) + ( + "main", + None, + base_revids[local_tree.branch.name], + local_tree.last_revision(), + ) + ) proposed_commit_message = ( - "Merge new upstream release %s" % result.new_upstream_version) + "Merge new upstream release %s" % result.new_upstream_version + ) return ChangerResult( - description="Merged new upstream version %s" % ( - result.new_upstream_version), - mutator=result, tags=tags, + description="Merged new upstream version %s" + % (result.new_upstream_version), + mutator=result, + tags=tags, branches=branches, sufficient_for_proposal=True, - proposed_commit_message=proposed_commit_message) + proposed_commit_message=proposed_commit_message, + ) def get_proposal_description( - self, merge_upstream_result, description_format, unused_proposal): - return ("Merge new upstream release %s" % - merge_upstream_result.new_upstream_version) + self, merge_upstream_result, description_format, unused_proposal + ): + return ( + "Merge new upstream release %s" % merge_upstream_result.new_upstream_version + ) def describe(self, merge_upstream_result, publish_result): if publish_result.proposal: if publish_result.is_new: - note('Created new merge proposal %s.', - publish_result.proposal.url) + logging.info("Created new merge proposal %s.", publish_result.proposal.url) else: - note('Updated merge proposal %s.', - publish_result.proposal.url) + logging.info("Updated merge proposal %s.", publish_result.proposal.url) -if __name__ == '__main__': +if __name__ == "__main__": import sys + sys.exit(run_mutator(NewUpstreamChanger)) diff -Nru silver-platter-0.4.0/silver_platter/__init__.py silver-platter-0.4.1/silver_platter/__init__.py --- silver-platter-0.4.0/silver_platter/__init__.py 2021-02-01 23:29:57.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/__init__.py 2021-02-17 22:45:11.000000000 +0000 @@ -25,5 +25,5 @@ import breezy.plugins.github # For github support # noqa: F401 import breezy.plugins.debian # For apt: URL support # noqa: F401 -__version__ = (0, 4, 0) -version_string = '.'.join(map(str, __version__)) +__version__ = (0, 4, 1) +version_string = ".".join(map(str, __version__)) diff -Nru silver-platter-0.4.0/silver_platter/__main__.py silver-platter-0.4.1/silver_platter/__main__.py --- silver-platter-0.4.0/silver_platter/__main__.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/__main__.py 2021-02-17 22:45:01.000000000 +0000 @@ -16,67 +16,71 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import argparse -import silver_platter # noqa: F401 +import logging +import silver_platter # noqa: F401 import sys from typing import Optional, List, Callable, Dict from . import ( run, version_string, - ) - -from breezy.trace import show_error +) def hosters_main(argv: List[str]) -> Optional[int]: from breezy.propose import hosters - parser = argparse.ArgumentParser(prog='svp hosters') + + parser = argparse.ArgumentParser(prog="svp hosters") parser.parse_args(argv) for name, hoster_cls in hosters.items(): for instance in hoster_cls.iter_instances(): - print('%s (%s)' % (instance.base_url, name)) + print("%s (%s)" % (instance.base_url, name)) return None def login_main(argv: List[str]) -> Optional[int]: - parser = argparse.ArgumentParser(prog='svp login') - parser.add_argument('url', help='URL of branch to work on.', type=str) + parser = argparse.ArgumentParser(prog="svp login") + parser.add_argument("url", help="URL of branch to work on.", type=str) args = parser.parse_args(argv) from launchpadlib import uris as lp_uris hoster = None # TODO(jelmer): Don't special case various hosters here - if args.url.startswith('https://github.com'): - hoster = 'github' + if args.url.startswith("https://github.com"): + hoster = "github" for key, root in lp_uris.web_roots.items(): - if args.url.startswith(root) or args.url == root.rstrip('/'): - hoster = 'launchpad' + if args.url.startswith(root) or args.url == root.rstrip("/"): + hoster = "launchpad" lp_service_root = lp_uris.service_roots[key] if hoster is None: - hoster = 'gitlab' + hoster = "gitlab" - if hoster == 'gitlab': + if hoster == "gitlab": from breezy.plugins.gitlab.cmds import cmd_gitlab_login + cmd = cmd_gitlab_login() cmd._setup_outf() return cmd.run(args.url) - elif hoster == 'github': + elif hoster == "github": from breezy.plugins.github.cmds import cmd_github_login + cmd = cmd_github_login() cmd._setup_outf() return cmd.run() - elif hoster == 'launchpad': + elif hoster == "launchpad": from breezy.plugins.launchpad.cmds import cmd_launchpad_login + cmd = cmd_launchpad_login() cmd._setup_outf() cmd.run() from breezy.plugins.launchpad import lp_api - lp_api.connect_launchpad(lp_service_root, version='devel') + + lp_api.connect_launchpad(lp_service_root, version="devel") return None else: - show_error('Unknown hoster %r.', hoster) + logging.exception("Unknown hoster %r.", hoster) return 1 @@ -85,8 +89,12 @@ parser = argparse.ArgumentParser() parser.add_argument( - '--status', default='open', choices=['open', 'merged', 'closed'], - type=str, help='Only display proposals with this status.') + "--status", + default="open", + choices=["open", "merged", "closed"], + type=str, + help="Only display proposals with this status.", + ) args = parser.parse_args(argv) for hoster, proposal, status in iter_all_mps([args.status]): @@ -94,36 +102,38 @@ subcommands: Dict[str, Callable[[List[str]], Optional[int]]] = { - 'hosters': hosters_main, - 'login': login_main, - 'proposals': proposals_main, - 'run': run.main, - } + "hosters": hosters_main, + "login": login_main, + "proposals": proposals_main, + "run": run.main, +} def main(argv: Optional[List[str]] = None) -> Optional[int]: import breezy + breezy.initialize() - parser = argparse.ArgumentParser(prog='svp', add_help=False) + parser = argparse.ArgumentParser(prog="svp", add_help=False) parser.add_argument( - '--version', action='version', version='%(prog)s ' + version_string) - parser.add_argument( - '--help', action='store_true', - help='show this help message and exit') + "--version", action="version", version="%(prog)s " + version_string + ) parser.add_argument( - 'subcommand', type=str, choices=list(subcommands.keys())) + "--help", action="store_true", help="show this help message and exit" + ) + parser.add_argument("subcommand", type=str, choices=list(subcommands.keys())) + logging.basicConfig(level=logging.INFO) args, rest = parser.parse_known_args(argv) if args.help: if args.subcommand is None: parser.print_help() parser.exit() else: - rest.append('--help') + rest.append("--help") if args.subcommand is None: parser.print_usage() return 1 return subcommands[args.subcommand](rest) -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main()) diff -Nru silver-platter-0.4.0/silver_platter/proposal.py silver-platter-0.4.1/silver_platter/proposal.py --- silver-platter-0.4.0/silver_platter/proposal.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/proposal.py 2021-02-17 22:45:01.000000000 +0000 @@ -16,17 +16,20 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA from typing import ( - List, Optional, Tuple, Iterator, - ) + List, + Optional, + Tuple, + Iterator, +) from breezy.branch import Branch from breezy.errors import ( PermissionDenied, - ) +) from breezy.merge_directive import ( MergeDirective, MergeDirective2, - ) +) from breezy.transport import Transport from breezy.propose import ( get_hoster, @@ -36,18 +39,20 @@ NoSuchProject, UnsupportedHoster, HosterLoginRequired, - ) +) try: from breezy.propose import ( iter_hoster_instances, SourceNotDerivedFromTarget, - ) + ) except ImportError: # breezy < 3.1.1 + def iter_hoster_instances(): for name, hoster_cls in hosters.items(): for instance in hoster_cls.iter_instances(): yield instance + SourceNotDerivedFromTarget = None import breezy.plugins.gitlab # noqa: F401 @@ -58,7 +63,7 @@ from .utils import ( open_branch, full_branch_url, - ) +) from .publish import ( push_changes, push_derived_changes, @@ -68,67 +73,80 @@ DryRunProposal, find_existing_proposed, SUPPORTED_MODES, - ) +) from .workspace import ( Workspace, PublishResult, - ) +) __all__ = [ - 'HosterLoginRequired', - 'UnsupportedHoster', - 'PermissionDenied', - 'NoSuchProject', - 'get_hoster', - 'hosters', - 'iter_all_mps', - 'push_changes', - 'SUPPORTED_MODES', - 'push_derived_changes', - 'propose_changes', - 'PublishResult', - 'Workspace', - 'DryRunProposal', - 'check_proposal_diff', - 'EmptyMergeProposal', - 'find_existing_proposed', - ] + "HosterLoginRequired", + "UnsupportedHoster", + "PermissionDenied", + "NoSuchProject", + "get_hoster", + "hosters", + "iter_all_mps", + "push_changes", + "SUPPORTED_MODES", + "push_derived_changes", + "propose_changes", + "PublishResult", + "Workspace", + "DryRunProposal", + "check_proposal_diff", + "EmptyMergeProposal", + "find_existing_proposed", +] if SourceNotDerivedFromTarget is not None: - __all__.append('SourceNotDerivedFromTarget') + __all__.append("SourceNotDerivedFromTarget") def enable_tag_pushing(branch: Branch) -> None: stack = branch.get_config() - stack.set_user_option('branch.fetch_tags', True) + stack.set_user_option("branch.fetch_tags", True) def merge_directive_changes( - local_branch: Branch, main_branch: Branch, hoster: Hoster, name: str, - message: str, include_patch: bool = False, - include_bundle: bool = False, - overwrite_existing: bool = False) -> MergeDirective: + local_branch: Branch, + main_branch: Branch, + hoster: Hoster, + name: str, + message: str, + include_patch: bool = False, + include_bundle: bool = False, + overwrite_existing: bool = False, +) -> MergeDirective: from breezy import osutils import time + remote_branch, public_branch_url = hoster.publish_derived( - local_branch, main_branch, name=name, - overwrite=overwrite_existing) + local_branch, main_branch, name=name, overwrite=overwrite_existing + ) public_branch = open_branch(public_branch_url) directive = MergeDirective2.from_objects( - local_branch.repository, local_branch.last_revision(), time.time(), - osutils.local_time_offset(), main_branch, - public_branch=public_branch, include_patch=include_patch, - include_bundle=include_bundle, message=message, - base_revision_id=main_branch.last_revision()) + local_branch.repository, + local_branch.last_revision(), + time.time(), + osutils.local_time_offset(), + main_branch, + public_branch=public_branch, + include_patch=include_patch, + include_bundle=include_bundle, + message=message, + base_revision_id=main_branch.last_revision(), + ) return directive -def iter_all_mps(statuses: Optional[List[str]] = None - ) -> Iterator[Tuple[Hoster, MergeProposal, str]]: +def iter_all_mps( + statuses: Optional[List[str]] = None, +) -> Iterator[Tuple[Hoster, MergeProposal, str]]: """iterate over all existing merge proposals.""" if statuses is None: - statuses = ['open', 'merged', 'closed'] + statuses = ["open", "merged", "closed"] for instance in iter_hoster_instances(): for status in statuses: try: @@ -138,15 +156,16 @@ pass -def iter_conflicted(branch_name: str) -> Iterator[ - Tuple[str, Branch, str, Branch, Hoster, MergeProposal, bool]]: +def iter_conflicted( + branch_name: str, +) -> Iterator[Tuple[str, Branch, str, Branch, Hoster, MergeProposal, bool]]: """Find conflicted branches owned by the current user. Args: branch_name: Branch name to search for """ possible_transports: List[Transport] = [] - for hoster, mp, status in iter_all_mps(['open']): + for hoster, mp, status in iter_all_mps(["open"]): try: if mp.can_be_merged(): continue @@ -154,16 +173,23 @@ # TODO(jelmer): Check some other way that the branch is conflicted? continue main_branch = open_branch( - mp.get_target_branch_url(), - possible_transports=possible_transports) + mp.get_target_branch_url(), possible_transports=possible_transports + ) resume_branch = open_branch( - mp.get_source_branch_url(), - possible_transports=possible_transports) + mp.get_source_branch_url(), possible_transports=possible_transports + ) if resume_branch.name != branch_name and not ( - not resume_branch.name and - resume_branch.user_url.endswith(branch_name)): + not resume_branch.name and resume_branch.user_url.endswith(branch_name) + ): continue # TODO(jelmer): Find out somehow whether we need to modify a subpath? - subpath = '' - yield (full_branch_url(resume_branch), main_branch, subpath, - resume_branch, hoster, mp, True) + subpath = "" + yield ( + full_branch_url(resume_branch), + main_branch, + subpath, + resume_branch, + hoster, + mp, + True, + ) diff -Nru silver-platter-0.4.0/silver_platter/publish.py silver-platter-0.4.1/silver_platter/publish.py --- silver-platter-0.4.0/silver_platter/publish.py 2021-02-01 23:26:25.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/publish.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +import logging from typing import List, Union, Dict, Optional, Tuple, Any, Callable from breezy.branch import Branch @@ -22,7 +23,7 @@ errors, merge as _mod_merge, revision as _mod_revision, - ) +) from breezy.errors import PermissionDenied from breezy.propose import ( get_hoster, @@ -31,14 +32,13 @@ MergeProposalExists, NoSuchProject, UnsupportedHoster, - ) -from breezy.trace import note +) from breezy.transport import Transport try: from breezy.propose import ( SourceNotDerivedFromTarget, - ) + ) except ImportError: # breezy < 3.1.1 SourceNotDerivedFromTarget = None @@ -47,33 +47,33 @@ open_branch, MemoryBranch, full_branch_url, - ) +) __all__ = [ - 'push_changes', - 'push_derived_changes', - 'propose_changes', - 'EmptyMergeProposal', - 'check_proposal_diff', - 'DryRunProposal', - 'find_existing_proposed', - 'NoSuchProject', - 'PermissionDenied', - 'UnsupportedHoster', - ] - - -MODE_PUSH = 'push' -MODE_ATTEMPT_PUSH = 'attempt-push' -MODE_PROPOSE = 'propose' -MODE_PUSH_DERIVED = 'push-derived' + "push_changes", + "push_derived_changes", + "propose_changes", + "EmptyMergeProposal", + "check_proposal_diff", + "DryRunProposal", + "find_existing_proposed", + "NoSuchProject", + "PermissionDenied", + "UnsupportedHoster", +] + + +MODE_PUSH = "push" +MODE_ATTEMPT_PUSH = "attempt-push" +MODE_PROPOSE = "propose" +MODE_PUSH_DERIVED = "push-derived" SUPPORTED_MODES: List[str] = [ MODE_PUSH, MODE_ATTEMPT_PUSH, MODE_PROPOSE, MODE_PUSH_DERIVED, - ] +] def _tag_selector_from_tags(tags): @@ -82,81 +82,103 @@ def push_result( - local_branch: Branch, - remote_branch: Branch, - additional_colocated_branches: Optional[List[str]] = None, - tags: Optional[Union[Dict[str, bytes], List[str]]] = None, - stop_revision: Optional[bytes] = None - ) -> None: + local_branch: Branch, + remote_branch: Branch, + additional_colocated_branches: Optional[List[str]] = None, + tags: Optional[Union[Dict[str, bytes], List[str]]] = None, + stop_revision: Optional[bytes] = None, +) -> None: kwargs = {} if tags is not None: - kwargs['tag_selector'] = _tag_selector_from_tags(tags) + kwargs["tag_selector"] = _tag_selector_from_tags(tags) try: local_branch.push( - remote_branch, overwrite=False, - stop_revision=stop_revision, **kwargs) + remote_branch, overwrite=False, stop_revision=stop_revision, **kwargs + ) except errors.LockFailed as e: # Almost certainly actually a PermissionDenied error.. - raise errors.PermissionDenied( - path=full_branch_url(remote_branch), extra=e) + raise errors.PermissionDenied(path=full_branch_url(remote_branch), extra=e) for branch_name in additional_colocated_branches or []: try: add_branch = local_branch.controldir.open_branch(name=branch_name) except errors.NotBranchError: pass else: - remote_branch.controldir.push_branch( - add_branch, name=branch_name, **kwargs) + remote_branch.controldir.push_branch(add_branch, name=branch_name, **kwargs) -def push_changes(local_branch: Branch, main_branch: Branch, - hoster: Hoster, - possible_transports: Optional[List[Transport]] = None, - additional_colocated_branches: Optional[List[str]] = None, - dry_run: bool = False, - tags: Optional[Union[Dict[str, bytes], List[str]]] = None, - stop_revision: Optional[bytes] = None - ) -> None: +def push_changes( + local_branch: Branch, + main_branch: Branch, + hoster: Optional[Hoster], + possible_transports: Optional[List[Transport]] = None, + additional_colocated_branches: Optional[List[str]] = None, + dry_run: bool = False, + tags: Optional[Union[Dict[str, bytes], List[str]]] = None, + stop_revision: Optional[bytes] = None, +) -> None: """Push changes to a branch.""" - push_url = hoster.get_push_url(main_branch) - note('pushing to %s', push_url) - target_branch = open_branch( - push_url, possible_transports=possible_transports) + if hoster is None: + push_url = main_branch.user_url + else: + push_url = hoster.get_push_url(main_branch) + logging.info("pushing to %s", push_url) + target_branch = open_branch(push_url, possible_transports=possible_transports) if not dry_run: push_result( - local_branch, target_branch, additional_colocated_branches, - tags=tags, stop_revision=stop_revision) + local_branch, + target_branch, + additional_colocated_branches, + tags=tags, + stop_revision=stop_revision, + ) def push_derived_changes( - local_branch: Branch, main_branch: Branch, hoster: Hoster, name: str, - overwrite_existing: Optional[bool] = False, - owner: Optional[str] = None, - tags: Optional[Union[Dict[str, bytes], List[str]]] = None, - stop_revision: Optional[bytes] = None - ) -> Tuple[Branch, str]: + local_branch: Branch, + main_branch: Branch, + hoster: Hoster, + name: str, + overwrite_existing: Optional[bool] = False, + owner: Optional[str] = None, + tags: Optional[Union[Dict[str, bytes], List[str]]] = None, + stop_revision: Optional[bytes] = None, +) -> Tuple[Branch, str]: kwargs = {} if tags is not None: - kwargs['tag_selector'] = _tag_selector_from_tags(tags) + kwargs["tag_selector"] = _tag_selector_from_tags(tags) remote_branch, public_branch_url = hoster.publish_derived( - local_branch, main_branch, name=name, overwrite=overwrite_existing, - owner=owner, revision_id=stop_revision, **kwargs) + local_branch, + main_branch, + name=name, + overwrite=overwrite_existing, + owner=owner, + revision_id=stop_revision, + **kwargs + ) return remote_branch, public_branch_url -def propose_changes( - local_branch: Branch, main_branch: Branch, - hoster: Hoster, name: str, mp_description: str, - resume_branch: Optional[Branch] = None, - resume_proposal: Optional[MergeProposal] = None, - overwrite_existing: Optional[bool] = True, - labels: Optional[List[str]] = None, - dry_run: bool = False, commit_message: Optional[str] = None, - additional_colocated_branches: Optional[List[str]] = None, - allow_empty: bool = False, reviewers: Optional[List[str]] = None, - tags: Optional[Union[Dict[str, bytes], List[str]]] = None, - owner: Optional[str] = None, stop_revision: Optional[bytes] = None, - allow_collaboration: bool = False) -> Tuple[MergeProposal, bool]: +def propose_changes( # noqa: C901 + local_branch: Branch, + main_branch: Branch, + hoster: Hoster, + name: str, + mp_description: str, + resume_branch: Optional[Branch] = None, + resume_proposal: Optional[MergeProposal] = None, + overwrite_existing: Optional[bool] = True, + labels: Optional[List[str]] = None, + dry_run: bool = False, + commit_message: Optional[str] = None, + additional_colocated_branches: Optional[List[str]] = None, + allow_empty: bool = False, + reviewers: Optional[List[str]] = None, + tags: Optional[Union[Dict[str, bytes], List[str]]] = None, + owner: Optional[str] = None, + stop_revision: Optional[bytes] = None, + allow_collaboration: bool = False, +) -> Tuple[MergeProposal, bool]: """Create or update a merge proposal. Args: @@ -184,71 +206,94 @@ check_proposal_diff(local_branch, main_branch, stop_revision) push_kwargs = {} if tags is not None: - push_kwargs['tag_selector'] = _tag_selector_from_tags(tags) + push_kwargs["tag_selector"] = _tag_selector_from_tags(tags) if not dry_run: if resume_branch is not None: local_branch.push( - resume_branch, overwrite=overwrite_existing, + resume_branch, + overwrite=overwrite_existing, stop_revision=stop_revision, - **push_kwargs) + **push_kwargs + ) remote_branch = resume_branch else: remote_branch, public_branch_url = hoster.publish_derived( - local_branch, main_branch, name=name, + local_branch, + main_branch, + name=name, overwrite=overwrite_existing, revision_id=stop_revision, - owner=owner, **push_kwargs) - for colocated_branch_name in (additional_colocated_branches or []): + owner=owner, + **push_kwargs + ) + for colocated_branch_name in additional_colocated_branches or []: try: local_colo_branch = local_branch.controldir.open_branch( - name=colocated_branch_name) + name=colocated_branch_name + ) except errors.NotBranchError: pass else: remote_branch.controldir.push_branch( - source=local_colo_branch, overwrite=overwrite_existing, + source=local_colo_branch, + overwrite=overwrite_existing, name=colocated_branch_name, - **push_kwargs) + **push_kwargs + ) if resume_proposal is not None and dry_run: resume_proposal = DryRunProposal.from_existing( - resume_proposal, source_branch=local_branch) - if (resume_proposal is not None and - getattr(resume_proposal, 'is_closed', None) and - resume_proposal.is_closed()): + resume_proposal, source_branch=local_branch + ) + if ( + resume_proposal is not None + and getattr(resume_proposal, "is_closed", None) + and resume_proposal.is_closed() + ): from breezy.propose import ( ReopenFailed, - ) + ) + try: resume_proposal.reopen() except ReopenFailed: - note('Reopening existing proposal failed. Creating new proposal.') + logging.info( + "Reopening existing proposal failed. Creating new proposal.") resume_proposal = None if resume_proposal is None: if not dry_run: proposal_builder = hoster.get_proposer(remote_branch, main_branch) kwargs: Dict[str, Any] = {} - kwargs['commit_message'] = commit_message - kwargs['allow_collaboration'] = allow_collaboration + kwargs["commit_message"] = commit_message + kwargs["allow_collaboration"] = allow_collaboration try: mp = proposal_builder.create_proposal( - description=mp_description, labels=labels, - reviewers=reviewers, **kwargs) + description=mp_description, + labels=labels, + reviewers=reviewers, + **kwargs + ) except MergeProposalExists as e: - if getattr(e, 'existing_proposal', None) is None: + if getattr(e, "existing_proposal", None) is None: # Hoster didn't tell us where the actual proposal is. raise resume_proposal = e.existing_proposal except errors.PermissionDenied: - note('Permission denied while trying to create ' - 'proposal.') + logging.info( + "Permission denied while trying to create " "proposal.") raise else: return (mp, True) else: mp = DryRunProposal( - local_branch, main_branch, labels=labels, - description=mp_description, commit_message=commit_message, - reviewers=reviewers, owner=owner, stop_revision=stop_revision) + local_branch, + main_branch, + labels=labels, + description=mp_description, + commit_message=commit_message, + reviewers=reviewers, + owner=owner, + stop_revision=stop_revision, + ) return (mp, True) # Check that the proposal doesn't already has this description. # Setting the description (regardless of whether it changes) @@ -272,8 +317,8 @@ def check_proposal_diff( - other_branch: Branch, main_branch: Branch, - stop_revision: Optional[bytes] = None) -> None: + other_branch: Branch, main_branch: Branch, stop_revision: Optional[bytes] = None +) -> None: if stop_revision is None: stop_revision = other_branch.last_revision() main_revid = main_branch.last_revision() @@ -281,11 +326,10 @@ with other_branch.lock_read(): main_tree = other_branch.repository.revision_tree(main_revid) revision_graph = other_branch.repository.get_graph() - tree_branch = MemoryBranch( - other_branch.repository, (None, main_revid), None) + tree_branch = MemoryBranch(other_branch.repository, (None, main_revid), None) merger = _mod_merge.Merger( - tree_branch, this_tree=main_tree, - revision_graph=revision_graph) + tree_branch, this_tree=main_tree, revision_graph=revision_graph + ) merger.set_other_revision(stop_revision, other_branch) try: merger.find_base() @@ -305,16 +349,20 @@ :ivar url: URL for the merge proposal """ - def __init__(self, source_branch: Branch, target_branch: Branch, - labels: Optional[List[str]] = None, - description: Optional[str] = None, - commit_message: Optional[str] = None, - reviewers: Optional[List[str]] = None, - owner: Optional[str] = None, - stop_revision: Optional[bytes] = None): + def __init__( + self, + source_branch: Branch, + target_branch: Branch, + labels: Optional[List[str]] = None, + description: Optional[str] = None, + commit_message: Optional[str] = None, + reviewers: Optional[List[str]] = None, + owner: Optional[str] = None, + stop_revision: Optional[bytes] = None, + ): self.description = description self.closed = False - self.labels = (labels or []) + self.labels = labels or [] self.source_branch = source_branch self.target_branch = target_branch self.commit_message = commit_message @@ -324,8 +372,9 @@ self.stop_revision = stop_revision @classmethod - def from_existing(cls, mp: MergeProposal, - source_branch: Optional[Branch] = None) -> MergeProposal: + def from_existing( + cls, mp: MergeProposal, source_branch: Optional[Branch] = None + ) -> MergeProposal: if source_branch is None: source_branch = open_branch(mp.get_source_branch_url()) commit_message = mp.get_commit_message() @@ -333,11 +382,15 @@ source_branch=source_branch, target_branch=open_branch(mp.get_target_branch_url()), description=mp.get_description(), - commit_message=commit_message) + commit_message=commit_message, + ) def __repr__(self) -> str: return "%s(%r, %r)" % ( - self.__class__.__name__, self.source_branch, self.target_branch) + self.__class__.__name__, + self.source_branch, + self.target_branch, + ) def get_description(self) -> Optional[str]: """Get the description of the merge proposal.""" @@ -376,11 +429,13 @@ pass -def find_existing_proposed(main_branch: Branch, hoster: Hoster, name: str, - overwrite_unrelated: bool = False, - owner: Optional[str] = None - ) -> Tuple[ - Optional[Branch], Optional[bool], Optional[MergeProposal]]: +def find_existing_proposed( + main_branch: Branch, + hoster: Hoster, + name: str, + overwrite_unrelated: bool = False, + owner: Optional[str] = None, +) -> Tuple[Optional[Branch], Optional[bool], Optional[MergeProposal]]: """Find an existing derived branch with the specified name, and proposal. Args: @@ -395,25 +450,28 @@ means there is an existing branch in place that should be overwritten. """ try: - existing_branch = hoster.get_derived_branch( - main_branch, name=name, owner=owner) + existing_branch = hoster.get_derived_branch(main_branch, name=name, owner=owner) except errors.NotBranchError: return (None, None, None) else: - note('Branch %s already exists (branch at %s)', name, - full_branch_url(existing_branch)) + logging.info( + "Branch %s already exists (branch at %s)", + name, + full_branch_url(existing_branch), + ) # If there is an open or rejected merge proposal, resume that. merged_proposal = None - for mp in hoster.iter_proposals( - existing_branch, main_branch, status='all'): + for mp in hoster.iter_proposals(existing_branch, main_branch, status="all"): if not mp.is_closed() and not mp.is_merged(): return (existing_branch, False, mp) else: merged_proposal = mp else: if merged_proposal is not None: - note('There is a proposal that has already been merged at %s.', - merged_proposal.url) + logging.info( + "There is a proposal that has already been merged at %s.", + merged_proposal.url, + ) return (None, True, None) else: # No related merge proposals found, but there is an existing @@ -426,8 +484,8 @@ def merge_conflicts( - main_branch: Branch, other_branch: Branch, - other_revision: Optional[bytes] = None) -> bool: + main_branch: Branch, other_branch: Branch, other_revision: Optional[bytes] = None +) -> bool: """Check whether two branches are conflicted when merged. Args: @@ -441,24 +499,28 @@ if other_revision is None: other_revision = other_branch.last_revision() if other_branch.repository.get_graph().is_ancestor( - main_branch.last_revision(), other_revision): + main_branch.last_revision(), other_revision + ): return False other_branch.repository.fetch( - main_branch.repository, - revision_id=main_branch.last_revision()) + main_branch.repository, revision_id=main_branch.last_revision() + ) # Reset custom merge hooks, since they could make it harder to detect # conflicted merges that would appear on the hosting site. - old_file_content_mergers = _mod_merge.Merger.hooks['merge_file_content'] - _mod_merge.Merger.hooks['merge_file_content'] = [] + old_file_content_mergers = _mod_merge.Merger.hooks["merge_file_content"] + _mod_merge.Merger.hooks["merge_file_content"] = [] other_tree = other_branch.repository.revision_tree(other_revision) try: try: merger = _mod_merge.Merger.from_revision_ids( - other_tree, other_branch=other_branch, - other=main_branch.last_revision(), tree_branch=other_branch) + other_tree, + other_branch=other_branch, + other=main_branch.last_revision(), + tree_branch=other_branch, + ) except errors.UnrelatedBranches: # Unrelated branches don't technically *have* to lead to # conflicts, but there's not a lot to be salvaged here, either. @@ -468,16 +530,15 @@ with tree_merger.make_preview_transform(): return bool(tree_merger.cooked_conflicts) finally: - _mod_merge.Merger.hooks['merge_file_content'] = ( - old_file_content_mergers) + _mod_merge.Merger.hooks["merge_file_content"] = old_file_content_mergers class PublishResult(object): """A object describing the result of a publish action.""" - def __init__(self, mode: str, - proposal: Optional[MergeProposal] = None, - is_new: bool = False) -> None: + def __init__( + self, mode: str, proposal: Optional[MergeProposal] = None, is_new: bool = False + ) -> None: self.mode = mode self.proposal = proposal self.is_new = is_new @@ -488,25 +549,27 @@ def publish_changes( - local_branch: Branch, - main_branch: Branch, - resume_branch: Optional[Branch], - mode: str, name: str, - get_proposal_description: Callable[ - [str, Optional[MergeProposal]], str], - get_proposal_commit_message: Callable[ - [Optional[MergeProposal]], Optional[str]] = None, - dry_run: bool = False, - hoster: Optional[Hoster] = None, - allow_create_proposal: bool = True, - labels: Optional[List[str]] = None, - overwrite_existing: Optional[bool] = True, - existing_proposal: Optional[MergeProposal] = None, - reviewers: Optional[List[str]] = None, - tags: Optional[Union[List[str], Dict[str, bytes]]] = None, - derived_owner: Optional[str] = None, - allow_collaboration: bool = False, - stop_revision: Optional[bytes] = None) -> PublishResult: + local_branch: Branch, + main_branch: Branch, + resume_branch: Optional[Branch], + mode: str, + name: str, + get_proposal_description: Callable[[str, Optional[MergeProposal]], str], + get_proposal_commit_message: Callable[ + [Optional[MergeProposal]], Optional[str] + ] = None, + dry_run: bool = False, + hoster: Optional[Hoster] = None, + allow_create_proposal: bool = True, + labels: Optional[List[str]] = None, + overwrite_existing: Optional[bool] = True, + existing_proposal: Optional[MergeProposal] = None, + reviewers: Optional[List[str]] = None, + tags: Optional[Union[List[str], Dict[str, bytes]]] = None, + derived_owner: Optional[str] = None, + allow_collaboration: bool = False, + stop_revision: Optional[bytes] = None, +) -> PublishResult: """Publish a set of changes. Args: @@ -535,7 +598,7 @@ if stop_revision == main_branch.last_revision(): if existing_proposal is not None: - note('closing existing merge proposal - no new revisions') + logging.info("closing existing merge proposal - no new revisions") existing_proposal.close() return PublishResult(mode) @@ -543,16 +606,22 @@ # No new revisions added on this iteration, but changes since main # branch. We may not have gotten round to updating/creating the # merge proposal last time. - note('No changes added; making sure merge proposal is up to date.') + logging.info("No changes added; making sure merge proposal is up to date.") if hoster is None: hoster = get_hoster(main_branch) if mode == MODE_PUSH_DERIVED: (remote_branch, public_url) = push_derived_changes( - local_branch, main_branch, hoster=hoster, name=name, - overwrite_existing=overwrite_existing, tags=tags, - owner=derived_owner, stop_revision=stop_revision) + local_branch, + main_branch, + hoster=hoster, + name=name, + overwrite_existing=overwrite_existing, + tags=tags, + owner=derived_owner, + stop_revision=stop_revision, + ) return PublishResult(mode) if mode in (MODE_PUSH, MODE_ATTEMPT_PUSH): @@ -560,43 +629,55 @@ # breezy would do this check too, but we want to be *really* sure. with local_branch.lock_read(): graph = local_branch.repository.get_graph() - if not graph.is_ancestor( - main_branch.last_revision(), - stop_revision): + if not graph.is_ancestor(main_branch.last_revision(), stop_revision): raise errors.DivergedBranches(main_branch, local_branch) push_changes( - local_branch, main_branch, hoster=hoster, - dry_run=dry_run, tags=tags, stop_revision=stop_revision) + local_branch, + main_branch, + hoster=hoster, + dry_run=dry_run, + tags=tags, + stop_revision=stop_revision, + ) except errors.PermissionDenied: if mode == MODE_ATTEMPT_PUSH: - note('push access denied, falling back to propose') + logging.info("push access denied, falling back to propose") mode = MODE_PROPOSE else: - note('permission denied during push') + logging.info("permission denied during push") raise else: return PublishResult(mode=mode) - assert mode == 'propose' + assert mode == "propose" if not resume_branch and not allow_create_proposal: # TODO(jelmer): Raise an exception of some sort here? return PublishResult(mode) mp_description = get_proposal_description( - getattr(hoster, 'merge_proposal_description_format', 'plain'), - existing_proposal if resume_branch else None) + getattr(hoster, "merge_proposal_description_format", "plain"), + existing_proposal if resume_branch else None, + ) if get_proposal_commit_message is not None: commit_message = get_proposal_commit_message( - existing_proposal if resume_branch else None) + existing_proposal if resume_branch else None + ) (proposal, is_new) = propose_changes( - local_branch, main_branch, - hoster=hoster, name=name, mp_description=mp_description, - resume_branch=resume_branch, - resume_proposal=existing_proposal, - overwrite_existing=overwrite_existing, - labels=labels, dry_run=dry_run, - commit_message=commit_message, - reviewers=reviewers, tags=tags, owner=derived_owner, - allow_collaboration=allow_collaboration, - stop_revision=stop_revision) + local_branch, + main_branch, + hoster=hoster, + name=name, + mp_description=mp_description, + resume_branch=resume_branch, + resume_proposal=existing_proposal, + overwrite_existing=overwrite_existing, + labels=labels, + dry_run=dry_run, + commit_message=commit_message, + reviewers=reviewers, + tags=tags, + owner=derived_owner, + allow_collaboration=allow_collaboration, + stop_revision=stop_revision, + ) return PublishResult(mode, proposal, is_new) diff -Nru silver-platter-0.4.0/silver_platter/run.py silver-platter-0.4.1/silver_platter/run.py --- silver-platter-0.4.0/silver_platter/run.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/run.py 2021-02-17 22:45:01.000000000 +0000 @@ -18,6 +18,7 @@ """Automatic proposal/push creation.""" import argparse +import logging import os import subprocess import sys @@ -28,7 +29,6 @@ from breezy import osutils from breezy import errors from breezy.commit import PointlessCommit -from breezy.trace import note, warning, show_error from breezy.workingtree import WorkingTree from breezy import propose as _mod_propose from .proposal import ( @@ -36,13 +36,13 @@ enable_tag_pushing, find_existing_proposed, get_hoster, - ) +) from .workspace import ( Workspace, - ) +) from .publish import ( SUPPORTED_MODES, - ) +) from .utils import ( open_branch, BranchMissing, @@ -57,9 +57,9 @@ _fmt = "Script made no changes." -def script_runner(local_tree: WorkingTree, - script: str, - commit_pending: Optional[bool] = None) -> str: +def script_runner( + local_tree: WorkingTree, script: str, commit_pending: Optional[bool] = None +) -> str: """Run a script in a tree and commit the result. This ignores newly added files. @@ -72,13 +72,14 @@ :return: Description as reported by script """ last_revision = local_tree.last_revision() - p = subprocess.Popen(script, cwd=local_tree.basedir, - stdout=subprocess.PIPE, shell=True) + p = subprocess.Popen( + script, cwd=local_tree.basedir, stdout=subprocess.PIPE, shell=True + ) (description_encoded, err) = p.communicate(b"") if p.returncode != 0: raise errors.BzrCommandError( - "Script %s failed with error code %d" % ( - script, p.returncode)) + "Script %s failed with error code %d" % (script, p.returncode) + ) new_revision = local_tree.last_revision() description = description_encoded.decode() if last_revision == new_revision and commit_pending is None: @@ -87,8 +88,7 @@ commit_pending = True if commit_pending: try: - new_revision = local_tree.commit( - description, allow_pointless=False) + new_revision = local_tree.commit(description, allow_pointless=False) except PointlessCommit: pass if new_revision == last_revision: @@ -97,78 +97,91 @@ def derived_branch_name(script: str) -> str: - return os.path.splitext(osutils.basename(script.split(' ')[0]))[0] + return os.path.splitext(osutils.basename(script.split(" ")[0]))[0] -def main(argv: List[str]) -> Optional[int]: +def main(argv: List[str]) -> Optional[int]: # noqa: C901 parser = argparse.ArgumentParser() - parser.add_argument('script', help='Path to script to run.', type=str) - parser.add_argument('url', help='URL of branch to work on.', type=str) - parser.add_argument('--derived-owner', type=str, default=None, - help='Owner for derived branches.') - parser.add_argument('--refresh', action="store_true", - help='Refresh changes if branch already exists') - parser.add_argument('--label', type=str, - help='Label to attach', action="append", default=[]) - parser.add_argument('--name', type=str, - help='Proposed branch name', default=None) - parser.add_argument('--diff', action="store_true", - help="Show diff of generated changes.") - parser.add_argument( - '--mode', - help='Mode for pushing', choices=SUPPORTED_MODES, - default="propose", type=str) - parser.add_argument( - '--commit-pending', - help='Commit pending changes after script.', - choices=['yes', 'no', 'auto'], - default='auto', type=str) + parser.add_argument("script", help="Path to script to run.", type=str) + parser.add_argument("url", help="URL of branch to work on.", type=str) + parser.add_argument( + "--derived-owner", type=str, default=None, help="Owner for derived branches." + ) + parser.add_argument( + "--refresh", + action="store_true", + help="Refresh changes if branch already exists", + ) + parser.add_argument( + "--label", type=str, help="Label to attach", action="append", default=[] + ) + parser.add_argument("--name", type=str, help="Proposed branch name", default=None) + parser.add_argument( + "--diff", action="store_true", help="Show diff of generated changes." + ) + parser.add_argument( + "--mode", + help="Mode for pushing", + choices=SUPPORTED_MODES, + default="propose", + type=str, + ) + parser.add_argument( + "--commit-pending", + help="Commit pending changes after script.", + choices=["yes", "no", "auto"], + default="auto", + type=str, + ) parser.add_argument( "--dry-run", help="Create branches but don't push or propose anything.", - action="store_true", default=False) + action="store_true", + default=False, + ) args = parser.parse_args(argv) try: main_branch = open_branch(args.url) except (BranchUnavailable, BranchMissing, BranchUnsupported) as e: - show_error('%s: %s', args.url, e) + logging.exception("%s: %s", args.url, e) return 1 if args.name is None: name = derived_branch_name(args.script) else: name = args.name - commit_pending = {'auto': None, 'yes': True, 'no': False}[ - args.commit_pending] + commit_pending = {"auto": None, "yes": True, "no": False}[args.commit_pending] overwrite = False try: hoster = get_hoster(main_branch) except UnsupportedHoster as e: - if args.mode != 'push': + if args.mode != "push": raise # We can't figure out what branch to resume from when there's no hoster # that can tell us. resume_branch = None existing_proposal = None - warning('Unsupported hoster (%s), will attempt to push to %s', - e, full_branch_url(main_branch)) + logging.warn( + "Unsupported hoster (%s), will attempt to push to %s", + e, + full_branch_url(main_branch), + ) else: - (resume_branch, resume_overwrite, existing_proposal) = ( - find_existing_proposed( - main_branch, hoster, name, owner=args.derived_owner)) + (resume_branch, resume_overwrite, existing_proposal) = find_existing_proposed( + main_branch, hoster, name, owner=args.derived_owner + ) if resume_overwrite is not None: overwrite = resume_overwrite if args.refresh: resume_branch = None with Workspace(main_branch, resume_branch=resume_branch) as ws: try: - description = script_runner( - ws.local_tree, args.script, commit_pending) + description = script_runner(ws.local_tree, args.script, commit_pending) except ScriptMadeNoChanges: - show_error('Script did not make any changes.') + logging.exception("Script did not make any changes.") return 1 def get_description(description_format, existing_proposal): @@ -182,30 +195,37 @@ try: publish_result = ws.publish_changes( - args.mode, name, + args.mode, + name, get_proposal_description=get_description, - dry_run=args.dry_run, hoster=hoster, - labels=args.label, overwrite_existing=overwrite, + dry_run=args.dry_run, + hoster=hoster, + labels=args.label, + overwrite_existing=overwrite, derived_owner=args.derived_owner, - existing_proposal=existing_proposal) + existing_proposal=existing_proposal, + ) except UnsupportedHoster as e: - show_error('No known supported hoster for %s. Run \'svp login\'?', - full_branch_url(e.branch)) + logging.exception( + "No known supported hoster for %s. Run 'svp login'?", + full_branch_url(e.branch), + ) return 1 except _mod_propose.HosterLoginRequired as e: - show_error( - 'Credentials for hosting site at %r missing. ' - 'Run \'svp login\'?', e.hoster.base_url) + logging.exception( + "Credentials for hosting site at %r missing. " "Run 'svp login'?", + e.hoster.base_url, + ) return 1 if publish_result.proposal: if publish_result.is_new: - note('Merge proposal created.') + logging.info("Merge proposal created.") else: - note('Merge proposal updated.') + logging.info("Merge proposal updated.") if publish_result.proposal.url: - note('URL: %s', publish_result.proposal.url) - note('Description: %s', publish_result.proposal.get_description()) + logging.info("URL: %s", publish_result.proposal.url) + logging.info("Description: %s", publish_result.proposal.get_description()) if args.diff: ws.show_diff(sys.stdout.buffer) @@ -213,5 +233,5 @@ return None -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main(sys.argv)) diff -Nru silver-platter-0.4.0/silver_platter/tests/__init__.py silver-platter-0.4.1/silver_platter/tests/__init__.py --- silver-platter-0.4.0/silver_platter/tests/__init__.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/__init__.py 2021-02-17 22:45:01.000000000 +0000 @@ -20,15 +20,15 @@ def test_suite(): names = [ - 'debian', - 'debian_lintian', - 'debian_upstream', - 'proposal', - 'publish', - 'run', - 'utils', - 'version', - ] - module_names = [__name__ + '.test_' + name for name in names] + "debian", + "debian_lintian", + "debian_upstream", + "proposal", + "publish", + "run", + "utils", + "version", + ] + module_names = [__name__ + ".test_" + name for name in names] loader = unittest.TestLoader() return loader.loadTestsFromNames(module_names) diff -Nru silver-platter-0.4.0/silver_platter/tests/test_debian_lintian.py silver-platter-0.4.1/silver_platter/tests/test_debian_lintian.py --- silver-platter-0.4.0/silver_platter/tests/test_debian_lintian.py 2020-04-17 23:42:53.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/test_debian_lintian.py 2021-02-17 22:45:01.000000000 +0000 @@ -22,54 +22,55 @@ create_mp_description, get_fixers, UnknownFixer, - ) +) class ParseMPDescriptionTests(unittest.TestCase): - def test_single_line(self): - self.assertEqual(['some change'], parse_mp_description('some change')) + self.assertEqual(["some change"], parse_mp_description("some change")) def test_multiple_lines(self): self.assertEqual( - ['some change', 'some other change'], - parse_mp_description("""Lintian fixes: + ["some change", "some other change"], + parse_mp_description( + """Lintian fixes: * some change * some other change -""")) +""" + ), + ) class CreateMPDescription(unittest.TestCase): - def test_single_line(self): - self.assertEqual( - "some change", create_mp_description('plain', ['some change'])) + self.assertEqual("some change", create_mp_description("plain", ["some change"])) def test_multiple_lines(self): - self.assertEqual("""\ + self.assertEqual( + """\ Fix some issues reported by lintian * some change * some other change -""", create_mp_description('plain', ['some change', 'some other change'])) +""", + create_mp_description("plain", ["some change", "some other change"]), + ) class GetFixersTests(unittest.TestCase): - def setUp(self): super(GetFixersTests, self).setUp() from lintian_brush import Fixer - self.fixers = [Fixer('foo', ['atag'])] + + self.fixers = [Fixer("foo", ["atag"])] def test_get_all(self): self.assertEqual([self.fixers[0]], list(get_fixers(self.fixers))) def test_get_specified(self): - self.assertEqual( - [self.fixers[0]], list(get_fixers(self.fixers, names=['foo']))) + self.assertEqual([self.fixers[0]], list(get_fixers(self.fixers, names=["foo"]))) def test_get_specified_tag(self): - self.assertEqual( - [self.fixers[0]], list(get_fixers(self.fixers, tags=['atag']))) + self.assertEqual([self.fixers[0]], list(get_fixers(self.fixers, tags=["atag"]))) def test_get_unknown(self): - self.assertRaises(UnknownFixer, get_fixers, self.fixers, names=['bar']) + self.assertRaises(UnknownFixer, get_fixers, self.fixers, names=["bar"]) diff -Nru silver-platter-0.4.0/silver_platter/tests/test_debian.py silver-platter-0.4.1/silver_platter/tests/test_debian.py --- silver-platter-0.4.0/silver_platter/tests/test_debian.py 2020-09-27 11:49:17.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/test_debian.py 2021-02-17 22:45:01.000000000 +0000 @@ -19,7 +19,7 @@ from breezy.tests import ( TestCase, - ) +) from breezy.bzr import RemoteBzrProber @@ -29,37 +29,35 @@ select_probers, convert_debian_vcs_url, UnsupportedVCSProber, - ) +) class SelectProbersTests(TestCase): - def test_none(self): self.assertIs(None, select_probers()) self.assertIs(None, select_probers(None)) def test_bzr(self): - self.assertEqual([RemoteBzrProber], select_probers('bzr')) + self.assertEqual([RemoteBzrProber], select_probers("bzr")) def test_git(self): - self.assertEqual([RemoteGitProber], select_probers('git')) + self.assertEqual([RemoteGitProber], select_probers("git")) def test_unsupported(self): - self.assertEqual([UnsupportedVCSProber('foo')], select_probers('foo')) + self.assertEqual([UnsupportedVCSProber("foo")], select_probers("foo")) class ConvertDebianVcsUrlTests(TestCase): - def test_git(self): self.assertEqual( - 'https://salsa.debian.org/jelmer/blah.git', - convert_debian_vcs_url( - 'Git', 'https://salsa.debian.org/jelmer/blah.git')) + "https://salsa.debian.org/jelmer/blah.git", + convert_debian_vcs_url("Git", "https://salsa.debian.org/jelmer/blah.git"), + ) def test_git_ssh(self): if breezy.version_info < (3, 1, 1): - self.knownFailure('breezy < 3.1.1 can not deal with ssh:// URLs') + self.knownFailure("breezy < 3.1.1 can not deal with ssh:// URLs") self.assertEqual( - 'ssh://git@git.kali.org/jelmer/blah.git', - convert_debian_vcs_url( - 'Git', 'ssh://git@git.kali.org/jelmer/blah.git')) + "ssh://git@git.kali.org/jelmer/blah.git", + convert_debian_vcs_url("Git", "ssh://git@git.kali.org/jelmer/blah.git"), + ) diff -Nru silver-platter-0.4.0/silver_platter/tests/test_debian_upstream.py silver-platter-0.4.1/silver_platter/tests/test_debian_upstream.py --- silver-platter-0.4.0/silver_platter/tests/test_debian_upstream.py 2020-04-17 23:42:53.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/test_debian_upstream.py 2021-02-17 22:45:01.000000000 +0000 @@ -20,51 +20,66 @@ from ..debian.upstream import ( update_packaging, - ) +) class UpdatePackagingTests(TestCaseWithTransport): - def test_autogen_sh(self): - t = self.make_branch_and_tree('.') - self.build_tree_contents([ - ('debian/', ), - ('debian/changelog', """\ + t = self.make_branch_and_tree(".") + self.build_tree_contents( + [ + ("debian/",), + ( + "debian/changelog", + """\ lintian-brush (0.37) UNRELEASED; urgency=medium * Add various more aliases for salsa team names. -- Jelmer Vernooij Fri, 18 Oct 2019 17:34:35 +0000 -"""), - ('debian/rules', """\ +""", + ), + ( + "debian/rules", + """\ %: \tdh % -""")]) - t.add(['debian', 'debian/changelog', 'debian/rules']) - oldrev = t.commit('Initial') - - self.build_tree_contents([ - ('autogen.sh', '#!/bin/sh\n')]) - t.add(['autogen.sh']) - t.commit('Add autogen') +""", + ), + ] + ) + t.add(["debian", "debian/changelog", "debian/rules"]) + oldrev = t.commit("Initial") + + self.build_tree_contents([("autogen.sh", "#!/bin/sh\n")]) + t.add(["autogen.sh"]) + t.commit("Add autogen") self.addCleanup(t.lock_write().unlock) update_packaging( - t, t.branch.repository.revision_tree(oldrev), - committer="Jelmer Vernooij ") + t, + t.branch.repository.revision_tree(oldrev), + committer="Jelmer Vernooij ", + ) - self.assertFileEqual("""\ + self.assertFileEqual( + """\ lintian-brush (0.37) UNRELEASED; urgency=medium * Add various more aliases for salsa team names. * Invoke autogen.sh from dh_autoreconf. -- Jelmer Vernooij Fri, 18 Oct 2019 17:34:35 +0000 -""", 'debian/changelog') - self.assertFileEqual("""\ +""", + "debian/changelog", + ) + self.assertFileEqual( + """\ %: \tdh % override_dh_autoreconf: \tdh_autoreconf ./autogen.sh -""", 'debian/rules') +""", + "debian/rules", + ) diff -Nru silver-platter-0.4.0/silver_platter/tests/test_proposal.py silver-platter-0.4.1/silver_platter/tests/test_proposal.py --- silver-platter-0.4.0/silver_platter/tests/test_proposal.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/test_proposal.py 2021-02-17 22:45:01.000000000 +0000 @@ -22,76 +22,73 @@ from ..workspace import ( Workspace, - ) +) class WorkspaceTests(TestCaseWithTransport): - def test_simple(self): - b = self.make_branch('target') + b = self.make_branch("target") with Workspace(b, dir=self.test_dir) as ws: self.assertIs(ws.resume_branch, None) self.assertFalse(ws.changes_since_main()) self.assertFalse(ws.changes_since_resume()) - ws.local_tree.commit('foo') + ws.local_tree.commit("foo") self.assertTrue(ws.changes_since_main()) self.assertTrue(ws.changes_since_main()) def test_with_resume(self): - b = self.make_branch_and_tree('target') - c = b.controldir.sprout('resume').open_workingtree() - c.commit('some change') - with Workspace(b.branch, resume_branch=c.branch, - dir=self.test_dir) as ws: + b = self.make_branch_and_tree("target") + c = b.controldir.sprout("resume").open_workingtree() + c.commit("some change") + with Workspace(b.branch, resume_branch=c.branch, dir=self.test_dir) as ws: self.assertEqual( - ws.local_tree.branch.last_revision(), - c.branch.last_revision()) + ws.local_tree.branch.last_revision(), c.branch.last_revision() + ) self.assertIs(ws.resume_branch, c.branch) self.assertTrue(ws.changes_since_main()) self.assertFalse(ws.changes_since_resume()) - ws.local_tree.commit('foo') + ws.local_tree.commit("foo") self.assertTrue(ws.changes_since_main()) self.assertTrue(ws.changes_since_resume()) def test_with_resume_conflicting(self): - b = self.make_branch_and_tree('target') - self.build_tree_contents([('target/foo', 'somecontents\n')]) - b.add(['foo']) - b.commit('initial') - c = b.controldir.sprout('resume').open_workingtree() - self.build_tree_contents([('target/foo', 'new contents in main\n')]) - b.commit('add conflict in main') - self.build_tree_contents([('resume/foo', 'new contents in resume\n')]) - c.commit('add conflict in resume') - with Workspace(b.branch, resume_branch=c.branch, - dir=self.test_dir) as ws: + b = self.make_branch_and_tree("target") + self.build_tree_contents([("target/foo", "somecontents\n")]) + b.add(["foo"]) + b.commit("initial") + c = b.controldir.sprout("resume").open_workingtree() + self.build_tree_contents([("target/foo", "new contents in main\n")]) + b.commit("add conflict in main") + self.build_tree_contents([("resume/foo", "new contents in resume\n")]) + c.commit("add conflict in resume") + with Workspace(b.branch, resume_branch=c.branch, dir=self.test_dir) as ws: self.assertIs(ws.resume_branch, None) self.assertEqual( - b.branch.last_revision(), ws.local_tree.branch.last_revision()) + b.branch.last_revision(), ws.local_tree.branch.last_revision() + ) self.assertFalse(ws.changes_since_main()) self.assertFalse(ws.changes_since_resume()) - ws.local_tree.commit('foo') + ws.local_tree.commit("foo") self.assertTrue(ws.changes_since_main()) self.assertTrue(ws.changes_since_resume()) def test_orig_tree(self): - b = self.make_branch_and_tree('target') - cid = b.commit('some change') + b = self.make_branch_and_tree("target") + cid = b.commit("some change") with Workspace(b.branch, dir=self.test_dir) as ws: - ws.local_tree.commit('blah') + ws.local_tree.commit("blah") self.assertEqual(cid, ws.orig_tree().get_revision_id()) def test_show_diff(self): - b = self.make_branch_and_tree('target') + b = self.make_branch_and_tree("target") with Workspace(b.branch, dir=self.test_dir) as ws: - self.build_tree_contents([ - (os.path.join(ws.local_tree.basedir, 'foo'), - 'some content\n')]) - ws.local_tree.add(['foo']) - ws.local_tree.commit('blah') + self.build_tree_contents( + [(os.path.join(ws.local_tree.basedir, "foo"), "some content\n")] + ) + ws.local_tree.add(["foo"]) + ws.local_tree.commit("blah") self.assertTrue(ws.changes_since_main()) self.assertTrue(ws.changes_since_resume()) f = BytesIO() ws.show_diff(outf=f) - self.assertContainsRe( - f.getvalue().decode('utf-8'), '\\+some content') + self.assertContainsRe(f.getvalue().decode("utf-8"), "\\+some content") diff -Nru silver-platter-0.4.0/silver_platter/tests/test_publish.py silver-platter-0.4.1/silver_platter/tests/test_publish.py --- silver-platter-0.4.0/silver_platter/tests/test_publish.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/test_publish.py 2021-02-17 22:45:01.000000000 +0000 @@ -21,80 +21,79 @@ EmptyMergeProposal, check_proposal_diff, push_result, - ) +) class PushResultTests(TestCaseWithTransport): - def test_simple(self): - target = self.make_branch('target') - source = self.make_branch_and_tree('source') - revid = source.commit('Some change') + target = self.make_branch("target") + source = self.make_branch_and_tree("source") + revid = source.commit("Some change") push_result(source.branch, target) self.assertEqual(target.last_revision(), revid) class CheckProposalDiffBase(object): - def test_no_new_commits(self): - orig = self.make_branch_and_tree('orig', format=self.format) - self.build_tree(['orig/a']) - orig.add(['a']) - orig.commit('blah') + orig = self.make_branch_and_tree("orig", format=self.format) + self.build_tree(["orig/a"]) + orig.add(["a"]) + orig.commit("blah") - proposal = orig.controldir.sprout('proposal').open_branch() + proposal = orig.controldir.sprout("proposal").open_branch() self.addCleanup(proposal.lock_write().unlock) self.assertRaises( - EmptyMergeProposal, check_proposal_diff, proposal, orig.branch) + EmptyMergeProposal, check_proposal_diff, proposal, orig.branch + ) def test_no_op_commits(self): - orig = self.make_branch_and_tree('orig', format=self.format) - self.build_tree(['orig/a']) - orig.add(['a']) - orig.commit('blah') + orig = self.make_branch_and_tree("orig", format=self.format) + self.build_tree(["orig/a"]) + orig.add(["a"]) + orig.commit("blah") - proposal = orig.controldir.sprout('proposal').open_workingtree() - proposal.commit('another commit that is pointless') + proposal = orig.controldir.sprout("proposal").open_workingtree() + proposal.commit("another commit that is pointless") self.addCleanup(proposal.lock_write().unlock) self.assertRaises( - EmptyMergeProposal, check_proposal_diff, proposal.branch, - orig.branch) + EmptyMergeProposal, check_proposal_diff, proposal.branch, orig.branch + ) def test_indep(self): - orig = self.make_branch_and_tree('orig', format=self.format) - self.build_tree(['orig/a']) - orig.add(['a']) - orig.commit('blah') - - proposal = orig.controldir.sprout('proposal').open_workingtree() - self.build_tree_contents([('orig/b', 'b'), ('orig/c', 'c')]) - orig.add(['b', 'c']) - orig.commit('independent') + orig = self.make_branch_and_tree("orig", format=self.format) + self.build_tree(["orig/a"]) + orig.add(["a"]) + orig.commit("blah") + + proposal = orig.controldir.sprout("proposal").open_workingtree() + self.build_tree_contents([("orig/b", "b"), ("orig/c", "c")]) + orig.add(["b", "c"]) + orig.commit("independent") - self.build_tree_contents([('proposal/b', 'b')]) + self.build_tree_contents([("proposal/b", "b")]) if proposal.supports_setting_file_ids(): - proposal.add(['b'], [orig.path2id('b')]) + proposal.add(["b"], [orig.path2id("b")]) else: - proposal.add(['b']) - proposal.commit('not pointless') + proposal.add(["b"]) + proposal.commit("not pointless") self.addCleanup(proposal.lock_write().unlock) self.assertRaises( - EmptyMergeProposal, check_proposal_diff, proposal.branch, - orig.branch) + EmptyMergeProposal, check_proposal_diff, proposal.branch, orig.branch + ) def test_changes(self): - orig = self.make_branch_and_tree('orig', format=self.format) - self.build_tree(['orig/a']) - orig.add(['a']) - orig.commit('blah') - - proposal = orig.controldir.sprout('proposal').open_workingtree() - self.build_tree(['proposal/b']) - proposal.add(['b']) - proposal.commit('not pointless') + orig = self.make_branch_and_tree("orig", format=self.format) + self.build_tree(["orig/a"]) + orig.add(["a"]) + orig.commit("blah") + + proposal = orig.controldir.sprout("proposal").open_workingtree() + self.build_tree(["proposal/b"]) + proposal.add(["b"]) + proposal.commit("not pointless") self.addCleanup(proposal.lock_write().unlock) check_proposal_diff(proposal.branch, orig.branch) @@ -102,9 +101,9 @@ class CheckProposalDiffGitTests(TestCaseWithTransport, CheckProposalDiffBase): - format = 'git' + format = "git" class CheckProposalDiffBzrTests(TestCaseWithTransport, CheckProposalDiffBase): - format = 'bzr' + format = "bzr" diff -Nru silver-platter-0.4.0/silver_platter/tests/test_run.py silver-platter-0.4.1/silver_platter/tests/test_run.py --- silver-platter-0.4.0/silver_platter/tests/test_run.py 2019-04-06 23:28:56.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/test_run.py 2021-02-17 22:45:01.000000000 +0000 @@ -24,66 +24,79 @@ from ..run import ( ScriptMadeNoChanges, script_runner, - ) +) class ScriptRunnerTests(TestCaseWithTransport): - def setUp(self): super(ScriptRunnerTests, self).setUp() - self.tree = self.make_branch_and_tree('tree') + self.tree = self.make_branch_and_tree("tree") - with open('foo.sh', 'w') as f: - f.write("""\ + with open("foo.sh", "w") as f: + f.write( + """\ #!/bin/sh echo Foo > bar echo "Some message" brz add --quiet bar -""") - os.chmod('foo.sh', 0o755) +""" + ) + os.chmod("foo.sh", 0o755) def test_simple_with_commit(self): description = script_runner( - self.tree, os.path.abspath('foo.sh'), commit_pending=True) - self.assertEqual(description, 'Some message\n') + self.tree, os.path.abspath("foo.sh"), commit_pending=True + ) + self.assertEqual(description, "Some message\n") def test_simple_with_autocommit(self): - description = script_runner(self.tree, os.path.abspath('foo.sh')) + description = script_runner(self.tree, os.path.abspath("foo.sh")) self.assertEqual( - self.tree.branch.repository.get_revision( - self.tree.last_revision()).message, - "Some message\n") - self.assertEqual(description, 'Some message\n') + self.tree.branch.repository.get_revision(self.tree.last_revision()).message, + "Some message\n", + ) + self.assertEqual(description, "Some message\n") def test_simple_with_autocommit_and_script_commits(self): - with open('foo.sh', 'w') as f: - f.write("""\ + with open("foo.sh", "w") as f: + f.write( + """\ #!/bin/sh echo Foo > bar echo "Some message" brz add --quiet bar brz commit --quiet -m blah -""") - os.chmod('foo.sh', 0o755) - description = script_runner( - self.tree, os.path.abspath('foo.sh')) +""" + ) + os.chmod("foo.sh", 0o755) + description = script_runner(self.tree, os.path.abspath("foo.sh")) self.assertEqual( - self.tree.branch.repository.get_revision( - self.tree.last_revision()).message, - "blah") - self.assertEqual(description, 'Some message\n') + self.tree.branch.repository.get_revision(self.tree.last_revision()).message, + "blah", + ) + self.assertEqual(description, "Some message\n") def test_simple_without_commit(self): self.assertRaises( - ScriptMadeNoChanges, script_runner, self.tree, - os.path.abspath('foo.sh'), commit_pending=False) + ScriptMadeNoChanges, + script_runner, + self.tree, + os.path.abspath("foo.sh"), + commit_pending=False, + ) def test_no_changes(self): - with open('foo.sh', 'w') as f: - f.write("""\ + with open("foo.sh", "w") as f: + f.write( + """\ #!/bin/sh echo "Some message" -""") +""" + ) self.assertRaises( - ScriptMadeNoChanges, script_runner, self.tree, - os.path.abspath('foo.sh'), commit_pending=True) + ScriptMadeNoChanges, + script_runner, + self.tree, + os.path.abspath("foo.sh"), + commit_pending=True, + ) diff -Nru silver-platter-0.4.0/silver_platter/tests/test_utils.py silver-platter-0.4.1/silver_platter/tests/test_utils.py --- silver-platter-0.4.0/silver_platter/tests/test_utils.py 2019-11-24 03:09:08.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/test_utils.py 2021-02-17 22:45:01.000000000 +0000 @@ -17,7 +17,7 @@ from breezy.tests import ( TestCaseWithTransport, - ) +) from ..utils import ( TemporarySprout, @@ -25,73 +25,78 @@ run_post_check, PreCheckFailed, PostCheckFailed, - ) +) class TemporarySproutTests(TestCaseWithTransport): - def test_simple(self): - builder = self.make_branch_builder('.') + builder = self.make_branch_builder(".") builder.start_series() - orig_revid = builder.build_snapshot(None, [ - ('add', ('', None, 'directory', '')), - ('add', ('debian/', None, 'directory', '')), - ('add', ('debian/control', None, 'file', b'initial'))], - message='Initial\n') + orig_revid = builder.build_snapshot( + None, + [ + ("add", ("", None, "directory", "")), + ("add", ("debian/", None, "directory", "")), + ("add", ("debian/control", None, "file", b"initial")), + ], + message="Initial\n", + ) builder.finish_series() branch = builder.get_branch() with TemporarySprout(branch, dir=self.test_dir) as tree: self.assertNotEqual(branch.control_url, tree.branch.control_url) - tree.commit('blah') + tree.commit("blah") # Commits in the temporary sprout don't affect the original branch. self.assertEqual(branch.last_revision(), orig_revid) def test_nonexistent_colocated(self): # Colocated branches that are specified but don't exist are ignored. - builder = self.make_branch_builder('.') + builder = self.make_branch_builder(".") builder.start_series() - orig_revid = builder.build_snapshot(None, [ - ('add', ('', None, 'directory', '')), - ('add', ('debian/', None, 'directory', ''))], - message='Initial\n') + orig_revid = builder.build_snapshot( + None, + [ + ("add", ("", None, "directory", "")), + ("add", ("debian/", None, "directory", "")), + ], + message="Initial\n", + ) builder.finish_series() branch = builder.get_branch() - with TemporarySprout(branch, ['foo'], dir=self.test_dir) as tree: + with TemporarySprout(branch, ["foo"], dir=self.test_dir) as tree: self.assertNotEqual(branch.control_url, tree.branch.control_url) - tree.commit('blah') + tree.commit("blah") # Commits in the temporary sprout don't affect the original branch. self.assertEqual(branch.last_revision(), orig_revid) class RunPreCheckTests(TestCaseWithTransport): - def test_none(self): - tree = self.make_branch_and_tree('tree') + tree = self.make_branch_and_tree("tree") self.assertIs(run_pre_check(tree, None), None) def test_false(self): - tree = self.make_branch_and_tree('tree') + tree = self.make_branch_and_tree("tree") self.assertRaises(PreCheckFailed, run_pre_check, tree, "/bin/false") def test_true(self): - tree = self.make_branch_and_tree('tree') + tree = self.make_branch_and_tree("tree") self.assertIs(run_pre_check(tree, "/bin/true"), None) class RunPostCheckTests(TestCaseWithTransport): - def test_none(self): - tree = self.make_branch_and_tree('tree') + tree = self.make_branch_and_tree("tree") self.assertIs(run_post_check(tree, None, None), None) def test_false(self): - tree = self.make_branch_and_tree('tree') - cid = tree.commit('a') + tree = self.make_branch_and_tree("tree") + cid = tree.commit("a") self.assertRaises( - PostCheckFailed, run_post_check, tree, "/bin/false", - since_revid=cid) + PostCheckFailed, run_post_check, tree, "/bin/false", since_revid=cid + ) def test_true(self): - tree = self.make_branch_and_tree('tree') - cid = tree.commit('a') + tree = self.make_branch_and_tree("tree") + cid = tree.commit("a") self.assertIs(run_post_check(tree, "/bin/true", since_revid=cid), None) diff -Nru silver-platter-0.4.0/silver_platter/tests/test_version.py silver-platter-0.4.1/silver_platter/tests/test_version.py --- silver-platter-0.4.0/silver_platter/tests/test_version.py 2020-05-31 02:02:41.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/tests/test_version.py 2021-02-17 22:45:01.000000000 +0000 @@ -23,19 +23,16 @@ class VersionMatchTest(TestCase): - def test_matches_setup_version(self): - if not os.path.exists('setup.py'): - self.skipTest( - 'no setup.py available. ' - 'Running outside of source tree?') + if not os.path.exists("setup.py"): + self.skipTest("no setup.py available. " "Running outside of source tree?") # TODO(jelmer): Surely there's a better way of doing this? - with open('setup.py', 'r') as f: + with open("setup.py", "r") as f: for line in f: m = re.match(r'[ ]*version=["\'](.*)["\'],', line) if m: setup_version = m.group(1) break else: - raise AssertionError('setup version not found') + raise AssertionError("setup version not found") self.assertEqual(version_string, setup_version) diff -Nru silver-platter-0.4.0/silver_platter/utils.py silver-platter-0.4.1/silver_platter/utils.py --- silver-platter-0.4.0/silver_platter/utils.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/utils.py 2021-02-17 22:45:01.000000000 +0000 @@ -26,7 +26,8 @@ errors, osutils, urlutils, - ) +) + try: from breezy.bzr import LineEndingError except ImportError: # brz < 3.1.1 @@ -35,7 +36,7 @@ from breezy.branch import ( Branch, BranchWriteLockResult, - ) +) from breezy.controldir import ControlDir, Prober from breezy.git.remote import RemoteGitError from breezy.revision import NULL_REVISION @@ -46,10 +47,11 @@ def create_temp_sprout( - branch: Branch, - additional_colocated_branches: Optional[List[str]] = None, - dir: Optional[str] = None, - path: Optional[str] = None) -> Tuple[WorkingTree, Callable[[], None]]: + branch: Branch, + additional_colocated_branches: Optional[List[str]] = None, + dir: Optional[str] = None, + path: Optional[str] = None, +) -> Tuple[WorkingTree, Callable[[], None]]: """Create a temporary sprout of a branch. This attempts to fetch the least amount of history as possible. @@ -62,29 +64,31 @@ def destroy() -> None: shutil.rmtree(td) + # Only use stacking if the remote repository supports chks because of # https://bugs.launchpad.net/bzr/+bug/375013 use_stacking = ( - branch._format.supports_stacking() and - branch.repository._format.supports_chks) + branch._format.supports_stacking() and branch.repository._format.supports_chks + ) try: # preserve whatever source format we have. to_dir = branch.controldir.sprout( - td, None, create_tree_if_local=True, + td, + None, + create_tree_if_local=True, source_branch=branch, - stacked=use_stacking) + stacked=use_stacking, + ) # TODO(jelmer): Fetch these during the initial clone for branch_name in set(additional_colocated_branches or []): try: add_branch = branch.controldir.open_branch(name=branch_name) - except (errors.NotBranchError, - errors.NoColocatedBranchSupport): + except (errors.NotBranchError, errors.NoColocatedBranchSupport): pass else: local_add_branch = to_dir.create_branch(name=branch_name) add_branch.push(local_add_branch) - assert (add_branch.last_revision() == - local_add_branch.last_revision()) + assert add_branch.last_revision() == local_add_branch.last_revision() return to_dir.open_workingtree(), destroy except BaseException as e: destroy() @@ -97,10 +101,12 @@ This attempts to fetch the least amount of history as possible. """ - def __init__(self, - branch: Branch, - additional_colocated_branches: Optional[List[str]] = None, - dir: Optional[str] = None): + def __init__( + self, + branch: Branch, + additional_colocated_branches: Optional[List[str]] = None, + dir: Optional[str] = None, + ): self.branch = branch self.additional_colocated_branches = additional_colocated_branches self.dir = dir @@ -109,7 +115,8 @@ tree, self._destroy = create_temp_sprout( self.branch, additional_colocated_branches=self.additional_colocated_branches, - dir=self.dir) + dir=self.dir, + ) return tree def __exit__(self, exc_type, exc_val, exc_tb): @@ -142,9 +149,9 @@ """The post check failed.""" -def run_post_check(tree: WorkingTree, - script: Optional[str], - since_revid: bytes) -> None: +def run_post_check( + tree: WorkingTree, script: Optional[str], since_revid: bytes +) -> None: """Run a script after making any changes to a tree. Args: @@ -158,8 +165,8 @@ return try: subprocess.check_call( - script, shell=True, cwd=tree.basedir, - env={'SINCE_REVID': since_revid}) + script, shell=True, cwd=tree.basedir, env={"SINCE_REVID": since_revid} + ) except subprocess.CalledProcessError: raise PostCheckFailed() @@ -175,6 +182,17 @@ return self.description +class BranchRateLimited(Exception): + """Opening branch was rate-limited.""" + + def __init__(self, url: str, description: str): + self.url = url + self.description = description + + def __str__(self) -> str: + return self.description + + class BranchMissing(Exception): """Branch did not exist.""" @@ -199,16 +217,18 @@ def _convert_exception(url: str, e: Exception) -> Optional[Exception]: if isinstance(e, socket.error): - return BranchUnavailable(url, 'Socket error: %s' % e) + return BranchUnavailable(url, "Socket error: %s" % e) if isinstance(e, errors.NotBranchError): - return BranchMissing(url, 'Branch does not exist: %s' % e) + return BranchMissing(url, "Branch does not exist: %s" % e) if isinstance(e, errors.UnsupportedProtocol): return BranchUnsupported(url, str(e)) if isinstance(e, errors.ConnectionError): return BranchUnavailable(url, str(e)) if isinstance(e, errors.PermissionDenied): return BranchUnavailable(url, str(e)) - if isinstance(e, errors.InvalidHttpResponse): + if isinstance(e, errors.InvalidHttpResponse): + if "Unexpected HTTP status 429" in str(e): + raise BranchRateLimited(url, str(e)) return BranchUnavailable(url, str(e)) if isinstance(e, errors.TransportError): return BranchUnavailable(url, str(e)) @@ -225,20 +245,21 @@ return None -def open_branch(url: str, - possible_transports: Optional[List[Transport]] = None, - probers: Optional[List[Prober]] = None, - name: str = None) -> Branch: +def open_branch( + url: str, + possible_transports: Optional[List[Transport]] = None, + probers: Optional[List[Prober]] = None, + name: str = None, +) -> Branch: """Open a branch by URL.""" url, params = urlutils.split_segment_parameters(url) if name is None: try: - name = urlutils.unquote(params['branch']) + name = urlutils.unquote(params["branch"]) except KeyError: name = None try: - transport = get_transport( - url, possible_transports=possible_transports) + transport = get_transport(url, possible_transports=possible_transports) dir = ControlDir.open_from_transport(transport, probers) return dir.open_branch(name=name) except Exception as e: @@ -249,15 +270,14 @@ def open_branch_containing( - url: str, - possible_transports: Optional[List[Transport]] = None, - probers: Optional[List[Prober]] = None) -> Tuple[Branch, str]: + url: str, + possible_transports: Optional[List[Transport]] = None, + probers: Optional[List[Prober]] = None, +) -> Tuple[Branch, str]: """Open a branch by URL.""" try: - transport = get_transport( - url, possible_transports=possible_transports) - dir, subpath = ControlDir.open_containing_from_transport( - transport, probers) + transport = get_transport(url, possible_transports=possible_transports) + dir, subpath = ControlDir.open_containing_from_transport(transport, probers) return dir.open_branch(), subpath except Exception as e: converted = _convert_exception(url, e) @@ -268,13 +288,13 @@ try: from breezy.memorybranch import MemoryBranch -except ImportError: # breezy < 3.1.1 +except ImportError: # breezy < 3.1.1 from breezy.lock import _RelockDebugMixin, LogicalLockResult class MemoryBranch(Branch, _RelockDebugMixin): # type: ignore - def __init__(self, repository, last_revision_info, tags): from breezy.tag import DisabledTags, MemoryTags + self.repository = repository self._last_revision_info = last_revision_info self._revision_history_cache = None @@ -287,7 +307,7 @@ self._revision_id_to_revno_cache = None self._partial_revision_id_to_revno_cache = {} self._partial_revision_history_cache = [] - self.base = 'memory://' + osutils.rand_chars(10) + self.base = "memory://" + osutils.rand_chars(10) def get_config(self): return _mod_config.Config() @@ -307,8 +327,7 @@ return self._last_revision_info def _gen_revision_history(self): - """Generate the revision history from last revision - """ + """Generate the revision history from last revision""" last_revno, last_revision = self.last_revision_info() self._extend_partial_history() return list(reversed(self._partial_revision_history_cache)) @@ -324,16 +343,15 @@ if last_revno is None: self._extend_partial_history() return self._partial_revision_history_cache[ - len(self._partial_revision_history_cache) - revno] + len(self._partial_revision_history_cache) - revno + ] else: if revno <= 0 or revno > last_revno: raise errors.NoSuchRevision(self, revno) distance_from_last = last_revno - revno - if len(self._partial_revision_history_cache) <= \ - distance_from_last: + if len(self._partial_revision_history_cache) <= distance_from_last: self._extend_partial_history(distance_from_last) - return self._partial_revision_history_cache[ - distance_from_last] + return self._partial_revision_history_cache[distance_from_last] def full_branch_url(branch): @@ -346,6 +364,6 @@ if branch.name is None: return branch.user_url url, params = urlutils.split_segment_parameters(branch.user_url) - if branch.name != '': - params['branch'] = urlutils.quote(branch.name, '') + if branch.name != "": + params["branch"] = urlutils.quote(branch.name, "") return urlutils.join_segment_parameters(url, params) diff -Nru silver-platter-0.4.0/silver_platter/workspace.py silver-platter-0.4.1/silver_platter/workspace.py --- silver-platter-0.4.0/silver_platter/workspace.py 2020-11-25 23:09:09.000000000 +0000 +++ silver-platter-0.4.1/silver_platter/workspace.py 2021-02-17 22:45:01.000000000 +0000 @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +import logging from typing import Optional, Callable, List, Union, Dict, BinaryIO, Any, Tuple from breezy.branch import Branch @@ -25,14 +26,15 @@ DivergedBranches, NotBranchError, NoColocatedBranchSupport, - ) +) from breezy.propose import ( get_hoster, Hoster, MergeProposal, - ) + UnsupportedHoster, +) -from breezy.trace import note +from breezy.transport.local import LocalTransport from .publish import ( merge_conflicts, @@ -41,16 +43,16 @@ push_derived_changes, publish_changes as _publish_changes, PublishResult, - ) +) from .utils import ( create_temp_sprout, full_branch_url, - ) +) __all__ = [ - 'Workspace', - ] + "Workspace", +] class Workspace(object): @@ -67,18 +69,20 @@ local_tree: WorkingTree main_branch_revid: Optional[bytes] - def __init__(self, main_branch: Branch, - resume_branch: Optional[Branch] = None, - cached_branch: Optional[Branch] = None, - additional_colocated_branches: Optional[List[str]] = None, - dir: Optional[str] = None, - path: Optional[str] = None) -> None: + def __init__( + self, + main_branch: Branch, + resume_branch: Optional[Branch] = None, + cached_branch: Optional[Branch] = None, + additional_colocated_branches: Optional[List[str]] = None, + dir: Optional[str] = None, + path: Optional[str] = None, + ) -> None: self.main_branch = main_branch self.main_branch_revid = None self.cached_branch = cached_branch self.resume_branch = resume_branch - self.additional_colocated_branches = ( - additional_colocated_branches or []) + self.additional_colocated_branches = additional_colocated_branches or [] self._destroy = None self._dir = dir self._path = path @@ -88,27 +92,39 @@ return "Workspace for %s" % full_branch_url(self.main_branch) else: return "Workspace for %s at %s" % ( - full_branch_url(self.main_branch), self._path) + full_branch_url(self.main_branch), + self._path, + ) def __repr__(self): return ( "%s(%r, resume_branch=%r, cached_branch=%r, " - "additional_colocated_branches=%r, dir=%r, path=%r)" % ( - type(self).__name__, self.main_branch, self.resume_branch, - self.cached_branch, self.additional_colocated_branches, - self._dir, self._path)) + "additional_colocated_branches=%r, dir=%r, path=%r)" + % ( + type(self).__name__, + self.main_branch, + self.resume_branch, + self.cached_branch, + self.additional_colocated_branches, + self._dir, + self._path, + ) + ) def __enter__(self) -> Any: self.local_tree, self._destroy = create_temp_sprout( self.cached_branch or self.resume_branch or self.main_branch, self.additional_colocated_branches, - dir=self._dir, path=self._path) + dir=self._dir, + path=self._path, + ) self.main_branch_revid = self.main_branch.last_revision() self.refreshed = False with self.local_tree.branch.lock_write(): if self.cached_branch: self.local_tree.pull( - self.resume_branch or self.main_branch, overwrite=True) + self.resume_branch or self.main_branch, overwrite=True + ) if self.resume_branch: try: self.local_tree.pull(self.main_branch, overwrite=False) @@ -116,20 +132,20 @@ pass for branch_name in self.additional_colocated_branches: try: - remote_colo_branch = ( - self.main_branch.controldir.open_branch( - name=branch_name)) - except (NotBranchError, - NoColocatedBranchSupport): + remote_colo_branch = self.main_branch.controldir.open_branch( + name=branch_name + ) + except (NotBranchError, NoColocatedBranchSupport): continue self.local_tree.branch.controldir.push_branch( - name=branch_name, source=remote_colo_branch, - overwrite=True) + name=branch_name, source=remote_colo_branch, overwrite=True + ) if merge_conflicts(self.main_branch, self.local_tree.branch): - note('restarting branch') + logging.info("restarting branch") self.local_tree.update(revision=self.main_branch_revid) self.local_tree.branch.generate_revision_history( - self.main_branch_revid) + self.main_branch_revid + ) self.resume_branch = None self.refreshed = True self.orig_revid = self.local_tree.last_revision() @@ -146,48 +162,78 @@ def changes_since_resume(self) -> bool: return self.orig_revid != self.local_tree.branch.last_revision() - def push(self, hoster: Optional[Hoster] = None, dry_run: bool = False, - tags: Optional[Union[Dict[str, bytes], List[str]]] = None, - stop_revision: Optional[bytes] = None) -> None: + def push( + self, + hoster: Optional[Hoster] = None, + dry_run: bool = False, + tags: Optional[Union[Dict[str, bytes], List[str]]] = None, + stop_revision: Optional[bytes] = None, + ) -> None: if hoster is None: - hoster = get_hoster(self.main_branch) + try: + hoster = get_hoster(self.main_branch) + except UnsupportedHoster: + if isinstance(self.main_branch.control_transport, LocalTransport): + hoster = None + else: + raise return push_changes( - self.local_tree.branch, self.main_branch, hoster=hoster, + self.local_tree.branch, + self.main_branch, + hoster=hoster, additional_colocated_branches=self.additional_colocated_branches, - dry_run=dry_run, tags=tags, stop_revision=stop_revision) - - def propose(self, name: str, description: str, - hoster: Optional[Hoster] = None, - existing_proposal: Optional[MergeProposal] = None, - overwrite_existing: Optional[bool] = None, - labels: Optional[List[str]] = None, - dry_run: bool = False, - commit_message: Optional[str] = None, - reviewers: Optional[List[str]] = None, - tags: Optional[Union[Dict[str, bytes], List[str]]] = None, - owner: Optional[str] = None, - allow_collaboration: bool = False, - stop_revision: Optional[bytes] = None) -> MergeProposal: + dry_run=dry_run, + tags=tags, + stop_revision=stop_revision, + ) + + def propose( + self, + name: str, + description: str, + hoster: Optional[Hoster] = None, + existing_proposal: Optional[MergeProposal] = None, + overwrite_existing: Optional[bool] = None, + labels: Optional[List[str]] = None, + dry_run: bool = False, + commit_message: Optional[str] = None, + reviewers: Optional[List[str]] = None, + tags: Optional[Union[Dict[str, bytes], List[str]]] = None, + owner: Optional[str] = None, + allow_collaboration: bool = False, + stop_revision: Optional[bytes] = None, + ) -> MergeProposal: if hoster is None: hoster = get_hoster(self.main_branch) return propose_changes( - self.local_tree.branch, self.main_branch, hoster=hoster, name=name, - mp_description=description, resume_branch=self.resume_branch, + self.local_tree.branch, + self.main_branch, + hoster=hoster, + name=name, + mp_description=description, + resume_branch=self.resume_branch, resume_proposal=existing_proposal, - overwrite_existing=(overwrite_existing or False), labels=labels, - dry_run=dry_run, commit_message=commit_message, - reviewers=reviewers, owner=owner, + overwrite_existing=(overwrite_existing or False), + labels=labels, + dry_run=dry_run, + commit_message=commit_message, + reviewers=reviewers, + owner=owner, additional_colocated_branches=self.additional_colocated_branches, - tags=tags, allow_collaboration=allow_collaboration, - stop_revision=stop_revision) - - def push_derived(self, - name: str, hoster: Optional[Hoster] = None, - overwrite_existing: Optional[bool] = False, - owner: Optional[str] = None, - tags: Optional[Union[Dict[str, bytes], List[str]]] = None, - stop_revision: Optional[bytes] = None - ) -> Tuple[Branch, str]: + tags=tags, + allow_collaboration=allow_collaboration, + stop_revision=stop_revision, + ) + + def push_derived( + self, + name: str, + hoster: Optional[Hoster] = None, + overwrite_existing: Optional[bool] = False, + owner: Optional[str] = None, + tags: Optional[Union[Dict[str, bytes], List[str]]] = None, + stop_revision: Optional[bytes] = None, + ) -> Tuple[Branch, str]: """Push a derived branch. Args: @@ -203,26 +249,39 @@ hoster = get_hoster(self.main_branch) return push_derived_changes( self.local_tree.branch, - self.main_branch, hoster, name, + self.main_branch, + hoster, + name, overwrite_existing=overwrite_existing, - owner=owner, tags=tags, stop_revision=stop_revision) + owner=owner, + tags=tags, + stop_revision=stop_revision, + ) def publish_changes(self, *args, **kwargs) -> PublishResult: - """Publish a set of changes. - """ + """Publish a set of changes.""" return _publish_changes( - self.local_tree.branch, self.main_branch, self.resume_branch, - *args, **kwargs) + self.local_tree.branch, + self.main_branch, + self.resume_branch, + *args, + **kwargs + ) def orig_tree(self) -> Tree: return self.local_tree.branch.repository.revision_tree(self.orig_revid) - def show_diff(self, outf: BinaryIO, - old_label: str = 'old/', new_label: str = 'new/') -> None: + def show_diff( + self, outf: BinaryIO, old_label: str = "old/", new_label: str = "new/" + ) -> None: orig_tree = self.orig_tree() show_diff_trees( - orig_tree, self.local_tree.basis_tree(), outf, - old_label=old_label, new_label=new_label) + orig_tree, + self.local_tree.basis_tree(), + outf, + old_label=old_label, + new_label=new_label, + ) def __exit__(self, exc_type, exc_val, exc_tb): if self._destroy: diff -Nru silver-platter-0.4.0/silver_platter.egg-info/PKG-INFO silver-platter-0.4.1/silver_platter.egg-info/PKG-INFO --- silver-platter-0.4.0/silver_platter.egg-info/PKG-INFO 2021-02-01 23:30:19.000000000 +0000 +++ silver-platter-0.4.1/silver_platter.egg-info/PKG-INFO 2021-02-17 22:45:13.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: silver-platter -Version: 0.4.0 +Version: 0.4.1 Summary: Automatic merge proposal creeator Home-page: https://jelmer.uk/code/silver-platter Author: Jelmer Vernooij diff -Nru silver-platter-0.4.0/silver_platter.egg-info/requires.txt silver-platter-0.4.1/silver_platter.egg-info/requires.txt --- silver-platter-0.4.0/silver_platter.egg-info/requires.txt 2021-02-01 23:30:19.000000000 +0000 +++ silver-platter-0.4.1/silver_platter.egg-info/requires.txt 2021-02-17 22:45:13.000000000 +0000 @@ -3,6 +3,8 @@ [debian] debmutate>=0.3 +distro-info lintian-brush>=0.50 python_debian pyyaml +upstream-ontologist diff -Nru silver-platter-0.4.0/silver_platter.egg-info/SOURCES.txt silver-platter-0.4.1/silver_platter.egg-info/SOURCES.txt --- silver-platter-0.4.0/silver_platter.egg-info/SOURCES.txt 2021-02-01 23:30:19.000000000 +0000 +++ silver-platter-0.4.1/silver_platter.egg-info/SOURCES.txt 2021-02-17 22:45:13.000000000 +0000 @@ -1,4 +1,5 @@ .bzrignore +.flake8 .gitignore AUTHORS LICENSE @@ -8,6 +9,7 @@ README.rst TODO debian-svp +releaser.conf setup.cfg setup.py svp