docs: wiki documentation for go-forge

Seven pages covering Home, Architecture, Services, Code Generation,
Configuration, Error Handling, and Development.

Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-02-21 17:04:59 +00:00
parent 33319590d4
commit f5f796cd16
7 changed files with 943 additions and 0 deletions

122
docs/wiki/Architecture.md Normal file
View file

@ -0,0 +1,122 @@
# Architecture
## Overview
go-forge is structured around three core ideas:
1. **Generic Resource** — a single `Resource[T, C, U]` type that provides CRUD methods for any Forgejo API resource.
2. **Code generation** — all 229 Go types are generated from `swagger.v1.json` via a custom codegen tool.
3. **Service embedding** — each service struct embeds `Resource` for free CRUD, then adds hand-written action methods for non-CRUD endpoints.
## File Layout
```
go-forge/
client.go HTTP client with auth, context, error handling
pagination.go Generic ListPage[T] and ListAll[T]
params.go Path variable resolution ({owner}/{repo} -> values)
resource.go Generic Resource[T, C, U] for CRUD
config.go Config resolution: flags -> env -> defaults
forge.go Top-level Forge client aggregating all 18 services
repos.go RepoService (embeds Resource)
issues.go IssueService (embeds Resource)
pulls.go PullService (embeds Resource)
orgs.go OrgService (embeds Resource)
users.go UserService (embeds Resource)
teams.go TeamService (embeds Resource)
branches.go BranchService (embeds Resource)
releases.go ReleaseService (embeds Resource)
webhooks.go WebhookService (embeds Resource)
admin.go AdminService (plain client)
labels.go LabelService (plain client)
contents.go ContentService (plain client)
actions.go ActionsService (plain client)
notifications.go NotificationService (plain client)
packages.go PackageService (plain client)
wiki.go WikiService (plain client)
misc.go MiscService (plain client)
commits.go CommitService (plain client)
cmd/forgegen/ Code generator
main.go CLI entry point
parser.go Swagger 2.0 spec parser
generator.go Go source code emitter
types/ Generated Go types (229 types across 36 files)
generate.go go:generate directive
repo.go Repository, CreateRepoOption, EditRepoOption, ...
issue.go Issue, CreateIssueOption, ...
...
testdata/
swagger.v1.json Forgejo Swagger 2.0 specification
```
## Generic Resource[T, C, U]
The core abstraction. `T` is the resource type (e.g. `types.Repository`), `C` is the create options type (e.g. `types.CreateRepoOption`), `U` is the update options type (e.g. `types.EditRepoOption`).
```go
type Resource[T any, C any, U any] struct {
client *Client
path string // e.g. "/api/v1/repos/{owner}/{repo}"
}
```
Provides six methods out of the box:
| Method | HTTP | Description |
|----------|----------|-----------------------------------|
| `List` | GET | Single page with `ListOptions` |
| `ListAll`| GET | All pages (auto-pagination) |
| `Get` | GET | Single resource by path params |
| `Create` | POST | Create with `*C` body |
| `Update` | PATCH | Update with `*U` body |
| `Delete` | DELETE | Delete by path params |
Path parameters like `{owner}` and `{repo}` are resolved at call time via `Params` maps:
```go
repo, err := f.Repos.Get(ctx, forge.Params{"owner": "core", "repo": "go-forge"})
```
## Service Pattern
Services that fit the CRUD model embed `Resource`:
```go
type RepoService struct {
Resource[types.Repository, types.CreateRepoOption, types.EditRepoOption]
}
```
This gives `RepoService` free `List`, `ListAll`, `Get`, `Create`, `Update`, and `Delete` methods. Action methods like `Fork`, `Transfer`, and `MirrorSync` are added as hand-written methods.
Services with heterogeneous endpoints (e.g. `AdminService`, `LabelService`) hold a plain `*Client` field instead of embedding `Resource`.
## Pagination
All list endpoints use Forgejo's `X-Total-Count` header for total item counts and `page`/`limit` query parameters.
- `ListPage[T]` — fetches a single page, returns `*PagedResult[T]` with `Items`, `TotalCount`, `Page`, `HasMore`.
- `ListAll[T]` — iterates all pages automatically, returns `[]T`.
## HTTP Client
`Client` is a low-level HTTP client that:
- Adds `Authorization: token <token>` to every request
- Sets `Accept: application/json` and `Content-Type: application/json`
- Wraps errors as `*APIError` with `StatusCode`, `Message`, `URL`
- Supports `Get`, `Post`, `Patch`, `Put`, `Delete`, `DeleteWithBody`, `GetRaw`, `PostRaw`
- Accepts `context.Context` on all methods
## Code Generation Pipeline
```
swagger.v1.json --> parser.go --> generator.go --> types/*.go
(extract) (emit Go) (229 types)
```
The parser reads the Swagger 2.0 spec, extracts type definitions, detects Create/Edit option pairs, and resolves Go types. The generator groups types by domain (repo, issue, PR, etc.) and writes one `.go` file per group with `// Code generated` headers.

View file

@ -0,0 +1,125 @@
# Code Generation
All Go types in the `types/` package are generated from the Forgejo Swagger 2.0 specification. This page explains how the pipeline works and how to regenerate types.
## Pipeline
```
testdata/swagger.v1.json
|
v
cmd/forgegen/parser.go (parse spec, extract types, detect CRUD pairs)
|
v
cmd/forgegen/generator.go (group types by domain, emit Go source)
|
v
types/*.go (229 types across 36 files)
```
## Regenerating Types
```bash
go generate ./types/...
```
This runs the `//go:generate` directive in `types/generate.go`:
```go
//go:generate go run ../cmd/forgegen/ -spec ../testdata/swagger.v1.json -out .
```
You can also run the generator directly:
```bash
go run ./cmd/forgegen/ -spec testdata/swagger.v1.json -out types/
```
## Upgrading Forgejo Version
1. Download the new `swagger.v1.json` from your Forgejo instance at `/swagger.json`.
2. Replace `testdata/swagger.v1.json` with the new file.
3. Regenerate types:
```bash
go generate ./types/...
```
4. Verify compilation:
```bash
go build ./...
```
5. Run tests:
```bash
go test ./...
```
6. Review the diff for new, changed, or removed types.
## How It Works
### Parser (`cmd/forgegen/parser.go`)
- **`LoadSpec`** — reads and parses the JSON spec file.
- **`ExtractTypes`** — converts all `definitions` into `GoType` structs with fields, JSON tags, and Go type mappings.
- **`DetectCRUDPairs`** — finds matching `Create*Option`/`Edit*Option` pairs (e.g. `CreateRepoOption` + `EditRepoOption` = base `Repo`).
Type mapping rules:
| Swagger Type | Go Type |
|--------------------|----------------|
| `string` | `string` |
| `string` + `date-time` | `time.Time` |
| `string` + `binary` | `[]byte` |
| `integer` + `int64` | `int64` |
| `integer` + `int32` | `int32` |
| `boolean` | `bool` |
| `number` + `float` | `float32` |
| `number` | `float64` |
| `array` | `[]<item type>`|
| `object` | `map[string]any`|
| `$ref` | `*<TypeName>` |
### Generator (`cmd/forgegen/generator.go`)
- **`classifyType`** — assigns each type to a domain file (e.g. `Repository` -> `repo.go`, `Issue` -> `issue.go`).
- **`Generate`** — groups types by file, sorts alphabetically, and writes each file.
- **`writeFile`** — uses `text/template` to emit valid Go with `package types`, conditional `import "time"`, and `// Code generated` headers.
### Type Grouping
Types are grouped by prefix matching against a domain map:
| Prefix/Name | File |
|------------------|-----------------|
| `Repository`, `Repo` | `repo.go` |
| `Issue` | `issue.go` |
| `PullRequest`, `Pull` | `pr.go` |
| `User` | `user.go` |
| `Organization`, `Org` | `org.go` |
| `Team` | `team.go` |
| `Branch` | `branch.go` |
| `Release` | `release.go` |
| `Hook` | `hook.go` |
| `Commit`, `Git` | `commit.go`/`git.go` |
| `Package` | `package.go` |
| `Action`, `Secret`, `Variable` | `action.go` |
| `Notification` | `notification.go` |
| `Wiki` | `wiki.go` |
| (unmatched) | `misc.go` |
## Generated File Format
Each file follows this structure:
```go
// Code generated by forgegen from swagger.v1.json — DO NOT EDIT.
package types
import "time" // only if time.Time fields are present
// TypeName — description from swagger spec.
type TypeName struct {
FieldName GoType `json:"field_name,omitempty"`
}
```
Fields marked as `required` in the spec omit the `,omitempty` JSON tag option.

View file

@ -0,0 +1,88 @@
# Configuration
go-forge resolves its Forgejo URL and API token from multiple sources with a clear priority chain.
## Priority Order
```
1. Flags (highest) — passed directly to NewForgeFromConfig or ResolveConfig
2. Environment variables — FORGE_URL, FORGE_TOKEN
3. Defaults (lowest) — http://localhost:3000 for URL, no token default
```
## Environment Variables
| Variable | Description | Default |
|---------------|--------------------------------------|--------------------------|
| `FORGE_URL` | Base URL of the Forgejo instance | `http://localhost:3000` |
| `FORGE_TOKEN` | API token for authentication | _(none — required)_ |
## Using NewForgeFromConfig
The simplest way to create a configured client:
```go
// Reads from FORGE_URL and FORGE_TOKEN environment variables.
f, err := forge.NewForgeFromConfig("", "")
if err != nil {
log.Fatal(err) // "no API token configured" if FORGE_TOKEN is unset
}
```
With flag overrides:
```go
// Flag values take priority over env vars.
f, err := forge.NewForgeFromConfig("https://forge.example.com", "my-token")
```
## Using ResolveConfig Directly
For more control, resolve the config separately:
```go
url, token, err := forge.ResolveConfig(flagURL, flagToken)
if err != nil {
log.Fatal(err)
}
// Use url and token as needed...
f := forge.NewForge(url, token)
```
## Using NewForge Directly
If you already have the URL and token:
```go
f := forge.NewForge("https://forge.lthn.ai", "my-api-token")
```
## Client Options
`NewForge` and `NewForgeFromConfig` accept variadic options:
```go
// Custom HTTP client (e.g. with timeouts, proxies, TLS config)
f := forge.NewForge(url, token,
forge.WithHTTPClient(&http.Client{Timeout: 30 * time.Second}),
)
// Custom User-Agent header
f := forge.NewForge(url, token,
forge.WithUserAgent("my-app/1.0"),
)
```
| Option | Description | Default |
|--------------------|-------------------------------|------------------|
| `WithHTTPClient` | Set a custom `*http.Client` | `http.DefaultClient` |
| `WithUserAgent` | Set the `User-Agent` header | `go-forge/0.1` |
## Accessing the Low-Level Client
If you need direct HTTP access for custom endpoints:
```go
client := f.Client() // returns *forge.Client
err := client.Get(ctx, "/api/v1/custom/endpoint", &result)
```

123
docs/wiki/Development.md Normal file
View file

@ -0,0 +1,123 @@
# Development
## Prerequisites
- Go 1.21+ (generics support required)
- Access to a Forgejo instance for integration testing (optional)
## Building
```bash
go build ./...
```
## Running Tests
```bash
# All tests
go test ./...
# Verbose output
go test -v ./...
# Single test
go test -v -run TestClient_Good_Get ./...
# With race detection
go test -race ./...
```
## Test Naming Convention
Tests use a `_Good`, `_Bad`, `_Ugly` suffix pattern:
| Suffix | Purpose |
|---------|--------------------------------------|
| `_Good` | Happy path — expected success |
| `_Bad` | Expected errors — invalid input, 404 |
| `_Ugly` | Edge cases — panics, empty data |
## Regenerating Types
When the Forgejo Swagger spec is updated:
```bash
# Using go generate
go generate ./types/...
# Or directly
go run ./cmd/forgegen/ -spec testdata/swagger.v1.json -out types/
```
Then verify:
```bash
go build ./...
go test ./...
go vet ./...
```
## Adding a New Service
1. Create `servicename.go` with the service struct:
- If CRUD applies: embed `Resource[T, C, U]` with the appropriate types.
- If endpoints are heterogeneous: use a plain `client *Client` field.
2. Add a constructor: `func newServiceNameService(c *Client) *ServiceNameService`
3. Add action methods for non-CRUD endpoints.
4. Create `servicename_test.go` with tests following the `_Good`/`_Bad`/`_Ugly` convention.
5. Wire the service in `forge.go`:
- Add the field to the `Forge` struct.
- Add `f.ServiceName = newServiceNameService(c)` in `NewForge`.
6. Run all tests: `go test ./...`
## Adding a New Action Method
Action methods are hand-written methods on service structs for endpoints that don't fit the CRUD pattern.
```go
func (s *ServiceName) ActionName(ctx context.Context, params...) (returnType, error) {
path := fmt.Sprintf("/api/v1/path/%s/%s", param1, param2)
var out types.ReturnType
if err := s.client.Post(ctx, path, body, &out); err != nil {
return nil, err
}
return &out, nil
}
```
All methods must:
- Accept `context.Context` as the first parameter
- Return `error` as the last return value
- Use `fmt.Sprintf` for path construction with parameters
## Project Conventions
- **UK English** in comments (organisation, colour, licence)
- **`context.Context`** as the first parameter on all methods
- Errors wrapped as `*APIError` for HTTP responses
- Generated code has `// Code generated` headers and must not be edited manually
- Commit messages use conventional commits (`feat:`, `fix:`, `docs:`)
## Project Structure
```
go-forge/
*.go Core library (client, pagination, resource, services)
*_test.go Tests for each module
cmd/forgegen/ Code generator
types/ Generated types (do not edit)
testdata/ Swagger specification
docs/ Documentation
```
## Forge Remote
```bash
git remote add forge ssh://git@forge.lthn.ai:2223/core/go-forge.git
git push -u forge main
```

View file

@ -0,0 +1,87 @@
# Error Handling
All go-forge methods return errors wrapped as `*APIError` for HTTP error responses. This page covers the error types and how to handle them.
## APIError
When the Forgejo API returns an HTTP status >= 400, go-forge wraps the response as:
```go
type APIError struct {
StatusCode int // HTTP status code (e.g. 404, 403, 409)
Message string // Error message from the API response body
URL string // The request path
}
```
The `Error()` method formats as: `forge: /api/v1/repos/core/missing 404: not found`
## Sentinel Checks
Three helper functions test for common HTTP error statuses:
```go
repo, err := f.Repos.Get(ctx, forge.Params{"owner": "core", "repo": "missing"})
if err != nil {
if forge.IsNotFound(err) {
// 404 — resource does not exist
fmt.Println("Repository not found")
} else if forge.IsForbidden(err) {
// 403 — insufficient permissions
fmt.Println("Access denied")
} else if forge.IsConflict(err) {
// 409 — conflict (e.g. resource already exists)
fmt.Println("Conflict")
} else {
// Other error (network, 500, etc.)
log.Fatal(err)
}
}
```
| Function | Status Code | Typical Cause |
|----------------|-------------|-----------------------------------|
| `IsNotFound` | 404 | Resource does not exist |
| `IsForbidden` | 403 | Insufficient permissions or scope |
| `IsConflict` | 409 | Resource already exists |
## Extracting APIError
Use `errors.As` to access the full `APIError`:
```go
var apiErr *forge.APIError
if errors.As(err, &apiErr) {
fmt.Printf("Status: %d\n", apiErr.StatusCode)
fmt.Printf("Message: %s\n", apiErr.Message)
fmt.Printf("URL: %s\n", apiErr.URL)
}
```
## Non-API Errors
Errors that are not HTTP responses (network failures, JSON decode errors, request construction failures) are returned as plain `error` values with descriptive prefixes:
| Prefix | Cause |
|-----------------------------|------------------------------------|
| `forge: marshal body:` | Failed to JSON-encode request body |
| `forge: create request:` | Failed to build HTTP request |
| `forge: request GET ...:` | Network error during request |
| `forge: decode response:` | Failed to JSON-decode response |
| `forge: parse url:` | Invalid URL in pagination |
| `forge: read response body:`| Failed to read raw response body |
## Context Cancellation
All methods accept `context.Context`. When the context is cancelled or times out, the underlying `http.Client` returns a context error:
```go
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
repos, err := f.Repos.ListOrgRepos(ctx, "core")
if err != nil {
// Could be context.DeadlineExceeded or context.Canceled
log.Fatal(err)
}
```

69
docs/wiki/Home.md Normal file
View file

@ -0,0 +1,69 @@
# go-forge
Full-coverage Go client for the [Forgejo](https://forgejo.org/) API.
**Module:** `forge.lthn.ai/core/go-forge`
## Features
- 18 service modules covering repositories, issues, pull requests, organisations, teams, users, admin, branches, releases, labels, webhooks, notifications, packages, actions, contents, wiki, commits, and miscellaneous endpoints
- Generic `Resource[T, C, U]` pattern providing free CRUD for most services
- 229 Go types generated from the Forgejo Swagger 2.0 specification
- Automatic pagination with `ListAll` and `ListPage` generics
- Config resolution from flags, environment variables, and defaults
- Typed error handling with `IsNotFound`, `IsForbidden`, `IsConflict` helpers
## Install
```bash
go get forge.lthn.ai/core/go-forge
```
## Quick Start
```go
package main
import (
"context"
"fmt"
"log"
"forge.lthn.ai/core/go-forge"
)
func main() {
// Create a client — reads FORGE_URL and FORGE_TOKEN from environment.
f, err := forge.NewForgeFromConfig("", "")
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Get the authenticated user.
me, err := f.Users.GetCurrent(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Hello, %s!\n", me.Login)
// List repositories for an organisation.
repos, err := f.Repos.ListOrgRepos(ctx, "core")
if err != nil {
log.Fatal(err)
}
for _, r := range repos {
fmt.Println(r.FullName)
}
}
```
## Documentation
- [Architecture](Architecture) — Generic Resource pattern, codegen pipeline, service design
- [Services](Services) — All 18 services with method signatures
- [Code Generation](Code-Generation) — How types are generated from the Swagger spec
- [Configuration](Configuration) — Environment variables, flags, defaults
- [Error Handling](Error-Handling) — APIError, sentinel checks, error wrapping
- [Development](Development) — Building, testing, contributing

329
docs/wiki/Services.md Normal file
View file

@ -0,0 +1,329 @@
# Services
go-forge provides 18 services accessible via the top-level `Forge` client. Each service groups related API endpoints.
```go
f := forge.NewForge("https://forge.lthn.ai", "my-token")
f.Repos // Repository operations
f.Issues // Issue operations
f.Pulls // Pull request operations
f.Orgs // Organisation operations
f.Users // User operations
f.Teams // Team operations
f.Admin // Site administration
f.Branches // Branch operations
f.Releases // Release operations
f.Labels // Label operations
f.Webhooks // Webhook operations
f.Notifications // Notification operations
f.Packages // Package registry
f.Actions // CI/CD actions
f.Contents // File read/write
f.Wiki // Wiki pages
f.Misc // Markdown, licences, gitignore, server info
f.Commits // Commit statuses and git notes
```
---
## RepoService
Embeds `Resource[Repository, CreateRepoOption, EditRepoOption]`.
Path: `/api/v1/repos/{owner}/{repo}`
**CRUD** (via Resource): `List`, `ListAll`, `Get`, `Create`, `Update`, `Delete`
**Action methods:**
| Method | Description |
|------------------|----------------------------------------------|
| `ListOrgRepos` | All repositories for an organisation |
| `ListUserRepos` | All repositories for the authenticated user |
| `Fork` | Fork a repository (optionally into an org) |
| `Transfer` | Initiate a repository transfer |
| `AcceptTransfer` | Accept a pending transfer |
| `RejectTransfer` | Reject a pending transfer |
| `MirrorSync` | Trigger a mirror sync |
---
## IssueService
Embeds `Resource[Issue, CreateIssueOption, EditIssueOption]`.
Path: `/api/v1/repos/{owner}/{repo}/issues/{index}`
**Action methods:**
| Method | Description |
|------------------|------------------------------------|
| `Pin` | Pin an issue |
| `Unpin` | Unpin an issue |
| `SetDeadline` | Set or update a deadline |
| `AddReaction` | Add a reaction emoji |
| `DeleteReaction` | Remove a reaction emoji |
| `StartStopwatch` | Start time tracking |
| `StopStopwatch` | Stop time tracking |
| `AddLabels` | Add labels by ID |
| `RemoveLabel` | Remove a single label |
| `ListComments` | List all comments on an issue |
| `CreateComment` | Create a comment |
---
## PullService
Embeds `Resource[PullRequest, CreatePullRequestOption, EditPullRequestOption]`.
Path: `/api/v1/repos/{owner}/{repo}/pulls/{index}`
**Action methods:**
| Method | Description |
|-------------------|----------------------------------------|
| `Merge` | Merge a pull request (merge, rebase, squash, etc.) |
| `Update` | Update branch with base branch |
| `ListReviews` | List all reviews |
| `SubmitReview` | Submit a new review |
| `DismissReview` | Dismiss a review |
| `UndismissReview` | Undismiss a review |
---
## OrgService
Embeds `Resource[Organization, CreateOrgOption, EditOrgOption]`.
Path: `/api/v1/orgs/{org}`
**Action methods:**
| Method | Description |
|----------------|--------------------------------------------|
| `ListMembers` | List all members of an organisation |
| `AddMember` | Add a user to an organisation |
| `RemoveMember` | Remove a user from an organisation |
| `ListUserOrgs` | List organisations for a given user |
| `ListMyOrgs` | List organisations for the authenticated user |
---
## UserService
Embeds `Resource[User, struct{}, struct{}]` (read-only via CRUD).
Path: `/api/v1/users/{username}`
**Action methods:**
| Method | Description |
|-----------------|--------------------------------------------|
| `GetCurrent` | Get the authenticated user |
| `ListFollowers` | List followers of a user |
| `ListFollowing` | List users a user is following |
| `Follow` | Follow a user |
| `Unfollow` | Unfollow a user |
| `ListStarred` | List starred repositories |
| `Star` | Star a repository |
| `Unstar` | Unstar a repository |
---
## TeamService
Embeds `Resource[Team, CreateTeamOption, EditTeamOption]`.
Path: `/api/v1/teams/{id}`
**Action methods:**
| Method | Description |
|----------------|------------------------------------|
| `ListMembers` | List all team members |
| `AddMember` | Add a user to a team |
| `RemoveMember` | Remove a user from a team |
| `ListRepos` | List repositories managed by team |
| `AddRepo` | Add a repository to a team |
| `RemoveRepo` | Remove a repository from a team |
| `ListOrgTeams` | List all teams in an organisation |
---
## AdminService
No Resource embedding (heterogeneous endpoints). Requires site admin privileges.
| Method | Description |
|-----------------------|------------------------------------------|
| `ListUsers` | List all users |
| `CreateUser` | Create a new user |
| `EditUser` | Edit an existing user |
| `DeleteUser` | Delete a user |
| `RenameUser` | Rename a user |
| `ListOrgs` | List all organisations |
| `RunCron` | Run a cron task by name |
| `ListCron` | List all cron tasks |
| `AdoptRepo` | Adopt an unadopted repository |
| `GenerateRunnerToken` | Generate an actions runner registration token |
---
## BranchService
Embeds `Resource[Branch, CreateBranchRepoOption, struct{}]`.
Path: `/api/v1/repos/{owner}/{repo}/branches/{branch}`
**Action methods:**
| Method | Description |
|--------------------------|--------------------------------------|
| `ListBranchProtections` | List all branch protection rules |
| `GetBranchProtection` | Get a single branch protection rule |
| `CreateBranchProtection` | Create a new branch protection rule |
| `EditBranchProtection` | Update a branch protection rule |
| `DeleteBranchProtection` | Delete a branch protection rule |
---
## ReleaseService
Embeds `Resource[Release, CreateReleaseOption, EditReleaseOption]`.
Path: `/api/v1/repos/{owner}/{repo}/releases/{id}`
**Action methods:**
| Method | Description |
|---------------|--------------------------------|
| `GetByTag` | Get a release by tag name |
| `DeleteByTag` | Delete a release by tag name |
| `ListAssets` | List assets for a release |
| `GetAsset` | Get a single release asset |
| `DeleteAsset` | Delete a release asset |
---
## LabelService
No Resource embedding (heterogeneous repo/org paths).
| Method | Description |
|------------------|-----------------------------------|
| `ListRepoLabels` | List all labels in a repository |
| `GetRepoLabel` | Get a single repository label |
| `CreateRepoLabel`| Create a label in a repository |
| `EditRepoLabel` | Update a repository label |
| `DeleteRepoLabel`| Delete a repository label |
| `ListOrgLabels` | List all labels in an organisation|
| `CreateOrgLabel` | Create a label in an organisation |
---
## WebhookService
Embeds `Resource[Hook, CreateHookOption, EditHookOption]`.
Path: `/api/v1/repos/{owner}/{repo}/hooks/{id}`
**Action methods:**
| Method | Description |
|---------------|----------------------------------------|
| `TestHook` | Trigger a test delivery for a webhook |
| `ListOrgHooks`| List all webhooks for an organisation |
---
## ContentService
No Resource embedding (varied operations on file paths).
| Method | Description |
|--------------|--------------------------------------------|
| `GetFile` | Get metadata and content for a file |
| `CreateFile` | Create a new file |
| `UpdateFile` | Update an existing file |
| `DeleteFile` | Delete a file (DELETE with body) |
| `GetRawFile` | Get raw file content as bytes |
---
## ActionsService
No Resource embedding (heterogeneous repo/org endpoints).
| Method | Description |
|----------------------|------------------------------------------|
| `ListRepoSecrets` | List secrets for a repository |
| `CreateRepoSecret` | Create or update a repository secret |
| `DeleteRepoSecret` | Delete a repository secret |
| `ListRepoVariables` | List action variables for a repository |
| `CreateRepoVariable` | Create an action variable |
| `DeleteRepoVariable` | Delete an action variable |
| `ListOrgSecrets` | List secrets for an organisation |
| `ListOrgVariables` | List action variables for an organisation|
| `DispatchWorkflow` | Trigger a workflow run |
---
## NotificationService
No Resource embedding.
| Method | Description |
|-----------------|------------------------------------------|
| `List` | List all notifications |
| `ListRepo` | List notifications for a repository |
| `MarkRead` | Mark all notifications as read |
| `GetThread` | Get a single notification thread |
| `MarkThreadRead`| Mark a single thread as read |
---
## PackageService
No Resource embedding.
| Method | Description |
|------------|------------------------------------------------|
| `List` | List all packages for an owner |
| `Get` | Get a package by owner, type, name, version |
| `Delete` | Delete a package |
| `ListFiles`| List files for a specific package version |
---
## WikiService
No Resource embedding.
| Method | Description |
|--------------|------------------------------|
| `ListPages` | List all wiki page metadata |
| `GetPage` | Get a single wiki page |
| `CreatePage` | Create a new wiki page |
| `EditPage` | Update an existing page |
| `DeletePage` | Delete a wiki page |
---
## MiscService
No Resource embedding (read-only utility endpoints).
| Method | Description |
|---------------------------|-------------------------------------|
| `RenderMarkdown` | Render markdown text to HTML |
| `ListLicenses` | List available licence templates |
| `GetLicense` | Get a single licence template |
| `ListGitignoreTemplates` | List gitignore template names |
| `GetGitignoreTemplate` | Get a single gitignore template |
| `GetNodeInfo` | Get Forgejo instance NodeInfo |
| `GetVersion` | Get server version |
---
## CommitService
No Resource embedding.
| Method | Description |
|---------------------|----------------------------------------------|
| `GetCombinedStatus` | Get combined status for a ref |
| `ListStatuses` | List all commit statuses for a ref |
| `CreateStatus` | Create a commit status for a SHA |
| `GetNote` | Get the git note for a commit SHA |