fork

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Overview

Package fork owns S27's fork orchestration. The DB row for a fork is created synchronously in Create; the on-disk `git clone --bare --shared` runs out-of-band as a `repo:fork_clone` worker job so fork creation returns fast even for large source repos.

Sync (fast-forward fork's default branch from upstream) is the other entrypoint here. Cross-fork PR support extends `internal/ pulls` and lives there; this package is just the fork lifecycle.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotLoggedIn         = errors.New("fork: login required")
	ErrSourceNotFound      = errors.New("fork: source repo not found")
	ErrSourceNotVisible    = errors.New("fork: source repo not visible to actor")
	ErrTargetNameTaken     = errors.New("fork: target name already exists for owner")
	ErrVisibilityFloor     = errors.New("fork: target visibility cannot exceed source visibility")
	ErrSelfForkSameName    = errors.New("fork: forking into the same owner requires a different name")
	ErrSourceArchived      = errors.New("fork: source repo is archived")
	ErrSourceDeleted       = errors.New("fork: source repo is deleted")
	ErrSyncDiverged        = errors.New("fork: fork has diverged from upstream; sync via your client")
	ErrSyncUpToDate        = errors.New("fork: already up to date")
	ErrSyncDefaultsMissing = errors.New("fork: source or fork default branch is empty")
	ErrSyncRefRaced        = errors.New("fork: ref changed concurrently; retry")
	ErrForkNotInitialized  = errors.New("fork: fork is still being prepared")
)

Errors surfaced to handlers.

Functions

This section is empty.

Types

type AheadBehindStats

type AheadBehindStats struct {
	Ahead      int
	Behind     int
	Comparable bool
}

AheadBehindStats describes how the fork's default branch relates to the source's default branch. Both numbers are commit counts: `Ahead` = commits in fork not in source; `Behind` = commits in source not in fork.

`Comparable` is false when either side's default ref doesn't exist (e.g. an empty fork before its first push, or a source that's never been initialized). The UI renders "—" in that case.

func AheadBehind

func AheadBehind(ctx context.Context, deps Deps, forkRepoID int64) (AheadBehindStats, error)

AheadBehind computes the stats by reading both default OIDs, then running `rev-list --left-right --count` inside the fork's bare repo. Because forks share object alternates with their source, the fork can resolve OIDs from the source without an explicit fetch — they're already reachable through the alternates link.

This is the floor implementation. S36's perf-pass sprint adds caching keyed on `(fork_repo_id, fork_default_oid, upstream_default_oid)` so the rev-list shells out only on push (the deferral pointer is already in S36's spec).

type CreateParams

type CreateParams struct {
	SourceRepoID  int64
	ActorUserID   int64
	TargetOwnerID int64 // user id; org id support lands with S31
	// TargetName is optional. Empty defaults to the source repo's
	// name; non-empty must pass the same name validator as repo
	// create (the lookup against the existing rows surfaces a
	// taken-name error if needed).
	TargetName string
	// TargetVisibility is optional. Empty defaults to source
	// visibility; non-empty must pass `allowedTargetVisibility`.
	// (Public source can fork to private; private source is
	// pinned to private.)
	TargetVisibility string
}

CreateParams describes a fork-create request.

type CreateResult

type CreateResult struct {
	Fork   reposdb.Repo
	Source reposdb.Repo
}

CreateResult is the inserted fork shell. The on-disk clone hasn't run yet; init_status is `init_pending`. The caller is expected to enqueue the `repo:fork_clone` worker job whose payload is {SourceRepoID, ForkRepoID}.

func Create

func Create(ctx context.Context, deps Deps, p CreateParams) (CreateResult, error)

Create writes the fork's `repos` row, applies the fork_count trigger, and emits the audit row. The on-disk clone is the caller's responsibility to enqueue (the web handler does this right after Create returns).

Authorization (visibility on source, login, fork:create policy) is the caller's responsibility — this orchestrator trusts the handler's policy gate. Visibility floor + same-owner-name guards are enforced here because they're domain rules, not auth rules.

type Deps

type Deps struct {
	Pool   *pgxpool.Pool
	RepoFS *storage.RepoFS
	Audit  *audit.Recorder
	Logger *slog.Logger
}

Deps wires this package against the rest of the runtime.

type SyncResult

type SyncResult struct {
	OldOID string
	NewOID string
}

SyncResult describes what Sync did. Reasons cover the four outcomes the spec enumerates: fast-forwarded, already up to date, diverged (refused), or default-branch-missing (typically a freshly initialized fork or upstream that's never been pushed to).

func Sync

func Sync(ctx context.Context, deps Deps, actorUserID, forkRepoID int64) (SyncResult, error)

Sync fast-forwards the fork's default branch to the upstream's. Refuses on diverged history (as the spec mandates — anything else belongs in the user's client). The CAS via UpdateRefCAS catches concurrent pushes to the fork: if a push lands between our read and our update, we return ErrSyncRefRaced and the caller can ask the user to retry.

The handler MUST authorize via policy.Can(ActionRepoWrite) on the fork before calling — Sync mutates the fork's refs and is a write action. Read access on the source is implied by ownership of the fork (you forked it; you saw it then).

Jump to

Keyboard shortcuts

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