Merge ~cjwatson/launchpad:cibuild-create-reports into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 5bb6484cc47d7b7bb286e163768c5c831faef25c
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:cibuild-create-reports
Merge into: launchpad:master
Diff against target: 198 lines (+72/-10)
3 files modified
lib/lp/archiveuploader/ciupload.py (+5/-4)
lib/lp/code/model/cibuild.py (+25/-4)
lib/lp/code/model/tests/test_cibuild.py (+42/-2)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+417037@code.launchpad.net

Commit message

Create RevisionStatusReports when requesting CIBuilds

Description of the change

This ensures that jobs that have been scheduled as part of these builds show up as pending in the web UI as soon as they're scheduled, rather than only becoming visible once the build completes and the resulting upload is processed.

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/archiveuploader/ciupload.py b/lib/lp/archiveuploader/ciupload.py
2index 6f8dea0..7cbd698 100644
3--- a/lib/lp/archiveuploader/ciupload.py
4+++ b/lib/lp/archiveuploader/ciupload.py
5@@ -61,10 +61,11 @@ class CIUpload:
6 report = getUtility(IRevisionStatusReportSet).getByCIBuildAndTitle(
7 build, job_name)
8 if not report:
9- # the report should normally exist, since the build request
10- # logic will eventually create report rows for the jobs it
11- # expects to run, but for robustness it's a good idea to
12- # ensure its existence here
13+ # The report should normally exist, since
14+ # lp.code.model.cibuild.CIBuildSet._tryToRequestBuild
15+ # creates report rows for the jobs it expects to run, but
16+ # for robustness it's a good idea to ensure its existence
17+ # here.
18 report = getUtility(IRevisionStatusReportSet).new(
19 creator=build.git_repository.owner,
20 title=job_name,
21diff --git a/lib/lp/code/model/cibuild.py b/lib/lp/code/model/cibuild.py
22index bdc570c..4da34fb 100644
23--- a/lib/lp/code/model/cibuild.py
24+++ b/lib/lp/code/model/cibuild.py
25@@ -49,6 +49,7 @@ from lp.code.interfaces.cibuild import (
26 MissingConfiguration,
27 )
28 from lp.code.interfaces.githosting import IGitHostingClient
29+from lp.code.interfaces.revisionstatus import IRevisionStatusReportSet
30 from lp.code.model.gitref import GitRef
31 from lp.code.model.lpcraft import load_configuration
32 from lp.registry.interfaces.pocket import PackagePublishingPocket
33@@ -427,14 +428,34 @@ class CIBuildSet(SpecificBuildFarmJobSourceMixin):
34 notify(ObjectCreatedEvent(build))
35 return build
36
37- def _tryToRequestBuild(self, git_repository, commit_sha1, das, logger):
38+ def _tryToRequestBuild(self, git_repository, commit_sha1, configuration,
39+ das, logger):
40 try:
41 if logger is not None:
42 logger.info(
43 "Requesting CI build for %s on %s/%s",
44 commit_sha1, das.distroseries.name, das.architecturetag,
45 )
46- self.requestBuild(git_repository, commit_sha1, das)
47+ build = self.requestBuild(git_repository, commit_sha1, das)
48+ # Create reports for each individual job in this build so that
49+ # they show up as pending in the web UI. The job names
50+ # generated here should match those generated by
51+ # lpbuildd.ci._make_job_id in launchpad-buildd;
52+ # lp.archiveuploader.ciupload looks for this report and attaches
53+ # artifacts to it.
54+ rsr_set = getUtility(IRevisionStatusReportSet)
55+ for stage in configuration.pipeline:
56+ for job_name in stage:
57+ for i in range(len(configuration.jobs.get(job_name, []))):
58+ # XXX cjwatson 2022-03-17: It would be better if we
59+ # could set some kind of meaningful description as
60+ # well.
61+ rsr_set.new(
62+ creator=git_repository.owner,
63+ title="%s:%s" % (job_name, i),
64+ git_repository=git_repository,
65+ commit_sha1=commit_sha1,
66+ ci_build=build)
67 except CIBuildAlreadyRequested:
68 pass
69 except Exception as e:
70@@ -463,9 +484,9 @@ class CIBuildSet(SpecificBuildFarmJobSourceMixin):
71 if logger is not None:
72 logger.error(e)
73 continue
74- for das in determine_DASes_to_build(configuration):
75+ for das in determine_DASes_to_build(configuration, logger=logger):
76 self._tryToRequestBuild(
77- git_repository, commit["sha1"], das, logger)
78+ git_repository, commit["sha1"], configuration, das, logger)
79
80 def getByID(self, build_id):
81 """See `ISpecificBuildFarmJobSource`."""
82diff --git a/lib/lp/code/model/tests/test_cibuild.py b/lib/lp/code/model/tests/test_cibuild.py
83index bd2c5e9..6118379 100644
84--- a/lib/lp/code/model/tests/test_cibuild.py
85+++ b/lib/lp/code/model/tests/test_cibuild.py
86@@ -16,6 +16,7 @@ import pytz
87 from storm.locals import Store
88 from testtools.matchers import (
89 Equals,
90+ MatchesSetwise,
91 MatchesStructure,
92 )
93 from zope.component import getUtility
94@@ -43,6 +44,7 @@ from lp.code.interfaces.cibuild import (
95 ICIBuildSet,
96 MissingConfiguration,
97 )
98+from lp.code.interfaces.revisionstatus import IRevisionStatusReportSet
99 from lp.code.model.cibuild import (
100 determine_DASes_to_build,
101 get_all_commits_for_paths,
102@@ -484,9 +486,17 @@ class TestCIBuildSet(TestCaseWithFactory):
103 )
104 configuration = dedent("""\
105 pipeline:
106- - test
107+ - build
108+ - test
109
110 jobs:
111+ build:
112+ matrix:
113+ - series: bionic
114+ architectures: amd64
115+ - series: focal
116+ architectures: amd64
117+ run: pyproject-build
118 test:
119 series: focal
120 architectures: amd64
121@@ -512,11 +522,21 @@ class TestCIBuildSet(TestCaseWithFactory):
122 )
123
124 build = getUtility(ICIBuildSet).findByGitRepository(repository).one()
125+ reports = list(
126+ getUtility(IRevisionStatusReportSet).findByRepository(repository))
127
128- # check that a build was created
129+ # check that a build and some reports were created
130 self.assertEqual(ref.commit_sha1, build.commit_sha1)
131 self.assertEqual("focal", build.distro_arch_series.distroseries.name)
132 self.assertEqual("amd64", build.distro_arch_series.architecturetag)
133+ self.assertThat(reports, MatchesSetwise(*(
134+ MatchesStructure.byEquality(
135+ creator=repository.owner,
136+ title=title,
137+ git_repository=repository,
138+ commit_sha1=ref.commit_sha1,
139+ ci_build=build)
140+ for title in ("build:0", "build:1", "test:0"))))
141
142 def test_requestBuildsForRefs_no_commits_at_all(self):
143 repository = self.factory.makeGitRepository()
144@@ -534,6 +554,10 @@ class TestCIBuildSet(TestCaseWithFactory):
145 self.assertTrue(
146 getUtility(ICIBuildSet).findByGitRepository(repository).is_empty()
147 )
148+ self.assertTrue(
149+ getUtility(IRevisionStatusReportSet).findByRepository(
150+ repository).is_empty()
151+ )
152
153 def test_requestBuildsForRefs_no_matching_commits(self):
154 repository = self.factory.makeGitRepository()
155@@ -554,6 +578,10 @@ class TestCIBuildSet(TestCaseWithFactory):
156 self.assertTrue(
157 getUtility(ICIBuildSet).findByGitRepository(repository).is_empty()
158 )
159+ self.assertTrue(
160+ getUtility(IRevisionStatusReportSet).findByRepository(
161+ repository).is_empty()
162+ )
163
164 def test_requestBuildsForRefs_configuration_parse_error(self):
165 ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
166@@ -592,6 +620,10 @@ class TestCIBuildSet(TestCaseWithFactory):
167 self.assertTrue(
168 getUtility(ICIBuildSet).findByGitRepository(repository).is_empty()
169 )
170+ self.assertTrue(
171+ getUtility(IRevisionStatusReportSet).findByRepository(
172+ repository).is_empty()
173+ )
174
175 self.assertEqual(
176 "ERROR Cannot parse .launchpad.yaml from %s: "
177@@ -646,6 +678,10 @@ class TestCIBuildSet(TestCaseWithFactory):
178 self.assertTrue(
179 getUtility(ICIBuildSet).findByGitRepository(repository).is_empty()
180 )
181+ self.assertTrue(
182+ getUtility(IRevisionStatusReportSet).findByRepository(
183+ repository).is_empty()
184+ )
185 self.assertEqual(
186 "INFO Requesting CI build "
187 "for %s on focal/amd64\n" % ref.commit_sha1,
188@@ -698,6 +734,10 @@ class TestCIBuildSet(TestCaseWithFactory):
189 self.assertTrue(
190 getUtility(ICIBuildSet).findByGitRepository(repository).is_empty()
191 )
192+ self.assertTrue(
193+ getUtility(IRevisionStatusReportSet).findByRepository(
194+ repository).is_empty()
195+ )
196
197 log_line1, log_line2 = logger.getLogBuffer().splitlines()
198 self.assertEqual(

Subscribers

People subscribed via source and target branches

to status/vote changes: