Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e4b0afa
Stub Series, OrderGroups, Subaccounts services for parallel endpoint …
UTXOnly Sep 11, 2026
29855be
Fix retry exhaustion panic, honor ctx during backoff, drop duplicate …
UTXOnly Sep 11, 2026
abab260
Merge branch 'worktree-agent-a2fda8926bec75bdd' into audit-fixes
UTXOnly Sep 11, 2026
c22a087
Bound DoConcurrent, drop dead auth/transport code, untrack binary and…
UTXOnly Sep 11, 2026
0fe2215
Merge branch 'worktree-agent-a37099eca1f7125bf' into audit-fixes
UTXOnly Sep 11, 2026
972af43
Fix WebSocket multi-channel subscribe, write races, silent drops, and…
UTXOnly Sep 11, 2026
694c782
Merge branch 'worktree-agent-a257446a6d327da1c' into audit-fixes
UTXOnly Sep 11, 2026
3d7db8b
types: add typed WS message structs and fixed-point price/count/time …
UTXOnly Sep 11, 2026
f469a36
Merge branch 'worktree-agent-a2b4574190629c4d6' into audit-fixes
UTXOnly Sep 11, 2026
4b504c2
Add Series, OrderGroups, Subaccounts services and remaining market/po…
UTXOnly Sep 11, 2026
0c5335a
Merge branch 'worktree-agent-abc923c0fe796d666' into audit-fixes
UTXOnly Sep 11, 2026
6b24b11
gofmt pre-existing unformatted type files
UTXOnly Sep 11, 2026
5db5934
Release 0.6.0: docs for audit fixes, new services, typed WS payloads
UTXOnly Sep 11, 2026
011643f
Add CI and release automation
UTXOnly Sep 11, 2026
11e6323
CI: run steps under bash on every OS, bump actions to v7
UTXOnly Sep 11, 2026
58d14e5
Declare breaking changes and enforce the bump policy in CI
UTXOnly Sep 11, 2026
6be0f1f
README: state the v0 versioning and breaking-change policy
UTXOnly Sep 11, 2026
5223760
CI: keep gorelease scratch files out of the checkout
UTXOnly Sep 11, 2026
3e846f9
Types: align CFBenchmarksAvgData with the AsyncAPI schema; add exchan…
UTXOnly Sep 12, 2026
a103cc2
WS: complete get_snapshot on the snapshot frame; return partial Subsc…
UTXOnly Sep 12, 2026
bd8c835
Refuse empty path parameters; retry non-idempotent writes on 429 only
UTXOnly Sep 12, 2026
0d7f351
Docs and CI for the review fixes
UTXOnly Sep 12, 2026
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
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: gomod
directory: /
schedule:
interval: weekly
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
218 changes: 218 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

defaults:
run:
shell: bash

jobs:
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: stable
- name: gofmt
run: |
out=$(gofmt -l .)
if [ -n "$out" ]; then echo "unformatted:"; echo "$out"; exit 1; fi
- name: go mod tidy is a no-op
run: |
go mod tidy
git diff --exit-code go.mod go.sum
- run: go vet ./...
- name: staticcheck
run: go run honnef.co/go/tools/cmd/staticcheck@latest ./...
- name: govulncheck
run: go run golang.org/x/vuln/cmd/govulncheck@latest ./...

test:
name: test (go ${{ matrix.go }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, go: "1.24" }
- { os: ubuntu-latest, go: stable }
- { os: macos-latest, go: stable }
- { os: windows-latest, go: stable }
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: ${{ matrix.go }}
- run: go build ./...
- run: go test -race -count=1 -shuffle=on -coverprofile=coverage.out ./...
- name: coverage summary
if: matrix.os == 'ubuntu-latest' && matrix.go == 'stable'
run: go tool cover -func=coverage.out | tail -1

version:
name: version consistency
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: version.go, CHANGELOG, README agree and the version is unreleased
env:
BASE_REF: ${{ github.base_ref || 'main' }}
run: |
set -euo pipefail
version=$(sed -n 's/^const Version = "\(.*\)"$/\1/p' oddrip/version.go)
echo "oddrip.Version = $version"
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "::error::Version '$version' is not X.Y.Z"; exit 1; }

top=$(grep -m1 -oE '^## \[[0-9]+\.[0-9]+\.[0-9]+\]' CHANGELOG.md | tr -d '[]# ')
[ "$top" = "$version" ] || { echo "::error::CHANGELOG top entry is $top but oddrip.Version is $version"; exit 1; }

grep -q "@v$version" README.md || { echo "::error::README does not pin @v$version"; exit 1; }

if git rev-parse -q --verify "refs/tags/v$version" >/dev/null; then
if [ "${{ github.event_name }}" = "pull_request" ]; then
git fetch -q origin "$BASE_REF"
if git diff --name-only "origin/$BASE_REF...HEAD" -- oddrip go.mod go.sum | grep -q .; then
echo "::error::v$version is already released; this PR changes code, so bump oddrip/version.go and add a CHANGELOG entry"
exit 1
fi
echo "v$version already released; docs-only change, no bump required"
else
echo "v$version already released"
fi
echo "released=true" >> "$GITHUB_ENV"
else
echo "v$version is unreleased; merging to main will tag and publish it"
echo "released=false" >> "$GITHUB_ENV"
fi
echo "version=$version" >> "$GITHUB_ENV"
- uses: actions/setup-go@v7
if: env.released == 'false'
with:
go-version: stable
- name: breaking changes are declared and the bump matches
if: env.released == 'false'
run: |
set -euo pipefail
prev=$(git tag -l 'v*' | sort -V | tail -1)
[ -n "$prev" ] || { echo "no previous tag; skipping"; exit 0; }
echo "previous release: $prev"

[ "$(printf '%s\n' "${prev#v}" "$version" | sort -V | tail -1)" = "$version" ] && [ "${prev#v}" != "$version" ] \
|| { echo "::error::oddrip.Version $version is not greater than latest tag $prev"; exit 1; }

awk -v v="$version" '$0 ~ "^## \\[" v "\\]" { on=1; next } on && /^## \[/ { exit } on { print }' CHANGELOG.md > "$RUNNER_TEMP/section.md"
declared=false; grep -q '^### Breaking' "$RUNNER_TEMP/section.md" && declared=true

go run golang.org/x/exp/cmd/gorelease@latest -base="$prev" -version="v$version" > "$RUNNER_TEMP/gorelease.txt" 2>&1 || true
{ echo "## gorelease $prev → v$version"; echo; echo '```'; cat "$RUNNER_TEMP/gorelease.txt"; echo '```'; } >> "$GITHUB_STEP_SUMMARY"
cat "$RUNNER_TEMP/gorelease.txt"
grep -q '^# summary' "$RUNNER_TEMP/gorelease.txt" || { echo "::error::gorelease did not complete; refusing to pass without an API diff"; exit 1; }

api_breaks=$(awk '/^## incompatible changes/{on=1; next} /^## /{on=0} on && NF && !/^Version: value changed/' "$RUNNER_TEMP/gorelease.txt" || true)
if [ -n "$api_breaks" ] && [ "$declared" = false ]; then
echo "::error::gorelease found API-incompatible changes but the $version CHANGELOG section has no '### Breaking' heading:"
echo "$api_breaks"
exit 1
fi

IFS=. read -r pmaj pmin _ <<< "${prev#v}"
IFS=. read -r cmaj cmin _ <<< "$version"
if [ "$declared" = true ]; then
if [ "$cmaj" -eq 0 ] && [ "$pmaj" -eq 0 ]; then
[ "$cmin" -gt "$pmin" ] || { echo "::error::$version declares breaking changes but does not bump the minor version from $prev (v0 policy)"; exit 1; }
else
[ "$cmaj" -gt "$pmaj" ] || { echo "::error::$version declares breaking changes but does not bump the major version from $prev"; exit 1; }
fi
echo "breaking changes declared; bump from $prev to v$version is acceptable"
else
echo "no breaking changes declared or detected"
fi

release:
name: release
needs: [lint, test, version]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-go@v7
with:
go-version: stable
# Tag and GitHub release are checked separately so a run that pushed the
# tag but failed to create the release is completed by the next push
# instead of being skipped as "already tagged".
- name: resolve version
id: v
env:
GH_TOKEN: ${{ github.token }}
run: |
version=$(sed -n 's/^const Version = "\(.*\)"$/\1/p' oddrip/version.go)
echo "version=$version" >> "$GITHUB_OUTPUT"
if git rev-parse -q --verify "refs/tags/v$version" >/dev/null; then
echo "tagged=true" >> "$GITHUB_OUTPUT"
echo "v$version already tagged"
else
echo "tagged=false" >> "$GITHUB_OUTPUT"
fi
if gh release view "v$version" >/dev/null 2>&1; then
echo "released=true" >> "$GITHUB_OUTPUT"
echo "v$version already has a GitHub release; nothing to do"
else
echo "released=false" >> "$GITHUB_OUTPUT"
fi
- name: extract release notes
if: steps.v.outputs.released == 'false'
run: |
awk -v v="${{ steps.v.outputs.version }}" '
$0 ~ "^## \\[" v "\\]" { on=1; next }
on && /^## \[/ { exit }
on { print }
' CHANGELOG.md > notes.md
[ -s notes.md ] || { echo "::error::no CHANGELOG section for ${{ steps.v.outputs.version }}"; exit 1; }
echo "--- notes.md ---"; cat notes.md
- name: tag
if: steps.v.outputs.tagged == 'false'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag -a "v${{ steps.v.outputs.version }}" -m "v${{ steps.v.outputs.version }}"
git push origin "v${{ steps.v.outputs.version }}"
- name: GitHub release
if: steps.v.outputs.released == 'false'
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "v${{ steps.v.outputs.version }}" \
--title "v${{ steps.v.outputs.version }}" \
--notes-file notes.md \
--verify-tag
- name: warm module proxy
if: steps.v.outputs.released == 'false'
env:
GOPROXY: https://proxy.golang.org
GOFLAGS: -mod=mod
run: |
cd "$(mktemp -d)" && go mod init tmp >/dev/null
for i in 1 2 3 4 5; do
go list -m "github.com/UTXOnly/oddrip@v${{ steps.v.outputs.version }}" && exit 0
sleep 15
done
echo "::warning::proxy.golang.org has not indexed v${{ steps.v.outputs.version }} yet; it will on first fetch"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@
*.out

.DS_Store

# Example binary and local credentials
/example
*.pem
cmd/example/key_id
Loading