detached 3237aa5

fix(ci): annotation titles up to 4096 runes (#37)

commit
3237aa551d929a9c7cd62c61dc9c55bb278a3013
author
brice · · 2026-10-16 07:43 UTC
committer
bnema · · 2026-10-16 07:43 UTC
parent
4d48ed2
signature
SSH UnverifiedSHA256:VOCA5lYARHcbKDZ7GhTV45VmcjWnJ6ZQIBazj17LivA The key is unknown
3 files · +6 -5
M internal/app/ci_results_test.go +2 -2
@@ -147,7 +147,7 @@ func TestCIAnnotationsAndSummariesOverTheAPI(t *testing.T) {
147147 "no level": {{Message: "m", StepNumber: 1}},
148148 "no message": {ann(notice, 1, "")},
149149 "message too long": {ann(notice, 1, strings.Repeat("é", 4097))},
150- "title too long": {{Level: notice, Message: "m", Title: strings.Repeat("t", 256), StepNumber: 1}},
150+ "title too long": {{Level: notice, Message: "m", Title: strings.Repeat("t", 4097), StepNumber: 1}},
151151 "file too long": {{Level: notice, Message: "m", File: strings.Repeat("f", 1025), StepNumber: 1}},
152152 "step zero": {ann(notice, 0, "m")},
153153 "step beyond 1000": {ann(notice, 1001, "m")},
@@ -159,7 +159,7 @@ func TestCIAnnotationsAndSummariesOverTheAPI(t *testing.T) {
159159 }
160160 // Characters, not bytes: 4096 two-byte characters pass.
161161 require.NoError(t, runner.update(a, nil, ann(notice, 11, strings.Repeat("é", 4096))))
162- require.NoError(t, runner.update(a, nil, &pb.Annotation{Level: notice, Message: "m", Title: strings.Repeat("t", 255), File: strings.Repeat("f", 1024), StepNumber: 11}))
162+ require.NoError(t, runner.update(a, nil, &pb.Annotation{Level: notice, Message: "m", Title: strings.Repeat("t", 4096), File: strings.Repeat("f", 1024), StepNumber: 11}))
163163 // An invalid call stored nothing: steps 1, 3 and 7 are as they were.
164164 after := c.annotations(runID, a.GetJobId()).GetAnnotations()
165165 require.GreaterOrEqual(t, len(after), len(before))
@@ -147,7 +147,7 @@ func TestCIAnnotationsAndSummariesOverTheAPI(t *testing.T) {
147 "no level": {{Message: "m", StepNumber: 1}},147 "no level": {{Message: "m", StepNumber: 1}},
148 "no message": {ann(notice, 1, "")},148 "no message": {ann(notice, 1, "")},
149 "message too long": {ann(notice, 1, strings.Repeat("é", 4097))},149 "message too long": {ann(notice, 1, strings.Repeat("é", 4097))},
150- "title too long": {{Level: notice, Message: "m", Title: strings.Repeat("t", 256), StepNumber: 1}},150+ "title too long": {{Level: notice, Message: "m", Title: strings.Repeat("t", 4097), StepNumber: 1}},
151 "file too long": {{Level: notice, Message: "m", File: strings.Repeat("f", 1025), StepNumber: 1}},151 "file too long": {{Level: notice, Message: "m", File: strings.Repeat("f", 1025), StepNumber: 1}},
152 "step zero": {ann(notice, 0, "m")},152 "step zero": {ann(notice, 0, "m")},
153 "step beyond 1000": {ann(notice, 1001, "m")},153 "step beyond 1000": {ann(notice, 1001, "m")},
@@ -159,7 +159,7 @@ func TestCIAnnotationsAndSummariesOverTheAPI(t *testing.T) {
159 }159 }
160 // Characters, not bytes: 4096 two-byte characters pass.160 // Characters, not bytes: 4096 two-byte characters pass.
161 require.NoError(t, runner.update(a, nil, ann(notice, 11, strings.Repeat("é", 4096))))161 require.NoError(t, runner.update(a, nil, ann(notice, 11, strings.Repeat("é", 4096))))
162- require.NoError(t, runner.update(a, nil, &pb.Annotation{Level: notice, Message: "m", Title: strings.Repeat("t", 255), File: strings.Repeat("f", 1024), StepNumber: 11}))162+ require.NoError(t, runner.update(a, nil, &pb.Annotation{Level: notice, Message: "m", Title: strings.Repeat("t", 4096), File: strings.Repeat("f", 1024), StepNumber: 11}))
163 // An invalid call stored nothing: steps 1, 3 and 7 are as they were.163 // An invalid call stored nothing: steps 1, 3 and 7 are as they were.
164 after := c.annotations(runID, a.GetJobId()).GetAnnotations()164 after := c.annotations(runID, a.GetJobId()).GetAnnotations()
165 require.GreaterOrEqual(t, len(after), len(before))165 require.GreaterOrEqual(t, len(after), len(before))
M internal/domain/ci_annotation.go +1 -1
@@ -32,7 +32,7 @@ const (
3232 // CIMaxAnnotationMessage, CIMaxAnnotationTitle and CIMaxAnnotationFile bound
3333 // the text fields of an annotation, in characters.
3434 CIMaxAnnotationMessage = 4096
35- CIMaxAnnotationTitle = 255
35+ CIMaxAnnotationTitle = 4096
3636 CIMaxAnnotationFile = 1024
3737 // CIMaxListedAnnotations is the most annotations ListAnnotations returns.
3838 CIMaxListedAnnotations = 1000
@@ -32,7 +32,7 @@ const (
32 // CIMaxAnnotationMessage, CIMaxAnnotationTitle and CIMaxAnnotationFile bound32 // CIMaxAnnotationMessage, CIMaxAnnotationTitle and CIMaxAnnotationFile bound
33 // the text fields of an annotation, in characters.33 // the text fields of an annotation, in characters.
34 CIMaxAnnotationMessage = 409634 CIMaxAnnotationMessage = 4096
35- CIMaxAnnotationTitle = 25535+ CIMaxAnnotationTitle = 4096
36 CIMaxAnnotationFile = 102436 CIMaxAnnotationFile = 1024
37 // CIMaxListedAnnotations is the most annotations ListAnnotations returns.37 // CIMaxListedAnnotations is the most annotations ListAnnotations returns.
38 CIMaxListedAnnotations = 100038 CIMaxListedAnnotations = 1000
M internal/domain/ci_annotation_test.go +3 -2
@@ -32,7 +32,8 @@ func TestCheckAnnotationsLimits(t *testing.T) {
3232 "ten of each level": append(append(same(n, 1, 10), same(w, 1, 10)...), same(f, 1, 10)...),
3333 "ten per level, two steps": append(same(n, 1, 10), same(n, 2, 10)...),
3434 "4096 characters, 8 KiB": {an(n, 1, strings.Repeat("é", 4096))},
35- "title 255, file 1024": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("é", 255), File: strings.Repeat("é", 1024)}},
35+ "title 4096, file 1024": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("é", 4096), File: strings.Repeat("é", 1024)}},
36+ "title 600": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("t", 600)}},
3637 "step 1000": {an(n, 1000, "m")},
3738 "end line equal to start": {{Level: n, Step: 1, Message: "m", StartLine: 3, EndLine: 3}},
3839 "end line without start": {{Level: n, Step: 1, Message: "m", EndLine: 3}},
@@ -46,7 +47,7 @@ func TestCheckAnnotationsLimits(t *testing.T) {
4647 "unknown level": {{Level: "debug", Step: 1, Message: "m"}},
4748 "no message": {an(n, 1, "")},
4849 "message 4097": {an(n, 1, strings.Repeat("é", 4097))},
49- "title 256": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("t", 256)}},
50+ "title 4097": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("t", 4097)}},
5051 "file 1025": {{Level: n, Step: 1, Message: "m", File: strings.Repeat("f", 1025)}},
5152 "step 0": {an(n, 0, "m")},
5253 "step 1001": {an(n, 1001, "m")},
@@ -32,7 +32,8 @@ func TestCheckAnnotationsLimits(t *testing.T) {
32 "ten of each level": append(append(same(n, 1, 10), same(w, 1, 10)...), same(f, 1, 10)...),32 "ten of each level": append(append(same(n, 1, 10), same(w, 1, 10)...), same(f, 1, 10)...),
33 "ten per level, two steps": append(same(n, 1, 10), same(n, 2, 10)...),33 "ten per level, two steps": append(same(n, 1, 10), same(n, 2, 10)...),
34 "4096 characters, 8 KiB": {an(n, 1, strings.Repeat("é", 4096))},34 "4096 characters, 8 KiB": {an(n, 1, strings.Repeat("é", 4096))},
35- "title 255, file 1024": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("é", 255), File: strings.Repeat("é", 1024)}},35+ "title 4096, file 1024": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("é", 4096), File: strings.Repeat("é", 1024)}},
36+ "title 600": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("t", 600)}},
36 "step 1000": {an(n, 1000, "m")},37 "step 1000": {an(n, 1000, "m")},
37 "end line equal to start": {{Level: n, Step: 1, Message: "m", StartLine: 3, EndLine: 3}},38 "end line equal to start": {{Level: n, Step: 1, Message: "m", StartLine: 3, EndLine: 3}},
38 "end line without start": {{Level: n, Step: 1, Message: "m", EndLine: 3}},39 "end line without start": {{Level: n, Step: 1, Message: "m", EndLine: 3}},
@@ -46,7 +47,7 @@ func TestCheckAnnotationsLimits(t *testing.T) {
46 "unknown level": {{Level: "debug", Step: 1, Message: "m"}},47 "unknown level": {{Level: "debug", Step: 1, Message: "m"}},
47 "no message": {an(n, 1, "")},48 "no message": {an(n, 1, "")},
48 "message 4097": {an(n, 1, strings.Repeat("é", 4097))},49 "message 4097": {an(n, 1, strings.Repeat("é", 4097))},
49- "title 256": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("t", 256)}},50+ "title 4097": {{Level: n, Step: 1, Message: "m", Title: strings.Repeat("t", 4097)}},
50 "file 1025": {{Level: n, Step: 1, Message: "m", File: strings.Repeat("f", 1025)}},51 "file 1025": {{Level: n, Step: 1, Message: "m", File: strings.Repeat("f", 1025)}},
51 "step 0": {an(n, 0, "m")},52 "step 0": {an(n, 0, "m")},
52 "step 1001": {an(n, 1001, "m")},53 "step 1001": {an(n, 1001, "m")},

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 45

↑↓ moveenter openesc close