Help us shape the future of Go! Take the 2026 Go Developer Survey

model

package
v0.24.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 25, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	StatusRunning = "running"
	StatusSuccess = "success"
	StatusFailed  = "failed"
)

Run status constants

View Source
const (
	StatusReceived   = "received"
	StatusProcessing = "processing"
	StatusProcessed  = "processed"
)

Webhook event status constants

View Source
const (
	TriggerManual  = "manual"
	TriggerCron    = "cron"
	TriggerWebhook = "webhook"
)

Trigger source constants

View Source
const (
	DriverMySQL  = "mysql"
	DriverSQLite = "sqlite"
)

Database driver constants

View Source
const (
	DefaultHost          = "0.0.0.0"
	DefaultPort          = 8890
	DefaultMaxIdleConns  = 10
	DefaultMaxOpenConns  = 100
	DefaultMaxConcurrent = 5
	DefaultTimeout       = 300
	DefaultRetryCount    = 3
	DefaultTempDir       = "/tmp/git-sync"

	DefaultConnMaxLifeSec    = 300 // 5 分钟
	DefaultConnMaxIdleSec    = 120 // 2 分钟
	DefaultWebhookRateLimit  = 10
	DefaultMaxBodySize       = 10 << 20 // 10MB
	DefaultRedisDialTimeout  = 5
	DefaultRedisReadTimeout  = 3
	DefaultRedisWriteTimeout = 3

	// 上限值
	MaxConcurrent       = 100
	MaxDBOpenConns      = 200
	MaxWebhookBodySize  = 100 << 20 // 100MB
	MaxWebhookRateLimit = 10000

	// Push retry 退避因子
	RetryBackoffMs = 500
)

Default configuration values

View Source
const (
	StepClone        = "clone"
	StepFetch        = "fetch"
	StepCheckout     = "checkout"
	StepEnsureRemote = "ensure_remote"
	StepPush         = "push"
	StepLFS          = "lfs"
	StepWiki         = "wiki"
	StepDivergeCheck = "diverge_check"
)

Step name constants

View Source
const (
	ErrorAuth      = "auth"
	ErrorDivergent = "divergent"
	ErrorConflict  = "conflict"
	ErrorNetwork   = "network"
	ErrorConfig    = "config"
	ErrorGit       = "git"
	ErrorUnknown   = "unknown"
)

Error type constants

View Source
const (
	TableRepos            = "repos"
	TableSyncTasks        = "sync_tasks"
	TableSyncRuns         = "sync_runs"
	TableSyncRunSteps     = "sync_run_steps"
	TableWebhookRules     = "webhook_rules"
	TableWebhookRuleTasks = "webhook_rule_tasks"
	TableWebhookEvents    = "webhook_events"
	TableOperationLogs    = "operation_logs"
)

Table name constants

View Source
const (
	DefaultBranch    = "main"
	DefaultPlatform  = "unknown"
	DefaultSyncMode  = "single"
	DefaultEventType = "push"
	DefaultAction    = "sync"
)

Model default value constants

View Source
const (
	HistoryRunPending = "pending"
	HistoryRunRunning = "running"
	HistoryRunSuccess = "success"
	HistoryRunFailed  = "failed"
)

历史同步执行状态

View Source
const (
	HistoryCredNone   = "none"
	HistoryCredToken  = "token"
	HistoryCredSSHKey = "ssh_key"
)

推送目标凭据类型

View Source
const (
	// HistoryRunKindApply 内容移植:产出新提交。
	HistoryRunKindApply = "apply"
	// HistoryRunKindPush 推送:把某次移植的产物推到远端。
	HistoryRunKindPush = "push"
	// HistoryRunKindRollback 回滚:把目标分支退回某个 ref。
	HistoryRunKindRollback = "rollback"
)

历史同步执行记录的类别。

View Source
const (
	// HistoryVerdictKeepTarget 保留目标侧内容(源侧的改动是内网特有,不该公开)。
	HistoryVerdictKeepTarget = "keep_target"
	// HistoryVerdictTakeSource 取源侧内容(源侧的改动是公开树需要的)。
	HistoryVerdictTakeSource = "take_source"
	// HistoryVerdictMerged 用裁决后的内容(两侧都要保留各自的部分)。
	HistoryVerdictMerged = "merged"
)

历史同步裁决类型(人工/AI 对某个 hold 文件的结论)。

View Source
const (
	MirrorModePublish = "publish" // 开源公开发布:身份改写 + 门禁 + 快照推送
	MirrorModeBackup  = "backup"  // 仓库备份:原样 ref 推送(P1)
)

镜像通道模式

View Source
const (
	MirrorRunPending   = "pending"
	MirrorRunRunning   = "running"
	MirrorRunSuccess   = "success"
	MirrorRunFailed    = "failed"
	MirrorRunDivergent = "divergent" // 远端同名 tag 内容不一致,默认拒绝覆盖
)

镜像执行状态

View Source
const (
	MirrorKindPublish = "publish"
	MirrorKindVerify  = "verify"
)

镜像执行类别

View Source
const (
	MirrorCredNone   = "none"
	MirrorCredToken  = "token"
	MirrorCredSSHKey = "ssh_key"
)

凭据类型

View Source
const (
	PlatformTypeGitHub      = string(provider.PlatformGitHub)      // "github"
	PlatformTypeGitLab      = string(provider.PlatformGitLab)      // "gitlab"
	PlatformTypeGitea       = string(provider.PlatformGitea)       // "gitea"
	PlatformTypeGitee       = string(provider.PlatformGitee)       // "gitee"
	PlatformTypeGitCode     = string(provider.PlatformGitCode)     // "gitcode"
	PlatformTypeTencentCode = string(provider.PlatformTencentCode) // "tencent_code"
	// SDK 未注册的扩展类型
	PlatformTypeAtomGit = "atomgit"
	PlatformTypeCustom  = "custom"
)

平台类型常量:SDK 已注册平台直接复用 provider.Platform 常量(字符串值相同); SDK 未注册的扩展类型保留本地定义。

View Source
const (
	PlatformStatusActive = "active"
	PlatformStatusError  = "error"
)

PlatformStatus 平台状态常量

View Source
const (
	ActionSync = "sync"
)

Webhook rule action constants

View Source
const RepoDirName = "repo"

RepoDirName 任务工作区里 git 仓库所在子目录名。 单源:executor 的工作区路径与 service 的 GetRepoDir 都必须用这一个名字, 两处各写一份字面量必然漂移(实测:备份推送曾把父目录当仓库用,报 "repository does not exist")。

View Source
const (
	RepoStatusActive = "active"
)

Repository status constants

Variables

View Source
var PlatformAPIBaseURLs = map[string]string{
	"github.com":       "https://api.github.com",
	"gitcode.com":      "https://api.gitcode.com/api/v5",
	"gitee.com":        "https://gitee.com/api/v5",
	"gitea.com":        "https://gitea.com/api/v1",
	"gitlab.com":       "https://gitlab.com/api/v4",
	"atomgit.com":      "https://atomgit.com/api/v1",
	"code.tencent.com": "https://git.code.tencent.com/api/v3",
}

PlatformAPIBaseURLs 已知 SaaS 实例的 API 基址(整域名,而非"主机+路径")。

这类平台的 REST API 不在"实例域名 + 固定路径"上:

  • GitHub SaaS 的 API 在 api.github.com。github.com/api/v3 是 **GitHub Enterprise** 的路径 —— 按它拼出来的平台必然 404 (实测:创建 GitHub 平台时连通性检测直接失败,平台建出来是坏的)。
  • GitCode 的 API 在 api.gitcode.com/api/v5。

与 SDK 的 provider.knownHostPlatforms 保持一致(SDK 是实际发请求的那一层, 这里只是"建平台时填 api_url"的推导)。

View Source
var PlatformAPIPaths = map[string]string{
	PlatformTypeGitHub:      "/api/v3",
	PlatformTypeGitLab:      "/api/v4",
	PlatformTypeGitea:       "/api/v1",
	PlatformTypeGitee:       "/api/v5",
	PlatformTypeGitCode:     "/api/v5",
	PlatformTypeAtomGit:     "/api/v1",
	PlatformTypeTencentCode: "/api/v3",
}

PlatformAPIPaths 各平台的 API 路径(壳层 GetAPIURL 用)。 SDK 已注册平台的值作为已知默认;扩展平台是唯一数据源。

View Source
var PlatformDefaultInstances = map[string]string{
	PlatformTypeGitHub:      "github.com",
	PlatformTypeGitLab:      "gitlab.com",
	PlatformTypeGitea:       "gitea.com",
	PlatformTypeGitee:       "gitee.com",
	PlatformTypeGitCode:     "gitcode.com",
	PlatformTypeAtomGit:     "atomgit.com",
	PlatformTypeTencentCode: "git.code.tencent.com",
}

PlatformDefaultInstances 各平台的默认实例地址。

Functions

func ComputeEntryHash added in v0.6.0

func ComputeEntryHash(prev string, e *OperationLog) string

ComputeEntryHash 计算审计条目哈希(prev 可为空)。

func ComputeHistoryRunHash added in v0.12.0

func ComputeHistoryRunHash(prev string, r *HistoryRun) string

ComputeHistoryRunHash 计算执行记录哈希。

与既有审计链同构:EntryHash = SHA256(PrevHash || payload), 篡改任一审计材料(基线 HEAD / commit 映射 / 检测报告 / ref 对照)都能检出。

只在**终态**计算:执行中的记录字段还会变,提前算出的哈希必然失配。

时间字段按**毫秒**归一(hashTimeLayout):与数据库的存储精度对齐, 否则写库时被四舍五入、读库后重算的哈希对不上(MySQL 上每条都误报)。

func GetAPIURL

func GetAPIURL(platformType, instanceURL string) string

GetAPIURL 根据实例地址生成 API URL。 自建实例(非默认域名)的 URL 由壳层传入 instanceURL 覆盖; SDK 的 provider.NewProvider 也能推导已知平台的 URL,但 DB 字段 NOT NULL 要求壳层在创建时就提供非空值,因此保留此辅助函数。

func HashTimeString added in v0.13.0

func HashTimeString(t time.Time) string

HashTimeString 把时间格式化成哈希载荷里的字符串。

**先截到毫秒再格式化**:与 TruncateDBTime 同一个理由 —— 哈希必须在「写库前」与「读库后」算出同一个值。

func HashTimeStringPtr added in v0.13.0

func HashTimeStringPtr(t *time.Time) string

HashTimeStringPtr 是 HashTimeString 的指针版本(nil → 空串)。

func InitDB

func InitDB(driver, dsn string) (*gorm.DB, error)

func NormalizeAuditHashInput added in v0.6.0

func NormalizeAuditHashInput(s string) string

NormalizeAuditHashInput 归一化字符串用于稳定哈希(去首尾空白)。

func TruncateDBTime added in v0.13.0

func TruncateDBTime(t time.Time) time.Time

TruncateDBTime 把时间截到数据库能原样存回的精度(毫秒)。

先取 UTC 再截断:Truncate 按绝对时刻取整,顺序不影响结果, 但统一成 UTC 让存进去的值与哈希里的字符串一一对应。

func TruncateDBTimePtr added in v0.13.0

func TruncateDBTimePtr(t *time.Time) *time.Time

TruncateDBTimePtr 是 TruncateDBTime 的指针版本(nil 安全)。

func ValidPlatformType

func ValidPlatformType(t string) bool

ValidPlatformType 检查平台类型是否合法:SDK 已注册平台 + 扩展白名单。 替代旧的 ValidPlatformTypes 静态 map,与 SDK 注册表自动同步。

func VerifyHistoryRunHash added in v0.13.0

func VerifyHistoryRunHash(prev string, r *HistoryRun, stored string) bool

VerifyHistoryRunHash 校验一条执行记录的哈希。

**只认当前载荷算法**:旧版载荷的哈希算法已删除 —— 留着它等于"升级前的记录,哪怕 kind / pushed_run_id 被改成任何值,链都照样报完好", 而这两个字段正是「这个产物推没推送」的判定依据。

Types

type BackupDestinationConfig added in v0.6.0

type BackupDestinationConfig struct {
	Type string `yaml:"type" json:"type"` // s3 | webdav | azure | local
	Name string `yaml:"name" json:"name"`
	// S3/OSS/MinIO
	Endpoint  string `yaml:"endpoint,omitempty" json:"endpoint,omitempty"`
	Region    string `yaml:"region,omitempty" json:"region,omitempty"`
	Bucket    string `yaml:"bucket,omitempty" json:"bucket,omitempty"`
	Prefix    string `yaml:"prefix,omitempty" json:"prefix,omitempty"`
	AccessKey string `yaml:"access_key,omitempty" json:"access_key,omitempty"`
	SecretKey string `yaml:"secret_key,omitempty" json:"secret_key,omitempty"`
	PathStyle bool   `yaml:"path_style,omitempty" json:"path_style,omitempty"`
	// WebDAV / local dir(用 url 字段)
	URL      string `yaml:"url,omitempty" json:"url,omitempty"`
	Username string `yaml:"username,omitempty" json:"username,omitempty"`
	Password string `yaml:"password,omitempty" json:"password,omitempty"`
	// Azure Blob
	AccountName string `yaml:"account_name,omitempty" json:"account_name,omitempty"`
	AccountKey  string `yaml:"account_key,omitempty" json:"account_key,omitempty"`
	Container   string `yaml:"container,omitempty" json:"container,omitempty"`
	Enabled     *bool  `yaml:"enabled,omitempty" json:"enabled,omitempty"`
}

BackupDestinationConfig 冷备多目的地之一(s3/webdav/azure/local)。

type BackupRemoteConfig added in v0.7.1

type BackupRemoteConfig struct {
	// Name 远端名(日志用)
	Name string `yaml:"name" json:"name"`
	// URL git 远端地址(https/ssh);支持 {owner}/{repo} 占位由任务推导
	URL string `yaml:"url" json:"url"`
	// Token 注入用;也可走 GIT_SYNC_TOKEN_<NAME>
	Token string `yaml:"token,omitempty" json:"token,omitempty"`
	// Force 是否允许 force(仍受任务 force_push_policy 约束)
	Force bool `yaml:"force" json:"force"`
	// Enabled 默认 true
	Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
}

BackupRemoteConfig 备份远端(git push)。

type Config

type Config struct {
	Server    ServerConfig    `yaml:"server"`
	Database  DatabaseConfig  `yaml:"database"`
	Redis     RedisConfig     `yaml:"redis"`
	Git       GitConfig       `yaml:"git"`
	Sync      SyncConfig      `yaml:"sync"`
	Webhook   WebhookConfig   `yaml:"webhook"`
	Log       LogConfig       `yaml:"log"`
	Templates TemplatesConfig `yaml:"templates"`
}

func LoadConfig

func LoadConfig(path string) (*Config, error)

LoadConfig 从指定路径加载配置文件。 path 参数由调用方控制(通常是启动参数或环境变量),不存在用户注入风险。 环境变量会覆盖 YAML 文件中的同名配置(env 优先级更高)。

func (*Config) Validate

func (c *Config) Validate() error

Validate 校验配置并填充默认值。 注意:环境变量覆盖发生在 Validate 之前,因此此处的默认值逻辑仅在 YAML 和环境变量均未提供对应字段时才生效。

type CreateRepoRequest

type CreateRepoRequest struct {
	Name        string `json:"name"`
	RemoteURL   string `json:"remoteUrl"`
	AccessToken string `json:"accessToken"`
	PlatformID  uint   `json:"platformId"`
}

type CreateRuleRequest

type CreateRuleRequest struct {
	Name          string   `json:"name"`
	RepoKey       string   `json:"repoKey"`
	EventType     string   `json:"eventType"`
	BranchPattern string   `json:"branchPattern"`
	Action        string   `json:"action"`
	TaskKeys      []string `json:"taskKeys"`
	MinInterval   int      `json:"minInterval"`
	Enabled       bool     `json:"enabled"`
	Description   string   `json:"description"`
}

type CreateTaskRequest

type CreateTaskRequest struct {
	Name          string `json:"name"`
	SourceRepoKey string `json:"source_repo_key"`
	SourceBranch  string `json:"source_branch"`
	TargetRepoKey string `json:"target_repo_key"`
	TargetBranch  string `json:"target_branch"`
	SyncMode      string `json:"sync_mode"`
	Cron          string `json:"cron"`
	GitTags       bool   `json:"git_tags"`
	GitForce      bool   `json:"git_force"`
	GitLFS        bool   `json:"git_lfs"`
	SyncWiki      bool   `json:"sync_wiki"`
	GitBundle     bool   `json:"git_bundle"`
	Submodules    bool   `json:"submodules"`
	GitPushPrune  bool   `json:"git_push_prune"`
	// KeepDivergent nil/缺省=true(安全);显式 false 才允许覆盖分歧
	KeepDivergent *bool `json:"keep_divergent"`
	// ForcePushPolicy allow|block|backup_on_demand;空=按 KeepDivergent 映射
	ForcePushPolicy string `json:"force_push_policy"`
	// IncludeBranches 逗号分隔 glob 白名单;空=全部
	IncludeBranches string `json:"include_branches"`
	// ExcludeRefPatterns 逗号分隔 ref glob 黑名单;空=使用默认 PR refs 排除
	ExcludeRefPatterns string `json:"exclude_ref_patterns"`
}

type DatabaseConfig

type DatabaseConfig struct {
	Driver         string `yaml:"driver" env:"GIT_SYNC_DB_DRIVER"`
	DSN            string `yaml:"dsn" env:"GIT_SYNC_DB_DSN"`
	MaxIdleConns   int    `yaml:"max_idle_conns" env:"GIT_SYNC_DB_MAX_IDLE_CONNS"`
	MaxOpenConns   int    `yaml:"max_open_conns" env:"GIT_SYNC_DB_MAX_OPEN_CONNS"`
	ConnMaxLifeSec int    `yaml:"conn_max_life_sec" env:"GIT_SYNC_DB_CONN_MAX_LIFE_SEC"` // 连接最大存活秒数,0 用默认 5 分钟
	ConnMaxIdleSec int    `yaml:"conn_max_idle_sec" env:"GIT_SYNC_DB_CONN_MAX_IDLE_SEC"` // 空闲连接最大存活秒数,0 用默认 2 分钟
}

type ForcePushApproval added in v0.9.1

type ForcePushApproval struct {
	ID         string     `gorm:"primaryKey;size:64" json:"id"`
	TaskKey    string     `gorm:"size:128;index" json:"task_key"`
	Branch     string     `gorm:"size:255" json:"branch"`
	Reason     string     `gorm:"size:512" json:"reason"`
	CreatedAt  time.Time  `json:"created_at"`
	Approved   bool       `json:"approved"`
	ApprovedBy string     `gorm:"size:128" json:"approved_by,omitempty"`
	ApprovedAt *time.Time `json:"approved_at,omitempty"`
	// TargetRef 申请审批时**目标分支的 HEAD SHA**。
	//
	// 放行必须绑定到它被批准时的目标状态:审批是"针对这一次分歧"的授权,
	// 目标侧若在此之后又前进/后退(独有提交从 1 个变成 50 个),
	// 旧审批就不该继续适用 —— 否则一次"批 1 个独有提交"会变成
	// "授权覆盖此后的一切"。
	// 空 = 早期版本创建的审批(未绑定),按未绑定处理(仍是一次性)。
	TargetRef string `gorm:"size:64;index" json:"target_ref,omitempty"`
	// RevokedAt / RevokedBy 放行被**撤销**的时间与操作者。
	//
	// 撤销是"我批错了/情况变了,这条放行作废"——与"用掉"不同:
	// 用掉 = 放行已经兑现过一次;撤销 = 放行还没兑现就被收回。
	// 两者都会让放行不再生效(IsApproved 判两者)。
	RevokedAt *time.Time `json:"revoked_at,omitempty"`
	RevokedBy string     `gorm:"size:128" json:"revoked_by,omitempty"`
	// ConsumedAt 放行被**用掉**的时间。
	//
	// 放行是**一次性**的(契约:"Admin 一次性放行后允许本次 force"):
	// 用掉之后,同一任务同一分支再出现分歧必须**重新审批** ——
	// 否则一次人工放行会变成该分支上的常驻后门,之后每次覆盖都无人复核。
	// 保留记录(而不是删掉)是为了留住审计线索:谁批的、什么时候批的、什么时候用的。
	ConsumedAt *time.Time `json:"consumed_at,omitempty"`
}

ForcePushApproval force-push 审批记录(block-and-approve 模式)。 JSON 字段与历史文件 <backup_dir>/force-push-approvals.json 逐字兼容, 供既有部署迁移导入与 HTTP 响应复用。

type GitConfig

type GitConfig struct {
	Backend string `yaml:"backend" env:"GIT_SYNC_GIT_BACKEND"`
	TempDir string `yaml:"temp_dir" env:"GIT_SYNC_GIT_TEMP_DIR"`
}

type HistoryChannel added in v0.12.0

type HistoryChannel struct {
	ID   uint   `gorm:"primaryKey" json:"id"`
	Name string `gorm:"size:128;not null;uniqueIndex" json:"name"`

	// SourceRepoKey / TargetRepoKey:两侧仓库的 key(取自 Repo 表)。
	// 为空则退回 SourceDir / TargetDir(本机已有克隆时直连)。
	SourceRepoKey string `gorm:"size:128;index" json:"sourceRepoKey"`
	TargetRepoKey string `gorm:"size:128;index" json:"targetRepoKey"`
	// SourceDir / TargetDir:本地路径直连。
	SourceDir string `gorm:"size:512" json:"sourceDir"`
	TargetDir string `gorm:"size:512" json:"targetDir"`

	// 身份映射:module 必填(改写 import 与 go.mod),host 可选。
	ModuleSource string `gorm:"size:255" json:"moduleSource"`
	ModuleTarget string `gorm:"size:255" json:"moduleTarget"`
	HostSource   string `gorm:"size:255" json:"hostSource"`
	HostTarget   string `gorm:"size:255" json:"hostTarget"`

	// AuthorName / AuthorEmail 目标侧新提交的作者身份(公开形态)。
	//
	// **不继承源提交的作者**:源侧是内网仓,作者是内网开发者
	// (姓名 + 企业邮箱)—— 直接继承等于把内网人员信息发布到公开仓。
	// 留空则用中性的公开身份(见 history.DefaultPublicAuthor)。
	AuthorName  string `gorm:"size:128" json:"authorName"`
	AuthorEmail string `gorm:"size:255" json:"authorEmail"`

	// LastEntryHash 链尾锚点:该通道**最后一条已入链**执行记录的哈希。
	//
	// 作用:检出「链尾被截断」。链本身只能证明「前后接得上」,
	// 删掉末尾几条记录,剩下的链照样接得上 —— 有了这个锚点,
	// 锚点指向的记录不在了就说明链被截断了。
	LastEntryHash string `gorm:"size:64;index" json:"lastEntryHash"`

	// PathRules 路径规则 JSON:[{"from":"docs/internal","to":"docs/archive"}]。
	// to 为空表示排除该路径。
	PathRules string `gorm:"type:text" json:"pathRules"`
	// ScrubRules 痕迹规则 JSON:
	// [{"name":"...","category":"...","pattern":"...","severity":"auto|mandatory","replacement":"..."}]
	ScrubRules string `gorm:"type:text" json:"scrubRules"`
	// ConflictRules 冲突自动判据 JSON:
	// [{"kind":"internal_trace|placeholder_domain|public_asset","enabled":true,"patterns":["..."]}]
	//
	// 空 = 不启用,所有冲突都交人工/AI。启用后,确定性判定解不了的冲突
	// 会先试这些判据(内网形态 → 保留目标侧)。
	ConflictRules string `gorm:"type:text" json:"conflictRules"`

	// SourceBranch 源分支,默认 HEAD。
	SourceBranch string `gorm:"size:128" json:"sourceBranch"`
	// TargetBranch 目标分支,默认 main。
	TargetBranch string `gorm:"size:128" json:"targetBranch"`

	// Enabled 关闭的通道不参与执行。
	//
	// **不用 gorm default:true** —— GORM 遇到零值 false 会省略该字段,
	// 让数据库默认值 true 生效,于是「显式禁用」会被悄悄改成「启用」。
	// 默认值由服务层负责(创建时未指定即启用)。
	Enabled bool `gorm:"not null" json:"enabled"`

	CreatedAt time.Time      `json:"createdAt"`
	UpdatedAt time.Time      `json:"updatedAt"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`

	// Targets 响应投影。
	Targets []*HistoryTarget `gorm:"-" json:"targets,omitempty"`
}

HistoryChannel 历史同步通道:两个各自有完整历史的仓库之间的单向内容同步。

与 MirrorChannel(镜像通道/身份镜像)并存,语义不同:

  • MirrorChannel:同一仓库的多个身份,每 tag 一个孤儿快照;
  • HistoryChannel:两个有完整历史的仓库,按内容差异叠加, 目标树的既有提交原样保留。

**通道是历史同步的唯一配置入口**:规则只存这里, 执行时按通道解析,不再由调用方每次重传一整套规则。

type HistoryOverride added in v0.12.0

type HistoryOverride struct {
	ID        uint `gorm:"primaryKey" json:"id"`
	ChannelID uint `gorm:"index:idx_history_override;not null" json:"channelId"`
	// Path 目标侧路径(裁决的定位键)。
	Path string `gorm:"size:512;not null;index:idx_history_override" json:"path"`
	// SourcePath 源侧路径(回溯用)。
	SourcePath string `gorm:"size:512" json:"sourcePath"`
	// Verdict 裁决:keep_target / take_source / merged。
	Verdict string `gorm:"size:16;not null" json:"verdict"`
	// Content 裁决后的内容(仅 merged 时有值)。
	Content string `gorm:"type:text" json:"content,omitempty"`
	// Reason 裁决理由(审计用)。
	Reason string `gorm:"type:text" json:"reason"`
	// DecidedBy 裁决者(人工或 AI 标识)。
	DecidedBy string `gorm:"size:128" json:"decidedBy"`

	CreatedAt time.Time      `json:"createdAt"`
	UpdatedAt time.Time      `json:"updatedAt"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}

HistoryOverride 对某个 hold 文件的裁决结果。

存在它是为了让「AI 建议 + 人工确认」的闭环真正落地: resolve 给出冲突卷宗 → 裁决写回这张表 → 再次 resolve 时按裁决出解 → apply 时用裁决内容。

裁决**只对 hold 生效**:其余文件仍走确定性判定。

type HistoryRun added in v0.12.0

type HistoryRun struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// ChannelID 通道 ID。
	//
	// 复合索引 idx_history_runs_channel_kind 覆盖
	// 「取通道最近一次某类别的执行记录」这类查询
	// (FindLatestByChannelKind:channel_id + kind)。
	ChannelID uint `gorm:"index;not null;index:idx_history_runs_channel_kind,priority:1" json:"channelId"`
	// Kind 记录类别:apply / push / rollback。
	//
	// **一次动作一条记录**:push 不修改已入链的 apply 记录,
	// 而是新建一条 —— 已入链的记录字段一旦被改动,哈希就与入链时算的不符,
	// 链会立刻报「被篡改」(实际是正常流程改了它)。
	//
	// 复合索引 idx_history_runs_kind_status 覆盖按类别/状态的查询
	// (待推送产物清单:kind=apply;已推送判定:kind=push + status=success)。
	Kind string `` /* 142-byte string literal not displayed */
	// PushedRunID push/rollback 记录引用被操作的 apply 记录。
	PushedRunID uint `gorm:"index" json:"pushedRunId"`
	// Status 执行状态:pending|running|success|failed。
	Status string `gorm:"size:16;not null;default:pending;index:idx_history_runs_kind_status,priority:2" json:"status"`

	// BaseHead 移植前的目标 HEAD(既有提交原样保留的基线)。
	BaseHead string `gorm:"size:64" json:"baseHead"`
	// Head 移植后的 HEAD(新提交链的顶端)。
	Head string `gorm:"size:64" json:"head"`
	// WorkRepoPath 移植产出的工作仓库路径(推送用)。
	WorkRepoPath string `gorm:"size:512" json:"-"`

	// PlanSummary 计划统计 JSON。
	PlanSummary string `gorm:"type:text" json:"planSummary"`
	// Commits commit 映射表 JSON:[{source,target,subject,files}]。
	Commits string `gorm:"type:text" json:"commits"`
	// Files 应用的文件 JSON。
	Files string `gorm:"type:text" json:"files"`
	// Skipped 未应用的文件 JSON。
	Skipped string `gorm:"type:text" json:"skipped"`
	// ScrubReport 痕迹检测报告 JSON。
	ScrubReport string `gorm:"type:text" json:"scrubReport"`
	// GateReport 门禁结果 JSON(gofmt + 类型检查)。
	GateReport string `gorm:"type:text" json:"gateReport"`
	// RefsBefore / RefsAfter 推送前后的 ref 对照 JSON。
	RefsBefore string `gorm:"type:text" json:"refsBefore"`
	RefsAfter  string `gorm:"type:text" json:"refsAfter"`

	Error string `gorm:"type:text" json:"error"`

	// PrevHash 上一条执行记录的 EntryHash(**该通道内**的链)。
	PrevHash string `gorm:"size:64;index" json:"prevHash"`
	// EntryHash 本条哈希链值。
	//
	// 链在**通道内**:不同通道的同步记录混在一条链里没有意义,
	// 而且链会随通道数无限增长。
	EntryHash string `gorm:"size:64;index" json:"entryHash"`

	StartedAt  *time.Time `json:"startedAt"`
	FinishedAt *time.Time `json:"finishedAt"`
	DurationMs int64      `json:"durationMs"`

	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

HistoryRun 历史同步的一次执行记录。

它同时承担三个角色:

  • **产物指针**:WorkRepoPath 记下移植产出的工作仓库路径, 推送时服务端自己取,调用方不必回传服务端的临时路径;
  • **审计留痕**:计划统计 / commit 映射 / 检测报告 / 门禁结果 / 推送前后 ref 对照;
  • **回滚锚点**:BaseHead 与 Head 界定了「这次同步改了什么」。

func (*HistoryRun) BeforeSave added in v0.13.0

func (r *HistoryRun) BeforeSave(tx *gorm.DB) error

BeforeSave 归一时间精度。

**哈希链覆盖时间字段** → 写进库里的时间必须与算哈希时用的时间逐字一致。 亚毫秒精度写进 MySQL(datetime(3))会被四舍五入,读回来就不是同一个值, 整条链都会被报「被篡改」—— 实测过:每一条都误报。

必须在这里截断,而不是只在算哈希时截断:算哈希时截断只能改哈希输入, 改不了库里已经存进去的值,两边照样对不上。

CreatedAt 缺省时在这里补:GORM 的自动时间戳是在 BeforeSave **之后** 才写入的,那时写进去的是纳秒值,已经来不及截断。

type HistoryTarget added in v0.12.0

type HistoryTarget struct {
	ID        uint `gorm:"primaryKey" json:"id"`
	ChannelID uint `gorm:"index;not null" json:"channelId"`
	// Name 目标名(backup / publish)。
	Name string `gorm:"size:64;not null" json:"name"`
	// RepoURL 是目标仓库的 git 地址(https/ssh/本地路径)。
	RepoURL string `gorm:"size:512;not null" json:"repoUrl"`

	// 凭据:Credential 整体加密存储,响应只回 HasCredential。
	CredType      string `gorm:"size:16;not null;default:none" json:"credType"`
	Credential    string `gorm:"size:2048" json:"-"`
	Username      string `gorm:"size:128" json:"username"`
	HasCredential bool   `gorm:"-" json:"hasCredential"`
	// CredentialUpdatedAt 凭据最后更新时间(轮换时刷新)。
	CredentialUpdatedAt *time.Time `json:"credentialUpdatedAt,omitempty"`
	// CredentialExpiresAt 凭据到期时间(可选);预检时会对过期/临期告警。
	CredentialExpiresAt *time.Time `json:"credentialExpiresAt,omitempty"`

	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

HistoryTarget 通道的推送目标。

顺序即优先级:**第一个是留底(本地裸镜像),其后才是发布(GitHub 真上游)**。 留底必须先落地,否则发布失败就没有回滚依据。

type LogConfig

type LogConfig struct {
	Level  string `yaml:"level" env:"GIT_SYNC_LOG_LEVEL"`
	Format string `yaml:"format" env:"GIT_SYNC_LOG_FORMAT"`
}

type MirrorChannel

type MirrorChannel struct {
	ID      uint   `gorm:"primaryKey" json:"id"`
	Name    string `gorm:"size:128;not null" json:"name"`
	Mode    string `gorm:"size:16;not null;default:publish" json:"mode"`
	RepoKey string `gorm:"size:128;not null;index" json:"repoKey"`
	// Module 是源 module 身份(publish 模式,创建时从 go.mod 读出)。
	Module string `gorm:"size:255" json:"module"`
	// ScrubRules 痕迹清理规则(JSON 串):发布前把内容里的内网痕迹清掉。
	//
	// 身份改写只管 module path;内网 registry 地址、部署代号、令牌
	// 这些**不在 module path 里**的标识,原样进公开 module 就是泄漏。
	// 规则形状与历史同步侧一致{name,category,pattern,severity,replacement}。
	ScrubRules string `gorm:"type:text" json:"scrubRules,omitempty"`

	CreatedAt time.Time      `json:"createdAt"`
	UpdatedAt time.Time      `json:"updatedAt"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
	// Targets 响应投影(GetMirrorChannel 组装)。
	Targets []*MirrorTarget `gorm:"-" json:"targets,omitempty"`
}

MirrorChannel 镜像通道:源仓库 → N 个远端目标的配置。

type MirrorRun

type MirrorRun struct {
	ID        uint   `gorm:"primaryKey" json:"id"`
	ChannelID uint   `gorm:"index:idx_mirror_channel;not null" json:"channelId"`
	TargetID  uint   `gorm:"index" json:"targetId"`
	Kind      string `gorm:"size:16;not null;default:publish" json:"kind"`
	// Tags 逗号分隔的本批 tag。
	Tags string `gorm:"size:1024" json:"tags"`
	// Status 整批状态:pending|running|success|failed|divergent。
	Status string `json:"status"`
	// TagStatuses 行级结果 JSON:{tag: {status, detail, commit, tree}}。
	TagStatuses string `gorm:"type:text" json:"tagStatuses"`
	// Steps 步骤时间线 JSON。
	Steps string `gorm:"type:text" json:"steps"`
	// Report 最后一次 core 报告 JSON(参考 mirror.TagReport)。
	Report string `gorm:"type:text" json:"report"`
	Error  string `gorm:"type:text" json:"error"`

	AllowOverwrite bool       `json:"allowOverwrite"`
	StartedAt      *time.Time `json:"startedAt"`
	FinishedAt     *time.Time `json:"finishedAt"`
	DurationMs     int64      `json:"durationMs"`

	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

MirrorRun 执行记录:一次发布/备份/验证动作。

type MirrorStep

type MirrorStep struct {
	Name   string `json:"name"`
	Status string `json:"status"` // running|success|failed|skipped
	Detail string `json:"detail,omitempty"`
}

MirrorStep 执行步骤(JSON 存储)。

type MirrorTarget

type MirrorTarget struct {
	ID        uint `gorm:"primaryKey" json:"id"`
	ChannelID uint `gorm:"index;not null" json:"channelId"`
	// Remote 是目标仓库在本地克隆里配置的远端名(如 github)。
	Remote string `gorm:"size:64;not null" json:"remote"`
	// RepoURL 是目标仓库的 git 地址(https/ssh)。
	RepoURL string `gorm:"size:512;not null" json:"repoUrl"`
	// TargetModule 是目标 module 身份(publish 模式)。
	TargetModule string `gorm:"size:255" json:"targetModule"`

	// 凭据:Credential 整体加密存储,响应只回 HasCredential。
	CredType      string `gorm:"size:16;not null;default:none" json:"credType"`
	Credential    string `gorm:"size:2048" json:"-"`
	Username      string `gorm:"size:128" json:"username"`
	HasCredential bool   `gorm:"-" json:"hasCredential"`

	// **SSH 主机密钥钉扎**(与源仓侧同一套字段):
	// 之前目标侧没法钉 —— 于是「检查路径」无 known_hosts 就硬错(fail-closed)、
	// 「推送路径」却用 accept-new(TOFU),同一次发布里两套策略相反。
	// 现在两边都从同一份 AuthConfig 走,配了指纹就都校验。
	//
	// **必须落库**:这一项是「放宽安全」的开关,丢了等于悄悄放宽。
	InsecureSkipTLS    bool   `gorm:"not null;default:false" json:"insecureSkipTLS,omitempty"`
	HostKeyFingerprint string `gorm:"size:255" json:"hostKeyFingerprint,omitempty"`
	KnownHostsPath     string `gorm:"size:512" json:"knownHostsPath,omitempty"`

	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

MirrorTarget 通道目标:publish 模式为身份映射,backup 模式为备份远端。

type OperationLog

type OperationLog struct {
	ID           uint   `json:"id" gorm:"primaryKey"`
	Action       string `json:"action" gorm:"size:32;not null;index"`  // create/update/delete/run/retry/sync
	ResourceType string `json:"resource_type" gorm:"size:32;not null"` // repo/task/rule/platform/event
	ResourceKey  string `json:"resource_key" gorm:"size:255;index"`    // 资源标识(key/name/id)
	Resource     string `json:"resource" gorm:"size:500"`              // 中文摘要,如 "创建仓库 repo-main"
	Actor        string `json:"actor" gorm:"size:128;index"`           // 操作者
	IP           string `json:"ip" gorm:"size:64"`
	Status       string `json:"status" gorm:"size:16;default:success"` // success/failed
	Detail       string `json:"detail" gorm:"type:text"`
	// PrevHash 上一条审计的 EntryHash(首条为空)
	PrevHash string `json:"prev_hash" gorm:"size:64;index"`
	// EntryHash 本条哈希链值
	EntryHash string    `json:"entry_hash" gorm:"size:64;index"`
	CreatedAt time.Time `json:"created_at" gorm:"index"`
}

OperationLog 记录用户对系统发起的写操作(审计日志)。 哈希链:EntryHash = SHA256(PrevHash || payload);篡改任意条目可被 VerifyAuditChain 检出。

func (OperationLog) TableName

func (OperationLog) TableName() string

type Platform

type Platform struct {
	ID          uint   `json:"id" gorm:"primaryKey"`
	Key         string `json:"key" gorm:"uniqueIndex;size:255;not null"`
	Name        string `json:"name" gorm:"size:100;not null"`
	Type        string `json:"type" gorm:"size:50;not null"`     // github, gitlab, gitea, gitee, gitcode, atomgit, tencent_code, custom
	InstanceURL string `json:"instance_url" gorm:"size:255"`     // 实例地址,如 github.com, gitlab.company.com
	APIURL      string `json:"api_url" gorm:"size:255;not null"` // API 地址,如 https://api.github.com
	AccessToken string `json:"-" gorm:"type:text"`               // 访问令牌(加密存储)
	// GitHub App 认证(优先于 PAT):安装级、可轮换、细粒度(借鉴 gickup/ghorg)
	GitHubAppID          int64  `json:"github_app_id" gorm:"default:0"`
	GitHubInstallationID int64  `json:"github_installation_id" gorm:"default:0"`
	GitHubPrivateKey     string `json:"-" gorm:"type:text"`                   // PEM 私钥(加密存储)
	SkipTLSVerify        bool   `json:"skip_tls_verify" gorm:"default:false"` // 跳过 TLS 证书验证
	CACertPath           string `json:"ca_cert_path" gorm:"size:500"`         // 自定义 CA 证书路径
	ProxyURL             string `json:"proxy_url" gorm:"size:255"`            // HTTP 代理地址
	// SSHHostKeyFingerprint SSH 主机公钥指纹钉扎("SHA256:xxx");设置后优先于 known_hosts
	SSHHostKeyFingerprint string `json:"ssh_host_key_fingerprint" gorm:"size:128"`
	// SSHKnownHostsPath 平台级 known_hosts 路径(空=用 ~/.ssh/known_hosts)
	SSHKnownHostsPath string         `json:"ssh_known_hosts_path" gorm:"size:500"`
	IsDefault         bool           `json:"is_default" gorm:"default:false"`      // 是否为默认平台
	Status            string         `json:"status" gorm:"size:20;default:active"` // 状态: active, error
	LastTestAt        *time.Time     `json:"last_test_at"`                         // 最后测试时间
	LastTestResult    string         `json:"last_test_result" gorm:"size:500"`     // 最后测试结果
	RepoCount         int            `json:"repo_count" gorm:"default:0"`          // 关联的仓库数量
	CreatedAt         time.Time      `json:"created_at"`
	UpdatedAt         time.Time      `json:"updated_at"`
	DeletedAt         gorm.DeletedAt `json:"-" gorm:"index"`
}

Platform 存储 Git 平台配置

func (Platform) TableName

func (Platform) TableName() string

type PreviewSyncRequest

type PreviewSyncRequest struct {
	SourceRepoKey string `json:"sourceRepoKey"`
	SourceBranch  string `json:"sourceBranch"`
	TargetRepoKey string `json:"targetRepoKey"`
	TargetBranch  string `json:"targetBranch"`
}

type PreviewSyncResult

type PreviewSyncResult struct {
	CanSync      bool   `json:"canSync"`
	SourceExists bool   `json:"sourceExists"`
	TargetExists bool   `json:"targetExists"`
	Message      string `json:"message"`
}

type RedisConfig

type RedisConfig struct {
	Addr            string `yaml:"addr" env:"GIT_SYNC_REDIS_ADDR"`
	Password        string `yaml:"password" env:"GIT_SYNC_REDIS_PASSWORD"`
	DB              int    `yaml:"db" env:"GIT_SYNC_REDIS_DB"`
	PoolSize        int    `yaml:"pool_size" env:"GIT_SYNC_REDIS_POOL_SIZE"`                 // 连接池大小,0 用 go-redis 默认(10*GOMAXPROCS)
	MinIdleConns    int    `yaml:"min_idle_conns" env:"GIT_SYNC_REDIS_MIN_IDLE_CONNS"`       // 最小空闲连接数,0 不预热
	DialTimeoutSec  int    `yaml:"dial_timeout_sec" env:"GIT_SYNC_REDIS_DIAL_TIMEOUT_SEC"`   // 建连超时秒数,0 不设超时
	ReadTimeoutSec  int    `yaml:"read_timeout_sec" env:"GIT_SYNC_REDIS_READ_TIMEOUT_SEC"`   // 读超时秒数,0 不设超时
	WriteTimeoutSec int    `yaml:"write_timeout_sec" env:"GIT_SYNC_REDIS_WRITE_TIMEOUT_SEC"` // 写超时秒数,0 不设超时
}

type Repo

type Repo struct {
	ID            uint           `json:"id" gorm:"primaryKey"`
	Key           string         `json:"key" gorm:"uniqueIndex;size:255;not null"`
	Name          string         `json:"name" gorm:"size:255;not null"`
	PlatformID    uint           `json:"platform_id" gorm:"index"` // 关联平台 ID
	Platform      string         `json:"platform" gorm:"size:50;not null;default:'unknown'"`
	PlatformOwner string         `json:"platform_owner" gorm:"size:200;not null;default:''"`
	PlatformRepo  string         `json:"platform_repo" gorm:"size:200;not null;default:''"`
	CloneURL      string         `json:"clone_url" gorm:"size:500"`
	SSHURL        string         `json:"ssh_url" gorm:"size:500"`
	DefaultBranch string         `json:"default_branch" gorm:"size:100;default:main"`
	AccessToken   string         `json:"-" gorm:"type:text"` // 保留用于兼容,优先使用 Platform 的 Token
	WebhookSecret string         `json:"-" gorm:"size:255"`
	WebhookID     int64          `json:"webhook_id"`
	Status        string         `json:"status" gorm:"size:20;default:active"`
	CreatedAt     time.Time      `json:"created_at"`
	UpdatedAt     time.Time      `json:"updated_at"`
	DeletedAt     gorm.DeletedAt `json:"-" gorm:"index"`
}

func (Repo) TableName

func (Repo) TableName() string

type ServerConfig

type ServerConfig struct {
	Host string `yaml:"host" env:"GIT_SYNC_SERVER_HOST"`
	Port int    `yaml:"port" env:"GIT_SYNC_SERVER_PORT"`
	Mode string `yaml:"mode" env:"GIT_SYNC_SERVER_MODE"`
}

ServerConfig 壳层 HTTP 监听相关配置。 用户登录 / API Key / SSO 等鉴权不属于本库;由 git-ferry / git-ferry-intranet 自行持有。 core 库本身不监听端口、不做用户鉴权。

type SyncConfig

type SyncConfig struct {
	// BackupDir git bundle 冷备输出目录(空=禁用)
	BackupDir string `yaml:"backup_dir" env:"GIT_SYNC_BACKUP_DIR"`
	// HistoryWorkDir 历史同步的移植产物目录(apply 的工作副本)。
	//
	// 空 = 系统临时目录下的 git-ferry-history 子目录。
	// **建议指到持久目录**:产物要活到「apply 之后的那次 push」,
	// 放临时目录的话,系统清理临时文件会把待推送的产物删掉。
	HistoryWorkDir string `yaml:"history_work_dir" env:"GIT_SYNC_HISTORY_WORK_DIR"`
	// BackupKeep 每任务保留最近 N 份 bundle(0=不轮转,全部保留)
	BackupKeep int `yaml:"backup_keep" env:"GIT_SYNC_BACKUP_KEEP"`
	// BackupS3 bundle 异地冷备(S3 兼容);空配置=只存本地
	BackupS3 struct {
		Endpoint  string `yaml:"endpoint"`
		Region    string `yaml:"region"`
		Bucket    string `yaml:"bucket"`
		Prefix    string `yaml:"prefix"`
		AccessKey string `yaml:"access_key"`
		SecretKey string `yaml:"secret_key"`
		PathStyle bool   `yaml:"path_style"`
	} `yaml:"backup_s3"`
	// BackupDestinations 多目的地扇出(s3/webdav/azure/local),与 BackupS3 并存;
	// 两者都配置时全部尝试,逐目的地独立成功/失败。
	BackupDestinations []BackupDestinationConfig `yaml:"backup_destinations"`
	// BackupEncryptKey 冷备加密密钥(base64 32 字节 AES-256-GCM);空=不加密。
	// 加密文件后缀 .bundle.enc,恢复时需同一密钥。
	BackupEncryptKey string `yaml:"backup_encrypt_key" env:"GIT_SYNC_BACKUP_ENCRYPT_KEY"`
	// BackupRetentionDays 冷备保留天数(0=不按天清理);与 BackupKeep 取更严者。
	BackupRetentionDays int `yaml:"backup_retention_days" env:"GIT_SYNC_BACKUP_RETENTION_DAYS"`
	// LegalHold 冻结清理(合规保留),true 时禁止自动轮转/过期删除。
	LegalHold bool `yaml:"legal_hold" env:"GIT_SYNC_LEGAL_HOLD"`
	// AutoDiscoverIntervalMinutes 平台自动发现周期(分钟);0=关闭。
	AutoDiscoverIntervalMinutes int `yaml:"auto_discover_interval_minutes" env:"GIT_SYNC_AUTO_DISCOVER_INTERVAL"`
	// AutoDiscoverImport 发现到新仓库时是否自动导入(否则仅报告)。
	AutoDiscoverImport bool `yaml:"auto_discover_import" env:"GIT_SYNC_AUTO_DISCOVER_IMPORT"`
	// PartialClone 部分克隆 filter(blob:none / tree:0),空=全量
	PartialClone   string `yaml:"partial_clone" env:"GIT_SYNC_PARTIAL_CLONE"`
	MaxConcurrent  int    `yaml:"max_concurrent" env:"GIT_SYNC_MAX_CONCURRENT"`
	DefaultTimeout int    `yaml:"default_timeout" env:"GIT_SYNC_DEFAULT_TIMEOUT"`
	RetryCount     int    `yaml:"retry_count" env:"GIT_SYNC_RETRY_COUNT"`
	// PostExecScript 同步结束(成功或失败)后执行的脚本;
	// 注入 GITFERRY_TASK / GITFERRY_RESULT / GITFERRY_RUN_ID / GITFERRY_TRIGGER。
	PostExecScript string `yaml:"post_exec_script" env:"GIT_SYNC_POST_EXEC_SCRIPT"`
	// BackupFormat 冷备形态:bundle(默认,git 语义) | zip(人工取件友好)
	BackupFormat string `yaml:"backup_format" env:"GIT_SYNC_BACKUP_FORMAT"`
	// BackupRemotes 额外备份远端(GitHub/GitLab 等),同步成功后 push 镜像副本。
	// 与「镜像中心开源发布」区分:此处不改写 module 身份,纯备份。
	BackupRemotes []BackupRemoteConfig `yaml:"backup_remotes"`
}

type SyncRun

type SyncRun struct {
	ID             uint          `json:"id" gorm:"primaryKey"`
	TaskKey        string        `json:"taskKey" gorm:"size:36;not null;index:idx_sync_runs_task_key_created,priority:1"`
	TriggerSource  string        `json:"triggerSource" gorm:"size:20;not null"`
	Status         string        `json:"status" gorm:"size:20;not null;index"`
	StartTime      time.Time     `json:"startTime"`
	EndTime        *time.Time    `json:"endTime"`
	CommitRange    string        `json:"commitRange" gorm:"size:255"`
	Details        string        `json:"details" gorm:"type:text"`
	ErrorMessage   string        `json:"errorMessage" gorm:"type:text"`
	WebhookEventID *uint         `json:"webhookEventId" gorm:"index"`
	DurationMs     int64         `json:"durationMs"`
	ErrorType      string        `json:"errorType" gorm:"size:30"`
	RetryTotal     int           `json:"retryTotal"`
	Steps          []SyncRunStep `json:"steps" gorm:"foreignKey:RunID"`
	CreatedAt      time.Time     `json:"createdAt" gorm:"index:idx_sync_runs_created_at;index:idx_sync_runs_task_key_created,priority:2"`
}

func (SyncRun) TableName

func (SyncRun) TableName() string

type SyncRunStep

type SyncRunStep struct {
	ID         uint       `json:"id" gorm:"primaryKey"`
	RunID      uint       `json:"runId" gorm:"not null;index"`
	StepName   string     `json:"stepName" gorm:"size:50;not null"`
	Status     string     `json:"status" gorm:"size:20;not null"`
	StartTime  time.Time  `json:"startTime"`
	EndTime    *time.Time `json:"endTime"`
	DurationMs int64      `json:"durationMs"`
	ErrorMsg   string     `json:"errorMsg" gorm:"type:text"`
	ErrorType  string     `json:"errorType" gorm:"size:30"`
	Output     string     `json:"output" gorm:"type:text"`
	RetryCount int        `json:"retryCount"`
	CreatedAt  time.Time  `json:"createdAt" gorm:"index"`
}

SyncRunStep records a single step within a sync run.

func (SyncRunStep) TableName

func (SyncRunStep) TableName() string

type SyncTask

type SyncTask struct {
	ID            uint   `json:"id" gorm:"primaryKey"`
	Key           string `json:"key" gorm:"uniqueIndex;size:36;not null;default:''"`
	Name          string `json:"name" gorm:"size:100;not null;default:''"`
	SourceRepoKey string `json:"source_repo_key" gorm:"size:255;not null;index;default:''"`
	SourceBranch  string `json:"source_branch" gorm:"size:255;not null;default:''"`
	TargetRepoKey string `json:"target_repo_key" gorm:"size:255;not null;index;default:''"`
	TargetBranch  string `json:"target_branch" gorm:"size:255;not null;default:''"`
	SyncMode      string `json:"sync_mode" gorm:"size:20;default:single"`
	Cron          string `json:"cron" gorm:"size:100"`
	WebhookToken  string `json:"webhook_token" gorm:"uniqueIndex;size:36"`
	Enabled       bool   `json:"enabled" gorm:"default:true;index"`
	GitTags       bool   `json:"git_tags" gorm:"default:false"`
	GitForce      bool   `json:"git_force" gorm:"default:false"`
	// GitLFS 同步 Git LFS 对象(需要环境安装 git-lfs)
	GitLFS bool `json:"git_lfs" gorm:"default:false"`
	// SyncWiki 同步 wiki 仓库(源/目标 URL 按 .wiki.git 规则推导)
	SyncWiki bool `json:"sync_wiki" gorm:"default:false"`
	// GitBundle 同步成功后生成 git bundle 冷备(需配置 Sync.BackupDir)
	GitBundle bool `json:"git_bundle" gorm:"default:false"`
	// Submodules 递归同步 git 子模块
	Submodules bool `json:"submodules" gorm:"default:false"`
	// GitPushPrune 推送后删除目标上源已不存在的同名分支(refspec prune)
	GitPushPrune bool `json:"git_push_prune" gorm:"default:false"`
	// KeepDivergent true=目标分支有源没有的提交时拒绝 force 覆盖(防丢代码);
	// false=允许强制覆盖分歧分支。默认 true(安全)。
	KeepDivergent bool `json:"keep_divergent" gorm:"default:true"`
	// ForcePushPolicy 强制推送保护策略:allow | block | backup_on_demand。
	// 空值按 KeepDivergent 兼容映射(keep_divergent=true → block)。
	ForcePushPolicy string `json:"force_push_policy" gorm:"size:32"`
	// IncludeBranches 逗号分隔分支 glob 白名单(如 "main,release/*")。
	// 空=不过滤;非空时推送侧仅同步匹配分支(在 SourceBranch 基础上再收窄)。
	IncludeBranches string `json:"include_branches" gorm:"size:512"`
	// ExcludeRefPatterns 逗号分隔 ref glob 黑名单(如 "refs/pull/*,refs/merge-requests/*")。
	// fetch/clone 后删除匹配 ref,避免 PR 引用污染目标。空=默认排除 refs/pull/* 与 refs/merge-requests/*。
	ExcludeRefPatterns string         `json:"exclude_ref_patterns" gorm:"size:512"`
	LastRunAt          *time.Time     `json:"last_run_at"`
	LastStatus         string         `json:"last_status" gorm:"size:20"`
	CreatedAt          time.Time      `json:"created_at"`
	UpdatedAt          time.Time      `json:"updated_at"`
	DeletedAt          gorm.DeletedAt `json:"-" gorm:"index"`
}

func (SyncTask) TableName

func (SyncTask) TableName() string

type TagStatus

type TagStatus struct {
	Tag    string `json:"tag"`
	Status string `json:"status"` // success|failed|divergent
	Detail string `json:"detail,omitempty"`
	Commit string `json:"commit,omitempty"`
	Tree   string `json:"tree,omitempty"`
}

TagStatus 行级发布结果(MirrorRun.TagStatuses 的元素)。

type TemplatesConfig added in v0.9.0

type TemplatesConfig struct {
	// Path 模板库文件路径,空 = data/templates.json(与历史壳层默认一致)。
	Path string `yaml:"path" env:"GIT_SYNC_TEMPLATES_PATH"`
}

TemplatesConfig 同步策略模板库(JSON 文件存储,壳层原本直接持有;下沉到 core 统一管理)。

type TestConnectionResult

type TestConnectionResult struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
}

type UpdateRepoRequest

type UpdateRepoRequest struct {
	Key         string `json:"key"`
	Name        string `json:"name"`
	AccessToken string `json:"accessToken"`
}

type UpdateRuleRequest

type UpdateRuleRequest struct {
	ID            uint     `json:"id"`
	Name          string   `json:"name"`
	EventType     string   `json:"eventType"`
	BranchPattern string   `json:"branchPattern"`
	Action        string   `json:"action"`
	TaskKeys      []string `json:"taskKeys"`
	MinInterval   int      `json:"minInterval"`
	Enabled       bool     `json:"enabled"`
	Description   string   `json:"description"`
}

type UpdateTaskRequest

type UpdateTaskRequest struct {
	Key  string `json:"key"`
	Name string `json:"name"`
	// SourceBranch/TargetBranch/SyncMode:空字符串=不修改
	SourceBranch string `json:"source_branch"`
	TargetBranch string `json:"target_branch"`
	SyncMode     string `json:"sync_mode"`
	// Cron 用指针:nil=不修改,**空串=清空定时**。
	// 之前是普通 string,空串与"没传"不可区分 ⇒ 一旦设了 cron 就再也改不掉
	// (只能删任务重建)。
	Cron *string `json:"cron"`
	// bool 字段用指针:nil=不修改,false=显式关闭。
	// 替代旧 bool 零值语义——此前客户端只改 name 也会把任务静默禁用。
	Enabled       *bool `json:"enabled"`
	GitTags       *bool `json:"git_tags"`
	GitForce      *bool `json:"git_force"`
	GitLFS        *bool `json:"git_lfs"`
	SyncWiki      *bool `json:"sync_wiki"`
	GitBundle     *bool `json:"git_bundle"`
	Submodules    *bool `json:"submodules"`
	GitPushPrune  *bool `json:"git_push_prune"`
	KeepDivergent *bool `json:"keep_divergent"`
	// ForcePushPolicy 用指针:nil=不修改,**空串=清空**。
	// 之前是普通 string,空串与"没传"不可区分 ⇒ 一旦设过就再也改不回去
	// (只能删任务重建)。与 Cron 同一口径。
	ForcePushPolicy *string `json:"force_push_policy"`
	// IncludeBranches/ExcludeRefPatterns 同样用指针:nil=不修改,空串=清空。
	IncludeBranches    *string `json:"include_branches"`
	ExcludeRefPatterns *string `json:"exclude_ref_patterns"`
}

type WebhookConfig

type WebhookConfig struct {
	RateLimit   int `yaml:"rate_limit" env:"GIT_SYNC_WEBHOOK_RATE_LIMIT"`
	MaxBodySize int `yaml:"max_body_size" env:"GIT_SYNC_WEBHOOK_MAX_BODY_SIZE"`
}

type WebhookEvent

type WebhookEvent struct {
	ID           uint       `json:"id" gorm:"primaryKey"`
	EventID      string     `json:"eventId" gorm:"uniqueIndex;size:100;not null"`
	RepoKey      string     `json:"repoKey" gorm:"size:255;index:idx_webhook_events_repo_key_created,priority:1"`
	EventType    string     `json:"eventType" gorm:"size:50;not null"`
	Source       string     `json:"source" gorm:"size:20;not null"`
	ActorName    string     `json:"actorName" gorm:"size:200"`
	Branch       string     `json:"branch" gorm:"size:255"`
	CommitSHA    string     `json:"commitSha" gorm:"size:40"`
	Payload      []byte     `json:"payload" gorm:"type:json"`
	Status       string     `json:"status" gorm:"size:20;default:received;index"`
	ErrorMessage string     `json:"errorMessage" gorm:"type:text"`
	ProcessedAt  *time.Time `json:"processedAt"`
	CreatedAt    time.Time  `json:"createdAt" gorm:"index:idx_webhook_events_created_at;index:idx_webhook_events_repo_key_created,priority:2"`
}

func (WebhookEvent) TableName

func (WebhookEvent) TableName() string

type WebhookRule

type WebhookRule struct {
	ID            uint              `json:"id" gorm:"primaryKey"`
	Name          string            `json:"name" gorm:"size:100;not null"`
	RepoKey       string            `json:"repoKey" gorm:"size:255;not null;index"`
	EventType     string            `json:"eventType" gorm:"size:100;default:push"`
	BranchPattern string            `json:"branchPattern" gorm:"size:255"`
	Action        string            `json:"action" gorm:"size:50;default:sync"`
	MinInterval   int               `json:"minInterval" gorm:"default:60"`
	Enabled       bool              `json:"enabled" gorm:"default:true;index"`
	Description   string            `json:"description" gorm:"type:text"`
	Tasks         []WebhookRuleTask `json:"tasks,omitempty" gorm:"foreignKey:RuleID"`
	CreatedAt     time.Time         `json:"createdAt"`
	UpdatedAt     time.Time         `json:"updatedAt"`
	DeletedAt     gorm.DeletedAt    `json:"-" gorm:"index"`
}

func (*WebhookRule) GetTaskKeys

func (r *WebhookRule) GetTaskKeys() []string

GetTaskKeys returns the task keys from the Tasks relationship

func (*WebhookRule) SetTaskKeys

func (r *WebhookRule) SetTaskKeys(keys []string)

SetTaskKeys updates the Tasks relationship

func (WebhookRule) TableName

func (WebhookRule) TableName() string

type WebhookRuleTask

type WebhookRuleTask struct {
	ID        uint      `json:"id" gorm:"primaryKey"`
	RuleID    uint      `json:"ruleId" gorm:"not null;index;uniqueIndex:idx_rule_task"`
	TaskKey   string    `json:"taskKey" gorm:"size:36;not null;uniqueIndex:idx_rule_task"`
	CreatedAt time.Time `json:"createdAt"`
}

func (WebhookRuleTask) TableName

func (WebhookRuleTask) TableName() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL