Documentation
¶
Overview ¶
Package provider is the public API of go-git-platform: one Go interface for GitHub, GitLab, Gitea, Forgejo, Gitee, GitCode, and Tencent Code (工蜂), plus the local-git entry points that hang off the same unified models.
Overview ¶
Start with NewProvider and the blank import that registers every shipped backend:
import _ "github.com/yi-nology/go-git-platform/backends/all"
p, err := provider.NewProvider(provider.Config{
Platform: provider.PlatformGitHub,
Token: "ghp_...",
})
The returned Provider composes eight core sub-interface families — repositories, change requests (PRs/MRs), webhooks, branches, diffs, commits, files, and releases — so consumer code can depend on the narrow slice it needs. Thirteen further capability families (issues, search, labels, milestones, reviews, commit statuses, notifications, reactions, branch protections, collaborators, deploy keys, repo stats, users) are optional: backends declare them via Capabilities() and consumers reach them with a type assertion.
Configuration surface ¶
Config carries everything a backend needs: platform, base URL (for self-hosted instances), credentials, retry, hooks, and logging. Two newer knobs are worth knowing:
- Config.TokenSource replaces the static Token with a per-request source, so expiring credentials (GitHub App installation tokens, OAuth flows) rotate without rebuilding the provider.
- Config.ConditionalRequests enables ETag-based conditional GETs: the transport replays cached 304 answers, which on GitHub do not count against the rate-limit budget — a large win for polling workloads like WaitForCommitStatus.
Cross-platform consistency ¶
Behavior parity is enforced, not aspirational: backends/contracttest runs the same suite against every platform, and every deliberate departure from unified semantics is registered in the backend's Divergence ledger (rendered to docs/divergence-ledger.md). The webhook event corpus (testdata/webhooks under each backend) pins the normalized event vocabulary — cr./push/tag./branch./issue./comment. — across platforms with golden files.
Automation helpers ¶
Beyond the raw managers, the package ships primitives for agent and CI use: WaitForCommitStatus (CI gating), GetFileContents (bounded concurrency batch reads), Each/Collect (page-walking iterators), EnsureWebhook/EnsureBranchProtection/EnsureDeployKey (idempotent desired-state convergence), and RateLimitRecovery (server-advised backoff hints from rate-limit errors).
Index ¶
- Constants
- Variables
- func BuildRawDiff(files []*ChangedFile) string
- func ClassifyStatus(statusCode int) error
- func Collect[T any](ctx context.Context, fetch PageFetch[T]) ([]T, error)
- func CollectBounded[T any](ctx context.Context, fetch PageFetch[T], maxPages int) ([]T, error)
- func CountDiffLines(diff string) (additions, deletions int)
- func DecodeFileContent(platform Platform, encoding, content string) (string, error)
- func Each[T any](ctx context.Context, fetch PageFetch[T], fn func(T) error) error
- func EachBounded[T any](ctx context.Context, fetch PageFetch[T], maxPages int, fn func(T) error) error
- func EnsureBranchProtection(ctx context.Context, bpm BranchProtectionManager, owner, repo string, ...) (EnsureAction, *BranchProtection, error)
- func EnsureDeployKey(ctx context.Context, dkm DeploymentKeyManager, owner, repo string, ...) (EnsureAction, *DeployKey, error)
- func EnsureWebhook(ctx context.Context, p WebhookManager, opts CreateWebhookOptions) (EnsureAction, *PlatformWebhook, error)
- func ExtractMentions(body string) []string
- func ExtractOwnerFromFullName(fullName string) string
- func HashToken(token string) string
- func Ignores(divs []Divergence, method, field string) bool
- func IsAuthentication(err error) bool
- func IsConflict(err error) bool
- func IsForbidden(err error) bool
- func IsInvalidInput(err error) bool
- func IsNotFound(err error) bool
- func IsNotImplemented(err error) bool
- func IsPlatformNotSupported(err error) bool
- func IsRateLimited(err error) bool
- func IsRegistered(p Platform) bool
- func IsWebhookValidation(err error) bool
- func New(platform Platform, op string, status int, body string) error
- func NormalizeBranchAction(action string) string
- func NormalizeCRAction(action string, merged bool) string
- func NormalizeIssueAction(action string) string
- func NormalizePageOpts(page, perPage int) (int, int)
- func NormalizeTagAction(action string) string
- func ParseTotalCountHeader(headers http.Header, fallback int) int
- func RateLimitRecovery(err error) (retryAfter time.Duration, resetAt time.Time, ok bool)
- func ReadAndRestoreBody(r *http.Request) ([]byte, error)
- func Register(p Platform, ctor ProviderConstructor)
- func RegisterHostAlias(host string, platform Platform, baseURL string)
- func RegisterStatusExtractor(p Platform, fn StatusExtractor)
- func ResolveMRSHAs(diffRefsHead, diffRefsBase, diffRefsStart, mergeCommitSHA, lastCommitID string) (head, base, start string)
- func SplitFullName(fullName string) (owner, name string)
- func Stubs(divs []Divergence, method string) bool
- func SumDiffStats(files []*ChangedFile) (additions, deletions int)
- func ValidateWebhookWithRegistry(p Platform, r *http.Request, secret string) error
- func Version() string
- func Wrap(platform Platform, op string, err error) error
- func WrapStatusError(err error, statusCode int) error
- func Wrapf(platform Platform, op, format string, args ...any) error
- type AddCollaboratorOptions
- type AddDeployKeyOptions
- type BatchOptions
- type BatchResult
- func GetCRs(ctx context.Context, p Provider, owner, repo string, numbers []string, ...) []BatchResult[*ChangeRequest]
- func GetFileContents(ctx context.Context, p Provider, owner, repo, ref string, paths []string, ...) []BatchResult[string]
- func SetCommitStatuses(ctx context.Context, p Provider, owner, repo, sha string, ...) []BatchResult[struct{}]
- type BranchManager
- type BranchProtection
- type BranchProtectionManager
- type CILogManager
- type CRComment
- type CRCommit
- type CRState
- type CRUser
- type CapabilitySet
- type ChangeRequest
- type ChangeRequestManager
- type ChangedFile
- type Collaborator
- type CollaboratorManager
- type CombinedCommitStatus
- type CommitInfo
- type CommitManager
- type CommitStatus
- type CommitStatusManager
- type CommitStatusOptions
- type CommitStatusState
- type CompareResult
- type Config
- type Contributor
- type CreateBranchProtectionOptions
- type CreateCROptions
- type CreateIssueOptions
- type CreateLabelOptions
- type CreateMigrationOptions
- type CreateMilestoneOptions
- type CreateReleaseOptions
- type CreateRepoOptions
- type CreateReviewOptions
- type CreateWebhookOptions
- type DeployKey
- type DeploymentKeyManager
- type DetectResult
- type DiffManager
- type DiscussionOptions
- type Divergence
- type DivergenceKind
- type EnsureAction
- type EventRepo
- type FileDeleteOptions
- type FileManager
- type FileOptions
- type FileResult
- type ForgejoWebhookValidator
- type ForkRepoOptions
- type Gist
- type GistFile
- type GistManager
- type GitCodeWebhookValidator
- type GiteeWebhookValidator
- type HMACSHA256Validator
- type HmacValidator
- type Hooks
- type Issue
- type IssueComment
- type IssueLabel
- type IssueManager
- type IssueState
- type JobLog
- type Label
- type LabelManager
- type ListCROptions
- type ListCommitsOptions
- type ListIssuesOptions
- type ListLabelsOptions
- type ListMilestonesOptions
- type ListNotificationsOptions
- type ListRepoOptions
- type Logger
- type Manager
- func (m *Manager) Cleanup()
- func (m *Manager) Get(cfg Config) (Provider, error)
- func (m *Manager) GetByURL(cloneURL, token string) (Provider, error)
- func (m *Manager) Len() int
- func (m *Manager) Purge()
- func (m *Manager) Remove(cfg Config)
- func (m *Manager) ResetStats()
- func (m *Manager) StartJanitor(ctx context.Context, interval time.Duration)
- func (m *Manager) Stats() Stats
- func (m *Manager) Stop()
- type ManagerOption
- type MarkNotificationsOptions
- type MergeCROptions
- type MergeDiff
- type MigrationInfo
- type MigrationManager
- type Milestone
- type MilestoneManager
- type MilestoneRef
- type MilestoneState
- type NormalizedEvent
- type NoteManager
- type Notification
- type NotificationManager
- type NotificationSubject
- type PageFetch
- type Platform
- type PlatformBranch
- type PlatformRepo
- type PlatformWebhook
- type Provider
- type ProviderConstructor
- type ProviderError
- type Reaction
- type ReactionManager
- type ReleaseAsset
- type ReleaseAssetManager
- type ReleaseInfo
- type ReleaseManager
- type RepoManager
- type RepoStatsManager
- type RequestHook
- type ResponseHook
- type RetryConfig
- type Review
- type ReviewComment
- type ReviewCommentResult
- type ReviewManager
- type ReviewResult
- type ReviewState
- type SearchIssueResult
- type SearchIssuesOptions
- type SearchManager
- type SearchRepoResult
- type SearchReposOptions
- type SearchUserResult
- type SearchUsersOptions
- type StarredManager
- type StaticTokenValidator
- type Stats
- type StatusError
- type StatusExtractor
- type TagInfo
- type TestConnectionResult
- type TokenSource
- type UpdateBranchProtectionOptions
- type UpdateCROptions
- type UpdateIssueOptions
- type UpdateLabelOptions
- type UpdateMilestoneOptions
- type UpdateReleaseOptions
- type UpdateRepoOptions
- type UpdateWebhookOptions
- type UserManager
- type ValidatorFunc
- type WaitOptions
- type WebhookConfigManager
- type WebhookEnvelope
- type WebhookManager
- type WebhookValidator
- type WebhookValidatorRegistry
Constants ¶
const ( ReactionPlusOne = "+1" ReactionMinusOne = "-1" ReactionLaugh = "laugh" ReactionConfused = "confused" ReactionHeart = "heart" ReactionHooray = "hooray" ReactionRocket = "rocket" ReactionEyes = "eyes" )
Standard emoji identifiers used across all platforms. GitLab maps these to its award-emoji names internally (e.g. +1 ↔ thumbsup).
const ( DefaultPage = 1 DefaultPerPage = 20 MaxPerPage = 100 )
const ( DefaultWaitInterval = 5 * time.Second DefaultWaitTimeout = 10 * time.Minute )
Default polling parameters for WaitForCommitStatus.
const ( // CR (change request / pull request / merge request) actions. CRActionOpened = "opened" CRActionClosed = "closed" CRActionMerged = "merged" CRActionReopened = "reopened" CRActionUpdated = "updated" // Event type prefixes. EventTypeCR = "cr." EventTypePush = "push" EventTypeTag = "tag." EventTypeBranch = "branch." EventTypeIssue = "issue." EventTypeComment = "comment." // Comment actions. GitHub delivers created/edited/deleted; the other // platforms only notify on creation today. CommentActionCreated = "created" CommentActionEdited = "edited" CommentActionDeleted = "deleted" )
const DefaultBatchConcurrency = 4
DefaultBatchConcurrency is the number of in-flight operations used by the batch helpers when BatchOptions.Concurrency is unset.
const DefaultGiteeSignMaxAge = 10 * time.Minute
DefaultGiteeSignMaxAge bounds the accepted X-Gitee-Timestamp drift in sign mode when GiteeWebhookValidator.MaxAge is zero.
const DefaultIterMaxPages = 100
DefaultIterMaxPages is the page budget applied by Each/Collect when no explicit bound is given. At the default page size (20) this caps a walk at 2000 items; with PerPage=100 it caps at 10000 — far beyond any real list. The budget is a safety net against platforms that ignore the page parameter (observed in the field: Forgejo 15.0.1 on issue-comment lists), so exhausting it is surfaced as ErrPageBudgetExceeded instead of spinning.
const MaxBatchConcurrency = 16
MaxBatchConcurrency caps the caller-configurable concurrency so a misconfigured batch cannot hammer a platform into rate limiting.
const SkipValidationSecret = "\x00skip-signature-validation"
SkipValidationSecret is the sentinel secret that makes WebhookEnvelope.Read skip the platform's signature validator.
It exists for hosts that verify the webhook signature themselves and then reuse the SDK purely as a payload parser. Two situations need it:
- The platform's header convention differs from the SDK's model (e.g. a GitLab-family payload delivered by a platform that brands its own token header).
- The host validates the signature before dispatch, so the SDK's validation would be a redundant second check on an already-trusted request.
The sentinel is intentionally unusable as a real secret: it contains a NUL byte, which no HTTP header value or config file can carry. It is honoured only inside WebhookEnvelope.Read; ValidateWebhookWithRegistry and Provider.ValidateWebhookSignature always run the real validator, so passing the sentinel there does NOT bypass signature checking.
Variables ¶
var ( ErrNotFound = errors.New("resource not found") ErrAuthentication = errors.New("authentication failed") ErrRateLimited = errors.New("rate limited") ErrForbidden = errors.New("forbidden") ErrConflict = errors.New("conflict") ErrNotImplemented = errors.New("not implemented") ErrInvalidInput = errors.New("invalid input") ErrWebhookValidation = errors.New("webhook validation failed") ErrConnectionFailed = errors.New("connection failed") ErrPlatformNotSupported = errors.New("platform not supported") )
Sentinel errors classify transport and provider failures so callers can branch on category without inspecting status codes or wrapped causes.
var ErrPageBudgetExceeded = oekiterrors.New("page budget exceeded before an empty page")
ErrPageBudgetExceeded is returned when the walk hits its MaxPages bound before the platform returns an empty page. Either the list is genuinely longer than the budget, or (more likely) the platform ignores the page parameter. Retry with a higher bound via EachBounded/CollectBounded if the former.
var ErrStopIteration = oekiterrors.New("iteration stopped")
ErrStopIteration is the sentinel a Each callback returns to stop the walk early without reporting an error. Everything fetched so far stands.
var ErrWaitTimedOut = oekiterrors.New("commit status did not reach a terminal state before the timeout")
ErrWaitTimedOut is returned by WaitForCommitStatus when the commit stays non-terminal past WaitOptions.Timeout.
Functions ¶
func BuildRawDiff ¶
func BuildRawDiff(files []*ChangedFile) string
BuildRawDiff constructs a raw diff string from a list of ChangedFiles.
func ClassifyStatus ¶
ClassifyStatus maps an HTTP status code to a sentinel error. Exposed so transports and platform implementations can produce consistent error categories without importing each other.
func Collect ¶ added in v0.72.0
Collect walks every page of a paginated list call and returns all items as one slice. It is the convenient counterpart of Each for callers that want the whole list in memory.
func CollectBounded ¶ added in v0.72.0
CollectBounded is Collect with an explicit page budget (maxPages <= 0 falls back to DefaultIterMaxPages).
func CountDiffLines ¶
CountDiffLines counts additions and deletions in a unified diff string.
func DecodeFileContent ¶ added in v0.99.7
DecodeFileContent 按平台返回的 Encoding 解码文件内容。
平台的「取文件内容」端点有两种形态:raw(直接给字节)与 JSON(base64 字段)。 **不按 Encoding 解码 ⇒ 调用方拿到 base64 串** —— 按 GitHub 直觉读文件会全错 (解析 YAML/JSON 直接失败),而调用方无从察觉。
只认 `base64`(大小写不敏感);其它 encoding 原样返回。
func Each ¶ added in v0.72.0
Each walks every page of a paginated list call, invoking fn once per item, until the platform returns an empty page. Pages are fetched lazily: fn sees items page by page, so a walk over a long list does not buffer it in memory. Use Collect instead when the full slice is wanted.
fn returning ErrStopIteration ends the walk with a nil error; any other error aborts immediately and is returned as-is. ctx cancellation between items and between page fetches is honored.
func EachBounded ¶ added in v0.72.0
func EachBounded[T any](ctx context.Context, fetch PageFetch[T], maxPages int, fn func(T) error) error
EachBounded is Each with an explicit page budget. maxPages <= 0 falls back to DefaultIterMaxPages. Exceeding the budget fails the walk with an error wrapping ErrPageBudgetExceeded (unlike the internal backend helper, a public walk must not truncate silently).
func EnsureBranchProtection ¶ added in v0.72.0
func EnsureBranchProtection(ctx context.Context, bpm BranchProtectionManager, owner, repo string, opts CreateBranchProtectionOptions) (EnsureAction, *BranchProtection, error)
EnsureBranchProtection converges the branch protection rule for opts.BranchName onto opts, creating, updating, or leaving it untouched as required, and returns the resulting rule plus the action taken. It targets the BranchProtectionManager directly so it works with any Provider (type-assert it at the call site) or test double.
func EnsureDeployKey ¶ added in v0.72.0
func EnsureDeployKey(ctx context.Context, dkm DeploymentKeyManager, owner, repo string, opts AddDeployKeyOptions) (EnsureAction, *DeployKey, error)
EnsureDeployKey converges the repository's deploy key titled opts.Title onto opts, creating, replacing, or leaving it untouched as required, and returns the resulting key plus the action taken.
Existing keys are matched by title; a title collision with different key material or read-only flag replaces the key (the manager interface has no update: delete + re-add), which changes its platform ID.
func EnsureWebhook ¶ added in v0.72.0
func EnsureWebhook(ctx context.Context, p WebhookManager, opts CreateWebhookOptions) (EnsureAction, *PlatformWebhook, error)
EnsureWebhook makes the repository carry exactly one webhook for opts.URL with opts.Events, creating or replacing as needed, and returns the resulting webhook plus the action taken. It is the idempotent building block automation wants: "make this hook exist, whatever it takes", safe to re-run.
Semantics:
- No webhook with that URL → created.
- Same URL, same event set → unchanged. Secrets are write-only on every platform (list responses never return them), so an existing hook's secret is not comparable; re-running with a different secret reports unchanged and keeps the old secret.
- Same URL, different event set → updated. The WebhookManager interface has no update method, so the hook is deleted and recreated; its platform ID changes as a result.
- Empty opts.Events defaults to {push, pull_request}, matching CreateWebhook's platform-side default.
Multiple existing hooks with the same URL are all replaced by one.
func ExtractMentions ¶
ExtractMentions returns the deduplicated list of @usernames found in body. Email addresses (foo@bar.com) are excluded by the leading non-word-char guard. Mentions inside URLs (e.g. `[@user](https://example.com/@user)`) are also excluded. The returned order follows first occurrence.
func ExtractOwnerFromFullName ¶
ExtractOwnerFromFullName returns just the owner portion of "owner/repo".
func HashToken ¶
HashToken returns the first 16 hex characters of SHA-256(token). It is the default token hasher used by Manager and is exported so callers can compute cache keys for diagnostics or external caches.
An empty token hashes to an empty string (no anonymous cache entries).
func Ignores ¶
func Ignores(divs []Divergence, method, field string) bool
Ignores reports whether the ledger registers an ignore of field on method.
func IsAuthentication ¶
IsAuthentication reports whether err wraps ErrAuthentication (HTTP 401).
func IsConflict ¶
IsConflict reports whether err wraps ErrConflict (HTTP 409).
func IsForbidden ¶
IsForbidden reports whether err wraps ErrForbidden (HTTP 403).
func IsInvalidInput ¶
IsInvalidInput reports whether err wraps ErrInvalidInput.
func IsNotFound ¶
IsNotFound reports whether err wraps ErrNotFound (HTTP 404).
func IsNotImplemented ¶
IsNotImplemented reports whether err wraps ErrNotImplemented.
func IsPlatformNotSupported ¶
IsPlatformNotSupported reports whether err wraps ErrPlatformNotSupported.
func IsRateLimited ¶
IsRateLimited reports whether err wraps ErrRateLimited (HTTP 429).
func IsRegistered ¶
IsRegistered checks if a platform has been registered.
func IsWebhookValidation ¶
IsWebhookValidation reports whether err wraps ErrWebhookValidation.
func NormalizeBranchAction ¶
NormalizeBranchAction maps platform-specific branch event actions.
func NormalizeCRAction ¶
NormalizeCRAction maps platform-specific PR/MR action strings to the canonical vocabulary. Each backend should call this instead of ad-hoc string mapping.
Mappings:
GitHub: "opened" → opened, "closed" (+merged) → merged/closed,
"reopened" → reopened, "synchronize"/"edited" → updated
GitLab: "open" → opened, "close" → closed, "merge" → merged,
"reopen" → reopened, "update" → updated
Gitee: "open" → opened, "close" (+merged check) → merged/closed
GitCode: "opened" → opened, "closed" (+merged check) → merged/closed
Gitea: "opened" → opened, "closed" (+merged check) → merged/closed
func NormalizeIssueAction ¶
NormalizeIssueAction maps platform-specific issue event actions.
func NormalizePageOpts ¶
NormalizePageOpts applies default values for page/perPage.
func NormalizeTagAction ¶
NormalizeTagAction maps platform-specific tag event actions to the canonical vocabulary. The canonical full event type is "tag.created": GitLab/Gitea/Tencent signal a tag with a tag_push hook (a tag being pushed is the tag coming into existence), and GitHub's create/delete events carry ref_type "tag".
func ParseTotalCountHeader ¶
ParseTotalCountHeader reads X-Total-Count or X-Total from response headers. Falls back to the provided default if neither header is present or valid.
func RateLimitRecovery ¶ added in v0.72.0
RateLimitRecovery extracts the server-advised recovery window from a rate-limited error, walking the wrapped chain for the transport hints (Retry-After / X-RateLimit-Reset). ok is true only when at least one of retryAfter or resetAt is known — callers rate-limited without hints should fall back to their own backoff.
if ra, reset, ok := provider.RateLimitRecovery(err); ok {
wait := ra
if reset.After(time.Now()) && (wait == 0 || time.Until(reset) > wait) {
wait = time.Until(reset)
}
time.Sleep(wait)
}
func ReadAndRestoreBody ¶
ReadAndRestoreBody reads the full body of r and replaces it with a fresh NopCloser so that downstream readers (signature verification, JSON decoding) can still consume it. Use it at the entry point of webhook handlers that need to inspect the raw bytes.
func Register ¶
func Register(p Platform, ctor ProviderConstructor)
Register registers a provider constructor for a platform. This is typically called from init() functions in platform implementation files.
func RegisterHostAlias ¶ added in v0.77.0
RegisterHostAlias teaches DetectPlatform that host (and its subdomains) identifies platform with the given base API URL — the registry extension matching Register: adding a self-hosted alias no longer requires editing the provider core. Panics on an empty host, an empty platform, or a duplicate host (same fail-fast convention as Register).
func RegisterStatusExtractor ¶ added in v0.83.0
func RegisterStatusExtractor(p Platform, fn StatusExtractor)
RegisterStatusExtractor teaches Wrap how to read the HTTP status out of the named platform's SDK error values — the explicit, type-safe replacement for the old reflection + error-message-parsing fallback. Backends register one extractor at init covering their SDK's error types via errors.As; a nil extractor (or no registration) means the platform's errors carry no status on the error value itself (use WrapStatusError / New at the call site, or thread the *Response status through the port as the family backends do). Panics on duplicate registration (same convention as Register).
func ResolveMRSHAs ¶
func ResolveMRSHAs(diffRefsHead, diffRefsBase, diffRefsStart, mergeCommitSHA, lastCommitID string) (head, base, start string)
ResolveMRSHAs derives the (head, base, start) SHAs for a GitLab-style merge request from the raw webhook fields. This encodes the shared priority used by the GitLab, TencentCode (and future GitCode) backends:
- head: diff_refs.head_sha when present, otherwise last_commit.id
- base: merge_commit_sha when present, otherwise diff_refs.base_sha
- start: diff_refs.start_sha (may be empty)
Keeping this in one place guarantees identical fallback semantics across the GitLab-family backends and avoids behavioural drift.
func SplitFullName ¶
SplitFullName splits "owner/repo" into (owner, repo). If the input doesn't contain "/", owner is empty.
func Stubs ¶
func Stubs(divs []Divergence, method string) bool
Stubs reports whether the ledger registers method as a stub.
func SumDiffStats ¶
func SumDiffStats(files []*ChangedFile) (additions, deletions int)
SumDiffStats returns total additions and deletions from a list of ChangedFiles.
func ValidateWebhookWithRegistry ¶ added in v0.77.0
ValidateWebhookWithRegistry validates req's webhook signature with the default registry entry for platform — the single implementation per signature scheme (STRATEGY dispatch). The body is read and restored so callers can keep parsing the payload afterwards. Platforms without a registered validator yield ErrNotImplemented; an empty secret is rejected (an empty HMAC key is trivially forgeable on predictable payloads).
Backend WebhookManager implementations delegate here instead of keeping an inline copy of their platform's crypto, which had already drifted from the registry (empty-secret semantics) before v0.77.0.
func Version ¶ added in v0.72.0
func Version() string
Version returns the runtime version of the go-git-platform module, as resolved from Go build info. It reports "dev" for development builds (in-module go run/go test) where no module version is stamped.
The value is also injected as part of the default User-Agent header on every outgoing HTTP request made through the transport layer, so platform operators can identify (and, where offered, rate-limit-mercy) SDK-driven traffic.
func Wrap ¶
Wrap creates a ProviderError from a raw error, classifying it when the cause is a transport error with a known status code. The original error chain is always preserved: Cause stays rooted at the raw error (with the classification sentinel wrapped in front via %w), so errors.Is matches both the sentinel (ErrNotFound & co.) and any error from the original chain, and the Error() message retains the platform's original detail. Use this in platform implementations to convert transport errors into the unified shape.
func WrapStatusError ¶
WrapStatusError wraps an error with an explicit HTTP status code. This is the preferred way to attach status codes to third-party SDK errors instead of relying on reflection-based detection.
Types ¶
type AddCollaboratorOptions ¶
type AddCollaboratorOptions struct {
Permission string `json:"permission,omitempty"` // "read", "write", "admin"
}
AddCollaboratorOptions contains options for adding a collaborator.
type AddDeployKeyOptions ¶
type AddDeployKeyOptions struct {
Title string `json:"title"`
Key string `json:"key"`
ReadOnly bool `json:"read_only,omitempty"`
}
AddDeployKeyOptions contains options for adding a deploy key.
type BatchOptions ¶
type BatchOptions struct {
// Concurrency is the maximum number of in-flight operations;
// defaults to DefaultBatchConcurrency, capped at
// MaxBatchConcurrency.
Concurrency int
}
BatchOptions tunes the batch helpers' concurrency. Zero fields take the defaults.
type BatchResult ¶
type BatchResult[T any] struct { // Key is the input selector: the file path, CR number, or the // status context. Key string // Value carries the operation result when Err is nil. Value T // Err is the per-item failure, already wrapped as a provider error // by the underlying call. Err error }
BatchResult pairs one batch item's outcome with its input key so callers can attribute per-item failures without re-deriving order. A per-item Err never aborts the whole batch.
func GetCRs ¶
func GetCRs(ctx context.Context, p Provider, owner, repo string, numbers []string, batchOpts ...BatchOptions) []BatchResult[*ChangeRequest]
GetCRs fetches many change requests from one repository with bounded concurrency, in input order. A lookup failure for one number fails only that item.
func GetFileContents ¶
func GetFileContents(ctx context.Context, p Provider, owner, repo, ref string, paths []string, batchOpts ...BatchOptions) []BatchResult[string]
GetFileContents reads many files from one repository with bounded concurrency. ref may be empty to use the repository's default branch (a single ref applies to the whole batch; per-path refs are expressible by calling the helper once per ref).
It is the context-economy read primitive for agent flows: fetch the handful of files that matter in one call, then trim each payload with projection if needed.
func SetCommitStatuses ¶
func SetCommitStatuses(ctx context.Context, p Provider, owner, repo, sha string, statuses []CommitStatusOptions, batchOpts ...BatchOptions) []BatchResult[struct{}]
SetCommitStatuses reports many statuses on one commit with bounded concurrency (the usual "CI publishes lint+test+build at once" shape). The provider must implement CommitStatusManager; a provider without it yields every item failed with ErrNotImplemented.
type BranchManager ¶
type BranchManager interface {
ListBranches(ctx context.Context, owner, repo string) ([]*PlatformBranch, error)
CreateBranch(ctx context.Context, owner, repo, branch, ref string) (*PlatformBranch, error)
DeleteBranch(ctx context.Context, owner, repo, branch string) error
}
BranchManager handles branch operations.
type BranchProtection ¶
type BranchProtection struct {
BranchName string `json:"branch_name"`
RequiredApprovingReviews int `json:"required_approving_reviews"`
RequiredStatusChecks bool `json:"required_status_checks"`
AllowForcePushes bool `json:"allow_force_pushes"`
AllowDeletions bool `json:"allow_deletions"`
}
BranchProtection represents a branch protection rule.
type BranchProtectionManager ¶
type BranchProtectionManager interface {
// ListBranchProtections returns all branch protection rules for a repo.
ListBranchProtections(ctx context.Context, owner, repo string) ([]*BranchProtection, error)
// GetBranchProtection returns the protection rule for a specific branch.
GetBranchProtection(ctx context.Context, owner, repo, branch string) (*BranchProtection, error)
// CreateBranchProtection creates a new branch protection rule.
CreateBranchProtection(ctx context.Context, owner, repo string, opts CreateBranchProtectionOptions) (*BranchProtection, error)
// UpdateBranchProtection updates an existing branch protection rule.
UpdateBranchProtection(ctx context.Context, owner, repo, branch string, opts UpdateBranchProtectionOptions) (*BranchProtection, error)
// DeleteBranchProtection removes the protection rule for a branch.
DeleteBranchProtection(ctx context.Context, owner, repo, branch string) error
}
BranchProtectionManager provides branch protection rule CRUD. It is an optional capability interface: consumers should gate on Provider.Capabilities().BranchProtections (or type-assert) before use.
Platform support: GitHub, GitCode, GitLab, Gitea, Forgejo, Gitee, TencentCode. TencentCode's list returns branch-row summaries (the platform has no list-protected endpoint; approver rules surface via GetBranchProtection), and allow-force-push is write-only there — see the tencentcode divergence ledger for the registered details. The platform- specific TencentCodeExtras still exposes the finer-grained protected- branch member management the unified contract does not model.
type CILogManager ¶ added in v0.67.0
type CILogManager interface {
// ListFailedJobLogs returns the failed jobs of the most recent pipeline
// for a commit, each with the tail of its execution log. A commit with
// no pipeline (or a green one) yields an empty slice, not an error.
ListFailedJobLogs(ctx context.Context, owner, repo, sha string) ([]JobLog, error)
}
CILogManager fetches failure diagnostics from a platform's CI system. It is an optional capability interface: consumers should type-assert before use. Only GitLab exposes per-job logs through its public REST API today; GitHub check-runs carry only summaries/annotations, so absence is expressed by not implementing the interface instead of stubbing.
type CRComment ¶
type CRComment struct {
ID int64 `json:"id"`
Body string `json:"body"`
Author *CRUser `json:"author"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
CRComment represents a comment on a change request.
type CRCommit ¶
type CRCommit struct {
SHA string `json:"sha"`
Message string `json:"message"`
Author *CRUser `json:"author"`
CreatedAt time.Time `json:"created_at"`
}
CRCommit represents a commit in a change request.
type CRState ¶
type CRState string
CRState represents the state of a change request.
func MapBoolStateToCR ¶
MapBoolStateToCR is a convenience for platforms with a separate merged boolean (Gitea, Forgejo).
func MapMRStateToCR ¶
MapMRStateToCR is a convenience for platforms with explicit "merged" state (GitLab, Tencent Code).
func MapStateToCR ¶
MapStateToCR maps common string state representations to CRState. mergedFn is called when state is "closed" to determine if it was merged. For platforms that use a separate "merged" field (Gitea, Forgejo), pass a non-nil mergedFn. For platforms where "merged" is a distinct state string (GitLab, Tencent Code), pass nil.
type CRUser ¶
type CRUser struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
AvatarURL string `json:"avatar_url"`
}
CRUser represents a user on a platform.
type CapabilitySet ¶
type CapabilitySet struct {
Issues bool // provider.IssueManager
Search bool // provider.SearchManager
Labels bool // provider.LabelManager
Milestones bool // provider.MilestoneManager
Reviews bool // provider.ReviewManager
CommitStatuses bool // provider.CommitStatusManager
Notifications bool // provider.NotificationManager
Reactions bool // provider.ReactionManager
BranchProtections bool // provider.BranchProtectionManager
Collaborators bool // provider.CollaboratorManager
WebhookConfig bool // provider.WebhookConfigManager
DeployKeys bool // provider.DeploymentKeyManager
RepoStats bool // provider.RepoStatsManager
Users bool // provider.UserManager
Gists bool // provider.GistManager
Starred bool // provider.StarredManager
Migrations bool // provider.MigrationManager
ReleaseAssets bool // provider.ReleaseAssetManager
}
CapabilitySet statically declares which optional capability interfaces a Provider implements. Values are compile-time constants per backend; no runtime probing is performed. Consumers should route on these flags instead of probing with type assertions:
if p.Capabilities().Labels {
lm := p.(provider.LabelManager)
// ...
}
When a new optional capability interface is added to the SDK, add a field here and update every backend's Capabilities method; the contract suite enforces that declarations match implementations.
func DeriveCapabilities ¶ added in v0.82.0
func DeriveCapabilities(p Provider) CapabilitySet
DeriveCapabilities builds a CapabilitySet from the concrete provider's optional-manager implementations — the runtime type assertion is the SINGLE source of truth for what a backend supports. Backend Capabilities() methods delegate here, so the declaration can no longer drift from the implementation (contracttest's bidirectional check then guards against a backend bypassing the derivation with a hand-written literal).
This collapses the historical dual channel: pre-0.82 each backend wrote a literal of 12–17 bools that consumers cross-checked against assertions.
type ChangeRequest ¶
type ChangeRequest struct {
ID int64 `json:"id"`
Number string `json:"number"`
Title string `json:"title"`
Description string `json:"description"`
State CRState `json:"state"`
SourceBranch string `json:"source_branch"`
TargetBranch string `json:"target_branch"`
// HeadSHA is the SHA of the source-branch tip.
// BaseSHA is the diff base: the merge-base (common ancestor) where GitLab/TencentCode
// expose it via diff_refs.base_sha. GitHub/Gitea do not expose a distinct merge base in
// webhook payloads, so BaseSHA there is the target-branch tip (equivalent to StartSHA).
// StartSHA is the SHA of the target-branch tip at event time (GitLab diff_refs.start_sha).
// On GitHub/Gitea it equals BaseSHA since no separate value is exposed.
HeadSHA string `json:"head_sha,omitempty"`
BaseSHA string `json:"base_sha,omitempty"`
StartSHA string `json:"start_sha,omitempty"`
// Draft reports the work-in-progress / draft state uniformly across platforms
// (GitHub pr.draft, Gitea draft, GitLab/TencentCode work_in_progress).
Draft bool `json:"draft"`
Author *CRUser `json:"author"`
Assignees []*CRUser `json:"assignees,omitempty"`
Reviewers []*CRUser `json:"reviewers"`
Labels []string `json:"labels"`
MergeStatus string `json:"merge_status"`
WebURL string `json:"web_url"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ChangeRequest represents a pull request or merge request. Number is the platform's change-request identifier as a string (numeric on every current platform), mirroring Issue.Number.
type ChangeRequestManager ¶
type ChangeRequestManager interface {
CreateCR(ctx context.Context, opts CreateCROptions) (*ChangeRequest, error)
GetCR(ctx context.Context, owner, repo, number string) (*ChangeRequest, error)
// ListCRs lists change requests. total is nil when the platform
// provided no authoritative total for the page (an unknown count is
// reported as unknown, never as the page length); a non-nil total is
// the platform's own metadata (exact or header-derived).
ListCRs(ctx context.Context, opts ListCROptions) ([]*ChangeRequest, *int, error)
MergeCR(ctx context.Context, owner, repo, number string, opts MergeCROptions) (*ChangeRequest, error)
CloseCR(ctx context.Context, owner, repo, number string) (*ChangeRequest, error)
ReopenCR(ctx context.Context, owner, repo, number string) (*ChangeRequest, error)
UpdateCR(ctx context.Context, owner, repo, number string, opts UpdateCROptions) (*ChangeRequest, error)
UpdateCRLabels(ctx context.Context, owner, repo, number string, labels []string) error
ListCRComments(ctx context.Context, owner, repo, number string) ([]*CRComment, error)
ListCRCommits(ctx context.Context, owner, repo, number string) ([]*CRCommit, error)
}
ChangeRequestManager handles pull request / merge request lifecycle. Change request numbers are strings (same addressing scheme as IssueManager); numeric platforms parse with strconv and fail with a wrapped "invalid pull request number" error.
type ChangedFile ¶
type ChangedFile struct {
OldPath string `json:"old_path"`
NewPath string `json:"new_path"`
Diff string `json:"diff"`
Additions int `json:"additions"`
Deletions int `json:"deletions"`
IsNew bool `json:"new_file"`
IsDeleted bool `json:"deleted_file"`
IsRenamed bool `json:"renamed_file"`
IsBinary bool `json:"binary"`
}
ChangedFile represents a file changed in a change request.
type Collaborator ¶
type Collaborator struct {
ID int64 `json:"id"`
Username string `json:"username"`
Permission string `json:"permission,omitempty"`
User *CRUser `json:"user,omitempty"`
}
Collaborator represents a repository collaborator.
type CollaboratorManager ¶
type CollaboratorManager interface {
// ListCollaborators returns all collaborators on a repository.
ListCollaborators(ctx context.Context, owner, repo string) ([]*Collaborator, error)
// AddCollaborator adds a user as a collaborator. Permission is
// platform-specific ("read", "write", "admin"; empty = default).
AddCollaborator(ctx context.Context, owner, repo, username string, opts AddCollaboratorOptions) error
// RemoveCollaborator removes a user from the repository.
RemoveCollaborator(ctx context.Context, owner, repo, username string) error
}
CollaboratorManager provides repository collaborator management. It is an optional capability interface: consumers should gate on Provider.Capabilities().Collaborators (or type-assert) before use.
Platform support: GitHub, GitCode, GitLab, Gitea, Forgejo, Gitee, TencentCode. GitLab-family platforms (GitLab, TencentCode) back this with the project-members API: mutations resolve the username to a numeric user ID first (TTL-cached), and the read/write/admin permission vocabulary maps onto platform access levels (registered mappings).
type CombinedCommitStatus ¶
type CombinedCommitStatus struct {
State CommitStatusState `json:"state"`
// Contexts maps each contributing context to its latest state.
Contexts map[string]CommitStatusState `json:"contexts,omitempty"`
}
CombinedCommitStatus is the fold of a commit's statuses with a snapshot of the per-context states it was derived from.
func (CombinedCommitStatus) String ¶
func (c CombinedCommitStatus) String() string
type CommitInfo ¶
type CommitInfo struct {
SHA string `json:"sha"`
Message string `json:"message"`
Author *CRUser `json:"author"`
Committer *CRUser `json:"committer"`
CreatedAt time.Time `json:"created_at"`
Additions int `json:"additions"`
Deletions int `json:"deletions"`
}
CommitInfo represents a commit.
type CommitManager ¶
type CommitManager interface {
GetCommit(ctx context.Context, owner, repo, sha string) (*CommitInfo, error)
ListCommits(ctx context.Context, owner, repo string, opts ListCommitsOptions) ([]*CommitInfo, error)
CompareCommits(ctx context.Context, owner, repo, base, head string) (*CompareResult, error)
}
CommitManager handles commit operations.
Commit statuses are NOT part of CommitManager: they are a CI reporting concern that not every platform exposes (Gitee's public REST API has no commit-status endpoint). See the optional CommitStatusManager capability interface and CapabilitySet.CommitStatuses.
type CommitStatus ¶
type CommitStatus struct {
State CommitStatusState `json:"state"`
Context string `json:"context"`
Description string `json:"description,omitempty"`
TargetURL string `json:"target_url,omitempty"`
}
CommitStatus is one status reported on a commit, unified across platforms. State is normalized via NormalizeCommitStatusState.
func LatestCommitStatuses ¶
func LatestCommitStatuses(statuses []CommitStatus) []CommitStatus
LatestCommitStatuses collapses a commit's status history to one status per context, keeping the FIRST occurrence of each context. All platform list endpoints return statuses newest-first (GitHub documents reverse chronological order; Gitea/GitLab/Gitee/GitCode/Forgejo/Tencent Code sort descending by creation), so first-seen is the most recent report of that context — the same entry GitHub's combined status would use. CI re-runs append history instead of replacing it, so folding the raw list would let a stale failure (or pending) outvote the latest result.
type CommitStatusManager ¶
type CommitStatusManager interface {
CreateCommitStatus(ctx context.Context, owner, repo, sha string, opts CommitStatusOptions) error
// ListCommitStatuses returns the statuses reported on a commit,
// newest first (the platforms' native order). State is normalized
// into the CommitStatusState vocabulary by the backend.
ListCommitStatuses(ctx context.Context, owner, repo, sha string) ([]CommitStatus, error)
}
CommitStatusManager reports CI statuses on commits. It is an optional capability interface: consumers should gate on Provider.Capabilities().CommitStatuses (or type-assert) before use.
It is deliberately separate from CommitManager: commit statuses are a CI reporting concern that not every platform exposes (Gitee's public REST API has no commit-status endpoint), so absence is expressed by not declaring the capability instead of stubbing the method.
type CommitStatusOptions ¶
type CommitStatusOptions struct {
State string `json:"state"`
Context string `json:"context"`
Description string `json:"description,omitempty"`
TargetURL string `json:"target_url,omitempty"`
}
CommitStatusOptions contains options for creating a commit status.
type CommitStatusState ¶
type CommitStatusState string
CommitStatusState is the unified state vocabulary for commit statuses. It covers the union of the platforms' verbs: GitHub (error/failure/pending/success), GitLab (pending/running/success/ failed/canceled and pipeline pre-states), Gitea/Forgejo (pending/success/error/failure/warning), and the GitHub-shaped verbs spoken by GitCode, Gitee (via check-run conclusions) and Tencent Code.
const ( // CommitStatusPending is the "not finished yet" state: the check is // queued or running. This is the only non-terminal state. CommitStatusPending CommitStatusState = "pending" // CommitStatusRunning is an alias of CommitStatusPending kept as a // distinct constant so callers can surface GitLab-style running // states verbatim; CombineCommitStatusStates treats it as pending. CommitStatusRunning CommitStatusState = "running" // CommitStatusSuccess is the terminal "passed" state. CommitStatusSuccess CommitStatusState = "success" // CommitStatusFailure is the terminal "failed" state. CommitStatusFailure CommitStatusState = "failure" // CommitStatusError is the terminal "errored before/without a run" // state. It is terminal like CommitStatusFailure but distinct so // infrastructure breakage stays tellable from test breakage. CommitStatusError CommitStatusState = "error" // CommitStatusCanceled is the terminal "canceled" state (GitLab). CommitStatusCanceled CommitStatusState = "canceled" )
func CombineCommitStatusStates ¶
func CombineCommitStatusStates(states []CommitStatusState) CommitStatusState
CombineCommitStatusStates folds per-context states into the single combined state of a commit, using the same precedence as GitHub's combined status: any error wins, then failure, then canceled; any pending/running keeps the commit pending; only an all-success set is success. An empty set is pending — a commit with no reported statuses has nothing to gate on yet.
func NormalizeCommitStatusState ¶
func NormalizeCommitStatusState(state string) CommitStatusState
NormalizeCommitStatusState maps a platform's raw status verb onto the unified CommitStatusState vocabulary. Unknown verbs normalize to CommitStatusPending so that unrecognised in-flight states keep callers waiting instead of concluding early; platform backends map their own verbs through this helper before returning CommitStatus values.
Gitea/Forgejo "warning" (build passed with warnings) normalizes to success: it is a terminal passing outcome, and merge gates treat it as such on the platform itself.
func WaitForCommitStatus ¶
func WaitForCommitStatus(ctx context.Context, p Provider, owner, repo, sha string, opts WaitOptions) (CommitStatusState, error)
WaitForCommitStatus polls ListCommitStatuses until the commit's combined state is terminal (success/failure/error/canceled) and returns it. It is the CI-gate primitive for automation and agent flows: create your status (or push a commit), wait, then decide.
The provider must implement CommitStatusManager; otherwise the error wraps ErrNotImplemented. Context cancellation is honored between and during polls. A combined state of pending/running past the timeout fails with ErrWaitTimedOut (so a red build is never confused with "gave up waiting"): distinguish them via errors.Is.
States are combined with CombineCommitStatusStates semantics — any error beats failure beats canceled; any pending/running keeps waiting; an all-success set succeeds. With WaitOptions.Contexts set, only the named contexts are folded; contexts that have not reported yet are simply absent, so the wait continues until each named context lands a terminal state.
func (CommitStatusState) Terminal ¶
func (s CommitStatusState) Terminal() bool
Terminal reports whether the state is a final outcome: success, failure, error, or canceled — anything but the pending/running family and the empty state.
type CompareResult ¶
type CompareResult struct {
Commits []*CommitInfo `json:"commits"`
Files []*ChangedFile `json:"files"`
TotalCommits int `json:"total_commits"`
AheadBy int `json:"ahead_by"`
BehindBy int `json:"behind_by"`
}
CompareResult represents the result of comparing two commits.
type Config ¶
type Config struct {
Platform Platform
BaseURL string
Token string
SkipTLS bool
// TokenSource, when non-nil, supplies the access token on every
// request through the transport layer and takes precedence over Token.
// Use it for credentials that rotate or expire (GitHub App installation
// tokens, OAuth flows); see the TokenSource interface. Static tokens
// keep using Token.
TokenSource TokenSource
// ConditionalRequests enables HTTP conditional requests for GETs: the
// transport caches responses keyed by their ETag, sends If-None-Match
// on re-reads, and replays the cached body when the platform answers
// 304. On platforms that meter 304s favorably (GitHub) this raises
// sustainable polling rates for wait-for-CI style workloads. Off by
// default; see transport.ETagCache for the exact semantics.
ConditionalRequests bool
// TokenStyle overrides the default authentication header style.
// Supported values: "private" (PRIVATE-TOKEN, default for GitLab),
// "bearer" (Authorization: Bearer). Empty string uses platform default.
TokenStyle string
// Logger for provider operations. Defaults to a no-op logger.
Logger Logger
// RetryConfig for automatic retry on transient failures. nil means no retry.
RetryConfig *RetryConfig
// Hooks for request/response lifecycle interception.
Hooks *Hooks
}
Config holds the configuration for creating a Provider.
type Contributor ¶
type Contributor struct {
Username string `json:"username"`
Contributions int `json:"contributions"`
}
Contributor represents a repository contributor.
type CreateBranchProtectionOptions ¶
type CreateBranchProtectionOptions struct {
BranchName string `json:"branch_name"`
RequiredApprovingReviews int `json:"required_approving_reviews,omitempty"`
RequiredStatusChecks bool `json:"required_status_checks,omitempty"`
AllowForcePushes bool `json:"allow_force_pushes,omitempty"`
AllowDeletions bool `json:"allow_deletions,omitempty"`
}
CreateBranchProtectionOptions contains options for creating a branch protection rule.
type CreateCROptions ¶
type CreateCROptions struct {
Owner string `json:"owner"`
Repo string `json:"repo"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
SourceBranch string `json:"source_branch"`
TargetBranch string `json:"target_branch"`
Labels []string `json:"labels,omitempty"`
RemoveSourceBranch bool `json:"remove_source_branch,omitempty"`
}
CreateCROptions contains options for creating a change request.
type CreateIssueOptions ¶
type CreateIssueOptions struct {
Owner string `json:"owner"`
Repo string `json:"repo"`
Title string `json:"title"`
Body string `json:"body,omitempty"`
Assignees []string `json:"assignees,omitempty"`
Labels []string `json:"labels,omitempty"`
Milestone string `json:"milestone,omitempty"` // milestone number/ID as a string; "" = do not set
}
CreateIssueOptions contains options for creating an issue.
type CreateLabelOptions ¶
type CreateLabelOptions struct {
Name string `json:"name"`
Color string `json:"color"`
Description string `json:"description,omitempty"`
}
CreateLabelOptions contains options for creating a repository label. Color uses the canonical 6-digit hex form without '#' (e.g. "ff0000").
type CreateMigrationOptions ¶ added in v0.72.0
type CreateMigrationOptions struct {
// LockRepositories 迁移期间锁定仓库(防止导出过程中数据变动)。
LockRepositories bool `json:"lock_repositories"`
// ExcludeMetadata 跳过 issues/PR 等元数据、只导出仓库内容。
ExcludeMetadata bool `json:"exclude_metadata"`
}
CreateMigrationOptions 发起归档迁移的选项。json tag 与 GitHub 迁移 API 请求体字段一致,便于后端直接序列化上送。
type CreateMilestoneOptions ¶
type CreateMilestoneOptions struct {
Title string `json:"title"`
Description string `json:"description,omitempty"`
DueOn *time.Time `json:"due_on,omitempty"`
}
CreateMilestoneOptions contains options for creating a repository milestone.
type CreateReleaseOptions ¶
type CreateReleaseOptions struct {
TagName string `json:"tag_name"`
Target string `json:"target,omitempty"`
Title string `json:"title"`
Body string `json:"body,omitempty"`
Draft bool `json:"draft,omitempty"`
Prerelease bool `json:"prerelease,omitempty"`
}
CreateReleaseOptions contains options for creating a release.
type CreateRepoOptions ¶
type CreateRepoOptions struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Private bool `json:"private,omitempty"`
AutoInit bool `json:"auto_init,omitempty"`
DefaultBranch string `json:"default_branch,omitempty"`
}
CreateRepoOptions contains options for creating a repository.
type CreateReviewOptions ¶
type CreateReviewOptions struct {
CommitID string `json:"commit_id,omitempty"`
Event string `json:"event,omitempty"`
Body string `json:"body,omitempty"`
Comments []ReviewComment `json:"comments,omitempty"`
}
CreateReviewOptions contains options for creating a review.
type CreateWebhookOptions ¶
type CreateWebhookOptions struct {
Owner string `json:"owner"`
Repo string `json:"repo"`
URL string `json:"url"`
Secret string `json:"secret,omitempty"`
Events []string `json:"events,omitempty"`
}
CreateWebhookOptions contains options for creating a webhook.
type DeployKey ¶
type DeployKey struct {
ID int64 `json:"id"`
Title string `json:"title"`
Key string `json:"key"`
ReadOnly bool `json:"read_only"`
}
DeployKey represents a deploy key on a repository.
type DeploymentKeyManager ¶
type DeploymentKeyManager interface {
// ListDeployKeys returns all deploy keys for a repository.
ListDeployKeys(ctx context.Context, owner, repo string) ([]*DeployKey, error)
// AddDeployKey adds a new deploy key to the repository.
AddDeployKey(ctx context.Context, owner, repo string, opts AddDeployKeyOptions) (*DeployKey, error)
// DeleteDeployKey removes a deploy key by its platform ID.
DeleteDeployKey(ctx context.Context, owner, repo string, keyID int64) error
}
DeploymentKeyManager provides deploy key CRUD for CI/CD. It is an optional capability interface: consumers should gate on Provider.Capabilities().DeployKeys (or type-assert) before use.
Platform support: GitHub, GitCode, GitLab, Gitea, Forgejo. Gitee and TencentCode have no deploy key API.
type DetectResult ¶
DetectResult holds the platform, owner, repo, and base API URL extracted from a git remote URL by DetectPlatform.
Owner/Repo are split as "first path segment = Owner, remainder = Repo". For GitLab repositories nested in subgroups the full subgroup path stays part of Repo: "https://gitlab.com/group/sub/repo" yields Owner="group" and Repo="sub/repo". Callers must therefore treat Repo as a path (it may contain "/"), not a bare repository name.
func DetectPlatform ¶
func DetectPlatform(remoteURL string) (*DetectResult, error)
DetectPlatform parses a git remote URL (HTTPS, SSH, or ssh://) and returns the detected platform, owner, repo name, and base API URL. Returns ErrPlatformNotSupported for unrecognized hosts; use NewProvider with explicit Config for self-hosted instances not in the known-host list.
type DiffManager ¶
type DiffManager interface {
GetCRDiff(ctx context.Context, owner, repo, number string) (*MergeDiff, error)
GetCRFiles(ctx context.Context, owner, repo, number string) ([]*ChangedFile, error)
CreateNote(ctx context.Context, owner, repo, number, body string) (string, error)
DeleteNote(ctx context.Context, owner, repo, number string, noteID string) error
CreateDiscussion(ctx context.Context, owner, repo, number string, opts DiscussionOptions) (string, error)
}
DiffManager handles diff and discussion operations. Review operations (CreateReview and friends) live on the optional ReviewManager capability interface; DiffManager itself carries five methods. Change request numbers are strings (same addressing scheme as IssueManager); numeric platforms parse with strconv and fail with a wrapped "invalid pull request number" error.
type DiscussionOptions ¶
type DiscussionOptions struct {
Body string `json:"body"`
FilePath string `json:"file_path,omitempty"`
NewLine int `json:"new_line,omitempty"`
OldLine int `json:"old_line,omitempty"`
StartNewLine int `json:"start_new_line,omitempty"`
BaseSHA string `json:"base_sha,omitempty"`
StartSHA string `json:"start_sha,omitempty"`
HeadSHA string `json:"head_sha,omitempty"`
}
DiscussionOptions contains options for creating a discussion comment.
type Divergence ¶
type Divergence struct {
Capability string
Method string
Field string
Kind DivergenceKind
Reason string
}
Divergence is one registered entry of a backend's divergence ledger. Capability and Method carry the provider interface and method names; Field names the affected option/result field for ignore and mapping entries (empty when the divergence is method-scoped). Reason is a one-sentence explanation surfaced in docs/divergence-ledger.md.
Backends expose their ledger via a package-level Divergences function and the Provider.Divergences method; the ledger is the machine-readable successor of the former "(spec §4.6)" comment registrations.
func FindByMethod ¶
func FindByMethod(divs []Divergence, method string) []Divergence
FindByMethod returns the ledger entries registered for method.
type DivergenceKind ¶
type DivergenceKind string
DivergenceKind classifies how a backend's behavior departs from the unified provider semantics for a given method.
const ( // DivergenceStub marks a method the platform cannot serve at all: the // call returns an error wrapping ErrNotImplemented and touches no wire. DivergenceStub DivergenceKind = "stub" // DivergenceIgnore marks a field or parameter that is silently dropped: // the call succeeds but the ignored input has no effect. DivergenceIgnore DivergenceKind = "ignore" // DivergenceMapping marks a semantic mapping: the call succeeds and // returns the closest platform equivalent, an approximation of the // unified semantics. DivergenceMapping DivergenceKind = "mapping" // DivergenceDetour marks an implementation detour: the method bypasses // the platform's third-party SDK and drives the raw transport client. // Behavior is unchanged; the entry exists for maintainers. DivergenceDetour DivergenceKind = "detour" )
type EnsureAction ¶ added in v0.72.0
type EnsureAction string
EnsureAction reports what an Ensure* call did to converge the resource onto its desired state.
const ( // EnsureCreated: the resource did not exist and was created. EnsureCreated EnsureAction = "created" // EnsureUpdated: the resource existed with different content and was // updated (for webhooks and deploy keys: replaced, see below). EnsureUpdated EnsureAction = "updated" // EnsureUnchanged: the resource already matched the desired state. EnsureUnchanged EnsureAction = "unchanged" )
Ensure* outcomes.
type EventRepo ¶
type EventRepo struct {
ID int64 `json:"id"`
FullName string `json:"full_name"`
Owner string `json:"owner"`
Name string `json:"name"`
}
EventRepo represents the repository in a webhook event.
func BuildEventRepo ¶
BuildEventRepo creates an EventRepo from a full name string.
type FileDeleteOptions ¶
type FileDeleteOptions struct {
Path string `json:"path"`
Message string `json:"message"`
Branch string `json:"branch,omitempty"`
SHA string `json:"sha,omitempty"`
Author string `json:"author,omitempty"`
Email string `json:"email,omitempty"`
}
FileDeleteOptions contains options for deleting a file.
type FileManager ¶
type FileManager interface {
GetFileContent(ctx context.Context, owner, repo, path, ref string) (string, error)
CreateFile(ctx context.Context, owner, repo string, opts FileOptions) (*FileResult, error)
UpdateFile(ctx context.Context, owner, repo string, opts FileOptions) (*FileResult, error)
DeleteFile(ctx context.Context, owner, repo string, opts FileDeleteOptions) (*FileResult, error)
}
FileManager handles file CRUD operations on repositories.
type FileOptions ¶
type FileOptions struct {
Path string `json:"path"`
Content string `json:"content"`
Message string `json:"message"`
Branch string `json:"branch,omitempty"`
SHA string `json:"sha,omitempty"`
Author string `json:"author,omitempty"`
Email string `json:"email,omitempty"`
}
FileOptions contains options for creating or updating a file.
type FileResult ¶
type FileResult struct {
SHA string `json:"sha,omitempty"`
CommitSHA string `json:"commit_sha,omitempty"`
}
FileResult is the result of a file operation.
type ForgejoWebhookValidator ¶ added in v0.72.0
type ForgejoWebhookValidator struct{}
ForgejoWebhookValidator validates Forgejo's HMAC-SHA256 webhook signature. Current Forgejo sends X-Forgejo-Signature; releases forked from older Gitea send X-Gitea-Signature, so both are accepted — whichever header is present is used (the signature format itself is identical raw-hex HMAC-SHA256).
func (ForgejoWebhookValidator) Name ¶ added in v0.72.0
func (ForgejoWebhookValidator) Name() string
Name implements WebhookValidator.
type ForkRepoOptions ¶
type ForkRepoOptions struct {
Organization string `json:"organization,omitempty"`
Name string `json:"name,omitempty"`
}
ForkRepoOptions contains options for forking a repository.
type Gist ¶ added in v0.72.0
type Gist struct {
ID string `json:"id"`
Description string `json:"description"`
Public bool `json:"public"`
HTMLURL string `json:"html_url"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Files map[string]GistFile `json:"files"`
}
Gist GitHub Gist 元数据。json tag 与 GitHub API 对齐,便于消费方直接 序列化落盘备份(下游 BackupGists 即整体 json.MarshalIndent)。
type GistFile ¶ added in v0.72.0
type GistFile struct {
Filename string `json:"filename"`
Language string `json:"language"`
RawURL string `json:"raw_url"`
Size int64 `json:"size"`
Content string `json:"content"`
}
GistFile 单个 gist 文件的元数据与内容。json tag 与 GitHub /gists 响应对齐, 与消费方(git-sync-service githubapi.Gist 内嵌结构)字段保持兼容。
type GistManager ¶ added in v0.72.0
type GistManager interface {
// ListMyGists 分页列出 token 用户可见的 gist(GET /gists:已认证调用
// 返回当前用户的 gist 列表)。page/perPage 语义与其他分页方法一致,
// 非法值经 NormalizePageOpts 归一。
ListMyGists(ctx context.Context, page, perPage int) ([]*Gist, error)
}
GistManager 提供认证用户自己的 gist 列表。可选能力接口:使用前先看 Provider.Capabilities().Gists(或类型断言)。目前只读——下游备份场景 只需要分页列出,创建/修改 gist 不在统一接口范围内。
type GitCodeWebhookValidator ¶ added in v0.72.0
type GitCodeWebhookValidator struct{}
GitCodeWebhookValidator accepts GitCode's two webhook verification modes: an HMAC-SHA256 body signature (X-GitCode-Signature, falling back to the gitea-inherited X-Gitea-Signature) or the documented static password in X-GitCode-Token. Whichever header is present is used.
func (GitCodeWebhookValidator) Name ¶ added in v0.72.0
func (GitCodeWebhookValidator) Name() string
Name implements WebhookValidator.
type GiteeWebhookValidator ¶
type GiteeWebhookValidator struct {
// MaxAge bounds |now - X-Gitee-Timestamp| in sign mode. Zero means
// DefaultGiteeSignMaxAge; a negative value disables the freshness
// check (not recommended — it enables indefinite replay).
MaxAge time.Duration
// AllowPasswordMode also accepts the plain-password form when
// X-Gitee-Timestamp is absent. Enable only when the webhook is known
// to be configured in password mode.
AllowPasswordMode bool
}
GiteeWebhookValidator verifies Gitee webhooks. Gitee offers two security modes and both ride the X-Gitee-Token header:
- 签名密钥 (sign) mode: X-Gitee-Timestamp carries the send time in unix millis and X-Gitee-Token carries Base64(HMAC-SHA256(key=secret, msg=timestamp+"\n"+secret)). This is the default mode this validator checks, including a timestamp freshness bound (replay protection).
- 密码 (password) mode: X-Gitee-Token carries the configured password verbatim, X-Gitee-Timestamp is absent, and the signature cannot be computed. Opt in with AllowPasswordMode; the token is then compared against the secret in constant time.
The webhook body plays no part in either scheme (Gitee signs the timestamp, not the payload) — transport-level integrity is delegated to TLS.
func (GiteeWebhookValidator) Name ¶
func (GiteeWebhookValidator) Name() string
Name implements WebhookValidator.
type HMACSHA256Validator ¶
type HMACSHA256Validator struct {
Header string
}
HMACSHA256Validator verifies a "Header: sha256=<hex>" style signature using HMAC-SHA256 over the request body. The expected header is configurable so it works for GitHub (X-Hub-Signature-256), Gitea (X-Gitea-Signature), Gitee (X-Gitee-Token) and others.
func (HMACSHA256Validator) Name ¶
func (HMACSHA256Validator) Name() string
Name implements WebhookValidator.
type HmacValidator ¶
type HmacValidator struct {
Header string
Algorithm string // "sha1", "sha256", "sha512"
Prefix string // expected signature prefix ("sha256=")
}
HmacValidator is a lower-level helper that supports arbitrary hash algorithms. It is intended for use by platform implementations that need something other than SHA-256.
func (*HmacValidator) Name ¶
func (h *HmacValidator) Name() string
Name implements WebhookValidator.
type Hooks ¶
type Hooks struct {
Request []RequestHook
Response []ResponseHook
}
Hooks holds request and response lifecycle hooks. These are mapped into transport.Hooks by each backend's constructor; direct callers should use the Hooks struct to register hooks via provider.Config.
func (*Hooks) AddRequestHook ¶
func (h *Hooks) AddRequestHook(hook RequestHook)
AddRequestHook appends a request hook.
func (*Hooks) AddResponseHook ¶
func (h *Hooks) AddResponseHook(hook ResponseHook)
AddResponseHook appends a response hook.
type Issue ¶
type Issue struct {
ID int64 `json:"id"`
Number string `json:"number"`
Title string `json:"title"`
Body string `json:"body"`
State IssueState `json:"state"`
Author *CRUser `json:"author,omitempty"`
Labels []string `json:"labels,omitempty"`
Assignees []string `json:"assignees,omitempty"`
Milestone *MilestoneRef `json:"milestone,omitempty"`
WebURL string `json:"web_url,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ClosedAt *time.Time `json:"closed_at,omitempty"`
// IsPullRequest 标记这条"issue"其实是 PR。
//
// **GitHub 的 issue 列表端点会把 PR 一起返回**(同一条记录既是 issue 也是 PR),
// 不标记的话消费方没法把两者分开 ⇒ 同一个 PR 既进 issues 快照又进
// pull_requests 快照,而且**占掉 issue 的数量预算**(默认 500)
// ⇒ PR 多的仓里真实 issue 可能整批落在预算之外,快照缺项且无任何告警。
//
// Gitea/Forgejo 家族的列表端点有 type=issues 过滤(本来就不含 PR),
// GitLab 的 issues 端点也不含 MR ⇒ 只有 GitHub 需要这个标记。
IsPullRequest bool `json:"is_pull_request,omitempty"`
}
Issue represents an issue on a platform. Number is the platform's issue identifier as a string (numeric on every current platform except Gitee, whose identifiers are alphanumeric).
type IssueComment ¶
type IssueComment struct {
ID int64 `json:"id"`
Body string `json:"body"`
Author *CRUser `json:"author,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
IssueComment represents a comment on an issue.
func (*IssueComment) Mentions ¶
func (c *IssueComment) Mentions() []string
Mentions returns the deduplicated @usernames found in the comment body.
type IssueLabel ¶
type IssueLabel struct {
ID int64 `json:"id"`
Name string `json:"name"`
Color string `json:"color,omitempty"`
}
IssueLabel represents a label on a repository.
type IssueManager ¶
type IssueManager interface {
ListIssues(ctx context.Context, opts ListIssuesOptions) ([]*Issue, int, error)
GetIssue(ctx context.Context, owner, repo, number string) (*Issue, error)
CreateIssue(ctx context.Context, opts CreateIssueOptions) (*Issue, error)
UpdateIssue(ctx context.Context, owner, repo, number string, opts UpdateIssueOptions) (*Issue, error)
CloseIssue(ctx context.Context, owner, repo, number string) (*Issue, error)
ReopenIssue(ctx context.Context, owner, repo, number string) (*Issue, error)
// ListIssueComments returns the issue's comments in full, exhausting
// the platform's pagination — the result is the complete comment list,
// not a single page, in the platform's default order.
ListIssueComments(ctx context.Context, owner, repo, number string) ([]*IssueComment, error)
CreateIssueComment(ctx context.Context, owner, repo, number, body string) (*IssueComment, error)
// UpdateIssueComment replaces a comment's body wholesale: every
// platform's edit surface is a body-only PATCH/PUT with no
// partial-update semantics, mirroring CreateIssueComment. The platform
// enforces authorship — only the comment's author (typically the token
// identity, e.g. a review bot updating its own comment) may edit — so
// the call fails for anyone else's comment. commentID is the
// IssueComment.ID from CreateIssueComment or ListIssueComments. number
// is ignored on platforms whose edit endpoint addresses the comment
// directly (GitHub, Gitea, Forgejo, GitCode, Gitee); GitLab and Tencent
// 工蜂 route through the issue, so it must carry that issue's number.
UpdateIssueComment(ctx context.Context, owner, repo, number string, commentID int64, body string) (*IssueComment, error)
ListIssueLabels(ctx context.Context, owner, repo string) ([]*IssueLabel, error)
AddIssueLabels(ctx context.Context, owner, repo, number string, labels []string) error
RemoveIssueLabel(ctx context.Context, owner, repo, number, name string) error
}
IssueManager provides issue CRUD, comments, and label management. Issue numbers are strings: every platform address is representable as a string, and Gitee natively uses alphanumeric identifiers (e.g. "IAINVA"). Backends on numeric platforms parse with strconv.Atoi and fail with a wrapped "invalid issue number" error.
type IssueState ¶
type IssueState string
IssueState represents the state of an issue.
const ( IssueStateOpen IssueState = "open" IssueStateClosed IssueState = "closed" )
type JobLog ¶ added in v0.67.0
type JobLog struct {
Name string `json:"name"`
Stage string `json:"stage"`
WebURL string `json:"web_url,omitempty"`
Trace string `json:"trace"` // 失败日志尾部(后端截断,量级 ~20KB)
Truncat bool `json:"truncated"`
}
JobLog is one failed CI job's identifying metadata plus the tail of its execution log, sized for LLM consumption rather than archival.
type Label ¶
type Label struct {
ID int64 `json:"id"`
Name string `json:"name"`
Color string `json:"color,omitempty"`
Description string `json:"description,omitempty"`
}
Label represents a repository label. Color is canonicalized to 6-digit hex without a leading '#' (e.g. "ff0000"); backends add the '#' when a platform requires it (GitLab, Gitea, Forgejo) and strip it on the way in.
type LabelManager ¶
type LabelManager interface {
// ListLabels lists the repository's labels.
ListLabels(ctx context.Context, owner, repo string, opts ListLabelsOptions) ([]*Label, error)
// CreateLabel creates a repository label.
CreateLabel(ctx context.Context, owner, repo string, opts CreateLabelOptions) (*Label, error)
// UpdateLabel updates the label with the given name. Nil fields in opts
// are left unchanged.
UpdateLabel(ctx context.Context, owner, repo, name string, opts UpdateLabelOptions) (*Label, error)
// DeleteLabel deletes the label with the given name.
DeleteLabel(ctx context.Context, owner, repo, name string) error
}
LabelManager provides repository-level label CRUD. It is an optional capability interface: consumers should gate on Provider.Capabilities() (or type-assert) before use. Labels are addressed by name; backends whose platform API addresses labels by numeric ID (GitLab, Gitea, Forgejo) resolve the name internally. Such backends scan labels with server-side pagination (100 per page, bounded to 50 pages); beyond that bound a label may be reported as not found by UpdateLabel/DeleteLabel even though it exists.
The issue-scoped operations (ListIssueLabels, AddIssueLabels, RemoveIssueLabel) remain on IssueManager because they operate on an issue, not on the repository's label set.
type ListCROptions ¶
type ListCROptions struct {
Owner string `json:"owner"`
Repo string `json:"repo"`
// State 过滤状态。**空 = 不过滤(全部)**。
//
// 各后端的原生词表不同(open/closed/merged 与 opened/closed)⇒ 平台层的
// "空" 语义必须统一,否则同一个调用在有的平台只拿到 open、在别的平台拿到全部
// —— 调用方无从察觉 closed/merged 的那部分**静默丢失**。
// (GitHub / GitLab / 工蜂 本来就是"空=不过滤";Gitee / Gitea / Forgejo /
// GitCode 曾把空值映射成 open ⇒ 已对齐。)
State CRState `json:"state,omitempty"`
SourceBranch string `json:"source_branch,omitempty"`
TargetBranch string `json:"target_branch,omitempty"`
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
ListCROptions contains options for listing change requests.
type ListCommitsOptions ¶
type ListCommitsOptions struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
Branch string `json:"branch,omitempty"`
Since string `json:"since,omitempty"` // RFC3339
Until string `json:"until,omitempty"` // RFC3339
}
ListCommitsOptions contains options for listing commits in a repository.
type ListIssuesOptions ¶
type ListIssuesOptions struct {
Owner string `json:"owner"`
Repo string `json:"repo"`
State IssueState `json:"state,omitempty"`
Assignee string `json:"assignee,omitempty"`
Labels string `json:"labels,omitempty"`
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
// Sort 排序字段("created"|"updated"|"comments"),空 = 平台默认。
//
// **增量备份必须用它**:平台默认按 created 倒序 ⇒ "上次备份后被改动的
// **老** issue"正好被挤在第一页之外,客户端再按 updated 过滤也捞不到
// (捞到的永远是"最新创建"的那批)。
//
// 支持情况(逐后端登记在各自的 divergence 账本里):
// - GitHub:支持(sort + direction);
// - GitLab:支持(order_by=created_at|updated_at + sort=asc|desc);
// - Gitee / Gitea / Forgejo / GitCode / 工蜂:当前 SDK 不暴露(或词表无法确证)
// ⇒ 传入被忽略(调用方需自己兜底,见 core 的增量采集)。
Sort string `json:"sort,omitempty"`
// Direction 排序方向("asc"|"desc"),空 = 平台默认。
Direction string `json:"direction,omitempty"`
}
ListIssuesOptions contains options for listing issues.
type ListLabelsOptions ¶
type ListLabelsOptions struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
ListLabelsOptions contains options for listing repository labels.
type ListMilestonesOptions ¶
type ListMilestonesOptions struct {
State string `json:"state,omitempty"`
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
ListMilestonesOptions contains options for listing repository milestones. State filters by "open" or "closed"; an empty State lists whatever the platform defaults to (GitHub/Gitea/Forgejo/Gitee default to open, GitLab to all). Tencent Code ignores State entirely — gongfeng's list options expose pagination only, so all states are listed.
type ListNotificationsOptions ¶
type ListNotificationsOptions struct {
All bool `json:"all,omitempty"` // include already-read notifications
Since string `json:"since,omitempty"` // RFC3339 timestamp
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
ListNotificationsOptions contains options for listing notifications.
type ListRepoOptions ¶
type ListRepoOptions struct {
Owner string `json:"owner,omitempty"`
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
ListRepoOptions contains options for listing repositories on a platform.
type Logger ¶
type Logger interface {
Debug(msg string, keysAndValues ...any)
Info(msg string, keysAndValues ...any)
Warn(msg string, keysAndValues ...any)
Error(msg string, keysAndValues ...any)
}
Logger is a minimal logging interface compatible with most Go logging libraries. Implementations include slog, zap, zerolog, logrus, etc.
func NewLogxLogger ¶ added in v0.85.0
NewLogxLogger returns a Logger backed by the oekit/logx facade, for consumers who run the oekit observability stack. The logger is lazily resolved (logx.Delegating): it follows whatever implementation the consumer installs via logx.SetDefault / logx.UseSlog, even when that happens after NewProvider. component identifies this SDK in log output (the logx convention: service name belongs to the consumer, packages identify themselves via the component attribute).
p, err := provider.NewProvider(provider.Config{
Platform: provider.PlatformGitHub,
Token: token,
Logger: provider.NewLogxLogger("git-platform"),
})
func NewNoopLogger ¶
func NewNoopLogger() Logger
NewNoopLogger returns a Logger that discards all output.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager caches Provider instances keyed by configuration so repeated constructions of the same (platform, baseURL, token) reuse the underlying HTTP client pools instead of leaking a fresh one per call.
It automatically detects the platform from clone URLs and reuses existing Provider instances within the TTL window. The cache key is derived from platform + baseURL + a SHA-256 hash of the token, so different tokens map to different entries without leaking the token itself in logs or memory dumps.
The type is deliberately thin: the cache mechanics (TTL, LRU capacity eviction, counters) live in ttlCache and the background-cleanup lifecycle in janitor, leaving Manager exactly key derivation + factory call.
func NewManager ¶
func NewManager(ttl time.Duration, opts ...ManagerOption) *Manager
NewManager creates a new Provider Manager with the given TTL. A TTL of 0 means providers never expire (until the process exits).
func (*Manager) Cleanup ¶
func (m *Manager) Cleanup()
Cleanup removes expired entries from the cache. Safe to call manually; also invoked periodically by StartJanitor.
func (*Manager) Get ¶
Get returns a cached or newly created Provider for the given config. The cache key is platform + baseURL + hash(token), so the same (platform, baseURL) with a different token gets a distinct entry.
func (*Manager) GetByURL ¶
GetByURL detects the platform from the clone URL and returns a cached or newly created Provider.
func (*Manager) ResetStats ¶
func (m *Manager) ResetStats()
ResetStats zeroes the hit/miss/eviction counters. Cache entries are not affected.
func (*Manager) StartJanitor ¶
StartJanitor launches a background goroutine that calls Cleanup every interval until ctx is cancelled or Stop is called. Calling StartJanitor more than once without an intervening Stop (or without the previous goroutine having exited) is a no-op. When the goroutine exits on its own — e.g. because ctx was cancelled — it resets the janitor state, so a subsequent StartJanitor with a fresh ctx launches a new goroutine instead of being mistaken for "already running".
type ManagerOption ¶
type ManagerOption func(*Manager)
ManagerOption configures a Manager at construction time.
func WithHasher ¶
func WithHasher(h func(token string) string) ManagerOption
WithHasher overrides the default SHA-256 token hasher. Useful for tests that want deterministic, human-readable keys.
func WithMaxSize ¶
func WithMaxSize(n int) ManagerOption
WithMaxSize caps the cache at n entries. When the cap is reached, the least recently used entry is evicted before a new one is inserted.
type MarkNotificationsOptions ¶
type MarkNotificationsOptions struct {
LastReadAt string `json:"last_read_at,omitempty"` // RFC3339; empty = mark all
}
MarkNotificationsOptions contains options for marking notifications as read.
type MergeCROptions ¶
type MergeCROptions struct {
MergeCommitMessage string `json:"merge_commit_message,omitempty"`
Squash bool `json:"squash,omitempty"`
RemoveSourceBranch bool `json:"remove_source_branch,omitempty"`
}
MergeCROptions contains options for merging a change request.
type MergeDiff ¶
type MergeDiff struct {
Files []*ChangedFile
TotalAdd int
TotalDel int
RawDiff string
}
MergeDiff represents the diff of a change request.
type MigrationInfo ¶ added in v0.72.0
type MigrationInfo struct {
ID int64 `json:"id"`
State string `json:"state"`
// ArchiveURL 归档下载地址(仅当 state 为 exported 时可用)。
ArchiveURL string `json:"archive_url"`
}
MigrationInfo 迁移任务状态。json tag 与 GitHub 迁移 API 响应对齐。
type MigrationManager ¶ added in v0.72.0
type MigrationManager interface {
// CreateMigration 发起迁移导出。org == "" 表示用户级迁移
// (POST /user/migrations),非空表示组织级(POST /orgs/{org}/migrations)
// ——同一语义贯穿本接口全部方法。
CreateMigration(ctx context.Context, org string, opts CreateMigrationOptions) (*MigrationInfo, error)
// GetMigration 查询迁移状态,org 语义与 CreateMigration 一致。
GetMigration(ctx context.Context, org string, id int64) (*MigrationInfo, error)
}
MigrationManager 提供平台原生的「一键全量归档导出」(GitHub Migrations API)。可选能力接口:使用前先看 Provider.Capabilities().Migrations (或类型断言)。迁移是异步的:CreateMigration 立即返回任务 ID,消费方 轮询 GetMigration 直到 state 进入终态。
type Milestone ¶
type Milestone struct {
Number string `json:"number"`
Title string `json:"title"`
Description string `json:"description"`
State MilestoneState `json:"state"`
DueOn *time.Time `json:"due_on,omitempty"`
}
Milestone represents a repository milestone. Number carries the platform's milestone addressing identifier as a string — the same value MilestoneRef.Number uses and MilestoneManager methods accept: the milestone number on GitHub, the platform milestone ID on GitLab, Gitea, Forgejo, GitCode, and Tencent Code, and the milestone serial number on Gitee (see MilestoneManager for the per-platform truth).
type MilestoneManager ¶
type MilestoneManager interface {
// ListMilestones lists the repository's milestones.
ListMilestones(ctx context.Context, owner, repo string, opts ListMilestonesOptions) ([]Milestone, error)
// GetMilestone fetches the milestone with the given number.
GetMilestone(ctx context.Context, owner, repo, number string) (*Milestone, error)
// CreateMilestone creates a repository milestone.
CreateMilestone(ctx context.Context, owner, repo string, opts CreateMilestoneOptions) (*Milestone, error)
// UpdateMilestone updates the milestone with the given number. Nil
// fields in opts are left unchanged.
UpdateMilestone(ctx context.Context, owner, repo, number string, opts UpdateMilestoneOptions) (*Milestone, error)
// DeleteMilestone deletes the milestone with the given number.
DeleteMilestone(ctx context.Context, owner, repo, number string) error
}
MilestoneManager provides repository-level milestone CRUD. It is an optional capability interface: consumers should gate on Provider.Capabilities() (or type-assert) before use.
Milestones are addressed by a string `number`, but what that string carries is platform-specific — the same identifier MilestoneRef.Number and Milestone.Number expose:
- GitHub: the milestone *number* (its per-repo serial number).
- GitLab, Gitea, Forgejo, GitCode, Tencent Code: the platform milestone *ID* (the write endpoints take exactly that identifier, so per-platform round-trips hold).
- Gitee: the milestone *serial number* (the "number" field of Gitee's milestone payload — the identifier Gitee's own issue and milestone write endpoints take; the SDK model exposes no id).
Values obtained from MilestoneRef.Number (issue payloads) or Milestone.Number (list/get results) round-trip back into these methods on the platform they came from.
type MilestoneRef ¶
MilestoneRef references a milestone from an issue. Number carries the platform's milestone addressing identifier as a string: the milestone *number* on GitHub, the platform milestone *ID* on GitLab, Gitea, Forgejo, GitCode, and Tencent Code (whose write endpoints take exactly that identifier, so per-platform round-trips hold), and Gitee's milestone *serial number* (the "number" field of Gitee's milestone payload — the identifier Gitee's own issue and milestone write endpoints take; the SDK model exposes no id). This is the same identifier Milestone.Number exposes and MilestoneManager methods accept, so refs round-trip through the milestone manager on the platform they came from.
type MilestoneState ¶
type MilestoneState string
MilestoneState represents the state of a milestone.
const ( MilestoneStateOpen MilestoneState = "open" MilestoneStateClosed MilestoneState = "closed" )
type NormalizedEvent ¶
type NormalizedEvent struct {
ID string `json:"id"`
Type string `json:"type"`
Source Platform `json:"source"`
Timestamp time.Time `json:"timestamp"`
Actor *CRUser `json:"actor"`
Repo *EventRepo `json:"repo"`
CR *ChangeRequest `json:"cr,omitempty"`
// Issue is set for issue.* events and for comments made on issues;
// Comment carries the comment body for comment.* events. A comment on
// a change request populates CR instead of (or alongside) nothing.
Issue *Issue `json:"issue,omitempty"`
Comment *IssueComment `json:"comment,omitempty"`
Branch string `json:"branch,omitempty"`
Tag string `json:"tag,omitempty"`
CommitSHA string `json:"commit_sha,omitempty"`
Action string `json:"action,omitempty"`
RawPayload json.RawMessage `json:"raw_payload"`
}
NormalizedEvent represents a normalized webhook event from any platform.
type NoteManager ¶ added in v0.67.2
type NoteManager interface {
// UpdateNote rewrites the body of one CR comment.
UpdateNote(ctx context.Context, owner, repo, number, noteID, body string) (*IssueComment, error)
// ListNotes returns every comment on the CR, oldest first (all pages).
ListNotes(ctx context.Context, owner, repo, number string) ([]*IssueComment, error)
}
NoteManager provides targeted update and full pagination over CR (MR/PR) comments — an optional capability (v0.67.2). Semantics are anchored to the CR comment thread: on GitLab these hit the MergeRequest Notes API, because IssueManager's comment methods go through the Issues Notes API and always 404 for merge requests (MRs and issues live in separate iid namespaces). Platforms where an issue IS the PR (GitHub, Gitea, Gitee) are already covered by IssueManager and need not implement this interface.
type Notification ¶
type Notification struct {
ID string `json:"id"`
Unread bool `json:"unread"`
Reason string `json:"reason"`
Subject NotificationSubject `json:"subject"`
Repo *EventRepo `json:"repo,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
}
Notification represents a single notification from a user's inbox.
type NotificationManager ¶
type NotificationManager interface {
// ListNotifications returns the authenticated user's notifications,
// exhausting the platform's pagination.
ListNotifications(ctx context.Context, opts ListNotificationsOptions) ([]*Notification, error)
// ListRepoNotifications returns notifications for a specific repository.
ListRepoNotifications(ctx context.Context, owner, repo string, opts ListNotificationsOptions) ([]*Notification, error)
// MarkNotificationRead marks a single notification thread as read.
MarkNotificationRead(ctx context.Context, threadID string) error
// MarkNotificationsRead marks all (or filtered) notifications as read.
MarkNotificationsRead(ctx context.Context, opts MarkNotificationsOptions) error
// MarkRepoNotificationsRead marks all notifications for a repository as read.
MarkRepoNotificationsRead(ctx context.Context, owner, repo string, opts MarkNotificationsOptions) error
}
NotificationManager provides access to a user's notification inbox and per-repository notification streams. It is an optional capability interface: consumers should gate on Provider.Capabilities().Notifications (or type-assert) before use.
Platform support: GitHub, GitCode, Gitea, Forgejo, Gitee. GitLab exposes only notification *settings* (no inbox) and TencentCode has no notification API at all — both report Notifications=false in CapabilitySet.
type NotificationSubject ¶
type NotificationSubject struct {
Title string `json:"title"`
Type string `json:"type"` // "Issue", "PullRequest", "Commit", etc.
URL string `json:"url"`
}
NotificationSubject describes the resource that triggered the notification.
type PageFetch ¶ added in v0.72.0
PageFetch fetches one page of a paginated list. page is the 1-based page number; the implementation must forward it into the platform call's page options (and should set an explicit PerPage so page sizes stay stable across the walk):
err := provider.Each(ctx, func(ctx context.Context, page int) ([]provider.PlatformRepo, error) {
return p.ListRepos(ctx, provider.ListRepoOptions{Owner: "org", Page: page, PerPage: 100})
}, func(r provider.PlatformRepo) error {
fmt.Println(r.FullName)
return nil
})
type Platform ¶
type Platform string
Platform represents a Git hosting platform.
func RegisteredPlatforms ¶
func RegisteredPlatforms() []Platform
RegisteredPlatforms returns a list of all registered platforms.
type PlatformBranch ¶
type PlatformBranch struct {
Name string `json:"name"`
}
PlatformBranch represents a branch on a platform.
type PlatformRepo ¶
type PlatformRepo struct {
ID int64 `json:"id"`
FullName string `json:"full_name"`
Name string `json:"name"`
Owner string `json:"owner"`
Description string `json:"description"`
CloneURL string `json:"clone_url"`
SSHURL string `json:"ssh_url"`
DefaultBranch string `json:"default_branch"`
Private bool `json:"private"`
Platform Platform `json:"platform"`
// 仓库元数据(用于导入过滤:排除 archived/fork、按 star/语言过滤)
Archived bool `json:"archived,omitempty"`
Fork bool `json:"fork,omitempty"`
Stars int `json:"stars,omitempty"`
Language string `json:"language,omitempty"`
}
PlatformRepo represents a repository on a platform.
type PlatformWebhook ¶
type PlatformWebhook struct {
ID int64 `json:"id"`
URL string `json:"url"`
Events []string `json:"events"`
}
PlatformWebhook represents a webhook on a platform.
type Provider ¶
type Provider interface {
// Platform returns the platform type.
Platform() Platform
// TestConnection verifies the connection and checks capabilities.
TestConnection(ctx context.Context) (*TestConnectionResult, error)
// Capabilities statically declares the optional capability interfaces
// this provider implements. See CapabilitySet.
Capabilities() CapabilitySet
// Divergences statically declares this backend's divergence ledger: the
// registered places where its behavior departs from the unified
// semantics (stub / ignore / mapping / detour). Consumers can route on
// these entries — e.g. provider.Ignores — and docs/divergence-ledger.md
// is generated from them. Like CapabilitySet this is a compile-time
// declaration; the contract suite locks ledger entries to behavior.
Divergences() []Divergence
RepoManager
ChangeRequestManager
WebhookManager
BranchManager
DiffManager
CommitManager
FileManager
ReleaseManager
}
Provider is the unified interface for all Git hosting platforms. It composes 8 focused sub-interfaces for high cohesion and low coupling.
Consumers can depend on smaller interfaces (e.g., WebhookManager) when they don't need full Provider capabilities.
IssueManager, SearchManager, and CommitStatusManager are NOT part of Provider: only some platforms support them. Consumers that need issues, search, or commit statuses should type-assert against the optional capability interfaces:
if ism, ok := p.(provider.IssueManager); ok { ... }
if sm, ok := p.(provider.SearchManager); ok { ... }
if csm, ok := p.(provider.CommitStatusManager); ok { ... }
Caps declares the same information programmatically: consumers can route
on p.Capabilities() instead of probing with type assertions.
func NewProvider ¶
NewProvider creates a Provider for the given platform using the registry. Returns ErrPlatformNotSupported if the platform is not registered.
Platform backends are registered via init() functions. Import "github.com/yi-nology/go-git-platform/backends/all" with a blank identifier to register every platform shipped with the SDK.
type ProviderConstructor ¶
ProviderConstructor is a function that creates a Provider from a Config.
type ProviderError ¶
type ProviderError struct {
Platform Platform
Op string // operation name, e.g., "ListRepos"
Resource string // optional resource identifier, e.g., "owner/repo"
StatusCode int // 0 when not applicable (e.g. configuration errors)
// RetryAfter / ResetAt carry the server-advised recovery window when
// the error is a rate-limit rejection and the platform sent hints
// (Retry-After header; X-RateLimit-Reset unix seconds). Zero when
// absent. Copied from the underlying transport error by Wrap; see
// RateLimitRecovery for the ergonomic accessor.
RetryAfter time.Duration
ResetAt time.Time
Cause error // underlying cause; nil when constructed from raw fields
}
ProviderError is a structured error from a provider operation. It carries enough context (platform, op, resource, status code, cause) to support logging, retry, and user-facing messages. It implements errors.Is so the sentinel errors above are matched by Cause, and errors.As for typed access.
func (*ProviderError) Error ¶
func (e *ProviderError) Error() string
Error implements the error interface.
func (*ProviderError) Is ¶
func (e *ProviderError) Is(target error) bool
Is implements errors.Is. It matches when the wrapped Cause equals the target, which lets callers write `errors.Is(err, provider.ErrNotFound)`.
func (*ProviderError) IsClientError ¶
func (e *ProviderError) IsClientError() bool
IsClientError reports 4xx.
func (*ProviderError) IsServerError ¶
func (e *ProviderError) IsServerError() bool
IsServerError reports 5xx.
func (*ProviderError) IsStatus ¶
func (e *ProviderError) IsStatus(code int) bool
IsStatus reports whether the error has the given HTTP status code.
func (*ProviderError) Unwrap ¶
func (e *ProviderError) Unwrap() error
Unwrap implements errors.Unwrap.
type Reaction ¶
type Reaction struct {
ID int64 `json:"id"`
Emoji string `json:"emoji"`
User *CRUser `json:"user,omitempty"`
}
Reaction represents an emoji reaction on an issue or comment.
type ReactionManager ¶
type ReactionManager interface {
// ListIssueReactions returns all reactions on an issue.
ListIssueReactions(ctx context.Context, owner, repo, number string) ([]*Reaction, error)
// AddIssueReaction adds a reaction emoji to an issue. emoji is one of
// the Reaction* constants (e.g. ReactionHeart).
AddIssueReaction(ctx context.Context, owner, repo, number, emoji string) (*Reaction, error)
// RemoveIssueReaction removes a reaction by its platform ID.
RemoveIssueReaction(ctx context.Context, owner, repo, number string, reactionID int64) error
// ListIssueCommentReactions returns all reactions on an issue comment.
ListIssueCommentReactions(ctx context.Context, owner, repo string, commentID int64) ([]*Reaction, error)
// AddIssueCommentReaction adds a reaction emoji to an issue comment.
AddIssueCommentReaction(ctx context.Context, owner, repo string, commentID int64, emoji string) (*Reaction, error)
// RemoveIssueCommentReaction removes a reaction by its platform ID.
RemoveIssueCommentReaction(ctx context.Context, owner, repo string, commentID int64, reactionID int64) error
// ListCRReactions returns all reactions on a change request (PR/MR).
ListCRReactions(ctx context.Context, owner, repo, number string) ([]*Reaction, error)
// ListCRCommentReactions returns all reactions on a change-request
// comment (PR review comment / MR note).
ListCRCommentReactions(ctx context.Context, owner, repo string, commentID int64) ([]*Reaction, error)
// AddCRCommentReaction adds a reaction emoji to a change-request comment.
AddCRCommentReaction(ctx context.Context, owner, repo string, commentID int64, emoji string) (*Reaction, error)
// RemoveCRCommentReaction removes a reaction by its platform ID.
RemoveCRCommentReaction(ctx context.Context, owner, repo string, commentID int64, reactionID int64) error
}
ReactionManager provides emoji reaction CRUD on issues and their comments (both issue comments and change-request comments). It is an optional capability interface: consumers should gate on Provider.Capabilities().Reactions (or type-assert) before use.
Platform support: GitHub, GitCode, GitLab (via award-emoji), Gitea, Forgejo. Gitee and TencentCode have no reaction API — both report Reactions=false in CapabilitySet.
GitLab maps reactions to its "award emoji" API; the SDK normalizes emoji names (e.g. +1 ↔ thumbsup, hooray ↔ tada) so callers use the same constants across all platforms.
type ReleaseAsset ¶ added in v0.72.0
type ReleaseAsset struct {
ID int64 `json:"id"`
Name string `json:"name"`
Size int64 `json:"size"`
ContentType string `json:"content_type"`
BrowserDownloadURL string `json:"browser_download_url"`
URL string `json:"url"`
}
ReleaseAsset Release 附件元数据。json tag 与 GitHub API 对齐,与消费方 (git-sync-service githubapi.ReleaseAsset)字段保持兼容,Size 放大到 int64。
type ReleaseAssetManager ¶ added in v0.72.0
type ReleaseAssetManager interface {
// DownloadReleaseAsset 下载 assetID 对应附件并流式写入 w。
// 非 2xx 响应或无响应体时返回错误。
DownloadReleaseAsset(ctx context.Context, owner, repo string, assetID int64, w io.Writer) error
}
ReleaseAssetManager 下载 Release 附件。可选能力接口:使用前先看 Provider.Capabilities().ReleaseAssets(或类型断言)。附件可能很大, 因此是流式接口而非返回 []byte,避免整读内存。
type ReleaseInfo ¶
type ReleaseInfo struct {
ID int64 `json:"id"`
TagName string `json:"tag_name"`
Title string `json:"title"`
Body string `json:"body"`
URL string `json:"url"`
Draft bool `json:"draft"`
Prerelease bool `json:"prerelease"`
CreatedAt time.Time `json:"created_at"`
PublishedAt time.Time `json:"published_at"`
// Assets 发布附件元数据(仅声明 ReleaseAssets 能力的后端填充)。
Assets []*ReleaseAsset `json:"assets,omitempty"`
}
ReleaseInfo represents a release.
type ReleaseManager ¶
type ReleaseManager interface {
ListTags(ctx context.Context, owner, repo string) ([]*TagInfo, error)
ListReleases(ctx context.Context, owner, repo string) ([]*ReleaseInfo, error)
CreateRelease(ctx context.Context, owner, repo string, opts CreateReleaseOptions) (*ReleaseInfo, error)
GetReleaseByTag(ctx context.Context, owner, repo, tag string) (*ReleaseInfo, error)
UpdateRelease(ctx context.Context, owner, repo, tag string, opts UpdateReleaseOptions) (*ReleaseInfo, error)
DeleteRelease(ctx context.Context, owner, repo, tag string) error
GetArchive(ctx context.Context, owner, repo, ref, format string) ([]byte, error)
}
ReleaseManager handles tags, releases, and archives. Releases are addressed by tag name across every method: tag names are stable and human-addressable, while the underlying numeric release IDs are not.
type RepoManager ¶
type RepoManager interface {
ListRepos(ctx context.Context, opts ListRepoOptions) ([]*PlatformRepo, error)
GetRepo(ctx context.Context, owner, repo string) (*PlatformRepo, error)
CreateRepo(ctx context.Context, owner string, opts CreateRepoOptions) (*PlatformRepo, error)
DeleteRepo(ctx context.Context, owner, repo string) error
UpdateRepo(ctx context.Context, owner, repo string, opts UpdateRepoOptions) (*PlatformRepo, error)
ForkRepo(ctx context.Context, owner, repo string, opts ForkRepoOptions) (*PlatformRepo, error)
}
RepoManager handles repository CRUD operations.
type RepoStatsManager ¶
type RepoStatsManager interface {
// ListForks returns all forks of the repository.
ListForks(ctx context.Context, owner, repo string) ([]*PlatformRepo, error)
// ListStargazers returns users who have starred the repository.
ListStargazers(ctx context.Context, owner, repo string) ([]*CRUser, error)
// ListContributors returns contributors ranked by commit count.
ListContributors(ctx context.Context, owner, repo string) ([]*Contributor, error)
}
RepoStatsManager provides read-only repository statistics: forks, stargazers, and contributors. It is an optional capability interface: consumers should gate on Provider.Capabilities().RepoStats (or type-assert) before use.
Not every backend implements every method; backends that lack a specific method return ErrNotImplemented and register the gap in their divergence ledger. A backend declares RepoStats=true if it implements at least one method.
type RequestHook ¶
RequestHook is called before an HTTP request is sent. It can modify the context (e.g., add tracing headers) or inspect the request.
type ResponseHook ¶
type ResponseHook func(ctx context.Context, req *http.Request, resp *http.Response, duration time.Duration, err error)
ResponseHook is called after an HTTP response is received.
type RetryConfig ¶
type RetryConfig struct {
// MaxRetries is the maximum number of retry attempts (not counting the
// initial request). <= 0 disables retry.
MaxRetries int
// BaseDelay is the initial backoff delay before the first retry.
BaseDelay time.Duration
// MaxDelay caps the backoff delay. Zero means 30s (the transport
// default).
MaxDelay time.Duration
// RetryOn lists extra HTTP status codes to retry on, in addition to the
// transport's default set (429 and 5xx).
RetryOn []int
}
RetryConfig controls automatic retry behavior for HTTP requests issued by the transport layer. It is the public-facing configuration type passed via provider.Config; the transport package has its own internal transport.RetryConfig that this is mapped into.
func DefaultRetryConfig ¶
func DefaultRetryConfig() RetryConfig
DefaultRetryConfig returns a sensible default retry configuration: 3 retries, 500ms base delay, 30s cap, no extra status codes.
type Review ¶
type Review struct {
ID int64 `json:"id"`
User string `json:"user"`
State ReviewState `json:"state"`
Body string `json:"body"`
SubmittedAt time.Time `json:"submitted_at"`
}
Review represents a code review on a change request (the ReviewManager view; ReviewResult above is the create-call response).
type ReviewComment ¶
type ReviewComment struct {
Path string `json:"path"`
Body string `json:"body"`
Line int `json:"line,omitempty"`
StartLine int `json:"start_line,omitempty"`
EndLine int `json:"end_line,omitempty"`
Side string `json:"side,omitempty"`
}
ReviewComment is a single inline comment in a code review.
func (*ReviewComment) Mentions ¶
func (c *ReviewComment) Mentions() []string
Mentions returns the deduplicated @usernames found in the comment body.
type ReviewCommentResult ¶
type ReviewCommentResult struct {
Path string `json:"path,omitempty"`
Line int `json:"line,omitempty"`
ExternalID string `json:"external_id,omitempty"`
Error string `json:"error,omitempty"`
}
ReviewCommentResult is the result of posting a single inline comment.
type ReviewManager ¶
type ReviewManager interface {
CreateReview(ctx context.Context, owner, repo, number string, opts CreateReviewOptions) (*ReviewResult, error)
ListReviews(ctx context.Context, owner, repo, number string) ([]Review, error)
GetReview(ctx context.Context, owner, repo, number string, reviewID int64) (*Review, error)
RequestReviewers(ctx context.Context, owner, repo, number string, reviewers []string) error
DismissReview(ctx context.Context, owner, repo, number string, reviewID int64, message string) error
}
ReviewManager provides code-review operations on change requests. Change request numbers are strings (same addressing scheme as IssueManager); individual reviews are addressed by their numeric platform ID. It is an optional capability: consumers should check Capabilities().Reviews before type-asserting.
type ReviewResult ¶
type ReviewResult struct {
ID string `json:"id"`
Body string `json:"body,omitempty"`
HTMLURL string `json:"html_url,omitempty"`
User *CRUser `json:"user,omitempty"`
Comments []ReviewCommentResult `json:"comments,omitempty"`
}
ReviewResult is the result of a CreateReview call.
type ReviewState ¶
type ReviewState string
ReviewState is the normalized state of a code review.
const ( ReviewStateApproved ReviewState = "approved" ReviewStateChangesRequested ReviewState = "changes_requested" ReviewStateCommented ReviewState = "commented" ReviewStatePending ReviewState = "pending" )
type SearchIssueResult ¶
type SearchIssueResult struct {
Number string `json:"number"`
Title string `json:"title"`
Body string `json:"body,omitempty"`
State IssueState `json:"state"`
WebURL string `json:"web_url,omitempty"`
Labels []string `json:"labels,omitempty"`
Comments int `json:"comments,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
SearchIssueResult is a single result from an issue search. Number is the platform's issue addressing identifier as a string, so results feed GetIssue(number string) directly (numeric platforms return "1", Gitee's alphanumeric identifiers return e.g. "IAINVA").
type SearchIssuesOptions ¶
type SearchIssuesOptions struct {
Query string `json:"q"`
Repo string `json:"repo,omitempty"`
State string `json:"state,omitempty"`
Sort string `json:"sort,omitempty"`
Order string `json:"order,omitempty"`
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
SearchIssuesOptions contains options for searching issues.
type SearchManager ¶
type SearchManager interface {
SearchRepos(ctx context.Context, opts SearchReposOptions) ([]*SearchRepoResult, *int, error)
SearchIssues(ctx context.Context, opts SearchIssuesOptions) ([]*SearchIssueResult, *int, error)
SearchUsers(ctx context.Context, opts SearchUsersOptions) ([]*SearchUserResult, *int, error)
}
SearchManager provides cross-platform search for repositories, issues, and users.
The *int return is the server-side total when the platform reports one, and nil when it does not — callers must not treat a total as guaranteed.
type SearchRepoResult ¶
type SearchRepoResult struct {
FullName string `json:"full_name"`
Description string `json:"description,omitempty"`
WebURL string `json:"web_url,omitempty"`
Stars int `json:"stars,omitempty"`
Forks int `json:"forks,omitempty"`
DefaultBranch string `json:"default_branch,omitempty"`
Private bool `json:"private,omitempty"`
}
SearchRepoResult is a single result from a repository search.
type SearchReposOptions ¶
type SearchReposOptions struct {
Query string `json:"q"`
Sort string `json:"sort,omitempty"`
Order string `json:"order,omitempty"`
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
SearchReposOptions contains options for searching repositories.
Sort and Order are platform-dependent: each backend forwards them to its platform's own vocabulary (e.g. GitHub's stars/forks/updated with asc/desc), so values valid on one platform may be ignored or rejected on another (gitea/forgejo reject unknown sort/order values with HTTP 422; gitlab's search API exposes no sort/order at all — a registered ignore). Consult the target platform's search documentation for the accepted values.
type SearchUserResult ¶
type SearchUserResult struct {
Login string `json:"login"`
Name string `json:"name,omitempty"`
AvatarURL string `json:"avatar_url,omitempty"`
WebURL string `json:"web_url,omitempty"`
}
SearchUserResult is a single result from a user search.
type SearchUsersOptions ¶
type SearchUsersOptions struct {
Query string `json:"q"`
Sort string `json:"sort,omitempty"`
Order string `json:"order,omitempty"`
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
}
SearchUsersOptions contains options for searching users.
type StarredManager ¶ added in v0.72.0
type StarredManager interface {
// ListStarred 分页列出认证用户 star 的仓库(GET /user/starred)。
// page/perPage 语义与其他分页方法一致,非法值经 NormalizePageOpts 归一。
ListStarred(ctx context.Context, page, perPage int) ([]*PlatformRepo, error)
}
StarredManager 列出认证用户 star 过的仓库。可选能力接口:使用前先看 Provider.Capabilities().Starred(或类型断言)。
直接复用 PlatformRepo 而非再造摘要类型:下游导入/org 镜像场景只消费 FullName/Name/Owner/CloneURL/Description/Archived/Fork/Stars/Language/ Private 这些现成字段,再造一套会引入无谓的字段映射漂移。GitHub 专属 (无跨平台抽象价值),故仅 github 后端实现。
type StaticTokenValidator ¶
type StaticTokenValidator struct {
Header string
}
StaticTokenValidator compares a static token header against the configured secret in constant time. Used for GitLab's X-Gitlab-Token.
func (StaticTokenValidator) Name ¶
func (StaticTokenValidator) Name() string
Name implements WebhookValidator.
type Stats ¶
Stats reports cache hit/miss counters and the current size. Counters are atomically incremented and safe to read concurrently.
type StatusError ¶
StatusError wraps an error with an explicit HTTP status code. Use this in platform backends when you need to attach a status code to an error from a third-party SDK that doesn't implement the statusCoder interface. This avoids the need for the reflection-based fallback in Wrap.
Example:
err := someSDK.DoSomething()
if err != nil {
return provider.WrapStatusError(err, 404)
}
func (*StatusError) Error ¶
func (e *StatusError) Error() string
func (*StatusError) StatusCode ¶
func (e *StatusError) StatusCode() int
func (*StatusError) Unwrap ¶
func (e *StatusError) Unwrap() error
type StatusExtractor ¶ added in v0.83.0
StatusExtractor reports the HTTP status carried by one of a platform's SDK error types. It is called per link of the chain Wrap walks, so the extractor only needs to handle its own error values (the chain walk handles wrapping).
type TestConnectionResult ¶
type TestConnectionResult struct {
Connected bool `json:"connected"`
Platform string `json:"platform"`
UserName string `json:"user_name"`
Message string `json:"message,omitempty"`
CanListRepos bool `json:"can_list_repos"`
CanReadCR bool `json:"can_read_cr"`
CanWriteCR bool `json:"can_write_cr"`
CanWebhook bool `json:"can_webhook"`
}
TestConnectionResult contains the result of a connection test.
type TokenSource ¶ added in v0.72.0
TokenSource supplies the access token used to authenticate platform API requests. When a Config.TokenSource is set, the transport layer consults it on every request, so rotating or expiring credentials — OAuth device-flow tokens, GitHub App installation tokens (hourly expiry), short-lived CI job tokens — take effect on the next request without rebuilding the provider.
The interface is deliberately identical to transport.TokenSource, so any implementation satisfies both and backends can forward the value unchanged. Implementations must be safe for concurrent use.
func StaticTokenSource ¶ added in v0.72.0
func StaticTokenSource(token string) TokenSource
StaticTokenSource returns a TokenSource that always returns token; it is the TokenSource equivalent of Config.Token and mostly useful for tests and for swapping a static credential into TokenSource-taking code paths.
type UpdateBranchProtectionOptions ¶
type UpdateBranchProtectionOptions struct {
RequiredApprovingReviews *int `json:"required_approving_reviews,omitempty"`
RequiredStatusChecks *bool `json:"required_status_checks,omitempty"`
AllowForcePushes *bool `json:"allow_force_pushes,omitempty"`
AllowDeletions *bool `json:"allow_deletions,omitempty"`
}
UpdateBranchProtectionOptions contains options for updating a branch protection rule. Nil fields are left unchanged.
type UpdateCROptions ¶
type UpdateCROptions struct {
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
TargetBranch string `json:"target_branch,omitempty"`
}
UpdateCROptions contains options for updating a change request.
type UpdateIssueOptions ¶
type UpdateIssueOptions struct {
Title string `json:"title,omitempty"`
Body string `json:"body,omitempty"`
State IssueState `json:"state,omitempty"`
Assignees []string `json:"assignees,omitempty"`
Labels []string `json:"labels,omitempty"`
Milestone string `json:"milestone,omitempty"` // milestone number/ID as a string; "" = leave unchanged
}
UpdateIssueOptions contains options for updating an issue.
type UpdateLabelOptions ¶
type UpdateLabelOptions struct {
NewName *string `json:"new_name,omitempty"`
Color *string `json:"color,omitempty"`
Description *string `json:"description,omitempty"`
}
UpdateLabelOptions contains options for updating a repository label. Nil fields are left unchanged.
type UpdateMilestoneOptions ¶
type UpdateMilestoneOptions struct {
Title *string `json:"title,omitempty"`
Description *string `json:"description,omitempty"`
State MilestoneState `json:"state,omitempty"`
DueOn *time.Time `json:"due_on,omitempty"`
}
UpdateMilestoneOptions contains options for updating a repository milestone. Nil fields are left unchanged.
type UpdateReleaseOptions ¶
type UpdateReleaseOptions struct {
Name *string `json:"name,omitempty"`
Body *string `json:"body,omitempty"`
Draft *bool `json:"draft,omitempty"`
Prerelease *bool `json:"prerelease,omitempty"`
}
UpdateReleaseOptions contains options for updating a release addressed by tag. Nil fields are left unchanged.
type UpdateRepoOptions ¶
type UpdateRepoOptions struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
DefaultBranch string `json:"default_branch,omitempty"`
Private *bool `json:"private,omitempty"`
}
UpdateRepoOptions contains options for updating a repository.
type UpdateWebhookOptions ¶ added in v0.99.9
type UpdateWebhookOptions struct {
URL *string `json:"url,omitempty"`
Secret *string `json:"secret,omitempty"`
Events []string `json:"events,omitempty"`
}
UpdateWebhookOptions contains options for updating a webhook (patch-style: nil fields are left unchanged). Events is the exception — see WebhookConfigManager for the full-replacement semantics.
type UserManager ¶
type UserManager interface {
// GetUser returns the user profile for the given username.
GetUser(ctx context.Context, username string) (*CRUser, error)
// ResolveUsernames maps a list of usernames to their platform IDs.
// The returned slice preserves input order; each entry's ID field
// carries the resolved numeric ID. If a username cannot be resolved,
// an error is returned for that entry (the partial result up to that
// point is still valid).
ResolveUsernames(ctx context.Context, usernames []string) ([]*CRUser, error)
}
UserManager provides user lookup and username-to-ID resolution. It is an optional capability interface: consumers should gate on Provider.Capabilities().Users (or type-assert) before use.
Not every backend needs this — GitHub, Gitea, Forgejo, Gitee, and GitCode accept usernames directly in their APIs. GitLab and TencentCode require numeric user IDs for assignees and reviewers, so they implement this interface to expose their resolution logic.
Consumers can also use this interface to look up user profiles or validate that a username exists before passing it to other operations.
type ValidatorFunc ¶
ValidatorFunc adapts a plain function into a WebhookValidator.
type WaitOptions ¶
type WaitOptions struct {
// Interval is the poll cadence; defaults to DefaultWaitInterval and
// is clamped up to minWaitInterval.
Interval time.Duration
// Timeout bounds the whole wait. Zero uses DefaultWaitTimeout; a
// negative value disables the budget entirely (rely on your own
// context deadline). Expiry surfaces as ErrWaitTimedOut carrying the
// last observed combined state.
Timeout time.Duration
// Contexts, when non-empty, restricts the combined state to the
// named status contexts (e.g. []string{"ci/lint", "ci/test"}).
// Empty means every context reported on the commit.
Contexts []string
// InitialDelay defers the first poll; useful right after
// CreateCommitStatus, whose result may not be queryable for a
// moment. Defaults to no delay.
InitialDelay time.Duration
}
WaitOptions tunes the polling loop in WaitForCommitStatus.
type WebhookConfigManager ¶ added in v0.99.9
type WebhookConfigManager interface {
// GetWebhook returns one webhook by its platform ID.
GetWebhook(ctx context.Context, owner, repo string, webhookID int64) (*PlatformWebhook, error)
// UpdateWebhook patches one webhook. Nil URL/Secret leave the
// corresponding setting untouched; a nil Events slice leaves the event
// set untouched while a non-nil one replaces it wholesale.
UpdateWebhook(ctx context.Context, owner, repo string, webhookID int64, opts UpdateWebhookOptions) (*PlatformWebhook, error)
}
WebhookConfigManager provides single-webhook read and update on top of the core WebhookManager. It is an optional capability interface: consumers should gate on Provider.Capabilities().WebhookConfig (or type-assert) before use.
Platform support: all seven backends (GitHub, GitLab, Gitee, GitCode, Gitea, Forgejo, TencentCode). Update is patch-style — nil fields are left unchanged — with one documented exception: a non-nil Events slice always replaces the full event set (an empty slice clears every event), because event membership cannot be expressed incrementally on the platforms whose webhooks are boolean-flag based (GitLab/Gitee/TencentCode). The secret is write-only on every platform: GetWebhook never returns it.
type WebhookEnvelope ¶ added in v0.83.0
type WebhookEnvelope struct {
// Platform selects the registered signature validator.
Platform Platform
// EventHeaders are checked in order for the event-type header; the first
// non-empty value wins (multi-header dialects list fallbacks). Leave
// empty when the platform dispatches on a payload field (e.g. GitLab's
// object_kind) instead of a header.
EventHeaders []string
// IDPrefix prefixes generated event IDs ("<prefix>-<unixnano>-<key>").
// Empty falls back to the platform name — the ID is **never empty**
// (see NewEvent).
IDPrefix string
// IDHeaders are checked in order for the platform's **delivery ID**
// (e.g. GitHub's "X-GitHub-Delivery"); the first non-empty value wins.
//
// The delivery ID is a true idempotency key: the platform repeats the
// same value when it redelivers an event, so callers can deduplicate
// properly. Without it the ID is synthesized locally and differs on
// every delivery (no deduplication possible).
IDHeaders []string
}
WebhookEnvelope carries one platform's webhook dialect for the shared envelope steps every ParseWebhookEvent must run before its payload switch (validate → read/restore body → event header → event skeleton). Payload decoding and the event-type switch stay per-platform: those are the dialect, not the envelope.
func (WebhookEnvelope) NewEvent ¶ added in v0.83.0
func (e WebhookEnvelope) NewEvent(idKey int64, body []byte) *NormalizedEvent
NewEvent builds the event skeleton: Source, Timestamp, RawPayload — plus ID "<prefix>-<unixnano>-<idKey>". idKey is the platform's payload identifier for the event (issue number, MR IID, ...). Actor/Repo remain the caller's: they come from the payload the mapper decodes.
The ID is **never empty**: without an explicit IDPrefix the platform name is used as the prefix. An empty event ID is not merely "missing data" — callers commonly key their dedup table and their unique index on it, and an empty key makes every later event collide with the first one (silently dropping all events after the first).
func (WebhookEnvelope) NewEventWithID ¶ added in v0.99.3
func (e WebhookEnvelope) NewEventWithID(r *http.Request, idKey int64, body []byte) *NormalizedEvent
NewEventWithID behaves like NewEvent but prefers the platform's delivery ID (X-GitHub-Delivery and friends) as the event ID.
The delivery ID is a real idempotency key: the platform repeats it when it redelivers the same event, so a caller keying dedup on the event ID can actually suppress the duplicate. Falls back to NewEvent's synthesized ID when the platform sends no such header.
func (WebhookEnvelope) Read ¶ added in v0.83.0
Read validates the signature via the platform's registered validator, restores the body for downstream parsing, and returns the event-type header ("" when EventHeaders is empty or unmatched) plus the raw payload. Error ops mirror the historical hand-written sequence: body-read failures surface under ParseWebhookEvent, validation failures under ValidateWebhookSignature.
Passing secret == SkipValidationSecret skips the signature validation step: see that constant for the hosts that need parse-only access.
type WebhookManager ¶
type WebhookManager interface {
CreateWebhook(ctx context.Context, opts CreateWebhookOptions) (*PlatformWebhook, error)
DeleteWebhook(ctx context.Context, owner, repo string, webhookID int64) error
ListWebhooks(ctx context.Context, owner, repo string) ([]*PlatformWebhook, error)
ParseWebhookEvent(r *http.Request, secret string) (*NormalizedEvent, error)
ValidateWebhookSignature(r *http.Request, secret string) error
}
WebhookManager handles webhook CRUD and event parsing.
type WebhookValidator ¶
type WebhookValidator interface {
Name() string
Validate(r *http.Request, body []byte, secret string) error
}
WebhookValidator verifies the authenticity of an incoming webhook request. Implementations are stateless and safe for concurrent use.
The signature scheme varies per platform:
- GitHub: HMAC-SHA256 of the body, sent in X-Hub-Signature-256.
- GitLab: static token compared in constant time against X-Gitlab-Token.
- Gitea / Forgejo: HMAC-SHA256 of the body, sent in X-Gitea-Signature.
- GitCode: static password compared in constant time against X-GitCode-Token (an HMAC sign mode exists on the platform; its message format is not yet mirrored here).
- Tencent: static token compared in constant time against X-Token.
- Gitee: sign mode — Base64(HMAC-SHA256(secret, timestamp+"\n"+ secret)) in X-Gitee-Token with X-Gitee-Timestamp; or password mode — the plain password in X-Gitee-Token.
type WebhookValidatorRegistry ¶
type WebhookValidatorRegistry struct {
// contains filtered or unexported fields
}
WebhookValidatorRegistry indexes WebhookValidator implementations by platform. It is safe for concurrent use; registrations happen during package init and reads happen on the request path.
func DefaultWebhookRegistry ¶
func DefaultWebhookRegistry() *WebhookValidatorRegistry
DefaultWebhookRegistry returns the process-wide registry.
func NewWebhookValidatorRegistry ¶
func NewWebhookValidatorRegistry() *WebhookValidatorRegistry
NewWebhookValidatorRegistry builds an empty registry.
func (*WebhookValidatorRegistry) Get ¶
func (r *WebhookValidatorRegistry) Get(p Platform) WebhookValidator
Get returns the validator for the given platform, or nil if none is registered.
func (*WebhookValidatorRegistry) Register ¶
func (r *WebhookValidatorRegistry) Register(p Platform, v WebhookValidator)
Register associates a validator with a platform.
Source Files
¶
- batch.go
- capabilities.go
- commitstatus.go
- convertutil.go
- detect.go
- diffutil.go
- divergence.go
- doc.go
- ensure.go
- errors.go
- factory.go
- files.go
- iface_branch_protection.go
- iface_branches.go
- iface_changes.go
- iface_ci.go
- iface_collaborators.go
- iface_commits.go
- iface_commitstatus.go
- iface_deploy_keys.go
- iface_diffs.go
- iface_files.go
- iface_gists.go
- iface_issues.go
- iface_labels.go
- iface_migrations.go
- iface_milestones.go
- iface_notifications.go
- iface_reactions.go
- iface_releases.go
- iface_repo_stats.go
- iface_repos.go
- iface_reviews.go
- iface_search.go
- iface_starred.go
- iface_users.go
- iface_webhooks.go
- janitor.go
- logger.go
- manager.go
- middleware.go
- options.go
- pageiter.go
- pagination.go
- provider.go
- registry.go
- retry.go
- stateutil.go
- tokensource.go
- ttlcache.go
- version.go
- wait.go
- webhook.go