diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..d847e4e --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,105 @@ +# Strava API Client - AI Coding Agent Instructions + +This is a **generated Go client wrapper** around the Strava API v3, built using code generation from OpenAPI specs and containerized tooling. + +## Architecture Overview + +### Generated Client + Wrapper Pattern +- **Generated code**: `internal/gen/strava-api-go/` contains swagger-generated client (DO NOT EDIT) +- **Wrapper layer**: `client/*.go` provides user-friendly interfaces over generated code +- **Pattern**: Each API group (Activities, Athletes, Clubs, etc.) has: + - Interface in wrapper (e.g., `ActivitiesAPI`) + - Implementation struct (e.g., `activitiesService`) + - Constructor function (e.g., `newActivitiesApiService()`) + +### Code Generation Workflow +```bash +# Update API spec +make update-swagger-spec # Downloads latest from Strava + +# Regenerate client +make codegen # Runs: gen → sync-vendor → format-code → vet +``` + +Key files: +- `internal/generate.go` - Contains `//go:generate` directive for swagger codegen +- `docs/swagger.json` - Strava API specification (source of truth) +- Generated client uses go-openapi runtime with Bearer token auth + +## Development Workflow + +### Docker-Based Tooling +All linting/formatting/testing uses containerized tools via `ghcr.io/obalunenko/go-tools`: +```bash +# Primary commands (use these, not direct go commands) +make lint-full # Full linting suite +make fmt # Format code +make imports # Fix import sorting +make vet # Static analysis + +# Docker compose wraps all tools +docker compose -f deployments/docker-compose/go-tools-docker-compose.yml up --exit-code-from lint-full lint-full +``` + +### Testing Pattern +- Tests in `examples/client_example_test.go` serve as integration tests and usage documentation +- Tests require `STRAVA_ACCESS_TOKEN` environment variable +- Helper functions: `getToken(t)` for auth, `printJSON(t, v)` for debug output +- Uses `github.com/obalunenko/getenv` for environment variable handling + +## Code Patterns & Conventions + +### Wrapper Interface Design +```go +// Each API group follows this pattern: +type ActivitiesAPI interface { + // Method with context first, required params, then options + GetActivityById(ctx context.Context, id int64, opts ...GetActivityByIdOpts) (models.DetailedActivity, error) +} + +// Options structs for optional parameters +type GetActivityByIdOpts struct { + IncludeAllEfforts *bool `json:"include_all_efforts,omitempty"` +} +``` + +### Error Handling +- Custom errors in `client/errors.go` (e.g., `ErrTooManyOptions`) +- Generated client errors passed through from go-openapi +- No error wrapping - direct return of underlying errors + +### Dependencies & Integration +- **Auth**: Bearer token via `httptransport.BearerToken(token)` +- **Generated models**: Use `internal/gen/strava-api-go/models.*` types directly +- **Time handling**: `strfmt.DateTime` for API compatibility +- **Testing**: `github.com/stretchr/testify` with `require.*` assertions + +## File Organization + +``` +client/ # User-facing wrapper interfaces +├── client.go # Main APIClient struct and constructor +├── activities.go # Activities API wrapper +├── athletes.go # Athletes API wrapper +└── errors.go # Custom error types + +internal/gen/ # Generated code (DO NOT EDIT) +examples/ # Integration tests & usage documentation +scripts/ # Build and development scripts +deployments/ # Docker compose configurations +``` + +## Key Constraints + +1. **Never edit generated code** in `internal/gen/` - regenerate via `make codegen` +2. **Use containerized tools** - don't run go tools directly, use Make targets +3. **Follow wrapper pattern** - new APIs need interface + implementation + constructor +4. **Context-first parameters** in all API methods +5. **Options structs** for optional parameters instead of many function parameters + +## Common Tasks + +- **Add new API method**: Implement in relevant `client/*.go` file following existing patterns +- **Update API spec**: Run `make update-swagger-spec` then `make codegen` +- **Debug API calls**: Add test in `examples/` with `printJSON()` helper +- **Fix formatting**: Run `make format-code` (includes fmt + imports) \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f9a2286..afcf5e2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -34,7 +34,7 @@ jobs: matrix: language: [ 'go' ] os: [ 'ubuntu-24.04' ] - go-version: [1.24.x] + go-version: [1.25.x] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://git.io/codeql-language-support diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index eabef3d..bf83e5c 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -42,7 +42,7 @@ jobs: max-parallel: 3 matrix: os: [ 'ubuntu-24.04' ] - go-version: [1.24.x] + go-version: [1.25.x] runs-on: ${{ matrix.os }} name: Build steps: diff --git a/Makefile b/Makefile index 5a4ba61..dd02bd0 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ COMPOSE_TOOLS_CMD_BASE=docker compose -f $(COMPOSE_TOOLS_FILE) COMPOSE_TOOLS_CMD_UP=$(COMPOSE_TOOLS_CMD_BASE) up --exit-code-from COMPOSE_TOOLS_CMD_PULL=$(COMPOSE_TOOLS_CMD_BASE) build -GOVERSION:=1.24 +GOVERSION:=1.25 TARGET_MAX_CHAR_NUM=20 diff --git a/docs/swagger.json b/docs/swagger.json index 09d693a..a947d2d 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1528,7 +1528,7 @@ }, "/clubs/{id}": { "get": { - "description": "Returns a given club using its identifier.", + "description": "Returns a given a club using its identifier.", "tags": [ "Clubs" ], diff --git a/go.mod b/go.mod index 157a9af..4cf10a5 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/obalunenko/strava-api -go 1.24.0 +go 1.25 require ( github.com/go-openapi/errors v0.22.2 diff --git a/internal/gen/strava-api-go/client/clubs/clubs_client.go b/internal/gen/strava-api-go/client/clubs/clubs_client.go index 71a93fa..80a2749 100644 --- a/internal/gen/strava-api-go/client/clubs/clubs_client.go +++ b/internal/gen/strava-api-go/client/clubs/clubs_client.go @@ -150,7 +150,7 @@ func (a *Client) GetClubAdminsByID(params *GetClubAdminsByIDParams, authInfo run /* GetClubByID gets club -Returns a given club using its identifier. +Returns a given a club using its identifier. */ func (a *Client) GetClubByID(params *GetClubByIDParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetClubByIDOK, error) { // TODO: Validate the params before sending