Skip to content

Commit c80c32a

Browse files
committed
ci: gorm-upstream — drop ^ anchor, capture PIPESTATUS,
survive zero-match grep; fix linter
1 parent 19cce43 commit c80c32a

9 files changed

Lines changed: 67 additions & 40 deletions

File tree

.github/workflows/ci.yml

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,20 +272,39 @@ jobs:
272272
- name: Run gorm upstream test suite
273273
run: |
274274
cd "$WORK_DIR/gorm/tests"
275+
# tee duplicates output to a file we parse for PASS/FAIL counts
276+
# below. Two pitfalls we work around here:
277+
# 1. GitHub Actions prefixes every line with a UTC timestamp,
278+
# even in the file written by tee — so we cannot anchor our
279+
# grep with `^--- PASS:`. We use an unanchored match.
280+
# 2. `go test`'s exit code is masked by tee's (always 0). We
281+
# capture it via PIPESTATUS before the next command resets
282+
# $?, and disable errexit around the pipeline so a
283+
# legitimate test-fail doesn't abort our reporter.
284+
set +e
275285
go test -count=1 -timeout 5m -v ./... 2>&1 | tee /tmp/gorm-upstream.log
286+
rc=${PIPESTATUS[0]}
287+
set -e
288+
# `grep -c` exits 1 on zero matches; `|| true` keeps the
289+
# outer script alive so we can report the actual counts.
290+
PASS=$(grep -c -- '--- PASS:' /tmp/gorm-upstream.log || true)
291+
FAIL=$(grep -c -- '--- FAIL:' /tmp/gorm-upstream.log || true)
292+
SKIP=$(grep -c -- '--- SKIP:' /tmp/gorm-upstream.log || true)
276293
echo "--- summary ---"
277-
PASS=$(grep -cE '^--- PASS:' /tmp/gorm-upstream.log)
278-
FAIL=$(grep -cE '^--- FAIL:' /tmp/gorm-upstream.log)
279-
SKIP=$(grep -cE '^--- SKIP:' /tmp/gorm-upstream.log)
280-
echo "PASS=$PASS FAIL=$FAIL SKIP=$SKIP"
281-
# Floor matches docs/gorm-upstream.md (386 PASS / 0 FAIL on
282-
# 2026-05-26). If gorm adds tests, bump the floor; if it removes
283-
# tests, this catches a silent regression.
294+
echo "PASS=$PASS FAIL=$FAIL SKIP=$SKIP go-test-exit=$rc"
295+
if [ "$rc" -ne 0 ]; then
296+
echo "::error::go test exited with $rc"
297+
exit "$rc"
298+
fi
284299
if [ "$FAIL" -ne 0 ]; then
285300
echo "::error::gorm upstream suite reports $FAIL failures"
286301
exit 1
287302
fi
288-
if [ "$PASS" -lt 380 ]; then
289-
echo "::error::gorm upstream PASS count regressed: got $PASS, expected >= 380"
303+
# PASS count includes sub-test lines (which are indented in the
304+
# file too) — for gorm v1.31.1 the total is ~15000. Floor at
305+
# 10000 to catch a "no tests ran at all" regression without
306+
# being brittle on minor gorm bumps.
307+
if [ "$PASS" -lt 10000 ]; then
308+
echo "::error::gorm upstream PASS count regressed: got $PASS, expected >= 10000"
290309
exit 1
291310
fi

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,26 @@ Migrator path we care about for our dialector.
447447

448448
Run them with `just test` (or `go test ./...`).
449449

450+
## Sponsors
451+
452+
This project is supported by:
453+
454+
- **[ssh2incus](https://ssh2incus.com)** — an open-source SSH server
455+
that connects directly to [Incus](https://linuxcontainers.org/incus/)
456+
containers and virtual machines. Runs on the Incus host and routes
457+
incoming SSH connections to the right instance via the Incus API,
458+
so individual instances don't need their own SSH server.
459+
460+
- **[MobyDeck](https://github.com/mobydeck)** — a GitHub organization
461+
publishing open-source developer tools and infrastructure
462+
utilities across Go, C, TypeScript, shell, and Ruby. Projects
463+
include the SSH-for-Incus gateway above, container credential
464+
management, privilege-management system utilities, and status-page
465+
automation.
466+
467+
If your company benefits from this driver and you'd like to be listed
468+
here, open an issue.
469+
450470
## License
451471

452472
Apache 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).

fts/gorm/callbacks.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ func columnValues(mm *modelMeta, row reflect.Value) ([]any, error) {
185185
out := make([]any, len(mm.Fields))
186186
for i, f := range mm.Fields {
187187
v := row.FieldByIndex(f.FieldIndex)
188-
for v.Kind() == reflect.Ptr {
188+
for v.Kind() == reflect.Pointer {
189189
if v.IsNil() {
190190
return nil, fmt.Errorf("ftsgorm: %s field is nil pointer", f.FieldName)
191191
}
@@ -217,7 +217,7 @@ func isSoftDeleted(_ *modelMeta, row reflect.Value) bool {
217217

218218
// iterateRows normalizes db.Statement.ReflectValue into a flat list.
219219
func iterateRows(v reflect.Value) []reflect.Value {
220-
for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
220+
for v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface {
221221
v = v.Elem()
222222
}
223223
switch v.Kind() {
@@ -227,7 +227,7 @@ func iterateRows(v reflect.Value) []reflect.Value {
227227
out := make([]reflect.Value, 0, v.Len())
228228
for i := 0; i < v.Len(); i++ {
229229
elem := v.Index(i)
230-
for elem.Kind() == reflect.Ptr {
230+
for elem.Kind() == reflect.Pointer {
231231
elem = elem.Elem()
232232
}
233233
if elem.Kind() == reflect.Struct {

fts/gorm/plugin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func pluginFrom(db *gorm.DB) (*plugin, error) {
180180
func indirectType(t reflect.Type) reflect.Type {
181181
for {
182182
switch t.Kind() {
183-
case reflect.Ptr, reflect.Slice, reflect.Array:
183+
case reflect.Pointer, reflect.Slice, reflect.Array:
184184
t = t.Elem()
185185
default:
186186
return t

fts/gorm/search.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func Search[T any](ctx context.Context, db *gorm.DB, q fts.Query, opts ...Option
9696
return nil, err
9797
}
9898
if len(mm.Fields) == 0 {
99-
return nil, fmt.Errorf("ftsgorm: Search: %T has no fields tagged with fts5:", zero)
99+
return nil, fmt.Errorf("ftsgorm: Search: %T has no fields tagged with fts5", zero)
100100
}
101101

102102
var o options
@@ -106,8 +106,8 @@ func Search[T any](ctx context.Context, db *gorm.DB, q fts.Query, opts ...Option
106106

107107
if mm.Mode == ModeContentless && (o.snippet != nil || o.hilite != nil) {
108108
return nil, fmt.Errorf(
109-
"ftsgorm: %s uses contentless mode; snippet() and highlight() are unavailable. "+
110-
"Remove WithSnippet/WithHighlight or switch the model to external (default) or in-table mode.",
109+
"ftsgorm: %s uses contentless mode; snippet() and highlight() are unavailable "+
110+
"remove WithSnippet/WithHighlight or switch the model to external (default) or in-table mode",
111111
mm.Table)
112112
}
113113

@@ -258,7 +258,7 @@ func columnIndex(mm *modelMeta, name string) int {
258258
// helper of the same name.
259259
func pkAsInt64(f *schema.Field, row reflect.Value) (int64, bool) {
260260
v := row.FieldByIndex(f.StructField.Index)
261-
for v.Kind() == reflect.Ptr {
261+
for v.Kind() == reflect.Pointer {
262262
if v.IsNil() {
263263
return 0, false
264264
}

vec/gorm/callbacks.go

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func (p *plugin) afterDelete(db *gorm.DB) {
193193
// struct or a slice of structs depending on the call form) into a flat
194194
// []reflect.Value addressing each row.
195195
func iterateRows(v reflect.Value) []reflect.Value {
196-
for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
196+
for v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface {
197197
v = v.Elem()
198198
}
199199
switch v.Kind() {
@@ -203,7 +203,7 @@ func iterateRows(v reflect.Value) []reflect.Value {
203203
out := make([]reflect.Value, 0, v.Len())
204204
for i := 0; i < v.Len(); i++ {
205205
elem := v.Index(i)
206-
for elem.Kind() == reflect.Ptr {
206+
for elem.Kind() == reflect.Pointer {
207207
elem = elem.Elem()
208208
}
209209
if elem.Kind() == reflect.Struct {
@@ -220,7 +220,7 @@ func iterateRows(v reflect.Value) []reflect.Value {
220220
// because we already error in registerSchema on non-single PK setups).
221221
func pkAsInt64(f *schema.Field, row reflect.Value) (int64, bool) {
222222
v := row.FieldByIndex(f.StructField.Index)
223-
for v.Kind() == reflect.Ptr {
223+
for v.Kind() == reflect.Pointer {
224224
if v.IsNil() {
225225
return 0, false
226226
}
@@ -238,7 +238,7 @@ func pkAsInt64(f *schema.Field, row reflect.Value) (int64, bool) {
238238
// embeddingFrom reads a []float32 (or compatible) field off a row.
239239
func embeddingFrom(row reflect.Value, index []int) ([]float32, bool) {
240240
v := row.FieldByIndex(index)
241-
for v.Kind() == reflect.Ptr {
241+
for v.Kind() == reflect.Pointer {
242242
if v.IsNil() {
243243
return nil, false
244244
}
@@ -253,13 +253,3 @@ func embeddingFrom(row reflect.Value, index []int) ([]float32, bool) {
253253
}
254254
return out, true
255255
}
256-
257-
// rowids extracts the rowid column from a slice of vec.Item; used as the
258-
// IN-clause for the post-BatchInsert UPDATE that sets deleted=0.
259-
func rowids(items []vec.Item) []int64 {
260-
out := make([]int64, len(items))
261-
for i, it := range items {
262-
out[i] = it.Rowid
263-
}
264-
return out
265-
}

vec/gorm/knn.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func KNN[T any](
7777
}
7878
if len(mm.Fields) == 0 {
7979
return nil, fmt.Errorf(
80-
"vecgorm: KNN: %T has no fields tagged with vec:",
80+
"vecgorm: KNN: %T has no fields tagged with vec",
8181
zero)
8282
}
8383
if len(mm.Fields) > 1 {

vec/gorm/plugin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ func pluginFrom(db *gorm.DB) (*plugin, error) {
201201
func indirectType(t reflect.Type) reflect.Type {
202202
for {
203203
switch t.Kind() {
204-
case reflect.Ptr, reflect.Slice, reflect.Array:
204+
case reflect.Pointer, reflect.Slice, reflect.Array:
205205
t = t.Elem()
206206
default:
207207
return t

vec/gorm/tag.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ func preflightTags(rt reflect.Type) error {
167167
if !hasGormIgnore(gormTag) {
168168
return fmt.Errorf(
169169
"vecgorm: %s.%s has a vec:\"...\" tag but is missing gorm:\"-\" "+
170-
"and is not declared as vecgorm.Embedding. Either change the "+
170+
"and is not declared as vecgorm.Embedding — either change the "+
171171
"field type to vecgorm.Embedding (preferred) or add gorm:\"-\" "+
172-
"so gorm's schema parser doesn't reject the unknown []float32 type.",
172+
"so gorm's schema parser doesn't reject the unknown []float32 type",
173173
rt.Name(), f.Name)
174174
}
175175
}
@@ -181,12 +181,10 @@ func preflightTags(rt reflect.Type) error {
181181
// schema parsing.
182182
func hasGormDataType(t reflect.Type) bool {
183183
type dataTyper interface{ GormDataType() string }
184-
if reflect.Zero(t).Interface().(any) != nil {
185-
if _, ok := reflect.Zero(t).Interface().(dataTyper); ok {
186-
return true
187-
}
184+
if _, ok := reflect.Zero(t).Interface().(dataTyper); ok {
185+
return true
188186
}
189-
if t.Kind() != reflect.Ptr {
187+
if t.Kind() != reflect.Pointer {
190188
pt := reflect.PointerTo(t)
191189
if _, ok := reflect.Zero(pt).Interface().(dataTyper); ok {
192190
return true

0 commit comments

Comments
 (0)