Skip to content

Commit b0749f1

Browse files
authored
Merge branch 'master' into DOC-4439-conn-mgmt-cmd-examples
2 parents 61c3953 + 7bc12bb commit b0749f1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2215
-305
lines changed

.github/actions/run-tests/action.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ runs:
2525
2626
# Mapping of redis version to redis testing containers
2727
declare -A redis_version_mapping=(
28-
["8.0.1"]="8.0.1-pre"
29-
["7.4.2"]="rs-7.4.0-v2"
30-
["7.2.7"]="rs-7.2.0-v14"
28+
["8.2.x"]="8.2-RC1-pre"
29+
["8.0.x"]="8.0.2"
30+
["7.4.x"]="rs-7.4.0-v5"
31+
["7.2.x"]="rs-7.2.0-v17"
3132
)
3233
3334
if [[ -v redis_version_mapping[$REDIS_VERSION] ]]; then

.github/workflows/build.yml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ jobs:
1818
fail-fast: false
1919
matrix:
2020
redis-version:
21-
- "8.0.1" # 8.0.1
22-
- "7.4.2" # should use redis stack 7.4
21+
- "8.2.x" # Redis CE 8.2
22+
- "8.0.x" # Redis CE 8.0
23+
- "7.4.x" # Redis stack 7.4
2324
go-version:
2425
- "1.23.x"
2526
- "1.24.x"
@@ -43,8 +44,9 @@ jobs:
4344
4445
# Mapping of redis version to redis testing containers
4546
declare -A redis_version_mapping=(
46-
["8.0.1"]="8.0.1-pre"
47-
["7.4.2"]="rs-7.4.0-v2"
47+
["8.2.x"]="8.2-RC1-pre"
48+
["8.0.x"]="8.0.2"
49+
["7.4.x"]="rs-7.4.0-v5"
4850
)
4951
if [[ -v redis_version_mapping[$REDIS_VERSION] ]]; then
5052
echo "REDIS_VERSION=${redis_version_np}" >> $GITHUB_ENV
@@ -72,9 +74,10 @@ jobs:
7274
fail-fast: false
7375
matrix:
7476
redis-version:
75-
- "8.0.1" # 8.0.1
76-
- "7.4.2" # should use redis stack 7.4
77-
- "7.2.7" # should redis stack 7.2
77+
- "8.2.x" # Redis CE 8.2
78+
- "8.0.x" # Redis CE 8.0
79+
- "7.4.x" # Redis stack 7.4
80+
- "7.2.x" # Redis stack 7.2
7881
go-version:
7982
- "1.23.x"
8083
- "1.24.x"

.github/workflows/doctests.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ jobs:
1616

1717
services:
1818
redis-stack:
19-
image: redis/redis-stack-server:latest
20-
options: >-
21-
--health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
19+
image: redislabs/client-libs-test:8.0.2
20+
env:
21+
TLS_ENABLED: no
22+
REDIS_CLUSTER: no
23+
PORT: 6379
2224
ports:
2325
- 6379:6379
2426

@@ -38,4 +40,4 @@ jobs:
3840

3941
- name: Test doc examples
4042
working-directory: ./doctests
41-
run: go test -v
43+
run: make test

.github/workflows/spellcheck.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- name: Checkout
99
uses: actions/checkout@v4
1010
- name: Check Spelling
11-
uses: rojopolis/spellcheck-github-actions@0.49.0
11+
uses: rojopolis/spellcheck-github-actions@0.51.0
1212
with:
1313
config_path: .github/spellcheck-settings.yml
1414
task_name: Markdown

Makefile

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,19 @@ docker.stop:
88

99
test:
1010
$(MAKE) docker.start
11-
$(MAKE) test.ci
11+
@if [ -z "$(REDIS_VERSION)" ]; then \
12+
echo "REDIS_VERSION not set, running all tests"; \
13+
$(MAKE) test.ci; \
14+
else \
15+
MAJOR_VERSION=$$(echo "$(REDIS_VERSION)" | cut -d. -f1); \
16+
if [ "$$MAJOR_VERSION" -ge 8 ]; then \
17+
echo "REDIS_VERSION $(REDIS_VERSION) >= 8, running all tests"; \
18+
$(MAKE) test.ci; \
19+
else \
20+
echo "REDIS_VERSION $(REDIS_VERSION) < 8, skipping vector_sets tests"; \
21+
$(MAKE) test.ci.skip-vectorsets; \
22+
fi; \
23+
fi
1224
$(MAKE) docker.stop
1325

1426
test.ci:
@@ -17,15 +29,27 @@ test.ci:
1729
(cd "$${dir}" && \
1830
go mod tidy -compat=1.18 && \
1931
go vet && \
20-
go test -v -coverprofile=coverage.txt -covermode=atomic ./... -race); \
32+
go test -v -coverprofile=coverage.txt -covermode=atomic ./... -race -skip Example); \
33+
done
34+
cd internal/customvet && go build .
35+
go vet -vettool ./internal/customvet/customvet
36+
37+
test.ci.skip-vectorsets:
38+
set -e; for dir in $(GO_MOD_DIRS); do \
39+
echo "go test in $${dir} (skipping vector sets)"; \
40+
(cd "$${dir}" && \
41+
go mod tidy -compat=1.18 && \
42+
go vet && \
43+
go test -v -coverprofile=coverage.txt -covermode=atomic ./... -race \
44+
-run '^(?!.*(?:VectorSet|vectorset|ExampleClient_vectorset)).*$$' -skip Example); \
2145
done
2246
cd internal/customvet && go build .
2347
go vet -vettool ./internal/customvet/customvet
2448

2549
bench:
26-
go test ./... -test.run=NONE -test.bench=. -test.benchmem
50+
go test ./... -test.run=NONE -test.bench=. -test.benchmem -skip Example
2751

28-
.PHONY: all test bench fmt
52+
.PHONY: all test test.ci test.ci.skip-vectorsets bench fmt
2953

3054
build:
3155
go build .

RELEASE-NOTES.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,69 @@
11
# Release Notes
22

3+
# 9.11.0 (2025-06-24)
4+
5+
## 🚀 Highlights
6+
7+
Fixes TxPipeline to work correctly in cluster scenarios, allowing execution of commands
8+
only in the same slot.
9+
10+
# Changes
11+
12+
## 🚀 New Features
13+
14+
- Set cluster slot for `scan` commands, rather than random ([#2623](https://github.com/redis/go-redis/pull/2623))
15+
- Add CredentialsProvider field to UniversalOptions ([#2927](https://github.com/redis/go-redis/pull/2927))
16+
- feat(redisotel): add WithCallerEnabled option ([#3415](https://github.com/redis/go-redis/pull/3415))
17+
18+
## 🐛 Bug Fixes
19+
20+
- fix(txpipeline): keyless commands should take the slot of the keyed ([#3411](https://github.com/redis/go-redis/pull/3411))
21+
- fix(loading): cache the loaded flag for slave nodes ([#3410](https://github.com/redis/go-redis/pull/3410))
22+
- fix(txpipeline): should return error on multi/exec on multiple slots ([#3408](https://github.com/redis/go-redis/pull/3408))
23+
- fix: check if the shard exists to avoid returning nil ([#3396](https://github.com/redis/go-redis/pull/3396))
24+
25+
## 🧰 Maintenance
26+
27+
- feat: optimize connection pool waitTurn ([#3412](https://github.com/redis/go-redis/pull/3412))
28+
- chore(ci): update CI redis builds ([#3407](https://github.com/redis/go-redis/pull/3407))
29+
- chore: remove a redundant method from `Ring`, `Client` and `ClusterClient` ([#3401](https://github.com/redis/go-redis/pull/3401))
30+
- test: refactor TestBasicCredentials using table-driven tests ([#3406](https://github.com/redis/go-redis/pull/3406))
31+
- perf: reduce unnecessary memory allocation operations ([#3399](https://github.com/redis/go-redis/pull/3399))
32+
- fix: insert entry during iterating over a map ([#3398](https://github.com/redis/go-redis/pull/3398))
33+
- DOC-5229 probabilistic data type examples ([#3413](https://github.com/redis/go-redis/pull/3413))
34+
- chore(deps): bump rojopolis/spellcheck-github-actions from 0.49.0 to 0.51.0 ([#3414](https://github.com/redis/go-redis/pull/3414))
35+
36+
## Contributors
37+
We'd like to thank all the contributors who worked on this release!
38+
39+
[@andy-stark-redis](https://github.com/andy-stark-redis), [@boekkooi-impossiblecloud](https://github.com/boekkooi-impossiblecloud), [@cxljs](https://github.com/cxljs), [@dcherubini](https://github.com/dcherubini), [@dependabot[bot]](https://github.com/apps/dependabot), [@iamamirsalehi](https://github.com/iamamirsalehi), [@ndyakov](https://github.com/ndyakov), [@pete-woods](https://github.com/pete-woods), [@twz915](https://github.com/twz915) and [dependabot[bot]](https://github.com/apps/dependabot)
40+
41+
# 9.10.0 (2025-06-06)
42+
43+
## 🚀 Highlights
44+
45+
`go-redis` now supports [vector sets](https://redis.io/docs/latest/develop/data-types/vector-sets/). This data type is marked
46+
as "in preview" in Redis and its support in `go-redis` is marked as experimental. You can find examples in the documentation and
47+
in the `doctests` folder.
48+
49+
# Changes
50+
51+
## 🚀 New Features
52+
53+
- feat: support vectorset ([#3375](https://github.com/redis/go-redis/pull/3375))
54+
55+
## 🧰 Maintenance
56+
57+
- Add the missing NewFloatSliceResult for testing ([#3393](https://github.com/redis/go-redis/pull/3393))
58+
- DOC-5078 vector set examples ([#3394](https://github.com/redis/go-redis/pull/3394))
59+
60+
## Contributors
61+
We'd like to thank all the contributors who worked on this release!
62+
63+
[@AndBobsYourUncle](https://github.com/AndBobsYourUncle), [@andy-stark-redis](https://github.com/andy-stark-redis), [@fukua95](https://github.com/fukua95) and [@ndyakov](https://github.com/ndyakov)
64+
65+
66+
367
# 9.9.0 (2025-05-27)
468

569
## 🚀 Highlights

auth/auth_test.go

Lines changed: 84 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package auth
22

33
import (
44
"errors"
5+
"strings"
56
"sync"
67
"testing"
78
"time"
@@ -179,36 +180,90 @@ func TestStreamingCredentialsProvider(t *testing.T) {
179180
}
180181

181182
func TestBasicCredentials(t *testing.T) {
182-
t.Run("basic auth", func(t *testing.T) {
183-
creds := NewBasicCredentials("user1", "pass1")
184-
username, password := creds.BasicAuth()
185-
if username != "user1" {
186-
t.Fatalf("expected username 'user1', got '%s'", username)
187-
}
188-
if password != "pass1" {
189-
t.Fatalf("expected password 'pass1', got '%s'", password)
190-
}
191-
})
192-
193-
t.Run("raw credentials", func(t *testing.T) {
194-
creds := NewBasicCredentials("user1", "pass1")
195-
raw := creds.RawCredentials()
196-
expected := "user1:pass1"
197-
if raw != expected {
198-
t.Fatalf("expected raw credentials '%s', got '%s'", expected, raw)
199-
}
200-
})
183+
tests := []struct {
184+
name string
185+
username string
186+
password string
187+
expectedUser string
188+
expectedPass string
189+
expectedRaw string
190+
}{
191+
{
192+
name: "basic auth",
193+
username: "user1",
194+
password: "pass1",
195+
expectedUser: "user1",
196+
expectedPass: "pass1",
197+
expectedRaw: "user1:pass1",
198+
},
199+
{
200+
name: "empty username",
201+
username: "",
202+
password: "pass1",
203+
expectedUser: "",
204+
expectedPass: "pass1",
205+
expectedRaw: ":pass1",
206+
},
207+
{
208+
name: "empty password",
209+
username: "user1",
210+
password: "",
211+
expectedUser: "user1",
212+
expectedPass: "",
213+
expectedRaw: "user1:",
214+
},
215+
{
216+
name: "both username and password empty",
217+
username: "",
218+
password: "",
219+
expectedUser: "",
220+
expectedPass: "",
221+
expectedRaw: ":",
222+
},
223+
{
224+
name: "special characters",
225+
username: "user:1",
226+
password: "pa:ss@!#",
227+
expectedUser: "user:1",
228+
expectedPass: "pa:ss@!#",
229+
expectedRaw: "user:1:pa:ss@!#",
230+
},
231+
{
232+
name: "unicode characters",
233+
username: "ユーザー",
234+
password: "密碼123",
235+
expectedUser: "ユーザー",
236+
expectedPass: "密碼123",
237+
expectedRaw: "ユーザー:密碼123",
238+
},
239+
{
240+
name: "long credentials",
241+
username: strings.Repeat("u", 1000),
242+
password: strings.Repeat("p", 1000),
243+
expectedUser: strings.Repeat("u", 1000),
244+
expectedPass: strings.Repeat("p", 1000),
245+
expectedRaw: strings.Repeat("u", 1000) + ":" + strings.Repeat("p", 1000),
246+
},
247+
}
201248

202-
t.Run("empty username", func(t *testing.T) {
203-
creds := NewBasicCredentials("", "pass1")
204-
username, password := creds.BasicAuth()
205-
if username != "" {
206-
t.Fatalf("expected empty username, got '%s'", username)
207-
}
208-
if password != "pass1" {
209-
t.Fatalf("expected password 'pass1', got '%s'", password)
210-
}
211-
})
249+
for _, tt := range tests {
250+
t.Run(tt.name, func(t *testing.T) {
251+
creds := NewBasicCredentials(tt.username, tt.password)
252+
253+
user, pass := creds.BasicAuth()
254+
if user != tt.expectedUser {
255+
t.Errorf("BasicAuth() username = %q; want %q", user, tt.expectedUser)
256+
}
257+
if pass != tt.expectedPass {
258+
t.Errorf("BasicAuth() password = %q; want %q", pass, tt.expectedPass)
259+
}
260+
261+
raw := creds.RawCredentials()
262+
if raw != tt.expectedRaw {
263+
t.Errorf("RawCredentials() = %q; want %q", raw, tt.expectedRaw)
264+
}
265+
})
266+
}
212267
}
213268

214269
func TestReAuthCredentialsListener(t *testing.T) {

bitmap_commands.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ type BitMapCmdable interface {
1212
BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
1313
BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
1414
BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
15+
BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd
16+
BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd
17+
BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd
18+
BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd
1519
BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
1620
BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
1721
BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd
@@ -78,22 +82,50 @@ func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string)
7882
return cmd
7983
}
8084

85+
// BitOpAnd creates a new bitmap in which users are members of all given bitmaps
8186
func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
8287
return c.bitOp(ctx, "and", destKey, keys...)
8388
}
8489

90+
// BitOpOr creates a new bitmap in which users are member of at least one given bitmap
8591
func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
8692
return c.bitOp(ctx, "or", destKey, keys...)
8793
}
8894

95+
// BitOpXor creates a new bitmap in which users are the result of XORing all given bitmaps
8996
func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
9097
return c.bitOp(ctx, "xor", destKey, keys...)
9198
}
9299

100+
// BitOpNot creates a new bitmap in which users are not members of a given bitmap
93101
func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
94102
return c.bitOp(ctx, "not", destKey, key)
95103
}
96104

105+
// BitOpDiff creates a new bitmap in which users are members of bitmap X but not of any of bitmaps Y1, Y2, …
106+
// Introduced with Redis 8.2
107+
func (c cmdable) BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd {
108+
return c.bitOp(ctx, "diff", destKey, keys...)
109+
}
110+
111+
// BitOpDiff1 creates a new bitmap in which users are members of one or more of bitmaps Y1, Y2, … but not members of bitmap X
112+
// Introduced with Redis 8.2
113+
func (c cmdable) BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd {
114+
return c.bitOp(ctx, "diff1", destKey, keys...)
115+
}
116+
117+
// BitOpAndOr creates a new bitmap in which users are members of bitmap X and also members of one or more of bitmaps Y1, Y2, …
118+
// Introduced with Redis 8.2
119+
func (c cmdable) BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
120+
return c.bitOp(ctx, "andor", destKey, keys...)
121+
}
122+
123+
// BitOpOne creates a new bitmap in which users are members of exactly one of the given bitmaps
124+
// Introduced with Redis 8.2
125+
func (c cmdable) BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd {
126+
return c.bitOp(ctx, "one", destKey, keys...)
127+
}
128+
97129
// BitPos is an API before Redis version 7.0, cmd: bitpos key bit start end
98130
// if you need the `byte | bit` parameter, please use `BitPosSpan`.
99131
func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {

0 commit comments

Comments
 (0)