mirror of
https://github.com/lukaszraczylo/go-telegram.git
synced 2026-06-10 23:09:04 +00:00
Initial release of go-telegram
A fully-generated, strongly-typed Go client for the Telegram Bot API. * 176 methods + 301 types generated from Bot API v10.0 * 1408 auto-generated tests (8 scenarios per method) * Typed unions throughout — no 'any' in the public surface * Pluggable HTTP transport and JSON codec (default goccy/go-json) * Built-in retry middleware honouring Telegram's retry_after * Generic dispatcher with filters and conversation handlers * Self-verifying codegen pipeline (regen → audit → emit → run tests) * 14 example bots covering common patterns
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,499 @@
|
||||
# go-telegram — Design Spec
|
||||
|
||||
- **Date:** 2026-05-08
|
||||
- **Module:** `github.com/lukaszraczylo/go-telegram`
|
||||
- **License:** MIT
|
||||
- **Status:** Approved for planning
|
||||
- **Author:** Lukasz Raczylo (with Claude assistance)
|
||||
|
||||
## 1. Purpose & scope
|
||||
|
||||
A Go library for the Telegram Bot API, primarily a portfolio piece showcasing:
|
||||
|
||||
- Codegen-driven full API coverage (parsed from `https://core.telegram.org/bots/api`)
|
||||
- Pragmatic Go generics
|
||||
- Pluggable HTTP transport and JSON codec for resource-conscious deployments
|
||||
- Long-poll and webhook update delivery behind a unified interface
|
||||
- A typed dispatcher/router for handlers, commands, and callbacks
|
||||
- Comprehensive testify-based unit tests with golden fixtures for codegen
|
||||
|
||||
Out of scope for v1: the daily auto-regen GitHub Action (deferred — see §11).
|
||||
|
||||
## 2. Non-goals
|
||||
|
||||
- Competing on completeness/maturity with `mymmrac/telego` or `go-telegram-bot-api/telegram-bot-api`. We optimise for clarity and design.
|
||||
- Bot-framework features beyond the dispatcher (no plugin marketplace, no FSM, no scenes).
|
||||
- A documentation website. `pkg.go.dev` + README is sufficient.
|
||||
|
||||
## 3. Requirements
|
||||
|
||||
### Functional
|
||||
|
||||
1. Cover all Telegram Bot API methods and types via codegen.
|
||||
2. Support long-poll and webhook update delivery, both implementing one `Updater` interface.
|
||||
3. Allow the user to swap the HTTP client (e.g. `valyala/fasthttp`) and JSON codec (e.g. `goccy/go-json`).
|
||||
4. Provide a typed dispatcher with command, text-regex, callback, and inline-query matching plus generic middleware.
|
||||
5. Provide unit tests using `stretchr/testify` covering happy paths and explicit edge cases.
|
||||
6. Provide an optional integration test suite gated by build tag and env vars.
|
||||
|
||||
### Non-functional
|
||||
|
||||
- Lean dependency footprint (stdlib + `golang.org/x/net/html` + testify).
|
||||
- Deterministic, reproducible codegen (`go test ./... -run TestGen` is hermetic).
|
||||
- Generated files committed to the repo so consumers do not need to run codegen.
|
||||
- Doc comments on every exported symbol; generated types carry Telegram's verbatim prose.
|
||||
|
||||
## 4. Architecture
|
||||
|
||||
Two-stage codegen with a JSON intermediate representation:
|
||||
|
||||
```
|
||||
HTML page cmd/scrape api.json (IR) cmd/genapi api/*.gen.go
|
||||
```
|
||||
|
||||
The IR is committed; PRs from a future regen workflow show the diff against the previous IR, providing a readable changelog of Telegram-side changes.
|
||||
|
||||
### 4.1 Repository layout
|
||||
|
||||
```
|
||||
go-telegram/
|
||||
├── api/ GENERATED types + method wrappers (typed param structs)
|
||||
│ ├── types.gen.go
|
||||
│ ├── methods.gen.go
|
||||
│ └── enums.gen.go
|
||||
├── client/ HAND Bot client, request building, error handling
|
||||
│ ├── client.go
|
||||
│ ├── codec.go Codec interface + encoding/json default
|
||||
│ ├── httpclient.go HTTPDoer interface + net/http default
|
||||
│ ├── errors.go Typed APIError, NetworkError, ParseError
|
||||
│ └── result.go generic Result[T] decode
|
||||
├── transport/ HAND Updater abstraction
|
||||
│ ├── updater.go Updater interface
|
||||
│ ├── longpoll.go LongPoller
|
||||
│ └── webhook.go WebhookServer
|
||||
├── dispatch/ HAND Handler router
|
||||
│ ├── router.go Router, OnCommand/OnCallback/OnText
|
||||
│ ├── middleware.go Generic Middleware[T]
|
||||
│ └── context.go Per-update context
|
||||
├── internal/
|
||||
│ └── spec/ Shared IR types
|
||||
│ ├── ir.go Types describing parsed Telegram API
|
||||
│ └── api.json Committed golden IR (regenerated by scraper)
|
||||
├── cmd/
|
||||
│ ├── scrape/ HTML → api.json
|
||||
│ └── genapi/ api.json → api/*.gen.go
|
||||
├── examples/
|
||||
│ ├── echo/ Long-poll echo bot
|
||||
│ └── webhook/ Webhook bot with command router
|
||||
├── testdata/
|
||||
│ ├── html/ Golden HTML snapshots for scraper
|
||||
│ ├── golden/ Expected api.json + emitted Go for codegen tests
|
||||
│ └── responses/ Canned Telegram JSON responses
|
||||
├── .github/workflows/
|
||||
│ └── ci.yml lint + test + codegen-clean check
|
||||
├── Makefile regen, test, lint targets
|
||||
├── go.mod module github.com/lukaszraczylo/go-telegram
|
||||
├── LICENSE MIT
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 5. Core types and client (`client/`)
|
||||
|
||||
### 5.1 Pluggability interfaces
|
||||
|
||||
```go
|
||||
// Codec is the JSON encoder/decoder. Default impl wraps encoding/json.
|
||||
type Codec interface {
|
||||
Marshal(v any) ([]byte, error)
|
||||
Unmarshal(data []byte, v any) error
|
||||
}
|
||||
|
||||
// HTTPDoer is the HTTP transport. Default is *http.Client.
|
||||
type HTTPDoer interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// Logger is a slog-shaped interface; nil-safe default writes nowhere.
|
||||
type Logger interface {
|
||||
Debug(msg string, attrs ...any)
|
||||
Info(msg string, attrs ...any)
|
||||
Warn(msg string, attrs ...any)
|
||||
Error(msg string, attrs ...any)
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Bot client
|
||||
|
||||
```go
|
||||
type Bot struct {
|
||||
token string
|
||||
base string // https://api.telegram.org
|
||||
http HTTPDoer
|
||||
codec Codec
|
||||
logger Logger
|
||||
}
|
||||
|
||||
type Option func(*Bot)
|
||||
func WithHTTPClient(c HTTPDoer) Option
|
||||
func WithCodec(c Codec) Option
|
||||
func WithBaseURL(url string) Option
|
||||
func WithLogger(l Logger) Option
|
||||
|
||||
func New(token string, opts ...Option) *Bot
|
||||
```
|
||||
|
||||
Constructor-level functional options only; per-call params are typed structs (codegen-friendly).
|
||||
|
||||
### 5.3 Result envelope and call helper
|
||||
|
||||
```go
|
||||
type Result[T any] struct {
|
||||
OK bool `json:"ok"`
|
||||
Result T `json:"result,omitempty"`
|
||||
ErrorCode int `json:"error_code,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Parameters *ResponseParameters `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// Single point for marshalling, URL signing, decoding, error mapping.
|
||||
// Used by every generated method wrapper.
|
||||
func call[Req, Resp any](ctx context.Context, b *Bot, method string, req Req) (Resp, error)
|
||||
```
|
||||
|
||||
Generated wrappers stay thin:
|
||||
|
||||
```go
|
||||
func (b *Bot) SendMessage(ctx context.Context, p *SendMessageParams) (*Message, error) {
|
||||
return call[*SendMessageParams, *Message](ctx, b, "sendMessage", p)
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 Errors
|
||||
|
||||
```go
|
||||
type APIError struct {
|
||||
Code int
|
||||
Description string
|
||||
Parameters *ResponseParameters // retry_after, migrate_to_chat_id
|
||||
}
|
||||
func (e *APIError) Error() string
|
||||
func (e *APIError) IsRetryable() bool // 429, 5xx
|
||||
func (e *APIError) RetryAfter() time.Duration
|
||||
|
||||
type NetworkError struct{ Err error }
|
||||
type ParseError struct{ Err error; Body []byte }
|
||||
```
|
||||
|
||||
Sentinel errors via `errors.Is`: `ErrUnauthorized`, `ErrChatNotFound`, `ErrMessageNotModified`, `ErrTooManyRequests`. Mapped from `error_code` plus description-prefix matching.
|
||||
|
||||
## 6. Codegen pipeline
|
||||
|
||||
### 6.1 Stage 1 — `cmd/scrape/`
|
||||
|
||||
- Input: live URL `https://core.telegram.org/bots/api` (default) or a local HTML fixture (`-input` flag).
|
||||
- Parser: `golang.org/x/net/html` (no goquery).
|
||||
- Walk strategy: traverse `<h4>` headings sequentially. Lowercase first letter → method. Uppercase → type.
|
||||
- Following `<p>` until next heading → description.
|
||||
- Following `<table>` → fields/params (columns: Field|Type|Required|Description for types; Parameter|Type|Required|Description for methods).
|
||||
- Return type extracted by regex on description: `Returns *X* on success`, `Returns an Array of X`, `Returns True on success`.
|
||||
- Italic markers in the type column denote optional, array depth, and union-member candidates.
|
||||
- "Recent changes" section parsed for current API version.
|
||||
|
||||
### 6.2 Intermediate representation (`internal/spec/ir.go`)
|
||||
|
||||
```go
|
||||
type API struct {
|
||||
Version string
|
||||
Types []TypeDecl
|
||||
Methods []MethodDecl
|
||||
}
|
||||
type TypeDecl struct {
|
||||
Name string
|
||||
Doc string
|
||||
Fields []Field
|
||||
OneOf []string // unions (InputMedia, ChatMember, …)
|
||||
}
|
||||
type MethodDecl struct {
|
||||
Name string // sendMessage
|
||||
Doc string
|
||||
Params []Field
|
||||
Returns TypeRef
|
||||
HasFiles bool // forces multipart
|
||||
}
|
||||
type Field struct {
|
||||
Name string
|
||||
JSONName string
|
||||
Type TypeRef
|
||||
Required bool
|
||||
Doc string
|
||||
}
|
||||
type Kind int
|
||||
const (
|
||||
KindPrimitive Kind = iota
|
||||
KindNamed
|
||||
KindArray
|
||||
KindOneOf
|
||||
)
|
||||
type TypeRef struct {
|
||||
Kind Kind
|
||||
Name string
|
||||
ElemType *TypeRef
|
||||
Variants []string
|
||||
}
|
||||
```
|
||||
|
||||
`internal/spec/api.json` is committed. Marshalling is stable (sorted fields, deterministic JSON output) so diffs read as a Telegram changelog.
|
||||
|
||||
### 6.3 Stage 2 — `cmd/genapi/`
|
||||
|
||||
- Reads `api.json`.
|
||||
- Emits Go via `text/template`, finalised with `go/format`.
|
||||
- Templates:
|
||||
- `types.tmpl` → struct per `TypeDecl`. Optional fields are pointers (or `omitempty` for slices/maps). Doc comments verbatim from API.
|
||||
- `enums.tmpl` → string consts for known enumerations (parse modes, chat types, etc., extracted from doc prose).
|
||||
- `oneof.tmpl` → union types as `interface { isFooBar() }` plus concrete impls and a `UnmarshalJSON` that switches on a discriminator field (typically `type` or `source`).
|
||||
- `methods.tmpl` → param struct + thin `Bot.<MethodName>` wrapper using `call[…]`.
|
||||
- `multipart.tmpl` → for methods with `HasFiles`, custom request builder using `mime/multipart`.
|
||||
- Header on every emitted file: `// Code generated by cmd/genapi. DO NOT EDIT.` + `//go:build !ignore_autogenerated`.
|
||||
|
||||
### 6.4 Makefile contract
|
||||
|
||||
The Makefile owns the codegen entry points; tools and CI call `make`, never raw `go run`:
|
||||
|
||||
| Target | What it does |
|
||||
|---|---|
|
||||
| `make snapshot` | `curl -fsSL https://core.telegram.org/bots/api > testdata/html/snapshot_<date>.html` and update a `latest.html` symlink. |
|
||||
| `make regen` | Run scraper against `testdata/html/latest.html`, then run emitter. Writes `internal/spec/api.json` and `api/*.gen.go`. |
|
||||
| `make regen-from-fixture` | Same as `make regen` but pinned to `testdata/html/snapshot_2026-05-08.html` for deterministic CI checks. |
|
||||
| `make test` | `go test -race ./...` |
|
||||
| `make test-update-golden` | `go test -run TestGen -update ./...` to refresh golden fixtures. |
|
||||
| `make lint` | `go vet` + `staticcheck`. |
|
||||
| `make integration` | `go test -tags=integration ./test/integration/...` (requires env). |
|
||||
|
||||
## 7. Transport (`transport/`)
|
||||
|
||||
```go
|
||||
type Updater interface {
|
||||
Updates() <-chan api.Update
|
||||
Run(ctx context.Context) error
|
||||
Stop(ctx context.Context) error
|
||||
}
|
||||
```
|
||||
|
||||
### 7.1 LongPoller
|
||||
|
||||
```go
|
||||
type LongPoller struct {
|
||||
Bot *client.Bot
|
||||
Timeout int // seconds, default 30
|
||||
Limit int // 1..100, default 100
|
||||
AllowedTypes []api.UpdateType
|
||||
Backoff BackoffStrategy
|
||||
}
|
||||
```
|
||||
|
||||
Calls `getUpdates` in a loop, tracks `offset`, applies exponential backoff on transient errors via `BackoffStrategy`.
|
||||
|
||||
### 7.2 WebhookServer
|
||||
|
||||
```go
|
||||
type WebhookServer struct {
|
||||
Bot *client.Bot
|
||||
SecretToken string // verify X-Telegram-Bot-Api-Secret-Token
|
||||
BufferSize int
|
||||
}
|
||||
func (w *WebhookServer) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
func (w *WebhookServer) ListenAndServe(ctx context.Context, addr string) error
|
||||
```
|
||||
|
||||
`ServeHTTP` lets users mount on their own router. `ListenAndServe` is a convenience for standalone use.
|
||||
|
||||
## 8. Dispatcher (`dispatch/`)
|
||||
|
||||
```go
|
||||
type Context struct {
|
||||
Ctx context.Context
|
||||
Bot *client.Bot
|
||||
Update *api.Update
|
||||
Values map[string]any // matched groups, command args
|
||||
}
|
||||
|
||||
type Handler[T any] func(ctx *Context, payload T) error
|
||||
type Middleware[T any] func(Handler[T]) Handler[T]
|
||||
|
||||
type Router struct{ /* … */ }
|
||||
|
||||
func New(bot *client.Bot) *Router
|
||||
|
||||
func (r *Router) OnCommand(cmd string, h Handler[*api.Message])
|
||||
func (r *Router) OnText(pattern string, h Handler[*api.Message])
|
||||
func (r *Router) OnCallback(pattern string, h Handler[*api.CallbackQuery])
|
||||
func (r *Router) OnInlineQuery(h Handler[*api.InlineQuery])
|
||||
func (r *Router) OnEditedMessage(h Handler[*api.Message])
|
||||
func (r *Router) Use(mw Middleware[*api.Update])
|
||||
|
||||
func (r *Router) Run(ctx context.Context, u transport.Updater) error
|
||||
```
|
||||
|
||||
Matchers run in registration order; first match wins. A panic-recovery middleware is registered automatically. Generic `Handler[T]` keeps payloads precisely typed in user code.
|
||||
|
||||
## 9. Testing strategy
|
||||
|
||||
### 9.1 Unit tests (every package, fast, no network)
|
||||
|
||||
- `testify/require` for assertions, `testify/mock` on `client.HTTPDoer`.
|
||||
- Edge cases explicitly covered:
|
||||
- API error decode for `429` with `retry_after` → `*APIError.IsRetryable()=true`, `RetryAfter()=N`.
|
||||
- Network error from transport → wrapped `*NetworkError`.
|
||||
- Malformed JSON → `*ParseError`.
|
||||
- Void-result methods (`setWebhook` returning `bool`).
|
||||
- Optional pointer fields nil round-trip.
|
||||
- OneOf union types unmarshal via discriminator.
|
||||
- Multipart upload path for methods with `InputFile`.
|
||||
- Context cancellation mid-call returns `ctx.Err()`.
|
||||
- Long-poller backoff after transient error.
|
||||
- Webhook secret-token mismatch → 401.
|
||||
- Webhook handles oversized body, malformed JSON, wrong content-type.
|
||||
- Router: command match with/without bot mention (`/start@MyBot`), regex matchers, panic recovery, middleware ordering, no-match update.
|
||||
|
||||
### 9.2 Codegen golden tests
|
||||
|
||||
```
|
||||
testdata/html/
|
||||
├── snapshot_2026-05-08.html full Bots API page snapshot
|
||||
└── small_fixture.html hand-crafted minimal page (1 type, 1 method)
|
||||
testdata/golden/
|
||||
├── api.json expected IR from snapshot
|
||||
└── *.gen.go expected emitted Go
|
||||
```
|
||||
|
||||
- `cmd/scrape` test: parse fixture → compare to golden `api.json`.
|
||||
- `cmd/genapi` test: read golden `api.json` → compare emitted Go to golden `*.gen.go`.
|
||||
- `-update` flag (custom in `internal/testutil`) regenerates goldens deliberately.
|
||||
|
||||
### 9.3 Optional integration suite
|
||||
|
||||
- Build tag `//go:build integration`.
|
||||
- Skipped by default `go test ./...`.
|
||||
- Activated by `go test -tags=integration ./test/integration/...`.
|
||||
- Requires `TELEGRAM_BOT_TOKEN` (and `TELEGRAM_TEST_CHAT_ID` where applicable).
|
||||
- Covers `getMe`, `sendMessage`, `setWebhook`/`deleteWebhook`, `getUpdates` loop with short timeout.
|
||||
- Not part of default CI to avoid flakes.
|
||||
|
||||
## 10. CI
|
||||
|
||||
`.github/workflows/ci.yml` (every push and PR):
|
||||
|
||||
- `actions/setup-go` matrix: 1.23, 1.24
|
||||
- `go vet ./...`
|
||||
- `staticcheck ./...`
|
||||
- `go test -race -coverprofile=coverage.out ./...`
|
||||
- Codegen-clean check: `make regen-from-fixture` + `git diff --exit-code` to assert generated files match the committed IR for the snapshot fixture (deterministic).
|
||||
- Upload coverage artifact.
|
||||
|
||||
## 11. Handling API changes & test maintenance
|
||||
|
||||
Telegram ships changes to the Bot API roughly every 1–3 months: new methods, new types, added optional fields, occasional removals or renames, occasional union-variant additions. The design must absorb these with minimum manual work.
|
||||
|
||||
### 11.1 Test-suite invariants under change
|
||||
|
||||
Tests are layered so that the cost of an API change is bounded.
|
||||
|
||||
| Test layer | Affected by API change? | Cost |
|
||||
|---|---|---|
|
||||
| `client/` unit tests (call helper, error mapping, codec, multipart builder) | No — they target `call[Req,Resp]`, not specific methods. | Zero. |
|
||||
| `transport/` unit tests (long-poll loop, webhook server) | No — they target update plumbing, not payload fields. | Zero. |
|
||||
| `dispatch/` unit tests (matchers, middleware, router) | No — generic over `*api.Update`. | Zero. |
|
||||
| Codegen golden tests (`cmd/scrape`, `cmd/genapi`) | Yes — golden `api.json` and `*.gen.go` will diff. | Refresh goldens deliberately (`go test -run TestGen -update`). |
|
||||
| Codegen "shape" smoke tests | Only if a code-generation pattern changes. | One test per pattern, not per method. |
|
||||
| Examples (`examples/echo`, `examples/webhook`) | Only if they reference a removed/renamed symbol. | Hand-fix; rare. |
|
||||
| Integration suite (build tag `integration`) | Only for the ~5 methods it touches. | Hand-fix on removal/rename; rare. |
|
||||
|
||||
The deliberate invariant: **we do not write a test per generated method.** All ~100+ generated wrappers funnel through `call[Req,Resp]` and the multipart builder; coverage of those two paths covers them all. Each generated method is then sanity-checked by being type-checked at compile time against the IR.
|
||||
|
||||
### 11.2 Shape smoke tests
|
||||
|
||||
In `api/api_test.go`, one test per code-generation pattern, hitting a representative method through a mocked `HTTPDoer`:
|
||||
|
||||
- **Simple** — `getMe` (no params, scalar response).
|
||||
- **Typed-struct param** — `sendMessage` (struct in, object out).
|
||||
- **Optional fields** — `sendMessage` with only required fields set; verify omitted fields do not appear in the request body.
|
||||
- **Array result** — `getUpdates` (array of `Update`).
|
||||
- **Bool result** — `setWebhook`.
|
||||
- **Multipart upload** — `sendDocument` with an `InputFile` (verify content-type, boundary, field names).
|
||||
- **OneOf union response** — `getChatMember` (returns `ChatMember` union).
|
||||
- **OneOf union request** — `sendMediaGroup` (accepts `[]InputMedia` union).
|
||||
|
||||
If new code-generation patterns appear (Telegram introducing a new shape we have not seen), one new shape test is added — not one per affected method.
|
||||
|
||||
### 11.3 Categories of change and how each is absorbed
|
||||
|
||||
| Change | Pipeline effect | Test effect |
|
||||
|---|---|---|
|
||||
| New type | Appears in `api.json`, emitted into `types.gen.go`. | Golden diff only. Refresh. |
|
||||
| New optional field | Same. | Golden diff only. |
|
||||
| New required field | Same. Breaking for users who construct that struct literally. | Golden diff only; example code may need update. |
|
||||
| Removed type/method/field | Disappears from emitted Go. Breaking for users referring to it. | Golden diff. Integration test or example may break — fix or skip. |
|
||||
| Renamed field | Old name disappears, new appears. | Same as above; no automatic rename (we treat as remove + add). |
|
||||
| New method | Wrapper generated; no new test required (shape tests cover the call path). | Golden diff. |
|
||||
| Return type changed for an existing method | Wrapper signature changes. Breaking. | Golden diff; integration test for that method may break. |
|
||||
| New OneOf variant | `UnmarshalJSON` switch grows a case. | Golden diff. If a brand-new variant style appears, may require scraper work and a new shape test. |
|
||||
| Telegram doc layout change | Scraper may misparse. | Scraper unit test against the new HTML fixture should be added before regenerating. |
|
||||
|
||||
### 11.4 The change procedure
|
||||
|
||||
When the scraper output changes:
|
||||
|
||||
1. Run `make regen-from-fixture` against the current `testdata/html/snapshot_*.html` (deterministic check) — confirm zero unrelated diffs.
|
||||
2. Capture a fresh HTML snapshot: `make snapshot` (writes `testdata/html/snapshot_<date>.html`).
|
||||
3. Run `make regen` against the new snapshot → IR diff appears in `internal/spec/api.json`.
|
||||
4. Review the IR diff as a Telegram changelog. This is the human read-through; it is the entire point of having an IR.
|
||||
5. Run `go test ./...` → expect golden codegen diffs.
|
||||
6. Refresh goldens: `go test -run TestGen -update`.
|
||||
7. Re-run `go test ./...` → green.
|
||||
8. If shape tests reveal a new code-generation pattern (e.g. a never-before-seen union shape), extend templates and add a shape test before refreshing goldens.
|
||||
9. If `examples/` or integration tests reference a removed symbol, fix them.
|
||||
10. Commit with a clear message: `chore(api): regenerate from Telegram Bot API vX.Y` plus a bullet list extracted from the IR diff (added/changed/removed types and methods).
|
||||
|
||||
This is the same procedure the future auto-regen workflow will run; doing it by hand first ensures the workflow has nothing surprising to do.
|
||||
|
||||
### 11.5 Versioning policy
|
||||
|
||||
- Library SemVer is decoupled from Telegram's API version.
|
||||
- Telegram-side additions → minor bump.
|
||||
- Telegram-side removals or signature changes → major bump (we do not preserve removed symbols as deprecated stubs; the breaking change ships).
|
||||
- Bug fixes in hand-written code → patch bump.
|
||||
- Each release records the Telegram API version it was generated against in the release notes and in a `// Generated from Bot API vX.Y` constant in `api/version.gen.go`.
|
||||
|
||||
## 12. Future work (deferred)
|
||||
|
||||
- **Auto-regen workflow** — daily cron + `workflow_dispatch` that runs `cmd/scrape` against the live URL, regenerates code, opens a PR with a diff summary, and auto-merges on green CI. Implementation sketch retained in design discussion; not part of v1 acceptance.
|
||||
- **Release workflow** — tag-triggered `goreleaser` pipeline producing GH Releases. SemVer for the library; Telegram's API version recorded in release notes.
|
||||
- **Additional codecs/HTTP adapters** as separate sub-packages or contrib modules so users can opt in without bringing transitive deps into the core.
|
||||
|
||||
## 13. Dependency policy
|
||||
|
||||
Production:
|
||||
- Go standard library
|
||||
- `golang.org/x/net/html` (scraper only)
|
||||
|
||||
Test-only:
|
||||
- `github.com/stretchr/testify`
|
||||
|
||||
Explicit non-deps: `goquery`, `cobra`, third-party logging, third-party HTTP clients, third-party JSON codecs (these are user-supplied via `HTTPDoer` and `Codec`).
|
||||
|
||||
## 14. Acceptance criteria
|
||||
|
||||
v1 is done when:
|
||||
|
||||
1. `go test ./...` passes on a clean checkout with no env vars.
|
||||
2. `make regen` produces zero diff against the committed `api.json` and `api/*.gen.go` when run against the committed HTML fixture.
|
||||
3. `examples/echo` and `examples/webhook` build and the echo example runs end-to-end against a real bot when `TELEGRAM_BOT_TOKEN` is set.
|
||||
4. `go vet`, `staticcheck`, and `go test -race` are clean.
|
||||
5. Every exported symbol in hand-written packages has a doc comment.
|
||||
6. README covers Why, Install, Quick Start, Custom HTTP/JSON, Webhooks, Dispatcher, Updating, Contributing.
|
||||
7. The integration test suite (`-tags=integration`) runs cleanly when env is provided.
|
||||
|
||||
## 15. Open questions
|
||||
|
||||
None at sign-off. (Auto-regen behaviour intentionally deferred.)
|
||||
Reference in New Issue
Block a user