Documentation
¶
Index ¶
- Variables
- func AugmentCoverLetterPatch(rawText string, discussion string, cfgURL string, prID int64) string
- func BuildDiscussion(events []*EventLog, users map[int64]*User) string
- func GenerateCoverLetterPatch(pr *PatchRequest, discussion string, cfgURL string) string
- func GenerateMboxWithCoverLetter(pr *PatchRequest, patches []*Patch, events []*EventLog, users map[int64]*User, ...) string
- func GetAuthorizedKeys(pubkeys []string) ([]ssh.PublicKey, error)
- func GitPatchRequestMiddleware(be *Backend, pr GitPatchRequest) pssh.SSHServerMiddleware
- func GitSshServer(ctx context.Context, cfg *GitCfg) *pssh.SSHServer
- func GitWebServer(cfg *GitCfg) http.Handler
- func HasCoverLetter(patches []*Patch) bool
- func LoadConfigFile(fpath string, logger *slog.Logger)
- func NewCli(sesh *pssh.SSHServerConnSession, be *Backend, pr GitPatchRequest) *cli.App
- func NewTabWriter(out io.Writer) *tabwriter.Writer
- func ParsePatch(patchRaw string) ([]*gitdiff.File, string, error)
- func RangeDiffToStr(diffs []*RangeDiffOutput) string
- func SqliteOpen(dsn string, logger *slog.Logger) (*sqlx.DB, error)
- func SupportsSemanticDiff(fileName string) bool
- type Acl
- type AllPatchData
- type Backend
- func (be *Backend) ComputeUserName(pubkey string) string
- func (be *Backend) IsAdmin(pk ssh.PublicKey) bool
- func (be *Backend) KeyForFingerprint(pk ssh.PublicKey) string
- func (be *Backend) KeyForKeyText(pk ssh.PublicKey) string
- func (be *Backend) KeysEqual(pka, pkb string) bool
- func (be *Backend) Pubkey(pk ssh.PublicKey) string
- func (be *Backend) PubkeyToPublicKey(pubkey string) (ssh.PublicKey, error)
- func (be *Backend) PublicKeysEqual(a, b ssh.PublicKey) bool
- type BasicData
- type EventData
- type EventLog
- type EventLogData
- type GitCfg
- type GitPatchRequest
- type MetaData
- type Patch
- type PatchData
- type PatchFile
- type PatchHunk
- type PatchRequest
- type PatchSummary
- type Patchset
- type PatchsetData
- type PatchsetOp
- type PrCmd
- func (cmd PrCmd) CreateEventLog(tx *sqlx.Tx, eventLog EventLog) error
- func (cmd PrCmd) DeletePatchsetByID(userID int64, prID int64, patchsetID int64) error
- func (cmd PrCmd) DiffPatchsets(prev *Patchset, next *Patchset) ([]*RangeDiffOutput, error)
- func (cmd PrCmd) GetEventLogs() ([]*EventLog, error)
- func (cmd PrCmd) GetEventLogsByPrID(prID int64) ([]*EventLog, error)
- func (cmd PrCmd) GetEventLogsByUserID(userID int64) ([]*EventLog, error)
- func (pr PrCmd) GetLatestPatchsetByPrID(prID int64) (*Patchset, error)
- func (cmd PrCmd) GetPatchRequestByID(prID int64) (*PatchRequest, error)
- func (cmd PrCmd) GetPatchRequests() ([]*PatchRequest, error)
- func (cmd PrCmd) GetPatchRequestsActive() ([]*PatchRequest, error)
- func (cmd PrCmd) GetPatchRequestsByPubkey(pubkey string) ([]*PatchRequest, error)
- func (cmd PrCmd) GetPatchRequestsByRepoName(repoName string) ([]*PatchRequest, error)
- func (cmd PrCmd) GetPatchRequestsByStatus(status Status) ([]*PatchRequest, error)
- func (cmd PrCmd) GetPatchRequestsInactive() ([]*PatchRequest, error)
- func (pr PrCmd) GetPatchesByPatchsetID(patchsetID int64) ([]*Patch, error)
- func (pr PrCmd) GetPatchsetByID(patchsetID int64) (*Patchset, error)
- func (pr PrCmd) GetPatchsetsByPrID(prID int64) ([]*Patchset, error)
- func (pr PrCmd) GetUserByID(id int64) (*User, error)
- func (pr PrCmd) GetUserByPubkey(pubkey string) (*User, error)
- func (pr PrCmd) GetUsers() ([]*User, error)
- func (pr PrCmd) IsBanned(pubkey, ipAddress string) error
- func (cmd PrCmd) SubmitIssue(userID int64, userPubkey string, repoName, title, body string) (*PatchRequest, error)
- func (cmd PrCmd) SubmitPatchRequest(userID int64, userPubkey string, repoName string, patchset io.Reader) (*PatchRequest, error)
- func (cmd PrCmd) SubmitPatchset(prID int64, userID int64, op PatchsetOp, patchset io.Reader) ([]*Patch, error)
- func (cmd PrCmd) UpdatePatchRequestName(prID int64, userPubkey string, name string) error
- func (cmd PrCmd) UpdatePatchRequestStatus(prID int64, userPubkey string, status Status, comment string) error
- func (pr PrCmd) UpsertUserByPubkey(pubkey string) (*User, error)
- type PrData
- type PrDetailData
- type PrListData
- type PrListItem
- type RangeDiffFile
- type RangeDiffHeader
- type RangeDiffOutput
- type RateLimiter
- type SemanticChange
- type SemanticChangeKind
- type SemanticSummary
- type Status
- type TabStatus
- type User
- type UserData
- type WebCtx
Constants ¶
This section is empty.
Variables ¶
var ( COST_MAX = 65536 RANGE_DIFF_CREATION_FACTOR_DEFAULT = 60 )
var ErrNotPrOwner = fmt.Errorf("only the PR creator can perform this action")
var ErrPatchExists = errors.New("patch already exists for patch request")
var GITPR_VERSION = "2026.02.25"
Functions ¶
func AugmentCoverLetterPatch ¶
AugmentCoverLetterPatch appends References trailer and discussion to an existing cover letter patch. Preserves original content.
func BuildDiscussion ¶
BuildDiscussion formats event logs into a plain-text discussion thread. Uses SSH pubkey fingerprints for user identity. Interleaves "Submitted revision ps-X" lines for patchset events.
func GenerateCoverLetterPatch ¶
func GenerateCoverLetterPatch(pr *PatchRequest, discussion string, cfgURL string) string
GenerateCoverLetterPatch creates a cover letter patch in mbox format. Empty tree, PR title as subject, References trailer + discussion in body.
func GenerateMboxWithCoverLetter ¶
func GenerateMboxWithCoverLetter(pr *PatchRequest, patches []*Patch, events []*EventLog, users map[int64]*User, cfgURL string, ) string
GenerateMboxWithCoverLetter returns the full mbox: cover letter + patches. If the first patch is already a cover letter, augments it with References + discussion. If not, generates a new cover letter from the PR name.
func GitPatchRequestMiddleware ¶
func GitPatchRequestMiddleware(be *Backend, pr GitPatchRequest) pssh.SSHServerMiddleware
func GitWebServer ¶
func HasCoverLetter ¶
HasCoverLetter checks if the first patch is a cover letter (no diff).
func LoadConfigFile ¶
func NewCli ¶
func NewCli(sesh *pssh.SSHServerConnSession, be *Backend, pr GitPatchRequest) *cli.App
func RangeDiffToStr ¶
func RangeDiffToStr(diffs []*RangeDiffOutput) string
RangeDiffToStr returns a simple string representation of the range diff.
func SqliteOpen ¶
Open opens a database connection.
func SupportsSemanticDiff ¶
SupportsSemanticDiff reports whether a file name's extension has a registered language spec, i.e. whether AnalyzeSemanticChanges can produce anything better than an empty result for it.
Types ¶
type Acl ¶
type Acl struct {
ID int64 `db:"id"`
Pubkey sql.NullString `db:"pubkey"`
IpAddress sql.NullString `db:"ip_address"`
Permission string `db:"permission"`
CreatedAt time.Time `db:"created_at"`
}
Acl is a db model for access control.
type AllPatchData ¶
type AllPatchData struct {
Patches []PatchSummary
Patchsets []*PatchsetData
}
type Backend ¶
func (*Backend) ComputeUserName ¶
ComputeUserName derives a username from an SSH public key. Uses the first 8 characters of the SHA256 hash of the key.
func (*Backend) PubkeyToPublicKey ¶
type EventData ¶
type EventLog ¶
type EventLog struct {
ID int64 `db:"id"`
UserID int64 `db:"user_id"`
PatchRequestID sql.NullInt64 `db:"patch_request_id"`
PatchsetID sql.NullInt64 `db:"patchset_id"`
Event string `db:"event"`
CreatedAt time.Time `db:"created_at"`
Data EventData `db:"data"`
}
EventLog is a event log for RSS or other notification systems.
type EventLogData ¶
type GitCfg ¶
type GitCfg struct {
DataDir string `koanf:"data_dir"`
Url string `koanf:"url"`
Host string `koanf:"host"`
SshPort string `koanf:"ssh_port"`
WebPort string `koanf:"web_port"`
PromPort string `koanf:"prom_port"`
AdminsStr []string `koanf:"admins"`
Admins []ssh.PublicKey `koanf:"admins_pk"`
Theme string `koanf:"theme"`
TimeFormat string `koanf:"time_format"`
Desc string `koanf:"desc"`
RateLimitCount int `koanf:"rate_limit_count"`
RateLimitInterval string `koanf:"rate_limit_interval"`
MaxStdinBytes int64 `koanf:"max_stdin_bytes"`
Logger *slog.Logger
}
type GitPatchRequest ¶
type GitPatchRequest interface {
GetUsers() ([]*User, error)
GetUserByID(userID int64) (*User, error)
GetUserByPubkey(pubkey string) (*User, error)
UpsertUserByPubkey(pubkey string) (*User, error)
IsBanned(pubkey, ipAddress string) error
SubmitPatchRequest(userID int64, userPubkey string, repoName string, patchset io.Reader) (*PatchRequest, error)
SubmitPatchset(prID, userID int64, op PatchsetOp, patchset io.Reader) ([]*Patch, error)
GetPatchRequestByID(prID int64) (*PatchRequest, error)
GetPatchRequests() ([]*PatchRequest, error)
GetPatchRequestsByRepoName(repoName string) ([]*PatchRequest, error)
GetPatchRequestsByPubkey(pubkey string) ([]*PatchRequest, error)
GetPatchsetsByPrID(prID int64) ([]*Patchset, error)
GetPatchsetByID(patchsetID int64) (*Patchset, error)
GetLatestPatchsetByPrID(prID int64) (*Patchset, error)
GetPatchesByPatchsetID(patchsetID int64) ([]*Patch, error)
UpdatePatchRequestStatus(prID int64, userPubkey string, status Status, comment string) error
UpdatePatchRequestName(prID int64, userPubkey string, name string) error
DeletePatchsetByID(userID, prID int64, patchsetID int64) error
SubmitIssue(userID int64, userPubkey string, repoName, title, body string) (*PatchRequest, error)
CreateEventLog(tx *sqlx.Tx, eventLog EventLog) error
GetEventLogs() ([]*EventLog, error)
GetEventLogsByPrID(prID int64) ([]*EventLog, error)
GetEventLogsByUserID(userID int64) ([]*EventLog, error)
DiffPatchsets(aset *Patchset, bset *Patchset) ([]*RangeDiffOutput, error)
}
type Patch ¶
type Patch struct {
ID int64 `db:"id"`
UserID int64 `db:"user_id"`
PatchsetID int64 `db:"patchset_id"`
AuthorName string `db:"author_name"`
AuthorEmail string `db:"author_email"`
AuthorDate time.Time `db:"author_date"`
Title string `db:"title"`
Body string `db:"body"`
BodyAppendix string `db:"body_appendix"`
CommitSha string `db:"commit_sha"`
ContentSha string `db:"content_sha"`
BaseCommitSha sql.NullString `db:"base_commit_sha"`
RawText string `db:"raw_text"`
CreatedAt time.Time `db:"created_at"`
Files []*gitdiff.File
}
Patch is a database model for a single entry in a patchset. This usually corresponds to a git commit.
type PatchData ¶
type PatchData struct {
*Patch
PatchFiles []*PatchFile
PatchHeader *gitdiff.PatchHeader
Url template.URL
FormattedAuthorDate string
SemanticSummary SemanticSummary
}
type PatchRequest ¶
type PatchRequest struct {
ID int64 `db:"id"`
UserID int64 `db:"user_id"`
RepoName string `db:"repo_name"` // Plain string namespace
Name string `db:"name"`
Text string `db:"text"`
Status Status `db:"status"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
LastActivity time.Time `db:"last_activity"`
}
PatchRequest is a database model for patches submitted to a Repo.
type PatchSummary ¶
PatchSummary is a lightweight view of a patch used for the commit list, without the expensive diff parsing/rendering that a full PatchData needs.
type PatchsetData ¶
type PatchsetData struct {
*Patchset
UserData
FormattedID string
Date string
RangeDiff []*RangeDiffOutput
}
type PrCmd ¶
type PrCmd struct {
Backend *Backend
}
func (PrCmd) DeletePatchsetByID ¶
func (PrCmd) DiffPatchsets ¶
func (cmd PrCmd) DiffPatchsets(prev *Patchset, next *Patchset) ([]*RangeDiffOutput, error)
func (PrCmd) GetEventLogs ¶
func (PrCmd) GetEventLogsByPrID ¶
func (PrCmd) GetEventLogsByUserID ¶
func (PrCmd) GetLatestPatchsetByPrID ¶
func (PrCmd) GetPatchRequestByID ¶
func (cmd PrCmd) GetPatchRequestByID(prID int64) (*PatchRequest, error)
func (PrCmd) GetPatchRequests ¶
func (cmd PrCmd) GetPatchRequests() ([]*PatchRequest, error)
func (PrCmd) GetPatchRequestsActive ¶
func (cmd PrCmd) GetPatchRequestsActive() ([]*PatchRequest, error)
func (PrCmd) GetPatchRequestsByPubkey ¶
func (cmd PrCmd) GetPatchRequestsByPubkey(pubkey string) ([]*PatchRequest, error)
func (PrCmd) GetPatchRequestsByRepoName ¶
func (cmd PrCmd) GetPatchRequestsByRepoName(repoName string) ([]*PatchRequest, error)
func (PrCmd) GetPatchRequestsByStatus ¶
func (cmd PrCmd) GetPatchRequestsByStatus(status Status) ([]*PatchRequest, error)
func (PrCmd) GetPatchRequestsInactive ¶
func (cmd PrCmd) GetPatchRequestsInactive() ([]*PatchRequest, error)
func (PrCmd) GetPatchesByPatchsetID ¶
func (PrCmd) GetPatchsetsByPrID ¶
func (PrCmd) SubmitIssue ¶
func (cmd PrCmd) SubmitIssue(userID int64, userPubkey string, repoName, title, body string) (*PatchRequest, error)
SubmitIssue creates a new patch request as an issue (text-only, no patches, starts open). The title is the issue subject, body is the full description.
func (PrCmd) SubmitPatchRequest ¶
func (cmd PrCmd) SubmitPatchRequest(userID int64, userPubkey string, repoName string, patchset io.Reader) (*PatchRequest, error)
SubmitPatchRequest creates a new patch request with draft status.
func (PrCmd) SubmitPatchset ¶
func (PrCmd) UpdatePatchRequestName ¶
UpdatePatchRequestName changes the PR title. Only the PR creator (by pubkey) can do this.
type PrDetailData ¶
type PrListData ¶
type PrListData struct {
PRs []PrListItem
MetaData
}
type PrListItem ¶
type RangeDiffFile ¶
type RangeDiffFile struct {
OldName string
NewName string
Type string // "added", "removed", "changed"
}
RangeDiffFile represents a file-level change between two matched commits.
type RangeDiffHeader ¶
type RangeDiffHeader struct {
OldIdx int
OldSha string
OldAuthorName string
OldAuthorEmail string
OldTitle string
OldBody string
NewIdx int
NewSha string
NewAuthorName string
NewAuthorEmail string
NewTitle string
NewBody string
Title string
ContentEqual bool
AuthorChanged bool
TitleChanged bool
BodyChanged bool
}
RangeDiffHeader is a header combining old and new commit pairs.
func NewRangeDiffHeader ¶
func NewRangeDiffHeader(a, b *Patch, aIndex, bIndex int) *RangeDiffHeader
NewRangeDiffHeader creates a header from two patch ranges.
func (*RangeDiffHeader) String ¶
func (hdr *RangeDiffHeader) String() string
type RangeDiffOutput ¶
type RangeDiffOutput struct {
Header *RangeDiffHeader
Order int
Files []*RangeDiffFile
Type string // "rm", "add", "equal", "changed"
}
RangeDiffOutput represents a single commit comparison entry in the range diff.
func RangeDiff ¶
func RangeDiff(a []*Patch, b []*Patch) []*RangeDiffOutput
RangeDiff compares two patchsets and returns commit-level changes.
type RateLimiter ¶
type RateLimiter struct {
// contains filtered or unexported fields
}
RateLimiter enforces a single global cap on submissions per interval, shared across all users (not keyed by pubkey or IP).
func NewRateLimiter ¶
func NewRateLimiter(max int, interval time.Duration) *RateLimiter
func (*RateLimiter) Allow ¶
func (r *RateLimiter) Allow() bool
Allow reports whether a new submission is permitted under the current window, incrementing the window's counter if so.
func (*RateLimiter) Error ¶
func (r *RateLimiter) Error() error
type SemanticChange ¶
type SemanticChange struct {
Kind SemanticChangeKind
EntityKind string
Name string
OldSig string
NewSig string
HunkIndex int
HunkAnchor string
}
SemanticChange is a single reviewer-facing summary line describing what changed about one entity in one hunk.
func AnalyzeSemanticChanges ¶
func AnalyzeSemanticChanges(file *gitdiff.File) []SemanticChange
AnalyzeSemanticChanges produces a reviewer-facing list of semantic changes for a single diffed file. It only has access to the hunks present in the patch, not the full pre/post-image files, so entity extraction runs per-hunk on the old and new fragment text. Unsupported languages or parse failures degrade to an empty, non-error result so callers can always fall back to the line diff.
type SemanticChangeKind ¶
type SemanticChangeKind string
SemanticChangeKind describes how an entity changed between the old and new side of a hunk.
const ( SemanticAdded SemanticChangeKind = "added" SemanticRemoved SemanticChangeKind = "removed" SemanticModified SemanticChangeKind = "modified" SemanticSignatureChanged SemanticChangeKind = "signature_changed" SemanticRenamed SemanticChangeKind = "renamed" )
type SemanticSummary ¶
type SemanticSummary struct {
Added int
Modified int
SignatureChanged int
Removed int
AnalyzedFileCount int
SkippedFiles []string
}
SemanticSummary aggregates semantic changes across every file in a patch, for a reviewer-facing rollup shown above the per-file breakdown.
func SummarizeSemanticChanges ¶
func SummarizeSemanticChanges(summary SemanticSummary, fileName string, supported bool, changes []SemanticChange) SemanticSummary
SummarizeSemanticChanges folds one file's changes into a running summary. Call once per file in a patch with its changes (possibly nil) and whether the file's language was supported, then use the returned summary as-is.
func (SemanticSummary) HasContent ¶
func (s SemanticSummary) HasContent() bool
func (SemanticSummary) Total ¶
func (s SemanticSummary) Total() int
type User ¶
type User struct {
ID int64 `db:"id"`
Pubkey string `db:"pubkey"`
Name string `db:"name"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
User is a db model for users.