Compare commits

..

No commits in common. "main" and "0.207" have entirely different histories.
main ... 0.207

29 changed files with 120 additions and 204 deletions

View File

@ -34,7 +34,6 @@ disable=fixme,locally-disabled,missing-docstring,useless-option-value,
duplicate-code,
too-many-instance-attributes,
too-many-nested-blocks,
too-many-positional-arguments,
too-many-lines,

View File

@ -25,7 +25,6 @@ import shutil
import subprocess
import sys
import tempfile
from typing import Any, NoReturn
from urllib.parse import quote
try:
@ -51,7 +50,7 @@ from ubuntutools.question import YesNoQuestion
Logger = getLogger()
def error(msg: str, *args: Any) -> NoReturn:
def error(msg, *args):
Logger.error(msg, *args)
sys.exit(1)

34
debian/changelog vendored
View File

@ -1,37 +1,3 @@
ubuntu-dev-tools (0.209) UNRELEASED; urgency=medium
[ Colin Watson ]
* Demote sudo to Recommends, and indicate which tools need it in the
package description.
[ Florent 'Skia' Jacquet ]
* pm-helper: make use of YesNoQuestion
-- Mattia Rizzolo <mattia@debian.org> Tue, 06 Jan 2026 17:55:43 +0100
ubuntu-dev-tools (0.208) unstable; urgency=medium
[ Gianfranco Costamagna ]
* ubuntu-build: consider amd64v3 as valid architecture
[ Sebastien Bacher ]
* ubuntu-build: fix non batch mode errors.
[ Benjamin Drung ]
* Format code with black and isort
* ubuntutools/pullpkg.py: initialize vcscmd
* make pylint and mypy happy
* mark non-returning functions with typing.NoReturn
* run-linters: add --errors-only mode and run this during package build
* Drop Lintian overrides related to .pyc files
* Drop obsolete Rules-Requires-Root: no
* run mypy during package build
* sponsor-patch: stop checking for bzr being present
* Modernize SourcePackage._run_lintian()
* requestsync: support pocket parameter in get_ubuntu_srcpkg (LP: #2115990)
-- Benjamin Drung <bdrung@debian.org> Wed, 03 Dec 2025 16:33:47 +0100
ubuntu-dev-tools (0.207) unstable; urgency=medium
* Team upload.

22
debian/control vendored
View File

@ -8,17 +8,16 @@ Uploaders:
Mattia Rizzolo <mattia@debian.org>,
Simon Quigley <tsimonq2@debian.org>,
Build-Depends:
debhelper-compat (= 13),
dh-make,
dh-python,
black <!nocheck>,
dctrl-tools,
debhelper-compat (= 13),
devscripts (>= 2.11.0~),
dh-make,
dh-python,
distro-info (>= 0.2~),
flake8,
isort <!nocheck>,
lsb-release,
mypy <!nocheck>,
pylint <!nocheck>,
python3-all,
python3-apt,
@ -31,9 +30,9 @@ Build-Depends:
python3-pytest,
python3-requests <!nocheck>,
python3-setuptools,
python3-typeshed <!nocheck>,
python3-yaml <!nocheck>,
Standards-Version: 4.7.2
Rules-Requires-Root: no
Vcs-Git: https://git.launchpad.net/ubuntu-dev-tools
Vcs-Browser: https://git.launchpad.net/ubuntu-dev-tools
Homepage: https://launchpad.net/ubuntu-dev-tools
@ -41,12 +40,12 @@ Homepage: https://launchpad.net/ubuntu-dev-tools
Package: ubuntu-dev-tools
Architecture: all
Depends:
dpkg-dev,
binutils,
dctrl-tools,
devscripts (>= 2.11.0~),
diffstat,
distro-info (>= 0.2~),
dpkg-dev,
dput,
lsb-release,
python3,
@ -60,6 +59,7 @@ Depends:
python3-ubuntutools (= ${binary:Version}),
python3-yaml,
sensible-utils,
sudo,
tzdata,
${misc:Depends},
${perl:Depends},
@ -72,11 +72,10 @@ Recommends:
genisoimage,
lintian,
patch,
sbuild | pbuilder | cowbuilder,
python3-dns,
quilt,
reportbug (>= 3.39ubuntu1),
sbuild | pbuilder | cowbuilder,
sudo,
ubuntu-keyring | ubuntu-archive-keyring,
Suggests:
bzr | brz,
@ -93,7 +92,7 @@ Description: useful tools for Ubuntu developers
willing to help fix it.
- check-mir - check support status of build/binary dependencies
- check-symbols - will compare and give you a diff of the exported symbols of
all .so files in a binary package. [sudo]
all .so files in a binary package.
- dch-repeat - used to repeat a change log into an older release.
- grab-merge - grabs a merge from merges.ubuntu.com easily.
- grep-merges - search for pending merges from Debian.
@ -101,10 +100,9 @@ Description: useful tools for Ubuntu developers
- merge-changelog - manually merges two Debian changelogs with the same base
version.
- mk-sbuild - script to create LVM snapshot chroots via schroot and
sbuild. [sbuild, sudo]
sbuild.
- pbuilder-dist, cowbuilder-dist - wrapper script for managing several build
chroots (for different Ubuntu and Debian releases) on the same system.
[pbuilder | cowbuilder, sudo]
- pull-debian-debdiff - attempts to find and download a specific version of
a Debian package and its immediate parent to generate a debdiff.
- pull-debian-source - downloads the latest source package available in
@ -124,7 +122,7 @@ Description: useful tools for Ubuntu developers
autopkgtests on the Ubuntu autopkgtest infrastructure
- seeded-in-ubuntu - query if a package is safe to upload during a freeze.
- setup-packaging-environment - assistant to get an Ubuntu installation
ready for packaging work. [sudo]
ready for packaging work.
- sponsor-patch - Downloads a patch from a Launchpad bug, patches the source
package, and uploads it (to Ubuntu or a PPA)
- submittodebian - automatically send your changes to Debian as a bug report.

3
debian/rules vendored
View File

@ -3,11 +3,10 @@
override_dh_auto_clean:
dh_auto_clean
rm -f .coverage
rm -rf .mypy_cache .tox
rm -rf .tox
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
./run-linters --errors-only
python3 -m pytest -v ubuntutools
endif

3
debian/source/lintian-overrides vendored Normal file
View File

@ -0,0 +1,3 @@
# pyc files are machine-generated; they're expected to have long lines and have unstated copyright
source: file-without-copyright-information *.pyc [debian/copyright]
source: very-long-line-length-in-source-file * > 512 [*.pyc:*]

View File

@ -4,5 +4,4 @@ Depends:
python3-pytest,
python3-setuptools,
@,
Restrictions:
allow-stderr,
Restrictions: allow-stderr

View File

@ -43,7 +43,7 @@ operations.
\fB\-a\fR ARCHITECTURE, \fB\-\-arch\fR=\fIARCHITECTURE\fR
Rebuild or rescore a specific architecture. Valid
architectures are:
armhf, arm64, amd64, amd64v3, i386, powerpc, ppc64el, riscv64, s390x.
armhf, arm64, amd64, i386, powerpc, ppc64el, riscv64, s390x.
.TP
Batch processing:
.IP
@ -66,7 +66,7 @@ Rescore builds to <priority>.
\fB\-\-arch\fR=\fIARCHITECTURE\fR
Affect only 'architecture' (can be used several
times). Valid architectures are:
armhf, arm64, amd64, amd64v3, i386, powerpc, ppc64el, riscv64, s390x.
arm64, amd64, i386, powerpc, ppc64el, riscv64, s390x.
.IP
\fB\-A=\fIARCHIVE\fR
Act on the named archive (ppa) instead of on the main Ubuntu archive.

View File

@ -23,7 +23,6 @@
import argparse
import sys
from typing import Any, NoReturn
from launchpadlib.errors import HTTPError
from launchpadlib.launchpad import Launchpad
@ -34,7 +33,7 @@ from ubuntutools.config import UDTConfig
Logger = getLogger()
def error_out(msg: str, *args: Any) -> NoReturn:
def error_out(msg, *args):
Logger.error(msg, *args)
sys.exit(1)

View File

@ -22,7 +22,6 @@
# pylint: enable=invalid-name
import sys
from typing import NoReturn
from debian.changelog import Changelog
@ -31,7 +30,7 @@ from ubuntutools import getLogger
Logger = getLogger()
def usage(exit_code: int = 1) -> NoReturn:
def usage(exit_code=1):
Logger.info(
"""Usage: merge-changelog <left changelog> <right changelog>

View File

@ -38,7 +38,6 @@ import shutil
import subprocess
import sys
from contextlib import suppress
from typing import NoReturn
import debian.deb822
from distro_info import DebianDistroInfo, DistroDataOutdated, UbuntuDistroInfo
@ -412,7 +411,7 @@ class PbuilderDist:
] + arguments
def show_help(exit_code: int = 0) -> NoReturn:
def show_help(exit_code=0):
"""help() -> None
Print a help message for pbuilder-dist, and exit with the given code.

View File

@ -22,7 +22,6 @@ from argparse import ArgumentParser
import yaml
from launchpadlib.launchpad import Launchpad
from ubuntutools.question import YesNoQuestion
from ubuntutools.utils import get_url
# proposed-migration is only concerned with the devel series; unlike other
@ -57,8 +56,10 @@ def claim_excuses_bug(launchpad, bug, package):
if our_task.assignee:
print(f"Currently assigned to {our_task.assignee.name}")
answer = YesNoQuestion().ask("Do you want to claim this bug?", "no")
if answer == "yes":
print("""Do you want to claim this bug? [yN] """, end="")
sys.stdout.flush()
response = sys.stdin.readline()
if response.strip().lower().startswith("y"):
our_task.assignee = launchpad.me
our_task.lp_save()
return True
@ -130,9 +131,7 @@ def main():
if not proposed_version:
print(f"Package {args.package} not found in -proposed.")
sys.exit(1)
answer = YesNoQuestion().ask("Do you want to create a bug?", "no")
if answer == "yes":
create_excuses_bug(args.launchpad, args.package, proposed_version)
create_excuses_bug(args.launchpad, args.package, proposed_version)
except ValueError as e:
sys.stderr.write(f"{e}\n")
else:

View File

@ -4,7 +4,3 @@ line-length = 99
[tool.isort]
line_length = 99
profile = "black"
[tool.mypy]
disallow_incomplete_defs = true
ignore_missing_imports = true

View File

@ -46,7 +46,7 @@ Logger = getLogger()
#
def main() -> None:
def main():
# Our usage options.
usage = "%(prog)s [options] <source package> [<target release> [base version]]"
parser = argparse.ArgumentParser(usage=usage)
@ -153,7 +153,6 @@ def main() -> None:
import DNS # pylint: disable=import-outside-toplevel
DNS.DiscoverNameServers()
# imported earlier, pylint: disable-next=possibly-used-before-assignment
mxlist = DNS.mxlookup(bug_mail_domain)
firstmx = mxlist[0]
mailserver_host = firstmx[1]
@ -215,7 +214,6 @@ def main() -> None:
if not args.release:
if lpapi:
# imported earlier, pylint: disable-next=possibly-used-before-assignment
args.release = Distribution("ubuntu").getDevelopmentSeries().name
else:
ubu_info = UbuntuDistroInfo()
@ -379,7 +377,6 @@ def main() -> None:
# Map status to the values expected by LP API
mapping = {"new": "New", "confirmed": "Confirmed"}
# Post sync request using LP API
# imported earlier, pylint: disable-next=possibly-used-before-assignment
post_bug(srcpkg, subscribe, mapping[status], title, report)
else:
email_from = ubu_email(export=False)[1]

View File

@ -4,45 +4,16 @@ set -eu
# Copyright 2023, Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0
PYTHON_SCRIPTS=$(find . -maxdepth 1 -type f -exec grep -l '^#! */usr/bin/python3$' {} +)
PYTHON_SCRIPTS=$(grep -l -r '^#! */usr/bin/python3$' .)
run_black() {
echo "Running black..."
black -C --check --diff . ${PYTHON_SCRIPTS}
}
echo "Running black..."
black --check --diff . $PYTHON_SCRIPTS
run_isort() {
echo "Running isort..."
isort --check-only --diff .
}
echo "Running isort..."
isort --check-only --diff .
run_flake8() {
echo "Running flake8..."
flake8 --max-line-length=99 --ignore=E203,W503 . $PYTHON_SCRIPTS
}
echo "Running flake8..."
flake8 --max-line-length=99 --ignore=E203,W503 . $PYTHON_SCRIPTS
run_mypy() {
echo "Running mypy..."
mypy .
mypy --scripts-are-modules $PYTHON_SCRIPTS
}
run_pylint() {
echo "Running pylint..."
pylint "$@" $(find * -name '*.py') $PYTHON_SCRIPTS
}
if test "${1-}" = "--errors-only"; then
# Run only linters that can detect real errors (ignore formatting)
run_black || true
run_isort || true
run_flake8 || true
run_mypy
run_pylint --errors-only
else
run_black
run_isort
run_flake8
run_mypy
run_pylint
fi
echo "Running pylint..."
pylint $(find * -name '*.py') $PYTHON_SCRIPTS

View File

@ -22,7 +22,6 @@
import argparse
import fnmatch
import functools
import logging
import os
import shutil
@ -50,6 +49,7 @@ from ubuntutools.requestsync.mail import get_debian_srcpkg as requestsync_mail_g
from ubuntutools.version import Version
Logger = getLogger()
cached_sync_blocklist = None
def remove_signature(dscname):
@ -436,14 +436,6 @@ def copy(src_pkg, release, bugs, sponsoree=None, simulate=False, force=False, ye
close_bugs(bugs, src_pkg.source, src_pkg.version.full_version, changes, sponsoree)
@functools.lru_cache(maxsize=1)
def _fetch_sync_blocklist() -> str:
url = "https://ubuntu-archive-team.ubuntu.com/sync-blocklist.txt"
with urllib.request.urlopen(url) as f:
sync_blocklist = f.read().decode("utf-8")
return sync_blocklist
def is_blocklisted(query):
"""Determine if package "query" is in the sync blocklist
Returns tuple of (blocklisted, comments)
@ -464,20 +456,24 @@ def is_blocklisted(query):
if diff.status == "Blacklisted always":
blocklisted = "ALWAYS"
try:
sync_blocklist = _fetch_sync_blocklist()
except OSError:
print("WARNING: unable to download the sync blocklist. Erring on the side of caution.")
return ("ALWAYS", "INTERNAL ERROR: Unable to fetch sync blocklist")
global cached_sync_blocklist
if not cached_sync_blocklist:
url = "https://ubuntu-archive-team.ubuntu.com/sync-blocklist.txt"
try:
with urllib.request.urlopen(url) as f:
cached_sync_blocklist = f.read().decode("utf-8")
except:
print("WARNING: unable to download the sync blocklist. Erring on the side of caution.")
return ("ALWAYS", "INTERNAL ERROR: Unable to fetch sync blocklist")
applicable_lines = []
for line in sync_blocklist.splitlines():
for line in cached_sync_blocklist.splitlines():
if not line.strip():
applicable_lines = []
continue
applicable_lines.append(line)
try:
line = line[: line.index("#")]
line = line[:line.index("#")]
except ValueError:
pass
source = line.strip()
@ -527,7 +523,7 @@ def parse():
"-y",
"--yes",
action="store_true",
help="Automatically sync without prompting. Use with caution and care.",
help="Automatically sync without prompting. Use with caution and care."
)
parser.add_argument("-d", "--distribution", help="Debian distribution to sync from.")
parser.add_argument("-r", "--release", help="Specify target Ubuntu release.")
@ -780,9 +776,7 @@ def main():
continue
if args.lp:
if not copy(
src_pkg, args.release, args.bugs, sponsoree, args.simulate, args.force, args.yes
):
if not copy(src_pkg, args.release, args.bugs, sponsoree, args.simulate, args.force, args.yes):
continue
else:
os.environ["DEB_VENDOR"] = "Ubuntu"

View File

@ -87,13 +87,17 @@ def retry_builds(pkg, archs):
return f"Retrying builds of '{pkg.source_package_name}':\n{msg}"
def parse_args(argv: list[str], valid_archs: set[str]) -> argparse.Namespace:
"""Parse command line arguments and return namespace."""
def main():
# Usage.
usage = "%(prog)s <srcpackage> <release> <operation>\n\n"
usage += "Where operation may be one of: rescore, retry, or status.\n"
usage += "Only Launchpad Buildd Admins may rescore package builds."
# Valid architectures.
valid_archs = set(
["armhf", "arm64", "amd64", "i386", "powerpc", "ppc64el", "riscv64", "s390x"]
)
# Prepare our option parser.
parser = argparse.ArgumentParser(usage=usage)
@ -144,23 +148,7 @@ def parse_args(argv: list[str], valid_archs: set[str]) -> argparse.Namespace:
parser.add_argument("packages", metavar="package", nargs="*", help=argparse.SUPPRESS)
# Parse our options.
args = parser.parse_args(argv)
if not args.batch:
# Check we have the correct number of arguments.
if len(args.packages) < 3:
parser.error("Incorrect number of arguments.")
return args
def main():
# Valid architectures.
valid_archs = set(
["armhf", "arm64", "amd64", "amd64v3", "i386", "powerpc", "ppc64el", "riscv64", "s390x"]
)
args = parse_args(sys.argv[1:], valid_archs)
args = parser.parse_args()
launchpad = Launchpad.login_with("ubuntu-dev-tools", "production", version="devel")
ubuntu = launchpad.distributions["ubuntu"]
@ -179,13 +167,21 @@ def main():
Logger.error(error)
sys.exit(1)
else:
package = str(args.packages[0]).lower()
release = str(args.packages[1]).lower()
operation = str(args.packages[2]).lower()
# Check we have the correct number of arguments.
if len(args.packages) < 3:
parser.error("Incorrect number of arguments.")
try:
package = str(args.packages[0]).lower()
release = str(args.packages[1]).lower()
operation = str(args.packages[2]).lower()
except IndexError:
parser.print_help()
sys.exit(1)
archive = launchpad.archives.getByReference(reference=args.archive)
try:
distroseries = ubuntu.getSeries(name_or_version=release.split("-")[0])
distroseries = ubuntu.getSeries(name_or_version=release)
except lazr.restfulclient.errors.NotFound as error:
Logger.error(error)
sys.exit(1)
@ -238,11 +234,11 @@ def main():
# are in place.
if operation == "retry":
necessary_privs = archive.checkUpload(
component=component,
component=sources.getComponent(),
distroseries=distroseries,
person=launchpad.me,
pocket=pocket,
sourcepackagename=sources.source_package_name,
sourcepackagename=sources.getPackageName(),
)
if not necessary_privs:
Logger.error(

View File

@ -65,7 +65,7 @@ def main():
err = True
continue
Logger.info("%s%s", prefix, version)
Logger.info(prefix + version)
if err:
sys.exit(1)

View File

@ -340,9 +340,11 @@ class SourcePackage(ABC):
def _archive_servers(self):
"Generator for mirror and master servers"
# Always provide the mirrors first
yield from self.mirrors
for server in self.mirrors:
yield server
# Don't repeat servers that are in both mirrors and masters
yield from set(self.masters) - set(self.mirrors)
for server in set(self.masters) - set(self.mirrors):
yield server
def _source_urls(self, name):
"Generator of sources for name"
@ -633,7 +635,8 @@ class DebianSourcePackage(SourcePackage):
def _source_urls(self, name):
"Generator of sources for name"
yield from super()._source_urls(name)
for url in super()._source_urls(name):
yield url
if name in self.snapshot_files:
yield self.snapshot_files[name]
@ -731,7 +734,6 @@ class PersonalPackageArchiveSourcePackage(UbuntuSourcePackage):
class UbuntuCloudArchiveSourcePackage(PersonalPackageArchiveSourcePackage):
"Download / unpack an Ubuntu Cloud Archive source package"
TEAM = "ubuntu-cloud-archive"
PROJECT = "cloud-archive"
VALID_POCKETS = ["updates", "proposed", "staging"]
@ -928,8 +930,8 @@ class UbuntuCloudArchiveSourcePackage(PersonalPackageArchiveSourcePackage):
class _WebJSON:
def getHostUrl(self):
raise NotImplementedError(f"{self.__class__.__name__}.getHostUrl() is not implemented")
def getHostUrl(self): # pylint: disable=no-self-use
raise Exception("Not implemented")
def load(self, path=""):
reader = codecs.getreader("utf-8")

View File

@ -50,7 +50,7 @@ class UDTConfig:
"KEYID": None,
}
# Populated from the configuration files:
config: dict[str, str] = {}
config = {}
def __init__(self, no_conf=False, prefix=None):
self.no_conf = no_conf
@ -61,7 +61,7 @@ class UDTConfig:
self.config = self.parse_devscripts_config()
@staticmethod
def parse_devscripts_config() -> dict[str, str]:
def parse_devscripts_config():
"""Read the devscripts configuration files, and return the values as a
dictionary
"""

View File

@ -26,7 +26,6 @@ import logging
import os
import re
from copy import copy
from typing import Any
from urllib.error import URLError
from urllib.parse import urlparse
@ -140,7 +139,7 @@ class BaseWrapper(metaclass=MetaWrapper):
A base class from which other wrapper classes are derived.
"""
resource_type: str | tuple[str, str] = "" # it's a base class after all
resource_type: str = None # it's a base class after all
def __new__(cls, data):
if isinstance(data, str) and data.startswith(str(Launchpad._root_uri)):
@ -668,19 +667,20 @@ class Archive(BaseWrapper):
rversion = getattr(record, "binary_package_version", None)
else:
rversion = getattr(record, "source_package_version", None)
skipmsg = f"Skipping version {rversion}: "
if record.pocket not in pockets:
err_msg = f"pocket {record.pocket} not in ({','.join(pockets)})"
Logger.debug("Skipping version %s: %s", rversion, err_msg)
Logger.debug(skipmsg + err_msg)
continue
if record.status not in statuses:
err_msg = f"status {record.status} not in ({','.join(statuses)})"
Logger.debug("Skipping version %s: %s", rversion, err_msg)
Logger.debug(skipmsg + err_msg)
continue
release = wrapper(record)
if binary and archtag and archtag != release.arch:
err_msg = f"arch {release.arch} does not match requested arch {archtag}"
Logger.debug("Skipping version %s: %s", rversion, err_msg)
Logger.debug(skipmsg + err_msg)
continue
# results are ordered so first is latest
cache[index] = release
@ -1502,7 +1502,7 @@ class Packageset(BaseWrapper): # pylint: disable=too-few-public-methods
resource_type = "packageset"
_lp_packagesets = None
_source_sets: dict[tuple[str, str | None, bool], Any] = {}
_source_sets = {}
@classmethod
def setsIncludingSource(cls, sourcepackagename, distroseries=None, direct_inclusion=False):

View File

@ -471,7 +471,6 @@ class PullPkg:
uri,
)
vcscmd = ""
if vcs == "Bazaar":
vcscmd = " $ bzr branch " + uri
elif vcs == "Git":

View File

@ -62,17 +62,8 @@ def get_debian_srcpkg(name, release):
return DebianSourcePackage(package=name, series=release).lp_spph
def get_ubuntu_srcpkg(name, release, pocket="Proposed"):
srcpkg = UbuntuSourcePackage(package=name, series=release, pocket=pocket)
try:
return srcpkg.lp_spph
except PackageNotFoundException:
if pocket != "Release":
parent_pocket = "Release"
if pocket == "Updates":
parent_pocket = "Proposed"
return get_ubuntu_srcpkg(name, release, parent_pocket)
raise
def get_ubuntu_srcpkg(name, release):
return UbuntuSourcePackage(package=name, series=release).lp_spph
def need_sponsorship(name, component, release):

View File

@ -16,7 +16,6 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import sys
from typing import NoReturn
from ubuntutools.question import Question, YesNoQuestion
@ -43,7 +42,7 @@ def ask_for_manual_fixing():
user_abort()
def user_abort() -> NoReturn:
def user_abort():
"""Print abort and quit the program."""
print("User abort.")

View File

@ -17,7 +17,6 @@
import logging
import os
import pathlib
import re
import subprocess
import sys
@ -408,16 +407,22 @@ class SourcePackage:
return True
def _run_lintian(self) -> str:
def _run_lintian(self):
"""Runs lintian on either the source or binary changes file.
Returns the filename of the created lintian output file.
"""
# Determine whether to use the source or binary build for lintian
package_and_version = f"{self._package}_{strip_epoch(self._version)}"
if self._build_log:
build_changes = f"{package_and_version}_{self._builder.get_architecture()}.changes"
build_changes = (
self._package
+ "_"
+ strip_epoch(self._version)
+ "_"
+ self._builder.get_architecture()
+ ".changes"
)
changes_for_lintian = os.path.join(self._buildresult, build_changes)
else:
changes_for_lintian = self._changes_file
@ -425,12 +430,18 @@ class SourcePackage:
# Check lintian
assert os.path.isfile(changes_for_lintian), f"{changes_for_lintian} does not exist."
cmd = ["lintian", "-IE", "--pedantic", "-q", "--profile", "ubuntu", changes_for_lintian]
lintian_file = pathlib.Path(self._workdir) / f"{package_and_version}.lintian"
Logger.debug("%s > %s", " ".join(cmd), lintian_file)
with lintian_file.open("wb") as outfile:
subprocess.run(cmd, stdout=outfile, check=True)
lintian_filename = os.path.join(
self._workdir, self._package + "_" + strip_epoch(self._version) + ".lintian"
)
Logger.debug("%s > %s", " ".join(cmd), lintian_filename)
report = subprocess.check_output(cmd, encoding="utf-8")
return str(lintian_file)
# write lintian report file
lintian_file = open(lintian_filename, "w", encoding="utf-8")
lintian_file.writelines(report)
lintian_file.close()
return lintian_filename
def sync(self, upload, series, bug_number, requester):
"""Does a sync of the source package."""

View File

@ -46,9 +46,11 @@ def is_command_available(command, check_sbin=False):
def check_dependencies():
"Do we have all the commands we need for full functionality?"
missing = []
for cmd in ("patch", "quilt", "dput", "lintian"):
for cmd in ("patch", "bzr", "quilt", "dput", "lintian"):
if not is_command_available(cmd):
missing.append(cmd)
if not is_command_available("bzr-buildpackage"):
missing.append("bzr-builddeb")
if not any(
is_command_available(cmd, check_sbin=True) for cmd in ("pbuilder", "sbuild", "cowbuilder")
):
@ -210,14 +212,14 @@ def get_open_ubuntu_bug_task(launchpad, bug, branch=None):
sys.exit(1)
elif len(ubuntu_tasks) == 1:
task = ubuntu_tasks[0]
elif branch and branch[1] == "ubuntu":
if len(ubuntu_tasks) > 1 and branch and branch[1] == "ubuntu":
tasks = [t for t in ubuntu_tasks if t.get_series() == branch[2] and t.package == branch[3]]
if len(tasks) > 1:
# A bug targeted to the development series?
tasks = [t for t in tasks if t.series is not None]
assert len(tasks) == 1
task = tasks[0]
else:
elif len(ubuntu_tasks) > 1:
task_list = [t.get_short_info() for t in ubuntu_tasks]
Logger.debug(
"%i Ubuntu tasks exist for bug #%i.\n%s",

View File

@ -60,7 +60,7 @@ class ExamplePackage:
with tempfile.TemporaryDirectory() as tmpdir:
self._create(Path(tmpdir))
def _create(self, directory: Path) -> None:
def _create(self, directory: Path):
pkgdir = directory / self.dirname
pkgdir.mkdir()
(pkgdir / self.content_filename).write_text(self.content_text)

View File

@ -28,7 +28,6 @@ class BinaryTests(unittest.TestCase):
def test_keyring_installed(self):
"""Smoke test for required lp api dependencies"""
try:
# pylint: disable-next=import-outside-toplevel,unused-import
import keyring # noqa: F401
except ModuleNotFoundError as error:
raise ModuleNotFoundError("package python3-keyring is not installed") from error
except ModuleNotFoundError:
raise ModuleNotFoundError("package python3-keyring is not installed")

View File

@ -12,7 +12,7 @@
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
"""Tests for running_autopkgtests
""" Tests for running_autopkgtests
Tests using cached data from autopkgtest servers.
These tests only ensure code changes don't change parsing behavior