detached 7ce70de

feat(workflow): export ErrTooManyConfigurations for the matrix limit

commit
7ce70dede57e4b9a9ce0b3bd97e172c59ba2c406
author
brice · · 2026-10-13 00:04 UTC
committer
brice · · 2026-10-18 14:59 UTC
parent
167d573
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +17 -1
M workflow/PORTING.md +2 -1
@@ -88,7 +88,8 @@ the recordings. The cases copied into the unit tests stay.
8888 line of spaces or tabs is not a blank line; more than two blank lines
8989 count like two.
9090 - [ ] **`ExpandMatrix`**: the unknown exclude key error (once per offending
91- entry) and the over-256 message (`configurationLimitError`) are the
91+ entry) and the over-256 message (`configurationLimitError`, which matches
92+ `ErrTooManyConfigurations` with `errors.Is`) are the
9293 texts observed on the github.com run page for matrix-edge-values and
9394 matrix-over-256, not in the recordings (a failed run with no job). To
9495 verify: order of the product (first key slowest), include
@@ -88,7 +88,8 @@ the recordings. The cases copied into the unit tests stay.
88 line of spaces or tabs is not a blank line; more than two blank lines88 line of spaces or tabs is not a blank line; more than two blank lines
89 count like two.89 count like two.
90 - [ ] **`ExpandMatrix`**: the unknown exclude key error (once per offending90 - [ ] **`ExpandMatrix`**: the unknown exclude key error (once per offending
91- entry) and the over-256 message (`configurationLimitError`) are the91+ entry) and the over-256 message (`configurationLimitError`, which matches
92+ `ErrTooManyConfigurations` with `errors.Is`) are the
92 texts observed on the github.com run page for matrix-edge-values and93 texts observed on the github.com run page for matrix-edge-values and
93 matrix-over-256, not in the recordings (a failed run with no job). To94 matrix-over-256, not in the recordings (a failed run with no job). To
94 verify: order of the product (first key slowest), include95 verify: order of the product (first key slowest), include
M workflow/matrix.go +9 -0
@@ -162,6 +162,12 @@ func (m message) Error() string { return string(m) }
162162 // the exclusions; this limit keeps the work bounded, see [MaxMatrixProduct].
163163 var errProductTooBig = fmt.Errorf("matrix too large: the cross product of the vectors exceeds %d combinations", MaxMatrixProduct)
164164
165+// ErrTooManyConfigurations is matched, with [errors.Is], by the error that
166+// [ExpandMatrix], [ParseStrategy] and [Job.EvaluateStrategy] return when a
167+// matrix produces more than [MaxMatrixJobs] configurations. The error itself
168+// carries the job and the count in its text.
169+var ErrTooManyConfigurations = errors.New("matrix produces too many configurations")
170+
165171 // configurationLimitError is returned when a matrix produces more than
166172 // [MaxMatrixJobs] configurations. Its text is the one observed on the
167173 // github.com run page for matrix-over-256 (not in the recordings, which only
@@ -176,6 +182,9 @@ type configurationLimitError struct {
176182 Count int
177183 }
178184
185+// Unwrap makes errors.Is(err, [ErrTooManyConfigurations]) hold.
186+func (e *configurationLimitError) Unwrap() error { return ErrTooManyConfigurations }
187+
179188 func (e *configurationLimitError) Error() string {
180189 subject := "Strategy"
181190 if e.Job != "" {
@@ -162,6 +162,12 @@ func (m message) Error() string { return string(m) }
162 // the exclusions; this limit keeps the work bounded, see [MaxMatrixProduct].162 // the exclusions; this limit keeps the work bounded, see [MaxMatrixProduct].
163 var errProductTooBig = fmt.Errorf("matrix too large: the cross product of the vectors exceeds %d combinations", MaxMatrixProduct)163 var errProductTooBig = fmt.Errorf("matrix too large: the cross product of the vectors exceeds %d combinations", MaxMatrixProduct)
164 164
165+// ErrTooManyConfigurations is matched, with [errors.Is], by the error that
166+// [ExpandMatrix], [ParseStrategy] and [Job.EvaluateStrategy] return when a
167+// matrix produces more than [MaxMatrixJobs] configurations. The error itself
168+// carries the job and the count in its text.
169+var ErrTooManyConfigurations = errors.New("matrix produces too many configurations")
170+
165 // configurationLimitError is returned when a matrix produces more than171 // configurationLimitError is returned when a matrix produces more than
166 // [MaxMatrixJobs] configurations. Its text is the one observed on the172 // [MaxMatrixJobs] configurations. Its text is the one observed on the
167 // github.com run page for matrix-over-256 (not in the recordings, which only173 // github.com run page for matrix-over-256 (not in the recordings, which only
@@ -176,6 +182,9 @@ type configurationLimitError struct {
176 Count int182 Count int
177 }183 }
178 184
185+// Unwrap makes errors.Is(err, [ErrTooManyConfigurations]) hold.
186+func (e *configurationLimitError) Unwrap() error { return ErrTooManyConfigurations }
187+
179 func (e *configurationLimitError) Error() string {188 func (e *configurationLimitError) Error() string {
180 subject := "Strategy"189 subject := "Strategy"
181 if e.Job != "" {190 if e.Job != "" {
M workflow/matrix_test.go +6 -0
@@ -325,6 +325,9 @@ func TestMatrixProductCap(t *testing.T) {
325325 if !errors.As(err, &limit) || limit.Count != MaxMatrixProduct {
326326 t.Errorf("err = %v", err)
327327 }
328+ if !errors.Is(err, ErrTooManyConfigurations) {
329+ t.Errorf("errors.Is(%v, ErrTooManyConfigurations) = false", err)
330+ }
328331 _, err = ExpandMatrix(ctxbg, jsonValue(t, `{"matrix": {"a": `+vec(MaxMatrixProduct+1)+`}}`))
329332 if err == nil || !strings.Contains(err.Error(), "matrix too large") {
330333 t.Errorf("one huge vector: %v", err)
@@ -433,6 +436,9 @@ jobs:
433436 if !errors.As(err, &limit) || limit.Job != "too-many" || limit.Count != 272 {
434437 t.Errorf("err = %#v", err)
435438 }
439+ if !errors.Is(err, ErrTooManyConfigurations) {
440+ t.Errorf("errors.Is(%v, ErrTooManyConfigurations) = false", err)
441+ }
436442 }
437443
438444 func TestMatrixEnvBounds(t *testing.T) {
@@ -325,6 +325,9 @@ func TestMatrixProductCap(t *testing.T) {
325 if !errors.As(err, &limit) || limit.Count != MaxMatrixProduct {325 if !errors.As(err, &limit) || limit.Count != MaxMatrixProduct {
326 t.Errorf("err = %v", err)326 t.Errorf("err = %v", err)
327 }327 }
328+ if !errors.Is(err, ErrTooManyConfigurations) {
329+ t.Errorf("errors.Is(%v, ErrTooManyConfigurations) = false", err)
330+ }
328 _, err = ExpandMatrix(ctxbg, jsonValue(t, `{"matrix": {"a": `+vec(MaxMatrixProduct+1)+`}}`))331 _, err = ExpandMatrix(ctxbg, jsonValue(t, `{"matrix": {"a": `+vec(MaxMatrixProduct+1)+`}}`))
329 if err == nil || !strings.Contains(err.Error(), "matrix too large") {332 if err == nil || !strings.Contains(err.Error(), "matrix too large") {
330 t.Errorf("one huge vector: %v", err)333 t.Errorf("one huge vector: %v", err)
@@ -433,6 +436,9 @@ jobs:
433 if !errors.As(err, &limit) || limit.Job != "too-many" || limit.Count != 272 {436 if !errors.As(err, &limit) || limit.Job != "too-many" || limit.Count != 272 {
434 t.Errorf("err = %#v", err)437 t.Errorf("err = %#v", err)
435 }438 }
439+ if !errors.Is(err, ErrTooManyConfigurations) {
440+ t.Errorf("errors.Is(%v, ErrTooManyConfigurations) = false", err)
441+ }
436 }442 }
437 443
438 func TestMatrixEnvBounds(t *testing.T) {444 func TestMatrixEnvBounds(t *testing.T) {

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 1

Tags 3

↑↓ moveenter openesc close