-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
175 lines (151 loc) · 6.33 KB
/
Copy pathMakefile
File metadata and controls
175 lines (151 loc) · 6.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
BINARY_NAME=deepseek
VERSION=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
LDFLAGS=-ldflags "-s -w -X main.version=$(VERSION)"
.PHONY: build
build:
go build -o $(BINARY_NAME) $(LDFLAGS) ./cmd/deepseek
.PHONY: test
test:
go test ./...
.PHONY: test-cover
test-cover:
go test ./... -coverprofile=cover.out -covermode=atomic
go tool cover -func=cover.out | tail -1
# The README carries a coverage badge. This is what keeps it from
# quietly becoming a lie: CI fails if coverage drops below the floor.
# Raise COVERAGE_FLOOR (and the badge) when coverage improves.
COVERAGE_FLOOR=68
.PHONY: cover-gate
cover-gate:
@go test ./... -coverprofile=cover.out -covermode=atomic >/dev/null
@total=$$(go tool cover -func=cover.out | awk '/^total:/ {gsub(/%/,"",$$3); print $$3}'); \
echo "coverage: $$total% (floor $(COVERAGE_FLOOR)%)"; \
awk -v t=$$total -v f=$(COVERAGE_FLOOR) 'BEGIN { if (t+0 < f+0) { print "FAIL: coverage below floor"; exit 1 } }'
# The documentation corpus compiled into the binary by `deepseek docs`.
#
# Source of truth is the mirror repo, which converts api-docs.deepseek.com
# page by page and extracts the FAQ out of its JS bundle. A sibling
# checkout is used when there is one — that is the loop while working on
# both — and otherwise it is fetched, so CI and a bare clone both work.
#
# The mirror also tracks dsh, DeepSeek's agent harness, in en/dsh — 112
# pages of a different product. This binary carries the API reference, so
# that subtree is excluded: it would quadruple the payload and it out-ranks
# the API pages on shared words like "tool" and "session".
CORPUS=internal/docs/corpus.tar.gz
CORPUS_EXCLUDE=--exclude=en/dsh
DOCS_REPO=https://github.com/thevibeworks/deepseek-docs
.PHONY: corpus
corpus:
@if [ -d ../deepseek-docs/content/en ]; then \
echo "packing from ../deepseek-docs"; \
tar -C ../deepseek-docs/content $(CORPUS_EXCLUDE) -czf $(CORPUS) en; \
else \
echo "fetching from $(DOCS_REPO)"; \
tmp=$$(mktemp -d); \
curl -sSL $(DOCS_REPO)/archive/refs/heads/main.tar.gz | tar -xz -C $$tmp --strip-components=1; \
tar -C $$tmp/content $(CORPUS_EXCLUDE) -czf $(CORPUS) en; \
rm -rf $$tmp; \
fi
@echo "$(CORPUS): $$(du -h $(CORPUS) | cut -f1), $$(tar tzf $(CORPUS) | grep -c '\.md$$') pages"
# Fails if the embedded corpus cannot be read back. An unreadable corpus
# breaks `docs` on a released binary and nothing else would catch it.
.PHONY: corpus-check
corpus-check:
@go test ./internal/docs/ -run TestEmbeddedCorpusLoads -count=1
# The free-tier gateway. A separate Go module on purpose: the CLI's
# dependency list is part of its pitch, and a server has no business
# widening it. See gateway/DESIGN.md.
GATEWAY_BINARY=dsgate
.PHONY: gateway
gateway:
cd gateway && go build -o ../$(GATEWAY_BINARY) -ldflags "-s -w -X main.version=$(VERSION)" ./cmd/dsgate
# Needs the CLI binary: the interop test runs the real `deepseek` against
# a real gateway, which is the only thing that proves the two independent
# implementations of the enrolment protocol actually agree.
.PHONY: gateway-test
gateway-test: build
cd gateway && go test ./... -race -count=1
.PHONY: gateway-check
gateway-check: gateway-test
@test -z "$$(cd gateway && gofmt -l .)" || { echo "gateway needs gofmt:"; cd gateway && gofmt -l .; exit 1; }
cd gateway && go vet ./...
$(MAKE) gateway
# The rate card exists twice — internal/deepseek/pricing.go for the CLI's
# cost estimates, gateway/internal/meter/meter.go for the gateway's
# budget — because they are separate modules and neither can import the
# other. Drift would mean the gateway believed it had spent a different
# amount than it had. This is what catches that.
.PHONY: price-check
price-check:
@pattern='CacheHitInput: [0-9.]+, CacheMissInput: [0-9.]+, Output: [0-9.]+'; \
cli=$$(grep -oE "$$pattern" internal/deepseek/pricing.go | sort); \
gw=$$(grep -oE "$$pattern" gateway/internal/meter/meter.go | sort); \
if [ -z "$$cli" ] || [ -z "$$gw" ]; then \
echo "FAIL: could not find a rate card in one of the two files"; exit 1; \
fi; \
if [ "$$cli" != "$$gw" ]; then \
echo "FAIL: the CLI and gateway rate cards have drifted"; \
echo " cli: $$cli"; echo " gateway: $$gw"; exit 1; \
fi; \
echo "rate cards match:"; echo "$$cli" | sed 's/^/ /'
# The site is generated HTML plus one page that is an application. The
# generator has its own --check; these cover the parts it cannot see —
# that the playground's script and markup still agree, that all three
# implementations of the enrolment puzzle still produce the same answers,
# that the sea still runs, stops when it should, and draws the same whale
# on the canvas as whale.svg draws for readers without JavaScript, and
# that the design rules in DESIGN.md still describe the stylesheet.
.PHONY: site-check
site-check:
python3 site/build.py --check
node site/pow.test.js
node site/md.test.js
node site/playground.test.js
node site/playground.dom.test.js
node site/pricing.test.js
node site/waves.test.js
node site/waves.dom.test.js
./site/bans.sh
.PHONY: site
site:
python3 site/build.py
.PHONY: vet
vet:
go vet ./...
.PHONY: fmt
fmt:
gofmt -w .
.PHONY: fmt-check
fmt-check:
@test -z "$$(gofmt -l .)" || { echo "needs gofmt:"; gofmt -l .; exit 1; }
.PHONY: check
check: fmt-check vet test corpus-check price-check build gateway-check site-check
@echo "All checks passed"
# Live smoke test against the real API. Needs DEEPSEEK_API_KEY and costs
# a fraction of a cent; kept out of `check` so the default path never
# depends on the network or on someone's balance.
.PHONY: smoke
smoke: build
./$(BINARY_NAME) check
# Aliases: the binary answers to whichever name invoked it, so these are
# symlinks rather than copies — one binary, three ways to type it.
ALIASES=ds dscli
.PHONY: install
install: build
@bindir=$${GOPATH:-$$HOME/go}/bin; mkdir -p $$bindir; \
cp $(BINARY_NAME) $$bindir/$(BINARY_NAME); \
for a in $(ALIASES); do ln -sf $(BINARY_NAME) $$bindir/$$a; done; \
echo "Installed $(BINARY_NAME) (aliases: $(ALIASES)) in $$bindir"
.PHONY: completions
completions: build
@mkdir -p completions
./$(BINARY_NAME) completion bash > completions/$(BINARY_NAME).bash
./$(BINARY_NAME) completion zsh > completions/_$(BINARY_NAME)
./$(BINARY_NAME) completion fish > completions/$(BINARY_NAME).fish
.PHONY: clean
clean:
go clean
rm -f $(BINARY_NAME) cover.out
rm -rf dist completions
.DEFAULT_GOAL := build