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 Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· 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. | |||
| 88 | 88 | line of spaces or tabs is not a blank line; more than two blank lines | |
| 89 | 89 | count like two. | |
| 90 | 90 | - [ ] **`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 | |
| 92 | 93 | texts observed on the github.com run page for matrix-edge-values and | |
| 93 | 94 | matrix-over-256, not in the recordings (a failed run with no job). To | |
| 94 | 95 | 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 lines | 88 | 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 offending | 90 | - [ ] **`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 | |||
| 92 | texts observed on the github.com run page for matrix-edge-values and | 93 | 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). To | 94 | matrix-over-256, not in the recordings (a failed run with no job). To | ||
| 94 | verify: order of the product (first key slowest), include | 95 | 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) } | |||
| 162 | 162 | // the exclusions; this limit keeps the work bounded, see [MaxMatrixProduct]. | |
| 163 | 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 | 171 | // configurationLimitError is returned when a matrix produces more than | |
| 166 | 172 | // [MaxMatrixJobs] configurations. Its text is the one observed on the | |
| 167 | 173 | // github.com run page for matrix-over-256 (not in the recordings, which only | |
| @@ -176,6 +182,9 @@ type configurationLimitError struct { | |||
| 176 | 182 | Count int | |
| 177 | 183 | } | |
| 178 | 184 | ||
| 185 | + | // Unwrap makes errors.Is(err, [ErrTooManyConfigurations]) hold. | |
| 186 | + | func (e *configurationLimitError) Unwrap() error { return ErrTooManyConfigurations } | |
| 187 | + | ||
| 179 | 188 | func (e *configurationLimitError) Error() string { | |
| 180 | 189 | subject := "Strategy" | |
| 181 | 190 | 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 than | 171 | // configurationLimitError is returned when a matrix produces more than | ||
| 166 | // [MaxMatrixJobs] configurations. Its text is the one observed on the | 172 | // [MaxMatrixJobs] configurations. Its text is the one observed on the | ||
| 167 | // github.com run page for matrix-over-256 (not in the recordings, which only | 173 | // github.com run page for matrix-over-256 (not in the recordings, which only | ||
| @@ -176,6 +182,9 @@ type configurationLimitError struct { | |||||
| 176 | Count int | 182 | 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) { | |||
| 325 | 325 | if !errors.As(err, &limit) || limit.Count != MaxMatrixProduct { | |
| 326 | 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 | 331 | _, err = ExpandMatrix(ctxbg, jsonValue(t, `{"matrix": {"a": `+vec(MaxMatrixProduct+1)+`}}`)) | |
| 329 | 332 | if err == nil || !strings.Contains(err.Error(), "matrix too large") { | |
| 330 | 333 | t.Errorf("one huge vector: %v", err) | |
| @@ -433,6 +436,9 @@ jobs: | |||
| 433 | 436 | if !errors.As(err, &limit) || limit.Job != "too-many" || limit.Count != 272 { | |
| 434 | 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 | 444 | 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) { | ||