← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:no-such-snap-base-oops into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:no-such-snap-base-oops into launchpad:master.

Commit message:
SnapRequestBuildsJob: make NoSuchSnapBase not OOPS

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/382100

This happens sometimes when people make a typo in the "base" field in snapcraft.yaml, and it should be treated as a user error rather than OOPSing.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:no-such-snap-base-oops into launchpad:master.
diff --git a/lib/lp/snappy/model/snapjob.py b/lib/lp/snappy/model/snapjob.py
index 719e94a..367450f 100644
--- a/lib/lp/snappy/model/snapjob.py
+++ b/lib/lp/snappy/model/snapjob.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2019 Canonical Ltd.  This software is licensed under the
+# Copyright 2018-2020 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Snap package jobs."""
@@ -59,6 +59,7 @@ from lp.snappy.interfaces.snap import (
     CannotParseSnapcraftYaml,
     MissingSnapcraftYaml,
     )
+from lp.snappy.interfaces.snapbase import NoSuchSnapBase
 from lp.snappy.interfaces.snapjob import (
     ISnapJob,
     ISnapRequestBuildsJob,
@@ -176,7 +177,11 @@ class SnapRequestBuildsJob(SnapJobDerived):
 
     class_job_type = SnapJobType.REQUEST_BUILDS
 
-    user_error_types = (CannotParseSnapcraftYaml, MissingSnapcraftYaml)
+    user_error_types = (
+        CannotParseSnapcraftYaml,
+        MissingSnapcraftYaml,
+        NoSuchSnapBase,
+        )
     retry_error_types = (CannotFetchSnapcraftYaml,)
 
     max_retries = 5
diff --git a/lib/lp/snappy/tests/test_snapjob.py b/lib/lp/snappy/tests/test_snapjob.py
index a61f276..00130b5 100644
--- a/lib/lp/snappy/tests/test_snapjob.py
+++ b/lib/lp/snappy/tests/test_snapjob.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2019 Canonical Ltd.  This software is licensed under the
+# Copyright 2018-2020 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for snap package jobs."""
@@ -209,3 +209,37 @@ class TestSnapRequestBuildsJob(TestCaseWithFactory):
                 GreaterThan(expected_date_created), LessThan(now)),
             error_message=Equals("Nonsense on stilts"),
             builds=AfterPreprocessing(set, MatchesSetwise())))
+
+    def test_run_failed_no_such_snap_base(self):
+        # A run where the snap base does not exist sets the job status to
+        # FAILED and records the error message.
+        [git_ref] = self.factory.makeGitRefs()
+        snap = self.factory.makeSnap(git_ref=git_ref)
+        expected_date_created = get_transaction_timestamp(IStore(snap))
+        job = SnapRequestBuildsJob.create(
+            snap, snap.registrant, snap.distro_series.main_archive,
+            PackagePublishingPocket.RELEASE, None)
+        snapcraft_yaml = "base: nonexistent\n"
+        self.useFixture(GitHostingFixture(blob=snapcraft_yaml))
+        with dbuser(config.ISnapRequestBuildsJobSource.dbuser):
+            JobRunner([job]).runAll()
+        now = get_transaction_timestamp(IStore(snap))
+        [notification] = self.assertEmailQueueLength(1)
+        self.assertThat(dict(notification), ContainsDict({
+            "From": Equals(config.canonical.noreply_from_address),
+            "To": Equals(format_address_for_person(snap.registrant)),
+            "Subject": Equals(
+                "Launchpad error while requesting builds of %s" % snap.name),
+            }))
+        self.assertEqual(
+            "Launchpad encountered an error during the following operation: "
+            "requesting builds of %s.  No such base: "
+            "'nonexistent'." % snap.name,
+            notification.get_payload(decode=True))
+        self.assertThat(job, MatchesStructure(
+            job=MatchesStructure.byEquality(status=JobStatus.FAILED),
+            date_created=Equals(expected_date_created),
+            date_finished=MatchesAll(
+                GreaterThan(expected_date_created), LessThan(now)),
+            error_message=Equals("No such base: 'nonexistent'."),
+            builds=AfterPreprocessing(set, MatchesSetwise())))