Documentation
¶
Index ¶
- Constants
- Variables
- func ComputeEntryHash(prev string, e *OperationLog) string
- func ComputeHistoryRunHash(prev string, r *HistoryRun) string
- func ComputeHistoryRunHashLegacy(prev string, r *HistoryRun) string
- func GetAPIURL(platformType, instanceURL string) string
- func HashTimeString(t time.Time) string
- func HashTimeStringPtr(t *time.Time) string
- func InitDB(driver, dsn string) (*gorm.DB, error)
- func NormalizeAuditHashInput(s string) string
- func TruncateDBTime(t time.Time) time.Time
- func TruncateDBTimePtr(t *time.Time) *time.Time
- func ValidPlatformType(t string) bool
- func VerifyHistoryRunHash(prev string, r *HistoryRun, stored string) bool
- type BackupDestinationConfig
- type BackupRemoteConfig
- type Config
- type CreateRepoRequest
- type CreateRuleRequest
- type CreateTaskRequest
- type DatabaseConfig
- type ForcePushApproval
- type GitConfig
- type HistoryChannel
- type HistoryOverride
- type HistoryRun
- type HistoryTarget
- type LogConfig
- type MirrorChannel
- type MirrorRun
- type MirrorStep
- type MirrorTarget
- type OperationLog
- type Platform
- type PreviewSyncRequest
- type PreviewSyncResult
- type RedisConfig
- type Repo
- type ServerConfig
- type SyncConfig
- type SyncRun
- type SyncRunStep
- type SyncTask
- type TagStatus
- type TemplatesConfig
- type TestConnectionResult
- type UpdateRepoRequest
- type UpdateRuleRequest
- type UpdateTaskRequest
- type WebhookConfig
- type WebhookEvent
- type WebhookRule
- type WebhookRuleTask
Constants ¶
const ( StatusRunning = "running" StatusSuccess = "success" StatusFailed = "failed" )
Run status constants
const ( StatusReceived = "received" StatusProcessing = "processing" StatusProcessed = "processed" )
Webhook event status constants
const ( TriggerManual = "manual" TriggerCron = "cron" TriggerWebhook = "webhook" )
Trigger source constants
const ( DriverMySQL = "mysql" DriverSQLite = "sqlite" )
Database driver constants
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
const ( StepClone = "clone" StepFetch = "fetch" StepCheckout = "checkout" StepEnsureRemote = "ensure_remote" StepPush = "push" StepLFS = "lfs" StepWiki = "wiki" StepDivergeCheck = "diverge_check" )
Step name constants
const ( ErrorAuth = "auth" ErrorDivergent = "divergent" ErrorConflict = "conflict" ErrorNetwork = "network" ErrorConfig = "config" ErrorGit = "git" ErrorUnknown = "unknown" )
Error type constants
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
const ( DefaultBranch = "main" DefaultPlatform = "unknown" DefaultSyncMode = "single" DefaultEventType = "push" DefaultAction = "sync" )
Model default value constants
const ( HistoryRunPending = "pending" HistoryRunRunning = "running" HistoryRunSuccess = "success" HistoryRunFailed = "failed" )
历史同步执行状态
const ( HistoryCredNone = "none" HistoryCredToken = "token" HistoryCredSSHKey = "ssh_key" )
推送目标凭据类型
const ( // HistoryRunKindApply 内容移植:产出新提交。 HistoryRunKindApply = "apply" // HistoryRunKindPush 推送:把某次移植的产物推到远端。 HistoryRunKindPush = "push" // HistoryRunKindRollback 回滚:把目标分支退回某个 ref。 HistoryRunKindRollback = "rollback" )
历史同步执行记录的类别。
const ( // HistoryVerdictKeepTarget 保留目标侧内容(源侧的改动是内网特有,不该公开)。 HistoryVerdictKeepTarget = "keep_target" // HistoryVerdictTakeSource 取源侧内容(源侧的改动是公开树需要的)。 HistoryVerdictTakeSource = "take_source" // HistoryVerdictMerged 用裁决后的内容(两侧都要保留各自的部分)。 HistoryVerdictMerged = "merged" )
历史同步裁决类型(人工/AI 对某个 hold 文件的结论)。
const ( MirrorModePublish = "publish" // 开源公开发布:身份改写 + 门禁 + 快照推送 MirrorModeBackup = "backup" // 仓库备份:原样 ref 推送(P1) )
镜像通道模式
const ( MirrorRunPending = "pending" MirrorRunRunning = "running" MirrorRunSuccess = "success" MirrorRunFailed = "failed" MirrorRunDivergent = "divergent" // 远端同名 tag 内容不一致,默认拒绝覆盖 )
镜像执行状态
const ( MirrorKindPublish = "publish" MirrorKindVerify = "verify" )
镜像执行类别
const ( MirrorCredNone = "none" MirrorCredToken = "token" MirrorCredSSHKey = "ssh_key" )
凭据类型
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 未注册的扩展类型保留本地定义。
const ( PlatformStatusActive = "active" PlatformStatusError = "error" )
PlatformStatus 平台状态常量
const (
ActionSync = "sync"
)
Webhook rule action constants
const RepoDirName = "repo"
RepoDirName 任务工作区里 git 仓库所在子目录名。 单源:executor 的工作区路径与 service 的 GetRepoDir 都必须用这一个名字, 两处各写一份字面量必然漂移(实测:备份推送曾把父目录当仓库用,报 "repository does not exist")。
const (
RepoStatusActive = "active"
)
Repository status constants
Variables ¶
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"的推导)。
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 已注册平台的值作为已知默认;扩展平台是唯一数据源。
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 ComputeHistoryRunHashLegacy ¶ added in v0.13.0
func ComputeHistoryRunHashLegacy(prev string, r *HistoryRun) string
ComputeHistoryRunHashLegacy 是**旧版**载荷算出的哈希。
载荷结构变过:新增了 kind / pushed_run_id,时间格式也从变宽的 RFC3339Nano 换成了定宽毫秒。升级前写入的记录用新算法算不出来 —— 直接判「被篡改」等于升级即毁掉全部历史防篡改证据。
所以校验时**两个算法都试**:任一命中即通过(见 VerifyHistoryRunHash)。
func GetAPIURL ¶
GetAPIURL 根据实例地址生成 API URL。 自建实例(非默认域名)的 URL 由壳层传入 instanceURL 覆盖; SDK 的 provider.NewProvider 也能推导已知平台的 URL,但 DB 字段 NOT NULL 要求壳层在创建时就提供非空值,因此保留此辅助函数。
func HashTimeString ¶ added in v0.13.0
HashTimeString 把时间格式化成哈希载荷里的字符串。
**先截到毫秒再格式化**:与 TruncateDBTime 同一个理由 —— 哈希必须在「写库前」与「读库后」算出同一个值。
func HashTimeStringPtr ¶ added in v0.13.0
HashTimeStringPtr 是 HashTimeString 的指针版本(nil → 空串)。
func NormalizeAuditHashInput ¶ added in v0.6.0
NormalizeAuditHashInput 归一化字符串用于稳定哈希(去首尾空白)。
func TruncateDBTime ¶ added in v0.13.0
TruncateDBTime 把时间截到数据库能原样存回的精度(毫秒)。
先取 UTC 再截断:Truncate 按绝对时刻取整,顺序不影响结果, 但统一成 UTC 让存进去的值与哈希里的字符串一一对应。
func TruncateDBTimePtr ¶ added in v0.13.0
TruncateDBTimePtr 是 TruncateDBTime 的指针版本(nil 安全)。
func ValidPlatformType ¶
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, 无条件兜底的话,升级前的记录里这两个字段被改成任何值链都照样报「完好」—— 而它们正是「这个产物推没推送」的判定依据。 所以: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 ¶
LoadConfig 从指定路径加载配置文件。 path 参数由调用方控制(通常是启动参数或环境变量),不存在用户注入风险。 环境变量会覆盖 YAML 文件中的同名配置(env 优先级更高)。
type CreateRepoRequest ¶
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"`
GitPrune bool `json:"git_prune"`
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"`
}
ForcePushApproval force-push 审批记录(block-and-approve 模式)。 JSON 字段与历史文件 <backup_dir>/force-push-approvals.json 逐字兼容, 供既有部署迁移导入与 HTTP 响应复用。
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 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 平台配置
type PreviewSyncRequest ¶
type PreviewSyncResult ¶
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"`
}
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"`
}
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"`
GitPrune bool `json:"git_prune" 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"`
}
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 UpdateRepoRequest ¶
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"`
GitPrune *bool `json:"git_prune"`
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 空=不修改
ForcePushPolicy string `json:"force_push_policy"`
// IncludeBranches/ExcludeRefPatterns:空字符串=不修改
IncludeBranches string `json:"include_branches"`
ExcludeRefPatterns string `json:"exclude_ref_patterns"`
}
type WebhookConfig ¶
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