Merge ~cjwatson/launchpad:ci-build-multi-arch-ui into launchpad:master

Proposed by Colin Watson
Status: Needs review
Proposed branch: ~cjwatson/launchpad:ci-build-multi-arch-ui
Merge into: launchpad:master
Diff against target: 44 lines (+12/-3)
2 files modified
lib/lp/code/browser/tests/test_gitref.py (+8/-2)
lib/lp/code/templates/git-macros.pt (+4/-1)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+449768@code.launchpad.net

Commit message

Clarify CI build links when they exist for multiple architectures

Description of the change

If you set up a `.launchpad.yaml` that runs builds on multiple architectures, the UI presentation currently looks like this:

  [ ] build:0 (build)
  [ ] build:0 (build)

That leaves something to be desired in terms of clarity. Show the series and architecture in the link text that currently just reads "build", so that it looks like this instead:

  [ ] build:0 (focal/amd64)
  [ ] build:0 (focal/arm64)

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

Great improvement!

Would it be possible to make the tests as expressive as the commit message?

I would love to see that we assert against literals more often.

This makes the tests easier to read and to debug, and in case a test breaks it is much easier to see at one glance what is going wrong.

review: Approve
Revision history for this message
Colin Watson (cjwatson) wrote :

I think we've previously established that we disagree about literals - I've seen too many cases where assertions on literals masked problems where things were inappropriately hardcoded in the code, but hey, they worked for that particular literal value! That's why I always prefer to use the object factory where I can and let it autogenerate test strings for me.

Perhaps we can find a compromise though. Could you point to exactly which bit of the tests you don't feel are expressive enough?

Revision history for this message
Jürgen Gmach (jugmac00) wrote :

Thanks for keeping this discussion going. Having tests "trivially correct upon inspection" is one of several building blocks which I would love to see for Launchpad to be incorporated, to make maintaining such a huge project, which was written and is and will be maintained by many generations of developers over decades more sustainable.

I see your point. I have been bitten by hardcoded test values myself. On the other hand, I have seen tests where both the input and the output were generated, and although both were wrong, the tests passed. You'd need to step through the tests in order to prove they do what they claim.

The issue with a hardcoded value can be mitigated by testing several values. In this special case we could use a couple of series and architectures. This is trivial with pytest's parametrization feature, but should also be also possible with our setup, either with subtests https://blog.ganssle.io/articles/2020/04/subtests-in-python.html or with asserting in a loop.

In case of "using several input values to mitigate the fact of one hardcoded value could mislead us" is not enough of a compromise, I also thought about adding comments.

e.g.
```
text=re.compile(r".*/.*"),
```
turns into
```
text=re.compile(r".*/.*"), # e.g. "focal/arm64"
```

This helps with understanding the test, but unfortunately does not help with "trivially correct upon inspection". And it brings all the problems along of diverging code and comments.

And as you asked me about where exactly to improve expressiveness - right after the "text=..." - there should be a string, e.g. `text=focal/arm64`, just as above in your commit message.

I have incorporated this kind of writing tests many years ago, and I strongly believe this is the way to go. As you mentioned, we had the discussion before and we agree to disagree. I respect that, and that is why I have approved the MP.

We should also keep two things in mind. Whenever possible we should write code in a way that it can be easily understood by all team members, not just by oneself. And as senior engineers, it is not just about a personal preference, every decision has a bigger impact.

By the way, the quote from above, i.e "trivially correct upon inspection", is from a book I just recently started reading: "Software Engineering at Google" - in which a couple of google engineers discuss what they have learned from maintaining massive code bases for decades. It is not like we need take everything written as gospel truth, but I have to admit it is kinda nice to provide a link to a highly regarded book to support one's standpoint:
https://abseil.io/resources/swe-book/html/ch12.html#donapostrophet_put_logic_in_tests

Unmerged commits

fc18aef... by Colin Watson

Clarify CI build links when they exist for multiple architectures

If you set up a `.launchpad.yaml` that runs builds on multiple
architectures, the UI presentation currently looks like this:

  [ ] build:0 (build)
  [ ] build:0 (build)

That leaves something to be desired in terms of clarity. Show the
series and architecture in the link text that currently just reads
"build", so that it looks like this instead:

  [ ] build:0 (focal/amd64)
  [ ] build:0 (focal/arm64)

Succeeded
[SUCCEEDED] docs:0 (build)
[SUCCEEDED] lint:0 (build)
[SUCCEEDED] mypy:0 (build)
13 of 3 results

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/code/browser/tests/test_gitref.py b/lib/lp/code/browser/tests/test_gitref.py
2index 0c02bac..8b5e8d3 100644
3--- a/lib/lp/code/browser/tests/test_gitref.py
4+++ b/lib/lp/code/browser/tests/test_gitref.py
5@@ -277,7 +277,9 @@ class TestGitRefView(BrowserTestCase):
6 soupmatchers.Within(
7 soupmatchers.Tag("first report title", "td"),
8 soupmatchers.Tag(
9- "first report CI build link", "a", text="build"
10+ "first report CI build link",
11+ "a",
12+ text=re.compile(r".*/.*"),
13 ),
14 )
15 ),
16@@ -307,7 +309,11 @@ class TestGitRefView(BrowserTestCase):
17 soupmatchers.Tag(
18 "second report CI build link",
19 "a",
20- text="build",
21+ text="%s/%s"
22+ % (
23+ report2.ci_build.distro_series.name,
24+ report2.ci_build.arch_tag,
25+ ),
26 attrs={
27 "href": canonical_url(
28 report2.ci_build, force_local_path=True
29diff --git a/lib/lp/code/templates/git-macros.pt b/lib/lp/code/templates/git-macros.pt
30index 3960408..254a805 100644
31--- a/lib/lp/code/templates/git-macros.pt
32+++ b/lib/lp/code/templates/git-macros.pt
33@@ -238,7 +238,10 @@
34 <td tal:define="url python: report.url if report.url is not None else path('report/latest_log/download_url | nothing')">
35 <a tal:attributes="href url" tal:content="report/title" />
36 <tal:ci_build condition="report/ci_build">
37- (<a tal:attributes="href report/ci_build/fmt:url">build</a>)
38+ (<a tal:define="archseries python: report.distro_arch_series or report.ci_build.distro_arch_series"
39+ tal:attributes="href report/ci_build/fmt:url"
40+ tal:content="string:${archseries/distroseries/name}/${archseries/architecturetag}"
41+ />)
42 </tal:ci_build>
43 </td>
44 <td tal:content="report/result_summary" />

Subscribers

People subscribed via source and target branches

to status/vote changes: