Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ jobs:
go mod tidy
diff go.mod go.mod.bak && diff go.sum go.sum.bak

- name: Run tests
run: go test -v ./...
- name: Run tests with coverage floor
run: make coverage

- name: Build
run: go build -o bin/hey ./cmd/hey
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ dist/
completions/
profiles/
benchmarks-*.txt
coverage.out
coverage.func.txt
coverage.packages.txt
*.test
.release-extra/
result
14 changes: 13 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
.PHONY: build test test-unit test-smoke fmt fmt-check vet lint tidy tidy-check \
.PHONY: build test test-unit test-smoke coverage fmt fmt-check vet lint tidy tidy-check \
race-test vuln secrets replace-check check-toolchain check security \
release-check release bench bench-save bench-compare \
check-surface check-surface-compat tools clean install help

BINARY := $(CURDIR)/bin/hey
COVERAGE_FLOOR ?= 70.8
COVERAGE_PROFILE ?= coverage.out
COVERAGE_FUNCTIONS ?= coverage.func.txt
COVERAGE_PACKAGES ?= coverage.packages.txt
# Local builds are "dev": a git-describe SHA would make them look like releases.
VERSION ?= dev
LDFLAGS := -s -w \
Expand All @@ -19,6 +23,7 @@ help:
@echo " make test-unit Run unit tests"
@echo " make test Alias for test-unit"
@echo " make test-smoke Run smoke tests against a live server"
@echo " make coverage Run cross-package coverage and enforce the 70.8% floor"
@echo " make clean Remove build artifacts"
@echo " make tidy Tidy dependencies"
@echo ""
Expand Down Expand Up @@ -70,6 +75,12 @@ test-unit: check-toolchain
# Alias for test-unit
test: test-unit

# Run repository-wide cross-package statement coverage and enforce the regression floor.
coverage: check-toolchain
HEY_NO_KEYRING=1 GOWORK=off go test ./... -coverpkg=./... -covermode=atomic -coverprofile=$(COVERAGE_PROFILE)
@./scripts/coverage-summary.sh $(COVERAGE_PROFILE) $(COVERAGE_FUNCTIONS) $(COVERAGE_PACKAGES)
@./scripts/check-coverage.sh $(COVERAGE_PROFILE) $(COVERAGE_FLOOR)

# Run smoke tests against a live HEY server.
# Requires: a running server (default http://app.hey.localhost:3003) and Chrome.
# Override defaults: make test-smoke HEY_SMOKE_BASE_URL=... HEY_SMOKE_EMAIL=... HEY_SMOKE_PASSWORD=...
Expand Down Expand Up @@ -198,6 +209,7 @@ tools:
# Clean build artifacts
clean:
rm -rf bin/
rm -f $(COVERAGE_PROFILE) $(COVERAGE_FUNCTIONS) $(COVERAGE_PACKAGES)
go clean

# Install binary to /usr/local/bin
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,15 @@ hey skill install # install the skill globally for your agent
## Development

```bash
make build # build binary
make test # run tests
make lint # run golangci-lint
make clean # remove build artifacts
make build # build binary
make test # run tests
make coverage # run cross-package coverage and enforce the 70.8% floor
make lint # run golangci-lint
make clean # remove build artifacts
```

`make coverage` writes `coverage.out`, `coverage.func.txt`, and `coverage.packages.txt`, then prints a concise package summary and the lowest-covered functions.

## License

This project is licensed under the MIT License. See [LICENSE.md](LICENSE.md) for details.
24 changes: 17 additions & 7 deletions internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,27 @@ const (
installID = "hey-cli"
)

type callbackWaiter func(context.Context, string, string, string, LoginOptions) (string, error)
type listenerFactory func(context.Context, string, string) (net.Listener, error)

// Manager handles OAuth authentication.
type Manager struct {
baseURL string
store *Store
httpClient *http.Client
mu sync.Mutex
baseURL string
store *Store
httpClient *http.Client
callbackWait callbackWaiter
listen listenerFactory
mu sync.Mutex
}

// NewManager creates a new auth manager.
func NewManager(baseURL string, httpClient *http.Client, configDir string) *Manager {
listenConfig := &net.ListenConfig{}
return &Manager{
baseURL: normalizeBaseURL(baseURL),
store: NewStore(configDir),
httpClient: httpClient,
listen: listenConfig.Listen,
}
}

Expand Down Expand Up @@ -165,7 +172,11 @@ func (m *Manager) Login(ctx context.Context, opts LoginOptions) error {
authURL := u.String()

// Start local callback server
code, err := m.waitForCallback(ctx, state, authURL, callbackAddr, opts)
waitForCallback := m.callbackWait
if waitForCallback == nil {
waitForCallback = m.waitForCallback
}
code, err := waitForCallback(ctx, state, authURL, callbackAddr, opts)
if err != nil {
return err
}
Expand Down Expand Up @@ -267,8 +278,7 @@ func (m *Manager) CredentialKey() string {
}

func (m *Manager) waitForCallback(ctx context.Context, expectedState, authURL, callbackAddr string, opts LoginOptions) (string, error) {
lc := net.ListenConfig{}
listener, err := lc.Listen(ctx, "tcp", callbackAddr)
listener, err := m.listen(ctx, "tcp", callbackAddr)
if err != nil {
return "", fmt.Errorf("failed to start callback server: %w", err)
}
Expand Down
Loading
Loading