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

Proposed by Colin Watson on 2016-11-21
Status: Rejected
Rejected by: Colin Watson on 2019-07-30
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.

Colin Watson (cjwatson) wrote :

I'm withdrawing this since I have no current plans to work on the problem William raised, and the code import workflow has been mostly superseded for automation purposes these days by building directly from external repositories instead.

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