Merge lp:~cjwatson/launchpad/snap-pending-import into lp:launchpad

Proposed by Colin Watson on 2016-11-21
Status: Needs review
Proposed branch: lp:~cjwatson/launchpad/snap-pending-import
Merge into: lp:launchpad
Diff against target: 140 lines (+97/-0)
2 files modified
lib/lp/snappy/model/snapbuild.py (+25/-0)
lib/lp/snappy/tests/test_snapbuild.py (+72/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/snap-pending-import
Reviewer Review Type Date Requested Status
Launchpad code reviewers 2016-11-21 Pending
Review via email: mp+311391@code.launchpad.net

Commit message

Don't dispatch SnapBuilds whose code object is empty, perhaps because an associated code import hasn't finished.

Description of the change

This should make it easier to create a code import, a snap, and some builds in quick succession (via automation) without needing to worry about whether the builds will be dispatched before the import has completed.

To post a comment you must log in.
William Grant (wgrant) wrote :

This seems risky. The set of snap builds that have to be considered in each dispatch will grow without bound as imports fail or refs to non-commits attempt to be built. I suppose we could just have graphs of that and check them occasionally.

Unmerged revisions

18280. By Colin Watson on 2016-11-21

Don't dispatch SnapBuilds whose code object is empty, perhaps because an associated code import hasn't finished.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/snappy/model/snapbuild.py'
--- lib/lp/snappy/model/snapbuild.py 2016-08-16 16:24:51 +0000
+++ lib/lp/snappy/model/snapbuild.py 2016-11-21 14:12:14 +0000
@@ -48,6 +48,7 @@
48 IMasterStore,48 IMasterStore,
49 IStore,49 IStore,
50 )50 )
51from lp.services.database.sqlbase import sqlvalues
51from lp.services.job.interfaces.job import JobStatus52from lp.services.job.interfaces.job import JobStatus
52from lp.services.job.model.job import Job53from lp.services.job.model.job import Job
53from lp.services.librarian.browser import ProxiedLibraryFileAlias54from lp.services.librarian.browser import ProxiedLibraryFileAlias
@@ -469,3 +470,27 @@
469 SnapBuild, SnapBuild.build_farm_job_id.is_in(470 SnapBuild, SnapBuild.build_farm_job_id.is_in(
470 bfj.id for bfj in build_farm_jobs))471 bfj.id for bfj in build_farm_jobs))
471 return DecoratedResultSet(rows, pre_iter_hook=self.preloadBuildsData)472 return DecoratedResultSet(rows, pre_iter_hook=self.preloadBuildsData)
473
474 def addCandidateSelectionCriteria(self, processor, virtualized):
475 """See `ISpecificBuildFarmJobSource`."""
476 return """
477 SELECT 1 FROM Snap, SnapBuild
478 WHERE
479 SnapBuild.build_farm_job = BuildQueue.build_farm_job AND
480 SnapBuild.snap = Snap.id AND
481 ((Snap.branch IS NOT NULL AND
482 EXISTS (
483 SELECT 1 FROM Branch
484 WHERE
485 Branch.id = Snap.branch AND
486 Branch.revision_count != 0))
487 OR
488 (Snap.git_repository IS NOT NULL AND
489 EXISTS (
490 SELECT 1 FROM GitRef
491 WHERE
492 GitRef.repository = Snap.git_repository AND
493 GitRef.path = Snap.git_path AND
494 GitRef.commit_message IS NOT NULL))) AND
495 SnapBuild.status = %s
496 """ % sqlvalues(BuildStatus.NEEDSBUILD)
472497
=== modified file 'lib/lp/snappy/tests/test_snapbuild.py'
--- lib/lp/snappy/tests/test_snapbuild.py 2016-08-16 16:24:51 +0000
+++ lib/lp/snappy/tests/test_snapbuild.py 2016-11-21 14:12:14 +0000
@@ -15,6 +15,10 @@
15 )15 )
1616
17import pytz17import pytz
18from testscenarios import (
19 load_tests_apply_scenarios,
20 WithScenarios,
21 )
18from testtools.matchers import (22from testtools.matchers import (
19 Equals,23 Equals,
20 MatchesDict,24 MatchesDict,
@@ -29,6 +33,8 @@
29from lp.buildmaster.interfaces.buildqueue import IBuildQueue33from lp.buildmaster.interfaces.buildqueue import IBuildQueue
30from lp.buildmaster.interfaces.packagebuild import IPackageBuild34from lp.buildmaster.interfaces.packagebuild import IPackageBuild
31from lp.buildmaster.interfaces.processor import IProcessorSet35from lp.buildmaster.interfaces.processor import IProcessorSet
36from lp.buildmaster.tests.mock_slaves import make_publisher
37from lp.code.interfaces.revision import IRevisionSet
32from lp.registry.enums import PersonVisibility38from lp.registry.enums import PersonVisibility
33from lp.services.config import config39from lp.services.config import config
34from lp.services.features.testing import FeatureFixture40from lp.services.features.testing import FeatureFixture
@@ -466,6 +472,69 @@
466 [], getUtility(ISnapBuildSet).getByBuildFarmJobs([]))472 [], getUtility(ISnapBuildSet).getByBuildFarmJobs([]))
467473
468474
475class TestSnapBuildFindBuildCandidate(WithScenarios, TestCaseWithFactory):
476
477 layer = LaunchpadZopelessLayer
478
479 scenarios = [
480 ("Branch", {"context_type": "branch"}),
481 ("GitRef", {"context_type": "gitref"}),
482 ]
483
484 def setUp(self):
485 super(TestSnapBuildFindBuildCandidate, self).setUp()
486 self.publisher = make_publisher()
487 self.publisher.prepareBreezyAutotest()
488 self.builder = self.factory.makeBuilder(
489 processors=[self.publisher.breezy_autotest_i386.processor],
490 virtualized=True)
491
492 def makeSnap(self, with_revisions=True):
493 if self.context_type == "branch":
494 branch = self.factory.makeBranch()
495 if with_revisions:
496 self.factory.makeRevisionsForBranch(branch)
497 return self.factory.makeSnap(branch=branch)
498 elif self.context_type == "gitref":
499 [ref] = self.factory.makeGitRefs()
500 if with_revisions:
501 person = self.factory.makePerson()
502 email = removeSecurityProxy(person).preferredemail.email
503 author = getUtility(IRevisionSet).acquireRevisionAuthors(
504 [email])[email]
505 now = datetime.now(pytz.UTC)
506 naked_ref = removeSecurityProxy(ref)
507 naked_ref.author = naked_ref.committer = author
508 naked_ref.author_date = naked_ref.committer_date = now
509 naked_ref.commit_message = u"something"
510 return self.factory.makeSnap(git_ref=ref)
511 else:
512 raise AssertionError("unknown context_type %s" % self.context_type)
513
514 def test_findBuildCandidate_ready(self):
515 # Builder._findBuildCandidate finds a SnapBuild with a usable code
516 # object.
517 snap = self.makeSnap()
518 build = self.factory.makeSnapBuild(
519 snap=snap, distroarchseries=self.publisher.breezy_autotest_i386)
520 build.queueBuild()
521 next_job = removeSecurityProxy(self.builder)._findBuildCandidate()
522 self.assertEqual(
523 build,
524 getUtility(ISnapBuildSet).getByBuildFarmJob(
525 removeSecurityProxy(next_job)._build_farm_job))
526
527 def test_findBuildCandidate_no_revisions(self):
528 # Builder._findBuildCandidate skips SnapBuilds without a usable code
529 # object, such as an imported branch whose import hasn't run yet.
530 snap = self.makeSnap(with_revisions=False)
531 build = self.factory.makeSnapBuild(
532 snap=snap, distroarchseries=self.publisher.breezy_autotest_i386)
533 build.queueBuild()
534 self.assertIsNone(
535 removeSecurityProxy(self.builder)._findBuildCandidate())
536
537
469class TestSnapBuildWebservice(TestCaseWithFactory):538class TestSnapBuildWebservice(TestCaseWithFactory):
470539
471 layer = LaunchpadFunctionalLayer540 layer = LaunchpadFunctionalLayer
@@ -621,3 +690,6 @@
621 browser = self.getNonRedirectingBrowser(user=self.person)690 browser = self.getNonRedirectingBrowser(user=self.person)
622 for file_url in file_urls:691 for file_url in file_urls:
623 self.assertCanOpenRedirectedUrl(browser, file_url)692 self.assertCanOpenRedirectedUrl(browser, file_url)
693
694
695load_tests = load_tests_apply_scenarios