launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #21798
[Merge] lp:~cjwatson/launchpad-buildd/build-snap-operation into lp:launchpad-buildd
Colin Watson has proposed merging lp:~cjwatson/launchpad-buildd/build-snap-operation into lp:launchpad-buildd with lp:~cjwatson/launchpad-buildd/build-livefs-operation as a prerequisite.
Commit message:
Convert buildsnap to the new Operation framework and add unit tests.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad-buildd/build-snap-operation/+merge/328659
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad-buildd/build-snap-operation into lp:launchpad-buildd.
=== added file 'bin/buildsnap'
--- bin/buildsnap 1970-01-01 00:00:00 +0000
+++ bin/buildsnap 2017-08-07 11:46:50 +0000
@@ -0,0 +1,25 @@
+#! /usr/bin/python -u
+#
+# Copyright 2015-2017 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Build a snap."""
+
+from __future__ import print_function
+
+__metaclass__ = type
+
+import os.path
+import sys
+
+from lpbuildd.target.build_snap import BuildSnap
+from lpbuildd.target.operation import configure_logging
+
+
+def main():
+ configure_logging()
+ return BuildSnap(os.path.dirname(__file__)).run()
+
+
+if __name__ == "__main__":
+ sys.exit(main())
=== modified file 'debian/changelog'
--- debian/changelog 2017-08-07 11:46:50 +0000
+++ debian/changelog 2017-08-07 11:46:50 +0000
@@ -21,6 +21,7 @@
unit tests.
* Rewrite scan-for-processes in Python, allowing it to have unit tests.
* Convert buildlivefs to the new Operation framework and add unit tests.
+ * Convert buildsnap to the new Operation framework and add unit tests.
-- Colin Watson <cjwatson@xxxxxxxxxx> Tue, 25 Jul 2017 23:07:58 +0100
=== modified file 'lpbuildd/snap.py'
--- lpbuildd/snap.py 2017-08-07 11:46:50 +0000
+++ lpbuildd/snap.py 2017-08-07 11:46:50 +0000
@@ -64,11 +64,7 @@
def doRunBuild(self):
"""Run the process to build the snap."""
- args = [
- "buildsnap",
- "--build-id", self._buildid,
- "--arch", self.arch_tag,
- ]
+ args = ["buildsnap"]
if self.proxy_url:
args.extend(["--proxy-url", self.proxy_url])
if self.revocation_endpoint:
@@ -80,7 +76,7 @@
if self.git_path is not None:
args.extend(["--git-path", self.git_path])
args.append(self.name)
- self.runSubProcess(self.build_snap_path, args)
+ self.runTargetSubProcess(self.build_snap_path, args)
def iterate_BUILD_SNAP(self, retcode):
"""Finished building the snap."""
=== renamed file 'bin/buildsnap' => 'lpbuildd/target/build_snap.py' (properties changed: +x to -x)
--- bin/buildsnap 2017-07-28 11:15:51 +0000
+++ lpbuildd/target/build_snap.py 2017-08-07 11:46:50 +0000
@@ -1,103 +1,94 @@
-#! /usr/bin/python -u
# Copyright 2015-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
-"""A script that builds a snap."""
-
from __future__ import print_function
__metaclass__ = type
import base64
+from collections import OrderedDict
import json
-from optparse import OptionParser
-import os
+import logging
+import os.path
import subprocess
-import sys
-import traceback
import urllib2
from urlparse import urlparse
-from lpbuildd.util import (
- set_personality,
- shell_escape,
- )
-
-
-RETCODE_SUCCESS = 0
+from lpbuildd.target.operation import Operation
+from lpbuildd.util import shell_escape
+
+
RETCODE_FAILURE_INSTALL = 200
RETCODE_FAILURE_BUILD = 201
-def get_build_path(build_id, *extra):
- """Generate a path within the build directory.
-
- :param build_id: the build id to use.
- :param extra: the extra path segments within the build directory.
- :return: the generated path.
- """
- return os.path.join(os.environ["HOME"], "build-" + build_id, *extra)
-
-
-class SnapBuilder:
- """Builds a snap."""
-
- def __init__(self, options, name):
- self.options = options
- self.name = name
- self.chroot_path = get_build_path(
- self.options.build_id, 'chroot-autobuild')
- # Set to False for local testing if your chroot doesn't have an
+logger = logging.getLogger(__name__)
+
+
+class BuildSnap(Operation):
+
+ description = "Build a snap."
+
+ def __init__(self, slavebin, args=None):
+ super(BuildSnap, self).__init__(args=args)
+ self.slavebin = slavebin
+ # Set to False for local testing if your target doesn't have an
# appropriate certificate for your codehosting system.
self.ssl_verify = True
- def chroot(self, args, echo=False, get_output=False):
- """Run a command in the chroot.
-
- :param args: the command and arguments to run.
- :param echo: if True, print the command before executing it.
- :param get_output: if True, return the output from the command.
- """
- args = set_personality(args, self.options.arch)
- if echo:
- print(
- "Running in chroot: %s" % ' '.join(
- "'%s'" % arg for arg in args))
- sys.stdout.flush()
- cmd = ["/usr/bin/sudo", "/usr/sbin/chroot", self.chroot_path] + args
- if get_output:
- return subprocess.check_output(cmd, universal_newlines=True)
- else:
- subprocess.check_call(cmd)
-
- def run_build_command(self, args, path="/build", env=None, echo=False,
- get_output=False):
- """Run a build command in the chroot.
-
- This is unpleasant because we need to run it in /build under sudo
- chroot, and there's no way to do this without either a helper
- program in the chroot or unpleasant quoting. We go for the
+ def make_parser(self):
+ parser = super(BuildSnap, self).make_parser()
+ build_from_group = parser.add_mutually_exclusive_group(required=True)
+ build_from_group.add_argument(
+ "--branch", metavar="BRANCH", help="build from this Bazaar branch")
+ build_from_group.add_argument(
+ "--git-repository", metavar="REPOSITORY",
+ help="build from this Git repository")
+ parser.add_argument(
+ "--git-path", metavar="REF-PATH",
+ help="build from this ref path in REPOSITORY")
+ parser.add_argument("--proxy-url", help="builder proxy url")
+ parser.add_argument(
+ "--revocation-endpoint",
+ help="builder proxy token revocation endpoint")
+ parser.add_argument("name", help="name of snap to build")
+ return parser
+
+ def parse_args(self, args=None):
+ parser = self.make_parser()
+ parsed_args = parser.parse_args(args=args)
+ if (parsed_args.git_repository is None and
+ parsed_args.git_path is not None):
+ parser.error("--git-path requires --git-repository")
+ self.args = parsed_args
+
+ def run_build_command(self, args, path="/build", env=None,
+ get_output=False, echo=False):
+ """Run a build command in the target.
+
+ This is unpleasant because we need to run it with /build as the
+ working directory, and there's no way to do this without either a
+ helper program in the target or unpleasant quoting. We go for the
unpleasant quoting.
:param args: the command and arguments to run.
- :param path: the working directory to use in the chroot.
+ :param path: the working directory to use in the target.
:param env: dictionary of additional environment variables to set.
+ :param get_output: if True, return the output from the command.
:param echo: if True, print the command before executing it.
- :param get_output: if True, return the output from the command.
"""
args = [shell_escape(arg) for arg in args]
path = shell_escape(path)
- full_env = {
- "LANG": "C.UTF-8",
- }
+ full_env = OrderedDict()
+ full_env["LANG"] = "C.UTF-8"
if env:
full_env.update(env)
args = ["env"] + [
"%s=%s" % (key, shell_escape(value))
for key, value in full_env.items()] + args
command = "cd %s && %s" % (path, " ".join(args))
- return self.chroot(
- ["/bin/sh", "-c", command], echo=echo, get_output=get_output)
+ return self.backend.run(
+ ["/bin/sh", "-c", command], get_output=get_output, echo=echo)
def save_status(self, status):
"""Save a dictionary of status information about this build.
@@ -105,161 +96,129 @@
This will be picked up by the build manager and included in XML-RPC
status responses.
"""
- status_path = get_build_path(self.options.build_id, "status")
+ status_path = os.path.join(self.backend.build_path, "status")
with open("%s.tmp" % status_path, "w") as status_file:
json.dump(status, status_file)
os.rename("%s.tmp" % status_path, status_path)
def install(self):
- print("Running install phase...")
+ logger.info("Running install phase...")
deps = ["snapcraft"]
- if self.options.branch is not None:
+ if self.args.branch is not None:
deps.append("bzr")
else:
deps.append("git")
- if self.options.proxy_url:
+ if self.args.proxy_url:
deps.extend(["python3", "socat"])
- self.chroot(["apt-get", "-y", "install"] + deps)
- if self.options.proxy_url:
- subprocess.check_call([
- "sudo", "cp", "-a",
- os.path.join(os.path.dirname(__file__), "snap-git-proxy"),
- os.path.join(
- self.chroot_path, "usr", "local", "bin", "snap-git-proxy"),
- ])
+ self.backend.run(["apt-get", "-y", "install"] + deps)
+ if self.args.proxy_url:
+ self.backend.copy_in(
+ os.path.join(self.slavebin, "snap-git-proxy"),
+ "/usr/local/bin/snap-git-proxy")
def repo(self):
"""Collect git or bzr branch."""
- print("Running repo phase...")
- env = {}
- if self.options.proxy_url:
- env["http_proxy"] = self.options.proxy_url
- env["https_proxy"] = self.options.proxy_url
+ logger.info("Running repo phase...")
+ env = OrderedDict()
+ if self.args.proxy_url:
+ env["http_proxy"] = self.args.proxy_url
+ env["https_proxy"] = self.args.proxy_url
env["GIT_PROXY_COMMAND"] = "/usr/local/bin/snap-git-proxy"
- if self.options.branch is not None:
+ if self.args.branch is not None:
self.run_build_command(['ls', '/build'])
- cmd = ["bzr", "branch", self.options.branch, self.name]
+ cmd = ["bzr", "branch", self.args.branch, self.args.name]
if not self.ssl_verify:
cmd.insert(1, "-Ossl.cert_reqs=none")
else:
- assert self.options.git_repository is not None
+ assert self.args.git_repository is not None
cmd = ["git", "clone"]
- if self.options.git_path is not None:
- cmd.extend(["-b", self.options.git_path])
- cmd.extend([self.options.git_repository, self.name])
+ if self.args.git_path is not None:
+ cmd.extend(["-b", self.args.git_path])
+ cmd.extend([self.args.git_repository, self.args.name])
if not self.ssl_verify:
env["GIT_SSL_NO_VERIFY"] = "1"
self.run_build_command(cmd, env=env)
- if self.options.git_repository is not None:
+ if self.args.git_repository is not None:
try:
self.run_build_command(
- ["git", "-C", self.name,
+ ["git", "-C", self.args.name,
"submodule", "update", "--init", "--recursive"],
env=env)
except subprocess.CalledProcessError as e:
- print(
+ logger.error(
"'git submodule update --init --recursive failed with "
"exit code %s (build may fail later)" % e.returncode)
status = {}
- if self.options.branch is not None:
+ if self.args.branch is not None:
status["revision_id"] = self.run_build_command(
- ["bzr", "revno", self.name], get_output=True).rstrip("\n")
+ ["bzr", "revno", self.args.name],
+ get_output=True).rstrip("\n")
else:
rev = (
- self.options.git_path
- if self.options.git_path is not None else "HEAD")
+ self.args.git_path
+ if self.args.git_path is not None else "HEAD")
status["revision_id"] = self.run_build_command(
- ["git", "-C", self.name, "rev-parse", rev],
+ ["git", "-C", self.args.name, "rev-parse", rev],
get_output=True).rstrip("\n")
self.save_status(status)
def pull(self):
"""Run pull phase."""
- print("Running pull phase...")
- env = {
- "SNAPCRAFT_LOCAL_SOURCES": "1",
- "SNAPCRAFT_SETUP_CORE": "1",
- }
- if self.options.proxy_url:
- env["http_proxy"] = self.options.proxy_url
- env["https_proxy"] = self.options.proxy_url
+ logger.info("Running pull phase...")
+ env = OrderedDict()
+ env["SNAPCRAFT_LOCAL_SOURCES"] = "1"
+ env["SNAPCRAFT_SETUP_CORE"] = "1"
+ if self.args.proxy_url:
+ env["http_proxy"] = self.args.proxy_url
+ env["https_proxy"] = self.args.proxy_url
env["GIT_PROXY_COMMAND"] = "/usr/local/bin/snap-git-proxy"
self.run_build_command(
["snapcraft", "pull"],
- path=os.path.join("/build", self.name),
+ path=os.path.join("/build", self.args.name),
env=env)
def build(self):
"""Run all build, stage and snap phases."""
- print("Running build phase...")
- env = {}
- if self.options.proxy_url:
- env["http_proxy"] = self.options.proxy_url
- env["https_proxy"] = self.options.proxy_url
+ logger.info("Running build phase...")
+ env = OrderedDict()
+ if self.args.proxy_url:
+ env["http_proxy"] = self.args.proxy_url
+ env["https_proxy"] = self.args.proxy_url
env["GIT_PROXY_COMMAND"] = "/usr/local/bin/snap-git-proxy"
self.run_build_command(
- ["snapcraft"], path=os.path.join("/build", self.name), env=env)
+ ["snapcraft"],
+ path=os.path.join("/build", self.args.name),
+ env=env)
def revoke_token(self):
"""Revoke builder proxy token."""
- print("Revoking proxy token...")
- url = urlparse(self.options.proxy_url)
+ logger.info("Revoking proxy token...")
+ url = urlparse(self.args.proxy_url)
auth = '{}:{}'.format(url.username, url.password)
headers = {
'Authorization': 'Basic {}'.format(base64.b64encode(auth))
}
- req = urllib2.Request(self.options.revocation_endpoint, None, headers)
+ req = urllib2.Request(self.args.revocation_endpoint, None, headers)
req.get_method = lambda: 'DELETE'
try:
urllib2.urlopen(req)
- except (urllib2.HTTPError, urllib2.URLError) as e:
- print('Unable to revoke token for %s: %s' % (url.username, e))
-
-
-def main():
- parser = OptionParser("%prog [options] NAME")
- parser.add_option("--build-id", help="build identifier")
- parser.add_option(
- "--arch", metavar="ARCH", help="build for architecture ARCH")
- parser.add_option(
- "--branch", metavar="BRANCH", help="build from this Bazaar branch")
- parser.add_option(
- "--git-repository", metavar="REPOSITORY",
- help="build from this Git repository")
- parser.add_option(
- "--git-path", metavar="REF-PATH",
- help="build from this ref path in REPOSITORY")
- parser.add_option("--proxy-url", help="builder proxy url")
- parser.add_option("--revocation-endpoint",
- help="builder proxy token revocation endpoint")
- options, args = parser.parse_args()
- if options.git_repository is None and options.git_path is not None:
- parser.error("--git-path requires --git-repository")
- if (options.branch is None) == (options.git_repository is None):
- parser.error(
- "must provide exactly one of --branch and --git-repository")
- if len(args) != 1:
- parser.error(
- "must provide a package name and no other positional arguments")
- [name] = args
- builder = SnapBuilder(options, name)
- try:
- builder.install()
- except Exception:
- traceback.print_exc()
- return RETCODE_FAILURE_INSTALL
- try:
- builder.repo()
- builder.pull()
- builder.build()
- except Exception:
- traceback.print_exc()
- return RETCODE_FAILURE_BUILD
- finally:
- if options.revocation_endpoint is not None:
- builder.revoke_token()
- return RETCODE_SUCCESS
-
-
-if __name__ == "__main__":
- sys.exit(main())
+ except (urllib2.HTTPError, urllib2.URLError):
+ logger.exception('Unable to revoke token for %s', url.username)
+
+ def run(self):
+ try:
+ self.install()
+ except Exception:
+ logger.exception('Install failed')
+ return RETCODE_FAILURE_INSTALL
+ try:
+ self.repo()
+ self.pull()
+ self.build()
+ except Exception:
+ logger.exception('Build failed')
+ return RETCODE_FAILURE_BUILD
+ finally:
+ if self.args.revocation_endpoint is not None:
+ self.revoke_token()
+ return 0
=== modified file 'lpbuildd/target/tests/test_build_livefs.py'
--- lpbuildd/target/tests/test_build_livefs.py 2017-08-07 11:46:50 +0000
+++ lpbuildd/target/tests/test_build_livefs.py 2017-08-07 11:46:50 +0000
@@ -5,6 +5,7 @@
import subprocess
+from fixtures import FakeLogger
from testtools import TestCase
from testtools.matchers import (
AnyMatch,
@@ -151,6 +152,7 @@
if run_args[0] == "apt-get":
raise subprocess.CalledProcessError(1, run_args)
+ self.useFixture(FakeLogger())
args = [
"--backend=fake", "--series=xenial", "--arch=amd64", "1",
"--project=ubuntu",
@@ -166,6 +168,7 @@
if run_args[0] == "/bin/sh":
raise subprocess.CalledProcessError(1, run_args)
+ self.useFixture(FakeLogger())
args = [
"--backend=fake", "--series=xenial", "--arch=amd64", "1",
"--project=ubuntu",
=== added file 'lpbuildd/target/tests/test_build_snap.py'
--- lpbuildd/target/tests/test_build_snap.py 1970-01-01 00:00:00 +0000
+++ lpbuildd/target/tests/test_build_snap.py 2017-08-07 11:46:50 +0000
@@ -0,0 +1,392 @@
+# Copyright 2017 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+__metaclass__ = type
+
+import json
+import os.path
+import stat
+import subprocess
+
+from fixtures import (
+ FakeLogger,
+ TempDir,
+ )
+from systemfixtures import FakeFilesystem
+from testtools import TestCase
+from testtools.matchers import (
+ AnyMatch,
+ Equals,
+ Is,
+ MatchesAll,
+ MatchesDict,
+ MatchesListwise,
+ )
+
+from lpbuildd.target.build_snap import (
+ BuildSnap,
+ RETCODE_FAILURE_BUILD,
+ RETCODE_FAILURE_INSTALL,
+ )
+from lpbuildd.tests.fakeslave import FakeMethod
+
+
+class RanCommand(MatchesListwise):
+
+ def __init__(self, args, get_output=None, echo=None, **env):
+ kwargs_matcher = {}
+ if get_output is not None:
+ kwargs_matcher["get_output"] = Is(get_output)
+ if echo is not None:
+ kwargs_matcher["echo"] = Is(echo)
+ if env:
+ kwargs_matcher["env"] = MatchesDict(env)
+ super(RanCommand, self).__init__(
+ [Equals((args,)), MatchesDict(kwargs_matcher)])
+
+
+class RanAptGet(RanCommand):
+
+ def __init__(self, *args):
+ super(RanAptGet, self).__init__(["apt-get", "-y"] + list(args))
+
+
+class RanBuildCommand(RanCommand):
+
+ def __init__(self, command, path="/build", get_output=False):
+ super(RanBuildCommand, self).__init__(
+ ["/bin/sh", "-c", "cd %s && %s" % (path, command)],
+ get_output=get_output, echo=False)
+
+
+class FakeRevisionID(FakeMethod):
+
+ def __init__(self, revision_id):
+ super(FakeRevisionID, self).__init__()
+ self.revision_id = revision_id
+
+ def __call__(self, run_args, *args, **kwargs):
+ super(FakeRevisionID, self).__call__(run_args, *args, **kwargs)
+ if run_args[0] == "/bin/sh":
+ command = run_args[2]
+ if "bzr revno" in command or "rev-parse" in command:
+ return "%s\n" % self.revision_id
+
+
+class TestBuildSnap(TestCase):
+
+ def test_run_build_command_no_env(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.run_build_command(["echo", "hello world"])
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand("env LANG=C.UTF-8 echo 'hello world'"),
+ ]))
+
+ def test_run_build_command_env(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.run_build_command(
+ ["echo", "hello world"], env={"FOO": "bar baz"})
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(
+ "env LANG=C.UTF-8 FOO='bar baz' echo 'hello world'"),
+ ]))
+
+ def test_install_bzr(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap"
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.install()
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanAptGet("install", "snapcraft", "bzr"),
+ ]))
+
+ def test_install_git(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--git-repository", "lp:foo", "test-snap"
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.install()
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanAptGet("install", "snapcraft", "git"),
+ ]))
+
+ def test_install_proxy(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--git-repository", "lp:foo",
+ "--proxy-url", "http://proxy.example:3128/",
+ "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ self.useFixture(FakeFilesystem()).add("/slavebin")
+ os.mkdir("/slavebin")
+ with open("/slavebin/snap-git-proxy", "w") as proxy_script:
+ proxy_script.write("proxy script\n")
+ os.fchmod(proxy_script.fileno(), 0o755)
+ build_snap.install()
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanAptGet("install", "snapcraft", "git", "python3", "socat"),
+ ]))
+ self.assertEqual(
+ (b"proxy script\n", stat.S_IFREG | 0o755),
+ build_snap.backend.backend_fs["/usr/local/bin/snap-git-proxy"])
+
+ def test_repo_bzr(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.build_path = self.useFixture(TempDir()).path
+ build_snap.backend.run = FakeRevisionID("42")
+ build_snap.repo()
+ env = "env LANG=C.UTF-8 "
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(env + "ls /build"),
+ RanBuildCommand(env + "bzr branch lp:foo test-snap"),
+ RanBuildCommand(env + "bzr revno test-snap", get_output=True),
+ ]))
+ status_path = os.path.join(build_snap.backend.build_path, "status")
+ with open(status_path) as status:
+ self.assertEqual({"revision_id": "42"}, json.load(status))
+
+ def test_repo_git(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--git-repository", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.build_path = self.useFixture(TempDir()).path
+ build_snap.backend.run = FakeRevisionID("0" * 40)
+ build_snap.repo()
+ env = "env LANG=C.UTF-8 "
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(env + "git clone lp:foo test-snap"),
+ RanBuildCommand(
+ env + "git -C test-snap submodule update --init --recursive"),
+ RanBuildCommand(
+ env + "git -C test-snap rev-parse HEAD", get_output=True),
+ ]))
+ status_path = os.path.join(build_snap.backend.build_path, "status")
+ with open(status_path) as status:
+ self.assertEqual({"revision_id": "0" * 40}, json.load(status))
+
+ def test_repo_git_with_path(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--git-repository", "lp:foo", "--git-path", "next", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.build_path = self.useFixture(TempDir()).path
+ build_snap.backend.run = FakeRevisionID("0" * 40)
+ build_snap.repo()
+ env = "env LANG=C.UTF-8 "
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(env + "git clone -b next lp:foo test-snap"),
+ RanBuildCommand(
+ env + "git -C test-snap submodule update --init --recursive"),
+ RanBuildCommand(
+ env + "git -C test-snap rev-parse next", get_output=True),
+ ]))
+ status_path = os.path.join(build_snap.backend.build_path, "status")
+ with open(status_path) as status:
+ self.assertEqual({"revision_id": "0" * 40}, json.load(status))
+
+ def test_repo_proxy(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--git-repository", "lp:foo",
+ "--proxy-url", "http://proxy.example:3128/",
+ "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.build_path = self.useFixture(TempDir()).path
+ build_snap.backend.run = FakeRevisionID("0" * 40)
+ build_snap.repo()
+ env = (
+ "env LANG=C.UTF-8 http_proxy=http://proxy.example:3128/ "
+ "https_proxy=http://proxy.example:3128/ "
+ "GIT_PROXY_COMMAND=/usr/local/bin/snap-git-proxy ")
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(env + "git clone lp:foo test-snap"),
+ RanBuildCommand(
+ env + "git -C test-snap submodule update --init --recursive"),
+ RanBuildCommand(
+ "env LANG=C.UTF-8 git -C test-snap rev-parse HEAD",
+ get_output=True),
+ ]))
+ status_path = os.path.join(build_snap.backend.build_path, "status")
+ with open(status_path) as status:
+ self.assertEqual({"revision_id": "0" * 40}, json.load(status))
+
+ def test_pull(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.pull()
+ env = (
+ "env LANG=C.UTF-8 "
+ "SNAPCRAFT_LOCAL_SOURCES=1 SNAPCRAFT_SETUP_CORE=1 ")
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(env + "snapcraft pull", path="/build/test-snap"),
+ ]))
+
+ def test_pull_proxy(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "--proxy-url", "http://proxy.example:3128/",
+ "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.pull()
+ env = (
+ "env LANG=C.UTF-8 "
+ "SNAPCRAFT_LOCAL_SOURCES=1 SNAPCRAFT_SETUP_CORE=1 "
+ "http_proxy=http://proxy.example:3128/ "
+ "https_proxy=http://proxy.example:3128/ "
+ "GIT_PROXY_COMMAND=/usr/local/bin/snap-git-proxy ")
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(env + "snapcraft pull", path="/build/test-snap"),
+ ]))
+
+ def test_build(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.build()
+ env = "env LANG=C.UTF-8 "
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(env + "snapcraft", path="/build/test-snap"),
+ ]))
+
+ def test_build_proxy(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "--proxy-url", "http://proxy.example:3128/",
+ "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.build()
+ env = (
+ "env LANG=C.UTF-8 "
+ "http_proxy=http://proxy.example:3128/ "
+ "https_proxy=http://proxy.example:3128/ "
+ "GIT_PROXY_COMMAND=/usr/local/bin/snap-git-proxy ")
+ self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+ RanBuildCommand(env + "snapcraft", path="/build/test-snap"),
+ ]))
+
+ # XXX cjwatson 2017-08-07: Test revoke_token. It may be easiest to
+ # convert it to requests first.
+
+ def test_run_succeeds(self):
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.build_path = self.useFixture(TempDir()).path
+ build_snap.backend.run = FakeRevisionID("42")
+ self.assertEqual(0, build_snap.run())
+ self.assertThat(build_snap.backend.run.calls, MatchesAll(
+ AnyMatch(RanAptGet("install", "snapcraft", "bzr")),
+ AnyMatch(RanBuildCommand(
+ "env LANG=C.UTF-8 bzr branch lp:foo test-snap")),
+ AnyMatch(RanBuildCommand(
+ "env LANG=C.UTF-8 "
+ "SNAPCRAFT_LOCAL_SOURCES=1 SNAPCRAFT_SETUP_CORE=1 "
+ "snapcraft pull", path="/build/test-snap")),
+ AnyMatch(RanBuildCommand(
+ "env LANG=C.UTF-8 snapcraft", path="/build/test-snap")),
+ ))
+
+ def test_run_install_fails(self):
+ class FailInstall(FakeMethod):
+ def __call__(self, run_args, *args, **kwargs):
+ super(FailInstall, self).__call__(run_args, *args, **kwargs)
+ if run_args[0] == "apt-get":
+ raise subprocess.CalledProcessError(1, run_args)
+
+ self.useFixture(FakeLogger())
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.run = FailInstall()
+ self.assertEqual(RETCODE_FAILURE_INSTALL, build_snap.run())
+
+ def test_run_repo_fails(self):
+ class FailRepo(FakeMethod):
+ def __call__(self, run_args, *args, **kwargs):
+ super(FailRepo, self).__call__(run_args, *args, **kwargs)
+ if run_args[0] == "/bin/sh":
+ command = run_args[2]
+ if "bzr branch" in command:
+ raise subprocess.CalledProcessError(1, run_args)
+
+ self.useFixture(FakeLogger())
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.run = FailRepo()
+ self.assertEqual(RETCODE_FAILURE_BUILD, build_snap.run())
+
+ def test_run_pull_fails(self):
+ class FailPull(FakeMethod):
+ def __call__(self, run_args, *args, **kwargs):
+ super(FailPull, self).__call__(run_args, *args, **kwargs)
+ if run_args[0] == "/bin/sh":
+ command = run_args[2]
+ if "bzr revno" in command:
+ return "42\n"
+ elif "snapcraft pull" in command:
+ raise subprocess.CalledProcessError(1, run_args)
+
+ self.useFixture(FakeLogger())
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.build_path = self.useFixture(TempDir()).path
+ build_snap.backend.run = FailPull()
+ self.assertEqual(RETCODE_FAILURE_BUILD, build_snap.run())
+
+ def test_run_build_fails(self):
+ class FailBuild(FakeMethod):
+ def __call__(self, run_args, *args, **kwargs):
+ super(FailBuild, self).__call__(run_args, *args, **kwargs)
+ if run_args[0] == "/bin/sh":
+ command = run_args[2]
+ if "bzr revno" in command:
+ return "42\n"
+ elif command.endswith(" snapcraft"):
+ raise subprocess.CalledProcessError(1, run_args)
+
+ self.useFixture(FakeLogger())
+ args = [
+ "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+ "--branch", "lp:foo", "test-snap",
+ ]
+ build_snap = BuildSnap("/slavebin", args=args)
+ build_snap.backend.build_path = self.useFixture(TempDir()).path
+ build_snap.backend.run = FailBuild()
+ self.assertEqual(RETCODE_FAILURE_BUILD, build_snap.run())
=== modified file 'lpbuildd/tests/test_snap.py'
--- lpbuildd/tests/test_snap.py 2017-08-07 11:46:50 +0000
+++ lpbuildd/tests/test_snap.py 2017-08-07 11:46:50 +0000
@@ -76,7 +76,7 @@
self.assertEqual(SnapBuildState.BUILD_SNAP, self.getState())
expected_command = [
"sharepath/slavebin/buildsnap", "buildsnap",
- "--build-id", self.buildid, "--arch", "i386",
+ "--backend=chroot", "--series=xenial", "--arch=i386", self.buildid,
"--git-repository", "https://git.launchpad.dev/~example/+git/snap",
"--git-path", "master",
"test-snap",