domain

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Jun 13, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package domain holds Githome's business logic and value objects. It sits between the API surface and the store: handlers call domain services, domain services call the store, and the result is a domain value the presenter renders. The single dependency path is api -> domain -> store; domain never imports api or presenter.

Index

Constants

View Source
const (
	RollupError    = "ERROR"
	RollupFailure  = "FAILURE"
	RollupPending  = "PENDING"
	RollupSuccess  = "SUCCESS"
	RollupExpected = "EXPECTED"
)

Rollup and combined-status states, worst first. A rollup takes the worst state present across every status and check run; the combined status uses the statuses-only subset (error folds into failure there).

View Source
const (
	EventPush                     = "push"
	EventIssues                   = "issues"
	EventIssueComment             = "issue_comment"
	EventPullRequest              = "pull_request"
	EventPullRequestReview        = "pull_request_review"
	EventPullRequestReviewComment = "pull_request_review_comment"
	EventRelease                  = "release"
	EventCreate                   = "create" // branch or tag created via REST or push
	EventDelete                   = "delete" // branch or tag deleted via REST or push
	EventRepositoryDispatch       = "repository_dispatch"
)

Webhook and Events API event names. These are the GitHub event identifiers the X-GitHub-Event delivery header and the Events API "type" both derive from.

View Source
const (
	JobDeliverEvent   = "deliver_event"
	JobDeliverWebhook = "deliver_webhook"
)

The fan-out job kinds the webhook milestone introduces. deliver_event loads one recorded event, renders its payload, and enqueues a delivery per subscribed hook; deliver_webhook performs one POST and records the result. The handlers live in the webhook package, which may import domain and presenter as a leaf consumer; defining the kinds here keeps the producer and the constants together the same way the push and recompute kinds are.

View Source
const (
	JobReindexSearch           = "reindex_search"
	JobRecomputeMergeability   = "recompute_mergeability"
	JobRecomputeReviewDecision = "recompute_review_decision"
)

The job kinds the push sink enqueues. The workers that consume them land with the milestones that own each kind (webhook fan-out in M7, mergeability in M5, search in a later pass); defining the kinds here, where they are produced, lets the worker package depend on domain rather than the other way around.

View Source
const (
	ReviewPending          = "PENDING"
	ReviewApproved         = "APPROVED"
	ReviewChangesRequested = "CHANGES_REQUESTED"
	ReviewCommented        = "COMMENTED"
	ReviewDismissed        = "DISMISSED"
)

Review states, the values a review row carries and the API renders.

View Source
const (
	EventApprove        = "APPROVE"
	EventRequestChanges = "REQUEST_CHANGES"
	EventComment        = "COMMENT"
)

Review events, the verbs a submit names (the gh pr review flags map onto them).

View Source
const MaxCompareCommits = 250

MaxCompareCommits caps how many commits a comparison loads, GitHub's own compare ceiling. A compare across a release boundary can span tens of thousands of commits; listing every one before render is unbounded work for a page nobody scrolls to the end of.

View Source
const OrgHookRepo = "_org"

OrgHookRepo is the name of the synthetic repository an organization's hooks anchor on. Org hooks reuse the repo hook storage wholesale: they live on a hidden {org}/_org repository row created on first use, and the fan-out side looks the anchor up by this name to deliver an org's repo events to them.

View Source
const ZeroSHA = "0000000000000000000000000000000000000000"

ZeroSHA is the all-zero object id git uses in a post-receive line to mark a created ref (as the old value) or a deleted ref (as the new value).

Variables

View Source
var (
	// ErrForbidden is returned when the actor may see the repository but not
	// write to it.
	ErrForbidden = errors.New("domain: write access denied")

	// ErrInvalidRef is returned for a ref name that is not a fully qualified,
	// well-formed reference.
	ErrInvalidRef = errors.New("domain: invalid reference name")

	// ErrRefExists is returned by CreateRef when the reference already exists.
	ErrRefExists = errors.New("domain: reference already exists")

	// ErrRefNotFound is returned by UpdateRef when the reference does not exist.
	ErrRefNotFound = errors.New("domain: reference not found")

	// ErrObjectMissing is returned when the target sha is not an object in the
	// repository.
	ErrObjectMissing = errors.New("domain: target object does not exist")

	// ErrNotFastForward is returned when a non-force update would not be a
	// fast-forward.
	ErrNotFastForward = errors.New("domain: update is not a fast-forward")
)

The git-ref write errors the REST layer maps to status: a forbidden write on a visible repository is a 403, an invalid ref name or a missing target object is a 422, an already-existing ref on create and a non-fast-forward update without force are 422 (GitHub reports both as unprocessable).

View Source
var (
	// ErrIssueNotFound is returned when no issue matches the lookup in a visible
	// repository.
	ErrIssueNotFound = errors.New("domain: issue not found")

	// ErrCommentNotFound is returned when no comment matches the lookup.
	ErrCommentNotFound = errors.New("domain: comment not found")

	// ErrLabelNotFound is returned when no label matches the lookup.
	ErrLabelNotFound = errors.New("domain: label not found")

	// ErrMilestoneNotFound is returned when no milestone matches the lookup.
	ErrMilestoneNotFound = errors.New("domain: milestone not found")

	// ErrValidation is returned for an edit that violates a field rule (an empty
	// title, an unknown state, a bad reaction content).
	ErrValidation = errors.New("domain: validation failed")

	// ErrLabelExists is returned by CreateLabel when the name is already taken.
	ErrLabelExists = errors.New("domain: label already exists")
)

The issue service errors the REST and GraphQL layers map to status. An issue in an invisible repository is reported as not found through the repository resolution, so the repo's existence never leaks; a missing issue in a visible repository is ErrIssueNotFound (404). A write the actor may not perform is ErrForbidden (403, reusing the git-write sentinel); a malformed edit is ErrValidation (422).

View Source
var (
	// ErrInvalidSSHKey is returned when the provided public key cannot be parsed.
	ErrInvalidSSHKey = errors.New("domain: invalid SSH public key")
	// ErrDuplicateKey is returned when the fingerprint is already registered.
	ErrDuplicateKey = errors.New("domain: SSH key fingerprint already in use")
	// ErrNotFound is returned when a keyed lookup finds no matching row.
	ErrNotFound = errors.New("domain: not found")
)
View Source
var (
	// ErrPullNotFound is returned when no pull request matches the lookup in a
	// visible repository.
	ErrPullNotFound = errors.New("domain: pull request not found")

	// ErrNotMergeable is returned when a pull request cannot be merged: it is
	// closed, already merged, conflicting, or has nothing to merge.
	ErrNotMergeable = errors.New("domain: pull request is not mergeable")

	// ErrHeadMismatch is returned when a merge's expected head sha does not match
	// the pull request's current head.
	ErrHeadMismatch = errors.New("domain: head sha does not match")

	// ErrInvalidMergeMethod is returned for a merge_method other than merge,
	// squash, or rebase.
	ErrInvalidMergeMethod = errors.New("domain: invalid merge method")

	// ErrReviewerNotFound is returned when a requested reviewer login does not
	// resolve to a user.
	ErrReviewerNotFound = errors.New("domain: requested reviewer not found")

	// ErrNoBaseUpdates is returned by UpdateBranch when the head branch already
	// contains the base branch's tip, so there is nothing to merge down.
	ErrNoBaseUpdates = errors.New("domain: no new commits on the base branch")

	// ErrReviewerIsAuthor is returned when a review is requested from the pull
	// request's own author.
	ErrReviewerIsAuthor = errors.New("domain: review cannot be requested from the author")
)

The pull request service errors the REST and GraphQL layers map to status. A pull request missing in a visible repository is ErrPullNotFound (404); a merge of a pull request that cannot land (closed, already merged, conflicting, or nothing to merge) is ErrNotMergeable (405); a merge whose expected head sha no longer matches is ErrHeadMismatch (409); a bad merge_method is ErrInvalidMergeMethod (422). Forbidden writes and validation reuse the shared sentinels.

View Source
var (
	// ErrMergeConflict is returned when a branch merge cannot apply cleanly. The
	// REST layer maps it to 409 Conflict.
	ErrMergeConflict = errors.New("domain: merge conflict")
	// ErrNothingToMerge is returned when the base branch already contains the
	// head, so the merge is a no-op. The REST layer maps it to 204 No Content.
	ErrNothingToMerge = errors.New("domain: nothing to merge")
	// ErrMergeMissing is returned when the base or head a branch merge names
	// cannot be resolved to a commit. The REST layer maps it to 404 Not Found.
	ErrMergeMissing = errors.New("domain: merge base or head not found")
)
View Source
var (
	// ErrRepoNotFound is returned when no repository matches the lookup or the
	// actor is not allowed to see it.
	ErrRepoNotFound = errors.New("domain: repository not found")

	// ErrGitNotFound is returned when a ref, revision, object id, or path does
	// not resolve within a repository.
	ErrGitNotFound = errors.New("domain: git object or path not found")

	// ErrEmptyRepo is returned by head-dependent reads on a repository that has
	// no commits yet.
	ErrEmptyRepo = errors.New("domain: repository is empty")

	// ErrBlobTooLarge is returned when a blob or file read exceeds the server's
	// blob size ceiling. The REST layer maps it to a 403 too_large.
	ErrBlobTooLarge = errors.New("domain: blob exceeds size limit")

	// ErrConflict is returned by a file write whose CurrentBlobSHA no longer
	// matches the blob at the path. The REST layer maps it to GitHub's 409.
	ErrConflict = errors.New("domain: current blob sha mismatch")

	// ErrRepoExists is returned when a create or fork would claim a name the
	// target account already uses for an unrelated repository.
	ErrRepoExists = errors.New("domain: repository name already exists")
)

The repo service errors. The REST layer maps them to status: a repository the actor cannot see is reported as not found rather than forbidden, so a private repo's existence never leaks through a 403. An empty repository is not an error for branch and tag listings (they come back empty) but is a 404 for the commit, tree, blob, and contents reads that need a head commit.

View Source
var (
	// ErrReviewNotFound is returned when no review or review comment matches the
	// lookup in a visible repository.
	ErrReviewNotFound = errors.New("domain: review not found")

	// ErrPendingReviewExists is returned when a user who already holds a pending
	// review draft on a pull request tries to open a second one.
	ErrPendingReviewExists = errors.New("domain: a pending review already exists")
)

The review service errors the REST and GraphQL layers map to status. A review or comment missing in a visible repository is ErrReviewNotFound (404); an anchor that is not part of the pull request's diff, a missing body where one is required, or an attempt to self-approve is ErrValidation (422). Forbidden writes reuse the shared ErrForbidden.

View Source
var ErrCheckNotFound = errors.New("domain: check run not found")

ErrCheckNotFound is returned when no check run matches the lookup in a visible repository.

View Source
var ErrGistCommentNotFound = errors.New("domain: gist comment not found")

ErrGistCommentNotFound is returned when a gist comment cannot be found, or names a comment on a different gist than the one in the request path.

View Source
var ErrGistNotFound = errors.New("domain: gist not found")

ErrGistNotFound is returned when a gist cannot be found.

View Source
var ErrHookNotFound = errors.New("domain: hook not found")

ErrHookNotFound is returned when no webhook or delivery matches the lookup in a repository the actor administers.

View Source
var ErrReleaseAssetNotFound = errors.New("domain: release asset not found")

ErrReleaseAssetNotFound is returned when a release asset cannot be found.

View Source
var ErrReleaseNotFound = errors.New("domain: release not found")

ErrReleaseNotFound is returned when a release cannot be found.

View Source
var ErrReleaseTagTaken = errors.New("domain: release tag already exists")

ErrReleaseTagTaken is returned when a release tag already exists.

View Source
var ErrSearchScopeRequired = errors.New("domain: code search requires a repo, user, or org qualifier")

ErrSearchScopeRequired is returned by the code search when the query names no repository or owner to scope the walk. GitHub rejects an unscoped code search the same way, since it cannot grep every repository on the host; the REST layer maps this to 422.

View Source
var ErrUserNotFound = errors.New("domain: user not found")

ErrUserNotFound is returned when no account matches the lookup.

Functions

func GitignoreTemplate added in v0.1.3

func GitignoreTemplate(name string) (string, bool)

GitignoreTemplate returns the .gitignore body for the named template. The lookup is case-insensitive; GitHub's canonical names are capitalized ("Go", "Python") but clients frequently send lowercase.

Types

type Batcher added in v0.1.1

type Batcher struct {
	// contains filtered or unexported fields
}

Batcher provides cross-domain batch loading for the GraphQL dataloaders. It is stateless; per-request memoization is handled by the dataloaders. The methods return domain types so the GraphQL layer never imports the store.

func NewBatcher added in v0.1.1

func NewBatcher(s batcherStore) *Batcher

NewBatcher returns a Batcher backed by s.

func (*Batcher) AssigneesByIssues added in v0.1.1

func (b *Batcher) AssigneesByIssues(ctx context.Context, issuePKs []int64) (map[int64][]*User, error)

AssigneesByIssues loads assignees for the given issue PKs. It resolves assignee user PKs in one additional batch load. Returns a map from issue PK to the ordered slice of domain Users.

func (*Batcher) CommentsPreviewByIssues added in v0.1.3

func (b *Batcher) CommentsPreviewByIssues(ctx context.Context, issuePKs []int64, limit int) (map[int64][]*Comment, error)

CommentsPreviewByIssues loads the first limit comments of every listed issue, chronological within each, with authors and reaction rollups batch-loaded alongside. It backs the GraphQL comment-preview dataloader, so a 50-issue connection selecting comments(first: 5) per node costs three queries instead of fifty list calls each with its own author lookups. The returned comments carry a zero IssueNumber: the caller asked per issue and fills it in before rendering.

func (*Batcher) LabelsByIssues added in v0.1.1

func (b *Batcher) LabelsByIssues(ctx context.Context, issuePKs []int64) (map[int64][]*Label, error)

LabelsByIssues loads labels for the given issue PKs and returns a map from issue PK to the ordered slice of domain Labels.

func (*Batcher) Users added in v0.1.1

func (b *Batcher) Users(ctx context.Context, pks []int64) (map[int64]*User, error)

Users loads users by primary key and returns a map from PK to domain User. PKs that have no live row are absent from the map (ghost authors).

type CheckRun

type CheckRun struct {
	PK      int64
	ID      int64
	SuitePK int64
	// SuiteID is the public id of the run's suite, the value the response's
	// check_suite reference carries so it round-trips through
	// GET /check-suites/{id}.
	SuiteID          int64
	RepoPK           int64
	HeadSHA          string
	Name             string
	Status           string
	Conclusion       *string
	DetailsURL       *string
	ExternalID       *string
	OutputTitle      *string
	OutputSummary    *string
	OutputText       *string
	StartedAt        *time.Time
	CompletedAt      *time.Time
	Actions          []CheckRunAction
	AnnotationsCount int
	CreatedAt        time.Time
	UpdatedAt        time.Time
}

CheckRun is one named check against a head sha inside a suite. Status is queued, in_progress, or completed; Conclusion is set once completed.

type CheckRunAction added in v0.1.3

type CheckRunAction struct {
	Label       string `json:"label"`
	Description string `json:"description"`
	Identifier  string `json:"identifier"`
}

CheckRunAction is one requested action button a check run offers, echoed back exactly as the reporter wrote it.

type CheckRunAnnotation added in v0.1.3

type CheckRunAnnotation struct {
	PK              int64
	CheckRunPK      int64
	Path            string
	StartLine       int64
	EndLine         int64
	StartColumn     *int64
	EndColumn       *int64
	AnnotationLevel string
	Message         string
	Title           *string
	RawDetails      *string
}

CheckRunAnnotation is one line-anchored note a check run attaches to a file. Annotations accumulate across check run updates.

type CheckRunInput

type CheckRunInput struct {
	Name          string
	HeadSHA       string
	Status        string
	Conclusion    string
	DetailsURL    string
	ExternalID    string
	OutputTitle   string
	OutputSummary string
	OutputText    string
	StartedAt     *time.Time
	CompletedAt   *time.Time
	Actions       []CheckRunAction
	Annotations   []CheckRunAnnotation
}

CheckRunInput is the create or update payload for a check run. StartedAt and CompletedAt override the stamped times when the reporter supplies its own; Actions replaces the run's action set when non-nil; Annotations append to the run's accumulated annotations.

type CheckSuite

type CheckSuite struct {
	PK         int64
	ID         int64
	RepoPK     int64
	HeadSHA    string
	AppSlug    string
	Status     string
	Conclusion *string
	Runs       []*CheckRun
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

CheckSuite is the per-app container for the check runs reported against a head sha.

type ChecksService

type ChecksService struct {
	// contains filtered or unexported fields
}

ChecksService implements the commit status and check run subsystem. Both are reported against a head sha by a client with write access and read back per sha to form the combined status and the status check rollup. The service leans on the repo service for visibility and authorization and on the git store to resolve a ref to the sha a status or check anchors to.

func NewChecksService

func NewChecksService(st checksStore, repos *RepoService, issues *IssueService, gs *git.Store) *ChecksService

NewChecksService builds a ChecksService over the store, the repo and issue services, and the git store.

func (*ChecksService) CheckRunRef added in v0.1.3

func (s *ChecksService) CheckRunRef(ctx context.Context, runDBID int64) (owner, repoName string, err error)

CheckRunRef resolves a check run by its public database ID and returns the owner login and repository name GetCheckRun takes. The GraphQL node() resolver uses it to turn a check-run node id back into an addressable run; GetCheckRun then enforces visibility.

func (*ChecksService) CombinedStatus

func (s *ChecksService) CombinedStatus(ctx context.Context, viewerPK int64, owner, name, ref string) (*CombinedStatus, error)

CombinedStatus folds the latest status per context against a ref into one state, the body of the combined-status endpoint.

func (*ChecksService) CreateCheckRun

func (s *ChecksService) CreateCheckRun(ctx context.Context, actorPK int64, owner, name string, in CheckRunInput) (*CheckRun, error)

CreateCheckRun reports a check run against a head sha, resolving or creating its suite first. It needs write access.

func (*ChecksService) CreateCheckSuite added in v0.1.3

func (s *ChecksService) CreateCheckSuite(ctx context.Context, actorPK int64, owner, name, headSHA string) (*CheckSuite, error)

CreateCheckSuite creates (or returns) the suite for a head sha, the POST /check-suites contract. The unique (repo, sha, app) key makes a re-create return the existing suite with its real id. It needs write access.

func (*ChecksService) CreateStatus

func (s *ChecksService) CreateStatus(ctx context.Context, actorPK int64, owner, name, sha string, in StatusInput) (*CommitStatus, error)

CreateStatus reports a commit status against a sha. It needs write access, validates the state, writes the row, and enqueues a decision recompute for every open pull request whose head is that sha so their rollup refreshes.

func (*ChecksService) GetCheckRun

func (s *ChecksService) GetCheckRun(ctx context.Context, viewerPK int64, owner, name string, runDBID int64) (*CheckRun, error)

GetCheckRun resolves one check run by id for the viewer.

func (*ChecksService) GetCheckSuite added in v0.1.3

func (s *ChecksService) GetCheckSuite(ctx context.Context, viewerPK int64, owner, name string, suiteDBID int64) (*CheckSuite, error)

GetCheckSuite resolves one check suite by its public id for the viewer, carrying its check runs.

func (*ChecksService) ListCheckRunAnnotations added in v0.1.3

func (s *ChecksService) ListCheckRunAnnotations(ctx context.Context, viewerPK int64, owner, name string, runDBID int64) ([]*CheckRunAnnotation, error)

ListCheckRunAnnotations returns a check run's accumulated annotations for the viewer, the body of GET /check-runs/{id}/annotations.

func (*ChecksService) ListCheckRuns

func (s *ChecksService) ListCheckRuns(ctx context.Context, viewerPK int64, owner, name, ref string) ([]*CheckRun, string, error)

ListCheckRuns returns every check run reported against a ref for the viewer.

func (*ChecksService) ListCheckSuites

func (s *ChecksService) ListCheckSuites(ctx context.Context, viewerPK int64, owner, name, ref string) ([]*CheckSuite, string, error)

ListCheckSuites returns the check suites reported against a ref for the viewer, each carrying its check runs.

func (*ChecksService) ListStatuses

func (s *ChecksService) ListStatuses(ctx context.Context, viewerPK int64, owner, name, ref string) ([]*CommitStatus, string, error)

ListStatuses returns every status reported against a ref for the viewer.

func (*ChecksService) RerequestCheckRun added in v0.1.3

func (s *ChecksService) RerequestCheckRun(ctx context.Context, actorPK int64, owner, name string, runDBID int64) error

RerequestCheckRun resets a finished check run back to queued, the transition POST /check-runs/{id}/rerequest performs so a reporter runs it again. It needs write access.

func (*ChecksService) RerequestCheckSuite added in v0.1.3

func (s *ChecksService) RerequestCheckSuite(ctx context.Context, actorPK int64, owner, name string, suiteDBID int64) error

RerequestCheckSuite resets a suite and every run inside it back to queued, the transition POST /check-suites/{id}/rerequest performs. It needs write access.

func (*ChecksService) Rollup

func (s *ChecksService) Rollup(ctx context.Context, viewerPK int64, owner, name, ref string) (*StatusCheckRollup, error)

Rollup folds a ref's statuses and check runs into the status check rollup for the viewer, the value the pull request and its head commit surface.

func (*ChecksService) RollupForPull

func (s *ChecksService) RollupForPull(ctx context.Context, repo *Repo, headSHA string) (*StatusCheckRollup, error)

RollupForPull builds the rollup at a pull request's recorded head, the path the GraphQL pull request resolver takes without re-resolving a ref.

func (*ChecksService) SuitesForPull added in v0.1.3

func (s *ChecksService) SuitesForPull(ctx context.Context, repo *Repo, headSHA string) ([]*CheckSuite, error)

SuitesForPull lists the check suites at a pull request's recorded head, each carrying its check runs, the path the PR Checks tab takes without re-resolving a ref. The caller already read-gated the repository, the same contract RollupForPull holds.

func (*ChecksService) UpdateCheckRun

func (s *ChecksService) UpdateCheckRun(ctx context.Context, actorPK int64, owner, name string, runDBID int64, in CheckRunInput) (*CheckRun, error)

UpdateCheckRun rolls a check run forward, the transition a run finishing or reporting progress performs. It needs write access.

type CodeResult

type CodeResult struct {
	Repo *Repo
	Path string
	Name string
	SHA  string
}

CodeResult is one matching file from a code search: the repository it lives in, its path within the head tree, and the blob's object id. The presenter renders the GitHub code-search item (name, path, sha, urls, repository) from it.

type CodeownerError added in v0.1.3

type CodeownerError struct {
	Line       int
	Column     int
	Kind       string
	Source     string
	Suggestion string
	Message    string
	Path       string
}

CodeownerError is one problem found while validating a CODEOWNERS file: the 1-based line, the offending source text, a short kind, a human message, and a suggested fix, matching the shape GitHub's codeowners/errors endpoint returns.

type CombinedStatus

type CombinedStatus struct {
	State      string // failure | pending | success
	SHA        string
	TotalCount int
	Statuses   []*CommitStatus
	Repo       *Repo
}

CombinedStatus folds the latest status per context into one state, the body of the combined-status endpoint. TotalCount is the number of contributing statuses; Statuses is the latest one per context.

type Comment

type Comment struct {
	ID          int64
	IssuePK     int64
	IssueNumber int64
	User        *User
	Body        string
	Reactions   ReactionRollup
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

Comment is the domain view of an issue comment. IssueNumber is the per-repo number of the issue the comment belongs to, carried so the presenter can build the comment's issue and html URLs without a second lookup.

type CommitStatus

type CommitStatus struct {
	PK          int64
	ID          int64
	RepoPK      int64
	SHA         string
	State       string // error | failure | pending | success
	Context     string
	TargetURL   *string
	Description *string
	Creator     *User
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

CommitStatus is one external report against a sha under a context.

type CommunityFile added in v0.1.3

type CommunityFile struct {
	Path string
}

CommunityFile is one community-health file the profile reports: its path in the repository at the default branch. The presenter expands it into the {url, html_url} object GitHub returns; an absent file is a nil pointer.

type CommunityProfile added in v0.1.3

type CommunityProfile struct {
	HealthPercentage    int
	HasDescription      bool
	CodeOfConduct       *CommunityFile
	Contributing        *CommunityFile
	IssueTemplate       *CommunityFile
	PullRequestTemplate *CommunityFile
	License             *CommunityFile
	Readme              *CommunityFile
}

CommunityProfile is the repository's community-health summary: which of the recommended files are present at the default branch and a percentage over the checks GitHub counts (description, readme, code of conduct, contributing, license, issue template, pull request template). It backs GET /repos/{owner}/{repo}/community/profile.

type CompareResult added in v0.1.3

type CompareResult struct {
	Base         git.Branch
	Head         git.Branch
	MergeBase    git.SHA
	Commits      []git.Commit
	TotalCommits int
	Behind       int
	Files        []git.FileChange
	Additions    int
	Deletions    int
	ChangedFiles int

	// BaseCommit and MergeBaseCommit are the full commit objects the compare
	// endpoint renders as base_commit and merge_base_commit. MergeBaseCommit
	// is zero when the two ends share no history.
	BaseCommit      git.Commit
	MergeBaseCommit git.Commit
}

CompareResult is the three-dot comparison between two branches. Files and Commits are the unique changes from base to head; Additions, Deletions, and ChangedFiles are the aggregated line counts. Commits is capped at MaxCompareCommits; TotalCommits is the real size of the range, so a capped result still reports honest counts.

type CreateDeletePayload added in v0.1.3

type CreateDeletePayload struct {
	Ref          string `json:"ref"`
	RefType      string `json:"ref_type"` // "branch" or "tag"
	MasterBranch string `json:"master_branch,omitempty"`
}

CreateDeletePayload carries the ref detail for create and delete webhook events. RefType is "branch" or "tag"; MasterBranch is only meaningful on create events.

type DeliverEventPayload

type DeliverEventPayload struct {
	EventPK      int64                `json:"event_pk"`
	Push         *PushPayload         `json:"push,omitempty"`
	CreateDelete *CreateDeletePayload `json:"create_delete,omitempty"`
	Detail       *EventDetail         `json:"detail,omitempty"`
}

DeliverEventPayload is the body of a deliver_event job: the recorded event to fan out, plus event-type-specific detail that has no home in a table and so rides along.

type DeliverWebhookPayload

type DeliverWebhookPayload struct {
	WebhookPK    int64                `json:"webhook_pk"`
	EventPK      int64                `json:"event_pk"`
	Push         *PushPayload         `json:"push,omitempty"`
	CreateDelete *CreateDeletePayload `json:"create_delete,omitempty"`
	Detail       *EventDetail         `json:"detail,omitempty"`
	RedeliverOf  int64                `json:"redeliver_of,omitempty"`
	Ping         bool                 `json:"ping,omitempty"`
	SenderPK     int64                `json:"sender_pk,omitempty"`
}

DeliverWebhookPayload is the body of a deliver_webhook job: the hook to POST to and the event whose body to render and send. Push carries the moved refs a push event has no table to reload from, propagated from the deliver_event job so each hook's body renders the same push. CreateDelete carries ref detail for create/delete events. RedeliverOf, when set, replays a recorded delivery instead of rendering the event afresh. Ping, when set, sends the ping body instead of an event: there is no event row, so EventPK is zero and SenderPK names the actor who triggered it.

type Event

type Event struct {
	ID        int64
	Type      string
	Actor     *User
	Repo      *Repo
	Payload   json.RawMessage
	Public    bool
	CreatedAt time.Time
}

Event is the domain view of one activity-feed entry: the resolved actor and repository, the GitHub event type, and the payload object the fan-out worker rendered and stored. Payload is the raw JSON the feed serves verbatim.

type EventDetail added in v0.1.3

type EventDetail struct {
	CommentPK       int64  `json:"comment_pk,omitempty"`
	ReviewPK        int64  `json:"review_pk,omitempty"`
	ReviewCommentPK int64  `json:"review_comment_pk,omitempty"`
	ReleasePK       int64  `json:"release_pk,omitempty"`
	Label           string `json:"label,omitempty"`
	Before          string `json:"before,omitempty"`
	After           string `json:"after,omitempty"`

	// Action and ClientPayload carry a repository_dispatch's caller-chosen event
	// type and opaque client payload, the two fields that event has no column
	// for. ClientPayload is the verbatim JSON the dispatch named.
	Action        string          `json:"action,omitempty"`
	ClientPayload json.RawMessage `json:"client_payload,omitempty"`
}

EventDetail pins the secondary coordinates some events render from and that have no column on the event row: the comment, review, or release the body embeds, the label a labeled action names, and the moved head shas a pull_request synchronize reports at the top level as before/after.

type EventService

type EventService struct {
	// contains filtered or unexported fields
}

EventService serves the pull-based activity feed: the global public timeline, a repository's timeline (gated by the same visibility rule as every other repo read), and a user's timeline. It reads the rendered payload the fan-out worker stored on each event, so the feed never re-derives what a delivery already built.

func NewEventService

func NewEventService(st EventStore, repos *RepoService) *EventService

NewEventService builds an EventService over the store and the repo service.

func (*EventService) OrgFeed added in v0.1.3

func (s *EventService) OrgFeed(ctx context.Context, viewerPK int64, org string, perPage int) ([]Event, error)

OrgFeed returns the timeline of an organization: the events on every repository the org owns. The org account itself (or a site admin viewer) sees private activity; every other viewer sees only the public subset. It backs GET /orgs/{org}/events.

func (*EventService) PublicFeed

func (s *EventService) PublicFeed(ctx context.Context, perPage int) ([]Event, error)

PublicFeed returns the global public timeline: events on public repositories that are themselves public, newest first.

func (*EventService) PublicUserFeed added in v0.1.3

func (s *EventService) PublicUserFeed(ctx context.Context, login string, perPage int) ([]Event, error)

PublicUserFeed returns the public events a user performed, regardless of who is viewing. It backs GET /users/{u}/events/public, which never exposes private activity even to the account itself.

func (*EventService) ReceivedFeed added in v0.1.3

func (s *EventService) ReceivedFeed(ctx context.Context, login string, perPage int, _ bool) ([]Event, error)

ReceivedFeed returns the events a user receives in their dashboard timeline. Githome does not model a follow graph yet, so the received feed degrades to the global public timeline: the activity any account would see before following anyone. The publicOnly flag is accepted for the /received_events/public twin and is a no-op while the feed is already public. It backs GET /users/{u}/received_events[/public].

func (*EventService) RepoFeed

func (s *EventService) RepoFeed(ctx context.Context, viewerPK int64, owner, name string, perPage int) ([]Event, error)

RepoFeed returns a repository's timeline. The visibility check is the repo service's: a viewer who cannot see the repository gets ErrRepoNotFound, never a leak, and a viewer who can see a private repository sees its private events.

func (*EventService) UserFeed

func (s *EventService) UserFeed(ctx context.Context, viewerPK int64, login string, perPage int) ([]Event, error)

UserFeed returns the events a user performed. A viewer reading their own feed sees their private activity; any other viewer sees only the public subset.

type EventStore

type EventStore interface {
	ListEvents(ctx context.Context, f store.EventFilter) ([]store.EventRow, error)
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
}

EventStore is the slice of the store the activity feed reads through: the scoped event list, the login lookup the per-user feed resolves an actor by, and the by-pk lookups that resolve each event's actor and repository into the compact objects the feed embeds.

type ForkInput added in v0.1.3

type ForkInput struct {
	Organization      string
	Name              string
	DefaultBranchOnly bool
}

ForkInput holds the caller-supplied options for forking a repository. Organization names the target account when the fork should land under an org the viewer administers; empty forks under the viewer. Name renames the fork; empty keeps the source's name. DefaultBranchOnly copies just the source's default branch instead of every ref.

type GenerateNotesInput added in v0.1.3

type GenerateNotesInput struct {
	TagName         string
	TargetCommitish string
	PreviousTagName string
}

GenerateNotesInput is the request for automatic release-notes generation.

type GeneratedNotes added in v0.1.3

type GeneratedNotes struct {
	TagName         string
	PreviousTagName string
	Commits         []git.Commit
}

GeneratedNotes carries the material for automatic release notes: the commits landing in the release and the previous tag the range was cut against, empty when the repository has no earlier release to diff from.

type GistFileUpdate added in v0.1.3

type GistFileUpdate struct {
	Content *string
	NewName *string
}

GistFileUpdate is one file entry in a gist update. Content replaces the file body; NewName renames the file, keeping its content unless Content is also given.

type GistInput added in v0.1.3

type GistInput struct {
	Description string
	Public      bool
	Files       map[string]string // filename → content
}

GistInput is the create payload for a gist.

type GistService added in v0.1.3

type GistService struct {
	// contains filtered or unexported fields
}

GistService manages gists and their files.

func NewGistService added in v0.1.3

func NewGistService(st GistStore) *GistService

NewGistService builds a GistService.

func (*GistService) CreateGist added in v0.1.3

func (s *GistService) CreateGist(ctx context.Context, userPK int64, in GistInput) (*store.GistRow, error)

CreateGist creates a new gist owned by userPK.

func (*GistService) CreateGistComment added in v0.1.3

func (s *GistService) CreateGistComment(ctx context.Context, gistID string, callerPK int64, body string) (*store.GistCommentRow, error)

CreateGistComment adds a comment to a gist.

func (*GistService) DeleteGist added in v0.1.3

func (s *GistService) DeleteGist(ctx context.Context, gistID string, callerPK int64) error

DeleteGist removes a gist owned by callerPK.

func (*GistService) DeleteGistComment added in v0.1.3

func (s *GistService) DeleteGistComment(ctx context.Context, gistID string, commentPK, callerPK int64) error

DeleteGistComment removes a comment. Only the comment author may delete.

func (*GistService) GetGist added in v0.1.3

func (s *GistService) GetGist(ctx context.Context, gistID string, callerPK int64) (*store.GistRow, error)

GetGist loads a gist by its hex ID, checking visibility for callerPK. callerPK == 0 means anonymous.

func (*GistService) GetGistComment added in v0.1.3

func (s *GistService) GetGistComment(ctx context.Context, gistID string, commentPK, callerPK int64) (*store.GistCommentRow, error)

GetGistComment returns one comment on a gist the caller can see.

func (*GistService) IsGistStarred added in v0.1.3

func (s *GistService) IsGistStarred(ctx context.Context, gistID string, callerPK int64) (bool, error)

IsGistStarred reports whether callerPK has starred gistID.

func (*GistService) ListAuthUserGists added in v0.1.3

func (s *GistService) ListAuthUserGists(ctx context.Context, userPK int64, page, perPage int) ([]*store.GistRow, int, error)

ListAuthUserGists returns all gists (public+private) for the authenticated user.

func (*GistService) ListGistComments added in v0.1.3

func (s *GistService) ListGistComments(ctx context.Context, gistID string, callerPK int64) ([]store.GistCommentRow, error)

ListGistComments returns all comments for a gist.

func (*GistService) ListPublicGists added in v0.1.3

func (s *GistService) ListPublicGists(ctx context.Context, page, perPage int) ([]*store.GistRow, int, error)

ListPublicGists returns public gists in update order.

func (*GistService) ListStarredGists added in v0.1.3

func (s *GistService) ListStarredGists(ctx context.Context, userPK int64, page, perPage int) ([]*store.GistRow, int, error)

ListStarredGists returns gists starred by userPK.

func (*GistService) ListUserGists added in v0.1.3

func (s *GistService) ListUserGists(ctx context.Context, ownerLogin string, callerPK int64, page, perPage int) ([]*store.GistRow, int, error)

ListUserGists returns gists for owner login. If callerPK != ownerPK, only public gists are returned.

func (*GistService) StarGist added in v0.1.3

func (s *GistService) StarGist(ctx context.Context, gistID string, callerPK int64) error

StarGist stars a gist for callerPK.

func (*GistService) UnstarGist added in v0.1.3

func (s *GistService) UnstarGist(ctx context.Context, gistID string, callerPK int64) error

UnstarGist removes the star.

func (*GistService) UpdateGist added in v0.1.3

func (s *GistService) UpdateGist(ctx context.Context, gistID string, callerPK int64, in GistUpdateInput) (*store.GistRow, error)

UpdateGist modifies a gist's description and/or files.

func (*GistService) UpdateGistComment added in v0.1.3

func (s *GistService) UpdateGistComment(ctx context.Context, gistID string, commentPK, callerPK int64, body string) (*store.GistCommentRow, error)

UpdateGistComment rewrites a comment's body. Only the comment author may edit.

type GistStore added in v0.1.3

type GistStore interface {
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	InsertGist(ctx context.Context, g *store.GistRow) error
	GetGistByID(ctx context.Context, gistID string) (*store.GistRow, error)
	ListGistsByOwner(ctx context.Context, ownerPK int64, page, perPage int) ([]*store.GistRow, int, error)
	ListPublicGists(ctx context.Context, page, perPage int) ([]*store.GistRow, int, error)
	ListStarredGists(ctx context.Context, userPK int64, page, perPage int) ([]*store.GistRow, int, error)
	UpdateGist(ctx context.Context, gistPK int64, description *string, files map[string]*string) error
	DeleteGist(ctx context.Context, gistID string) error
	StarGist(ctx context.Context, gistPK, userPK int64) error
	UnstarGist(ctx context.Context, gistPK, userPK int64) error
	IsGistStarred(ctx context.Context, gistPK, userPK int64) (bool, error)
	InsertGistComment(ctx context.Context, c *store.GistCommentRow) error
	ListGistComments(ctx context.Context, gistPK int64) ([]store.GistCommentRow, error)
	GetGistComment(ctx context.Context, commentPK int64) (*store.GistCommentRow, error)
	UpdateGistComment(ctx context.Context, commentPK int64, body string) error
	DeleteGistComment(ctx context.Context, commentPK int64) error
}

GistStore is the store slice the gist service needs.

type GistUpdateInput added in v0.1.3

type GistUpdateInput struct {
	Description *string
	Files       map[string]*GistFileUpdate // filename → change (nil = delete file)
}

GistUpdateInput is the update payload for a gist.

type GitEndpoint

type GitEndpoint struct {
	Label string
	Ref   string
	SHA   string
	Repo  *Repo
	User  *User
}

GitEndpoint is one side of a pull request, a base or a head. Label is the "owner:branch" form GitHub renders; Ref is the short branch name; SHA is the tip the pull request recorded. Repo and User are the repository the ref lives in and its owner; for a same-repository pull request both sides point at the one repository.

type Hook

type Hook struct {
	ID           int64
	Name         string
	Active       bool
	Events       []string
	Config       HookConfig
	LastResponse *HookResponse
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

Hook is the domain view of a repository webhook the API returns. It never carries the signing secret: HasSecret reports only whether one is set, so the secret cannot leak through a presenter. The delivery worker reads the secret straight from the store, off this path.

func HookForDelivery added in v0.1.3

func HookForDelivery(w *store.WebhookRow) *Hook

HookForDelivery maps a stored webhook to its domain view for the delivery worker, which renders the hook object a ping body embeds. It is the same secret-free view every hook read returns.

type HookConfig

type HookConfig struct {
	URL         string
	ContentType string
	InsecureSSL bool
	HasSecret   bool
}

HookConfig is the transport configuration of a hook minus the secret.

type HookDelivery

type HookDelivery struct {
	ID           int64
	GUID         string
	Event        string
	Action       *string
	StatusCode   int
	Status       string
	Duration     float64
	Redelivery   bool
	RepositoryID *int64
	DeliveredAt  time.Time
	Request      *HookDeliveryHTTP
	Response     *HookDeliveryHTTP
}

HookDelivery is the domain view of one recorded delivery attempt. Request and Response are populated only for the single-delivery detail view; the list view leaves them nil.

type HookDeliveryHTTP

type HookDeliveryHTTP struct {
	Headers map[string]string
	Body    string
}

HookDeliveryHTTP is one half (request or response) of a delivery's full record: the headers and the body.

type HookInput

type HookInput struct {
	Name        string
	URL         string
	ContentType string
	Secret      *string
	InsecureSSL bool
	Active      *bool
	Events      []string
}

HookInput is the create payload: the delivery URL, the content type, an optional signing secret, the TLS-verification setting, the active flag, and the subscribed event names. An empty event list defaults to push, matching GitHub.

type HookPatch

type HookPatch struct {
	URL          *string
	ContentType  *string
	Secret       *string
	InsecureSSL  *bool
	Active       *bool
	Events       *[]string
	AddEvents    []string
	RemoveEvents []string
}

HookPatch is the edit payload. A nil field is left unchanged. AddEvents and RemoveEvents adjust the subscription incrementally the way the REST config endpoint does, applied after a wholesale Events replacement.

type HookResponse

type HookResponse struct {
	Code    *int
	Status  string
	Message *string
}

HookResponse summarizes a hook's most recent delivery, the value the API reports as last_response.

type HookService

type HookService struct {
	// contains filtered or unexported fields
}

HookService manages a repository's webhooks. Webhook administration needs the same authority as writing to the repository, so every method authorizes write access first; the secret a hook carries is held but never returned, so the service maps each row to a domain view that omits it.

func NewHookService

func NewHookService(st HookStore, repos *RepoService, enq worker.Enqueuer) *HookService

NewHookService builds a HookService over the store and the repo service.

func (*HookService) CreateHook

func (s *HookService) CreateHook(ctx context.Context, actorPK int64, owner, name string, in HookInput) (*Hook, error)

CreateHook registers a webhook on the repository after authorizing write access and validating the URL and content type.

func (*HookService) CreateOrgHook added in v0.1.3

func (s *HookService) CreateOrgHook(ctx context.Context, actorPK int64, org string, in HookInput) (*Hook, error)

CreateOrgHook registers an organization-level webhook. The hook is stored as a repo hook on the org's synthetic anchor repository, created here on first use, so every read and edit after this goes through the ordinary hook methods addressed at (org, OrgHookRepo).

func (*HookService) DeleteHook

func (s *HookService) DeleteHook(ctx context.Context, actorPK int64, owner, name string, hookID int64) error

DeleteHook removes a webhook and its deliveries.

func (*HookService) GetHook

func (s *HookService) GetHook(ctx context.Context, actorPK int64, owner, name string, hookID int64) (*Hook, error)

GetHook resolves one webhook by its public id, secret omitted.

func (*HookService) GetHookDelivery

func (s *HookService) GetHookDelivery(ctx context.Context, actorPK int64, owner, name string, hookID, deliveryID int64) (*HookDelivery, error)

GetHookDelivery resolves one delivery of a webhook by its public id, with the full request and response record.

func (*HookService) ListHookDeliveries

func (s *HookService) ListHookDeliveries(ctx context.Context, actorPK int64, owner, name string, hookID int64, perPage int) ([]HookDelivery, error)

ListHookDeliveries returns a webhook's recent deliveries, newest first.

func (*HookService) ListHooks

func (s *HookService) ListHooks(ctx context.Context, actorPK int64, owner, name string) ([]Hook, error)

ListHooks returns the repository's webhooks, secrets omitted.

func (*HookService) ListOrgHooks added in v0.1.3

func (s *HookService) ListOrgHooks(ctx context.Context, actorPK int64, org string) ([]Hook, error)

ListOrgHooks returns an organization's webhooks. An org that never created a hook has no anchor repository; that is an empty list, not an error.

func (*HookService) PingHook added in v0.1.3

func (s *HookService) PingHook(ctx context.Context, actorPK int64, owner, name string, hookID int64) error

PingHook submits a ping delivery to the webhook: the {zen, hook_id, hook} body GitHub sends so an endpoint can be exercised without waiting for a real event. The same authorization as every other hook read applies.

func (*HookService) RedeliverHookDelivery

func (s *HookService) RedeliverHookDelivery(ctx context.Context, actorPK int64, owner, name string, hookID, deliveryID int64) error

RedeliverHookDelivery enqueues a replay of a recorded delivery: the worker re-sends the stored request and records a new delivery marked as a redelivery.

func (*HookService) TestHook added in v0.1.3

func (s *HookService) TestHook(ctx context.Context, actorPK int64, owner, name string, hookID int64) error

TestHook fires the hook against the repository's latest push, the way GitHub's tests endpoint exercises a real event rather than the ping body. The hook only receives the delivery when it subscribes to push events (explicitly or through the wildcard); otherwise the call authorizes and returns with no delivery, matching GitHub's 204-but-no-POST behavior. An empty repository has no head to push, so it too is a no-op.

func (*HookService) UpdateHook

func (s *HookService) UpdateHook(ctx context.Context, actorPK int64, owner, name string, hookID int64, p HookPatch) (*Hook, error)

UpdateHook applies a patch to a webhook and returns its domain view.

type HookStore

type HookStore interface {
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	RepoByOwnerName(ctx context.Context, owner, name string) (*store.RepoRow, error)
	InsertRepo(ctx context.Context, r *store.RepoRow) error

	InsertWebhook(ctx context.Context, w *store.WebhookRow) error
	GetWebhookForRepo(ctx context.Context, repoPK, dbID int64) (*store.WebhookRow, error)
	ListWebhooks(ctx context.Context, repoPK int64) ([]store.WebhookRow, error)
	UpdateWebhook(ctx context.Context, w *store.WebhookRow) error
	DeleteWebhook(ctx context.Context, repoPK, dbID int64) error
	ListDeliveries(ctx context.Context, webhookPK int64, limit int) ([]store.WebhookDeliveryRow, error)
	GetDeliveryForWebhook(ctx context.Context, webhookPK, dbID int64) (*store.WebhookDeliveryRow, error)
}

HookStore is the slice of the store the hook service writes and reads through: the webhook CRUD, its delivery history, the queue the redeliver replays through, and the lookups the org-hook anchor repo is resolved and created by.

type Issue

type Issue struct {
	PK     int64
	ID     int64
	RepoPK int64
	RepoID int64

	Number      int64
	Title       string
	Body        *string
	State       string
	StateReason *string
	Locked      bool
	// ActiveLockReason is the reason given when the conversation was locked,
	// one of GitHub's fixed set; nil when unlocked or locked without a reason.
	ActiveLockReason *string
	// IsPull marks the row as a pull request. Issues and pull requests share
	// one number sequence per repository; cross-type listings (search) use it
	// to tell the two apart.
	IsPull bool

	User          *User
	UserPK        int64 // internal PK for the author; zero for a ghost
	Assignees     []*User
	Labels        []*Label
	Milestone     *Milestone
	ClosedBy      *User
	Reactions     ReactionRollup
	CommentsCount int

	ClosedAt  *time.Time
	CreatedAt time.Time
	UpdatedAt time.Time
	// contains filtered or unexported fields
}

Issue is the domain view of an issue, assembled with its author and the related rows GitHub embeds on the issue resource: labels, assignees, the milestone, and the reaction rollup. ID is the public database id (issues.db_id); PK is the internal primary key the service carries for the write paths and never renders. RepoPK and RepoID locate the repository the presenter builds the issue's URLs from.

type IssueEvent added in v0.1.3

type IssueEvent struct {
	ID          int64
	IssueNumber int64
	Event       string
	Actor       *User
	CreatedAt   time.Time
}

IssueEvent is one entry of an issue's event log: an action (closed, reopened, locked, ...) performed by an actor at a point in time. IssueNumber is carried so the presenter can build the event's issue URLs without a second lookup.

type IssueHit

type IssueHit struct {
	Issue *Issue
	Repo  *Repo
}

IssueHit pairs a matched issue with the repository it belongs to, so the presenter can build the issue's URLs (which hang off the owner/name path) without a second lookup. Cross-repository search returns issues from many repositories, none of which is implied by the request path.

type IssueInput

type IssueInput struct {
	Title           string
	Body            *string
	Labels          []string
	AssigneeLogins  []string
	MilestoneNumber *int64
}

IssueInput is the create payload: a title, an optional body, and the labels, assignees, and milestone to attach. Labels and assignees are named (label names, user logins) the way the REST and GraphQL inputs name them; unknown names are skipped, matching GitHub.

type IssuePatch

type IssuePatch struct {
	Title           *string
	Body            *string
	State           *string
	StateReason     *string
	Labels          *[]string
	AssigneeLogins  *[]string
	MilestoneNumber *int64 // a pointer-to-zero clears the milestone
	ClearMilestone  bool
}

IssuePatch is the edit payload. A nil field is left unchanged; a non-nil field is written. State moves through Open/Closed and carries StateReason (completed, not_planned, reopened).

type IssueQuery

type IssueQuery struct {
	State           string
	Labels          []string
	CreatorLogin    string
	AssigneeLogin   string
	MilestoneNumber *int64
	Sort            string
	Direction       string
	Page            int
	PerPage         int
	// Cursor is an opaque token from the previous page's Link header. When set
	// and the sort is "created" DESC (the default), the store uses a keyset
	// seek instead of OFFSET so deep pages are O(1) in depth.
	Cursor string
	// AfterNumber is the per-repo number of the last issue on the previous
	// page, the seek key the GraphQL connection cursors carry. When set (and
	// Cursor is not), the filter resolves it to the issue's created_at with one
	// point read and pages with the same keyset seek a Cursor drives.
	AfterNumber int64
}

IssueQuery narrows the list endpoint.

type IssueService

type IssueService struct {
	// contains filtered or unexported fields
}

IssueService implements the issue subsystem over the store, reusing the repo service for repository resolution so the visibility and write rules stay in one place. Writes that touch several rows run inside one transaction; a create also records an `issues` webhook event in the durable queue, delivered when the webhook milestone lands.

func NewIssueService

func NewIssueService(st IssueStore, repos *RepoService) *IssueService

NewIssueService builds an IssueService over the store and the repo service.

func (*IssueService) AddAssignees added in v0.1.3

func (s *IssueService) AddAssignees(ctx context.Context, actorPK int64, owner, name string, number int64, logins []string) (*Issue, error)

AddAssignees links the given user logins to an issue's assignee list, ignoring logins that are not known.

func (*IssueService) AddLabels added in v0.1.3

func (s *IssueService) AddLabels(ctx context.Context, actorPK int64, owner, name string, number int64, labelNames []string) (*Issue, error)

AddLabels attaches the given label names to an issue, ignoring any that are already attached or do not exist. It is the additive counterpart to the full replacement that EditIssue performs when Labels is set.

func (*IssueService) CommentForEvent added in v0.1.3

func (s *IssueService) CommentForEvent(ctx context.Context, commentPK int64) (*Comment, error)

CommentForEvent loads one issue comment by its internal pk for the delivery renderer, off the visibility gate like every ForEvent loader: the event was authorized when it was recorded.

func (*IssueService) CommentRepoRef added in v0.1.3

func (s *IssueService) CommentRepoRef(ctx context.Context, dbID int64) (owner, repoName string, err error)

CommentRepoRef resolves an issue comment by its public database ID and returns the owner login and repository name GetComment takes. The GraphQL node() resolver uses it to turn a comment node id back into an addressable comment; GetComment then enforces visibility.

func (*IssueService) CountIssues added in v0.1.3

func (s *IssueService) CountIssues(ctx context.Context, viewerPK int64, owner, name string, q IssueQuery) (int, error)

CountIssues returns the total matching the filter without fetching a page. The GraphQL connections pair it with ListIssuesPage: the page itself is a keyset seek and the count stays its own query, resolved once per request for the connection's totalCount.

func (*IssueService) CreateComment

func (s *IssueService) CreateComment(ctx context.Context, actorPK int64, owner, name string, number int64, body string) (*Comment, error)

CreateComment adds a comment to an issue. Any authenticated viewer who can see the repository may comment; the post-receive write rule does not apply, so a reader of a public repository can join the discussion. The comment bumps the issue's cached count in the same transaction the insert runs in.

func (*IssueService) CreateCommentReaction

func (s *IssueService) CreateCommentReaction(ctx context.Context, actorPK int64, owner, name string, commentID int64, content string) (*Reaction, error)

CreateCommentReaction adds the actor's reaction to an issue comment.

func (*IssueService) CreateIssue

func (s *IssueService) CreateIssue(ctx context.Context, actorPK int64, owner, name string, in IssueInput) (*Issue, error)

CreateIssue opens an issue in the repository after authorizing write access. It allocates the per-repo number, inserts the row, attaches the resolved labels and assignees, bumps the repository's open-issue count, and enqueues the `issues` opened event, all in one transaction plus the durable enqueue.

func (*IssueService) CreateIssueReaction

func (s *IssueService) CreateIssueReaction(ctx context.Context, actorPK int64, owner, name string, number int64, content string) (*Reaction, error)

CreateIssueReaction adds the actor's reaction to an issue. The content must be one of GitHub's eight reaction names. Reacting twice with the same content is idempotent: the existing reaction comes back rather than a duplicate.

func (*IssueService) CreateLabel

func (s *IssueService) CreateLabel(ctx context.Context, actorPK int64, owner, name string, in LabelInput) (*Label, error)

CreateLabel adds a label to a repository. Write access is required. A name that already exists (case-insensitively) is a conflict.

func (*IssueService) CreateMilestone

func (s *IssueService) CreateMilestone(ctx context.Context, actorPK int64, owner, name string, in MilestoneInput) (*Milestone, error)

CreateMilestone adds a milestone to a repository. Write access is required.

func (*IssueService) DeleteComment

func (s *IssueService) DeleteComment(ctx context.Context, actorPK int64, owner, name string, commentID int64) error

DeleteComment removes a comment. The author or a user with write access may delete; the issue's cached count is decremented in the store.

func (*IssueService) DeleteCommentReaction

func (s *IssueService) DeleteCommentReaction(ctx context.Context, actorPK int64, owner, name string, commentID, reactionID int64) error

DeleteCommentReaction removes a reaction from a comment by its public id.

func (*IssueService) DeleteIssueReaction

func (s *IssueService) DeleteIssueReaction(ctx context.Context, actorPK int64, owner, name string, number, reactionID int64) error

DeleteIssueReaction removes a reaction from an issue by its public id.

func (*IssueService) DeleteLabel

func (s *IssueService) DeleteLabel(ctx context.Context, actorPK int64, owner, name, label string) error

DeleteLabel removes a label by name.

func (*IssueService) DeleteMilestone

func (s *IssueService) DeleteMilestone(ctx context.Context, actorPK int64, owner, name string, number int64) error

DeleteMilestone removes a milestone by number; issues pointing at it have their milestone cleared by the store's foreign key.

func (*IssueService) EditComment

func (s *IssueService) EditComment(ctx context.Context, actorPK int64, owner, name string, commentID int64, body string) (*Comment, error)

EditComment changes a comment's body. The author or a user with write access to the repository may edit.

func (*IssueService) EditIssue

func (s *IssueService) EditIssue(ctx context.Context, actorPK int64, owner, name string, number int64, p IssuePatch) (*Issue, error)

EditIssue applies a patch to an issue under the optimistic lock, retrying once on a lost race. It writes the state transition (stamping or clearing closed_at and closed_by), replaces labels and assignees when the patch names them, adjusts the open-issue count on a state change, records a timeline event for the transition, and enqueues the matching `issues` action.

func (*IssueService) GetComment

func (s *IssueService) GetComment(ctx context.Context, viewerPK int64, owner, name string, commentID int64) (*Comment, error)

GetComment resolves a single comment by its public id, gating on the repository the comment's issue belongs to being visible to the viewer.

func (*IssueService) GetIssue

func (s *IssueService) GetIssue(ctx context.Context, viewerPK int64, owner, name string, number int64) (*Issue, error)

GetIssue resolves one issue by number for the viewer.

func (*IssueService) GetLabel

func (s *IssueService) GetLabel(ctx context.Context, viewerPK int64, owner, name, label string) (*Label, error)

GetLabel resolves a single label by name.

func (*IssueService) GetMilestone

func (s *IssueService) GetMilestone(ctx context.Context, viewerPK int64, owner, name string, number int64) (*Milestone, error)

GetMilestone resolves a single milestone by number.

func (*IssueService) IssueForEvent

func (s *IssueService) IssueForEvent(ctx context.Context, repo *Repo, issuePK int64) (*Issue, error)

IssueForEvent assembles an issue by internal pk for the webhook renderer. The repository is already resolved by the caller; no visibility check applies because the event was authorized when it was recorded.

func (*IssueService) IssueRef

func (s *IssueService) IssueRef(ctx context.Context, issueDBID int64) (owner, name string, number int64, err error)

IssueRef resolves an issue's public database id to the owner login, repository name, and per-repo number, the coordinates the write methods take. The GraphQL mutations decode an issue node id to its database id and resolve it here. It does not authorize: the write method the caller invokes next (EditIssue, CreateComment) enforces write access and repository visibility.

func (*IssueService) LabelNameByDBID added in v0.1.3

func (s *IssueService) LabelNameByDBID(ctx context.Context, dbID int64) (string, error)

LabelNameByDBID resolves a label's name by its public database ID. The caller uses it to convert a GraphQL label node ID (which carries the DB ID) back to a name before calling add/remove/replace label methods.

func (*IssueService) LabelRepoRef added in v0.1.3

func (s *IssueService) LabelRepoRef(ctx context.Context, dbID int64) (name, owner, repoName string, err error)

LabelRepoRef resolves a label by its public database ID and returns the label name together with the owner login and repository name. Used by the GraphQL deleteLabel and updateLabel mutations which receive a label node ID.

func (*IssueService) ListCommentReactions

func (s *IssueService) ListCommentReactions(ctx context.Context, viewerPK int64, owner, name string, commentID int64) ([]*Reaction, error)

ListCommentReactions returns a comment's reactions, oldest first.

func (*IssueService) ListComments

func (s *IssueService) ListComments(ctx context.Context, viewerPK int64, owner, name string, number, page, perPage int64) ([]*Comment, error)

ListComments returns a page of an issue's comments, oldest first.

func (*IssueService) ListCommentsAfter added in v0.1.3

func (s *IssueService) ListCommentsAfter(ctx context.Context, viewerPK int64, owner, name string, number, afterID int64, limit int) ([]*Comment, error)

ListCommentsAfter returns the comments following the one afterID names, oldest first, via a keyset seek instead of the OFFSET walk ListComments pages with. The GraphQL connections call it when their after: cursor carries the previous page's last comment id. An afterID that no longer resolves, or that belongs to another issue, degrades to the first page, the same shape a stale offset cursor lands on.

func (*IssueService) ListIssueEvents added in v0.1.3

func (s *IssueService) ListIssueEvents(ctx context.Context, viewerPK int64, owner, name string, number int64) ([]*IssueEvent, error)

ListIssueEvents returns an issue's event log in chronological order, with each event's actor resolved. The events are the action entries EditIssue and the lock toggles append (closed, reopened, locked, unlocked, ...); the timeline endpoint merges them with comments, while the events endpoint returns them alone. The viewer must be able to see the repository.

func (*IssueService) ListIssueReactions

func (s *IssueService) ListIssueReactions(ctx context.Context, viewerPK int64, owner, name string, number int64) ([]*Reaction, error)

ListIssueReactions returns an issue's reactions, oldest first.

func (*IssueService) ListIssues

func (s *IssueService) ListIssues(ctx context.Context, viewerPK int64, owner, name string, q IssueQuery) ([]*Issue, int, error)

ListIssues returns a page of the repository's issues plus the total matching the filter, for the pagination headers.

func (*IssueService) ListIssuesPage added in v0.1.2

func (s *IssueService) ListIssuesPage(ctx context.Context, viewerPK int64, owner, name string, q IssueQuery) ([]*Issue, bool, error)

ListIssuesPage returns a keyset-paginated page of the repository's issues plus whether a further page exists, without the COUNT that ListIssues runs for the page-number Link header. It is the flat read path for cursor walks: deep pages of a several-hundred-thousand-issue repo cost the page, not a full count plus a deep OFFSET scan. The caller routes here only when the cursor decoded, so the filter is keyset-eligible.

func (*IssueService) ListIssuesVersion added in v0.1.3

func (s *IssueService) ListIssuesVersion(ctx context.Context, viewerPK int64, owner, name string, q IssueQuery) (int, string, error)

ListIssuesVersion returns the count and the latest updated_at marker of the filtered window, the seed the REST list handler hashes into a version ETag. A polling client's If-None-Match hit answers from this one aggregate query, skipping the page fetch, presenter assembly, and marshal entirely. The repository visibility check runs the same way the list itself would.

func (*IssueService) ListIssuesWindow added in v0.1.3

func (s *IssueService) ListIssuesWindow(ctx context.Context, viewerPK int64, owner, name string, q IssueQuery) ([]*Issue, error)

ListIssuesWindow returns a page of the repository's issues without the COUNT ListIssues runs. The REST handler pairs it with ListIssuesVersion, which already counted the window while seeding the ETag, so a 200 still pays one count, not two.

func (*IssueService) ListLabels

func (s *IssueService) ListLabels(ctx context.Context, viewerPK int64, owner, name string) ([]*Label, error)

ListLabels returns a repository's labels in name order.

func (*IssueService) ListMilestones

func (s *IssueService) ListMilestones(ctx context.Context, viewerPK int64, owner, name, state string) ([]*Milestone, error)

ListMilestones returns a repository's milestones filtered by state ("open"|"closed"|"all").

func (*IssueService) MilestoneRepoRef added in v0.1.3

func (s *IssueService) MilestoneRepoRef(ctx context.Context, dbID int64) (number int64, owner, repoName string, err error)

MilestoneRepoRef resolves a milestone by its public database ID and returns its per-repo number together with the owner login and repository name, the coordinates GetMilestone takes. The GraphQL node() resolver uses it to turn a milestone node id back into an addressable milestone.

func (*IssueService) RemoveAssignees added in v0.1.3

func (s *IssueService) RemoveAssignees(ctx context.Context, actorPK int64, owner, name string, number int64, logins []string) (*Issue, error)

RemoveAssignees unlinks the given user logins from an issue's assignee list.

func (*IssueService) RemoveLabels added in v0.1.3

func (s *IssueService) RemoveLabels(ctx context.Context, actorPK int64, owner, name string, number int64, labelNames []string) (*Issue, error)

RemoveLabels detaches the given label names from an issue, ignoring any that are not currently attached.

func (*IssueService) SetLocked added in v0.1.3

func (s *IssueService) SetLocked(ctx context.Context, actorPK int64, owner, name string, number int64, locked bool, reason *string) error

SetLocked locks or unlocks an issue's conversation. The lock reason is kept only while locked; unlocking always clears it. Both transitions append the matching locked/unlocked timeline event, the way GitHub's timeline shows them. The write goes through the optimistic-lock update like any other edit.

func (*IssueService) UpdateLabel

func (s *IssueService) UpdateLabel(ctx context.Context, actorPK int64, owner, name, current string, in LabelInput) (*Label, error)

UpdateLabel edits a label resolved by its current name. A rename onto another existing label's name is a conflict.

func (*IssueService) UpdateMilestone

func (s *IssueService) UpdateMilestone(ctx context.Context, actorPK int64, owner, name string, number int64, in MilestoneInput) (*Milestone, error)

UpdateMilestone edits a milestone resolved by number, including its open and closed state transition.

func (*IssueService) UserLoginByPK added in v0.1.3

func (s *IssueService) UserLoginByPK(ctx context.Context, pk int64) (string, error)

UserLoginByPK resolves a user's login by their internal primary key.

type IssueStore

type IssueStore interface {
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)

	GetIssueByNumber(ctx context.Context, repoPK, number int64) (*store.IssueRow, error)
	GetIssueByPK(ctx context.Context, pk int64) (*store.IssueRow, error)
	GetIssueByDBID(ctx context.Context, dbID int64) (*store.IssueRow, error)
	ListIssues(ctx context.Context, repoPK int64, f store.IssueFilter) ([]store.IssueRow, error)
	ListIssuesPage(ctx context.Context, repoPK int64, f store.IssueFilter) ([]store.IssueRow, bool, error)
	CountIssues(ctx context.Context, repoPK int64, f store.IssueFilter) (int, error)
	IssueListVersion(ctx context.Context, repoPK int64, f store.IssueFilter) (int, string, error)
	LabelsByIssue(ctx context.Context, issuePK int64) ([]store.LabelRow, error)
	ListAssigneePKs(ctx context.Context, issuePK int64) ([]int64, error)
	LabelsByIssuePKs(ctx context.Context, issuePKs []int64) (map[int64][]store.LabelRow, error)
	AssigneesByIssuePKs(ctx context.Context, issuePKs []int64) (map[int64][]int64, error)
	UsersByPKs(ctx context.Context, pks []int64) (map[int64]*store.UserRow, error)
	MilestonesByPKs(ctx context.Context, pks []int64) (map[int64]*store.MilestoneRow, error)
	ReactionRollupsBySubjectPKs(ctx context.Context, subjectType string, subjectPKs []int64) (map[int64]store.ReactionRollup, error)

	ListLabels(ctx context.Context, repoPK int64) ([]store.LabelRow, error)
	GetLabel(ctx context.Context, repoPK int64, name string) (*store.LabelRow, error)
	GetLabelByDBID(ctx context.Context, dbID int64) (*store.LabelRow, error)
	LabelsByNames(ctx context.Context, repoPK int64, names []string) ([]store.LabelRow, error)
	InsertLabel(ctx context.Context, l *store.LabelRow) error
	UpdateLabel(ctx context.Context, l *store.LabelRow) error
	DeleteLabel(ctx context.Context, pk int64) error

	ListMilestones(ctx context.Context, repoPK int64, state string) ([]store.MilestoneRow, error)
	GetMilestoneByNumber(ctx context.Context, repoPK, number int64) (*store.MilestoneRow, error)
	GetMilestoneByPK(ctx context.Context, pk int64) (*store.MilestoneRow, error)
	GetMilestoneByDBID(ctx context.Context, dbID int64) (*store.MilestoneRow, error)
	InsertMilestone(ctx context.Context, m *store.MilestoneRow) error
	UpdateMilestone(ctx context.Context, m *store.MilestoneRow) error
	DeleteMilestone(ctx context.Context, pk int64) error
	MilestoneIssueCounts(ctx context.Context, milestonePK int64) (open, closed int, err error)
	MilestoneIssueCountsByPKs(ctx context.Context, pks []int64) (map[int64]store.MilestoneCount, error)

	ListIssueComments(ctx context.Context, issuePK int64, limit, offset int) ([]store.CommentRow, error)
	ListIssueCommentsAfter(ctx context.Context, issuePK int64, createdAt time.Time, afterPK int64, limit int) ([]store.CommentRow, error)
	ListIssueEvents(ctx context.Context, issuePK int64) ([]store.IssueEventRow, error)
	GetComment(ctx context.Context, dbID int64) (*store.CommentRow, error)
	GetCommentByPK(ctx context.Context, pk int64) (*store.CommentRow, error)
	UpdateComment(ctx context.Context, c *store.CommentRow) error
	DeleteComment(ctx context.Context, pk int64) error

	ReactionRollupFor(ctx context.Context, subjectType string, subjectPK int64) (store.ReactionRollup, error)
	ListReactions(ctx context.Context, subjectType string, subjectPK int64) ([]store.ReactionRow, error)
	InsertReaction(ctx context.Context, r *store.ReactionRow) (bool, error)
	DeleteReaction(ctx context.Context, subjectType string, subjectPK, dbID int64) error

	WithTx(ctx context.Context, fn func(*store.Tx) error) error
	EnqueueJob(ctx context.Context, j *store.JobRow) (bool, error)
	InsertEvent(ctx context.Context, e *store.EventRow) error
}

IssueStore is the slice of the store the issue service needs: the issue, comment, label, milestone, and reaction reads and writes, the transaction entry point the multi-statement writes run through, the user and repository lookups it resolves participants and locations with, and the job enqueue it records the webhook event through.

type KeyService added in v0.1.3

type KeyService struct {
	// contains filtered or unexported fields
}

KeyService manages SSH keys (user and deploy) and branch protection rules.

func NewKeyService added in v0.1.3

func NewKeyService(st KeyStore) *KeyService

NewKeyService creates a KeyService over the store.

func (*KeyService) CreateDeployKey added in v0.1.3

func (s *KeyService) CreateDeployKey(ctx context.Context, repoPK, ownerPK int64,
	title, rawKey string, readOnly bool) (*store.SSHKeyRow, error)

CreateDeployKey parses and registers a new deploy key on repoPK.

func (*KeyService) CreateUserKey added in v0.1.3

func (s *KeyService) CreateUserKey(ctx context.Context, userPK int64, title, rawKey string) (*store.SSHKeyRow, error)

CreateUserKey parses and registers a new SSH key for userPK.

func (*KeyService) DeleteBranchProtection added in v0.1.3

func (s *KeyService) DeleteBranchProtection(ctx context.Context, repoPK int64, branch string) error

DeleteBranchProtection removes a branch protection rule.

func (*KeyService) DeleteDeployKey added in v0.1.3

func (s *KeyService) DeleteDeployKey(ctx context.Context, repoPK, dbID int64) error

DeleteDeployKey removes the deploy key identified by DBID from repoPK.

func (*KeyService) DeleteUserKey added in v0.1.3

func (s *KeyService) DeleteUserKey(ctx context.Context, userPK, dbID int64) error

DeleteUserKey removes the SSH key identified by DBID for userPK.

func (*KeyService) GetBranchProtection added in v0.1.3

func (s *KeyService) GetBranchProtection(ctx context.Context, repoPK int64, branch string) (*store.BranchProtectionRow, error)

GetBranchProtection returns the protection rule for a branch pattern.

func (*KeyService) GetDeployKey added in v0.1.3

func (s *KeyService) GetDeployKey(ctx context.Context, repoPK, dbID int64) (*store.SSHKeyRow, error)

GetDeployKey returns the deploy key with the given DBID belonging to repoPK.

func (*KeyService) ListDeployKeys added in v0.1.3

func (s *KeyService) ListDeployKeys(ctx context.Context, repoPK int64) ([]*store.SSHKeyRow, error)

ListDeployKeys returns all deploy keys for repoPK.

func (*KeyService) ListUserKeys added in v0.1.3

func (s *KeyService) ListUserKeys(ctx context.Context, userPK int64) ([]*store.SSHKeyRow, error)

ListUserKeys returns all SSH keys for userPK (not deploy keys).

func (*KeyService) SetBranchProtection added in v0.1.3

func (s *KeyService) SetBranchProtection(ctx context.Context, r *store.BranchProtectionRow) error

SetBranchProtection creates or replaces a branch protection rule.

type KeyStore added in v0.1.3

type KeyStore interface {
	SSHKeysByUser(ctx context.Context, userPK int64) ([]*store.SSHKeyRow, error)
	DeployKeysByRepo(ctx context.Context, repoPK int64) ([]*store.SSHKeyRow, error)
	SSHKeyByPK(ctx context.Context, pk int64) (*store.SSHKeyRow, error)
	SSHKeyByDBID(ctx context.Context, dbID int64) (*store.SSHKeyRow, error)
	InsertSSHKey(ctx context.Context, k *store.SSHKeyRow) error
	DeleteSSHKey(ctx context.Context, pk int64) error
	BranchProtectionByPattern(ctx context.Context, repoPK int64, pattern string) (*store.BranchProtectionRow, error)
	UpsertBranchProtection(ctx context.Context, r *store.BranchProtectionRow) error
	DeleteBranchProtection(ctx context.Context, repoPK int64, pattern string) error
}

KeyStore is the narrow store interface the KeyService depends on.

type Label

type Label struct {
	ID          int64
	Name        string
	Color       string
	Description *string
	Default     bool
	CreatedAt   time.Time
}

Label is the domain view of a repository label.

type LabelInput

type LabelInput struct {
	Name        string
	Color       string
	Description *string
}

LabelInput is the create/update payload for a label.

type License added in v0.1.3

type License struct {
	Key    string
	Name   string
	SPDXID string
	Body   string
}

License is a license template a repository can be created with. Key is the lowercase identifier the API accepts (license_template), matching GitHub's license keys. Body may contain the [year] and [fullname] placeholders the writer fills in.

func LicenseTemplate added in v0.1.3

func LicenseTemplate(key string) (License, bool)

LicenseTemplate returns the license for the given key ("mit", "apache-2.0", ...). The lookup is case-insensitive.

type MergeInput

type MergeInput struct {
	Method        git.MergeMethod
	CommitTitle   string
	CommitMessage string
	ExpectedHead  string
}

MergeInput is the merge payload: the strategy, the optional commit title and message overriding the defaults, and the optional expected head sha that guards against merging a head that moved out from under the caller.

type MergeResult

type MergeResult struct {
	SHA     string
	Merged  bool
	Message string
}

MergeResult is the outcome of a successful merge: the new commit on the base branch and the message it carries.

type MergeState

type MergeState struct {
	Mergeable    *bool
	State        string
	Rebaseable   *bool
	Additions    int
	Deletions    int
	ChangedFiles int
	Commits      int
}

MergeState is the worker-derived merge state of a pull request: the tri-state mergeable, the GitHub mergeable_state string, the rebaseable flag, the diff stats, and the commit count. The worker computes it and SetMergeability persists it; nil Mergeable is the unknown state.

type Milestone

type Milestone struct {
	ID           int64
	Number       int64
	Title        string
	Description  *string
	State        string
	Creator      *User
	OpenIssues   int
	ClosedIssues int
	DueOn        *time.Time
	ClosedAt     *time.Time
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

Milestone is the domain view of a milestone, including the open and closed issue counts computed on read.

type MilestoneInput

type MilestoneInput struct {
	Title       *string
	Description *string
	State       *string
	DueOn       *time.Time
	ClearDueOn  bool
}

MilestoneInput is the create/update payload for a milestone. A nil field on update leaves the value unchanged; State moves between open and closed.

type NotificationService added in v0.1.3

type NotificationService struct {
	// contains filtered or unexported fields
}

NotificationService maintains and serves notification threads. Fan-out is deliberately small: it covers the events the server already handles inline (comments, issue and pull creation, assignment, review requests) and never fails the write that triggered it.

func NewNotificationService added in v0.1.3

func NewNotificationService(st NotificationStore) *NotificationService

NewNotificationService builds a NotificationService over the store.

func (*NotificationService) DeleteSubscription added in v0.1.3

func (s *NotificationService) DeleteSubscription(ctx context.Context, userPK, id int64) error

DeleteSubscription resets the thread to its default subscription state.

func (*NotificationService) Get added in v0.1.3

func (s *NotificationService) Get(ctx context.Context, userPK, id int64) (*NotificationThread, error)

Get returns one thread. A thread that does not exist or belongs to another user is the same ErrNotFound, so thread ids cannot be probed.

func (*NotificationService) List added in v0.1.3

func (s *NotificationService) List(ctx context.Context, userPK, repoPK int64, all bool, page, perPage int) ([]*NotificationThread, int, error)

List returns one page of the user's threads plus the total for the filter. A zero repoPK spans all repositories; all=false keeps only unread threads.

func (*NotificationService) MarkAllRead added in v0.1.3

func (s *NotificationService) MarkAllRead(ctx context.Context, userPK, repoPK int64) error

MarkAllRead marks every thread of the user read, optionally scoped to one repository by its pk (zero spans all).

func (*NotificationService) MarkDone added in v0.1.3

func (s *NotificationService) MarkDone(ctx context.Context, userPK, id int64) error

MarkDone removes a thread from the user's inbox entirely.

func (*NotificationService) MarkRead added in v0.1.3

func (s *NotificationService) MarkRead(ctx context.Context, userPK, id int64) error

MarkRead marks one of the user's threads read.

func (*NotificationService) NotifyAssigned added in v0.1.3

func (s *NotificationService) NotifyAssigned(ctx context.Context, actorPK int64, owner, repo string, number int64, logins []string)

NotifyAssigned tells the named users they were assigned to the issue.

func (*NotificationService) NotifyIssueComment added in v0.1.3

func (s *NotificationService) NotifyIssueComment(ctx context.Context, actorPK int64, owner, repo string, number int64, body string)

NotifyIssueComment fans a new comment out to the thread's participants: the issue author, its assignees, the authors of earlier comments, and anyone @mentioned in the body. The commenter never notifies themselves.

func (*NotificationService) NotifyIssueOpened added in v0.1.3

func (s *NotificationService) NotifyIssueOpened(ctx context.Context, actorPK int64, owner, repo string, number int64, body string)

NotifyIssueOpened fans a new issue or pull request out to its assignees and to anyone @mentioned in the opening body.

func (*NotificationService) NotifyReviewRequested added in v0.1.3

func (s *NotificationService) NotifyReviewRequested(ctx context.Context, actorPK int64, owner, repo string, number int64, logins []string)

NotifyReviewRequested tells the named users their review was requested.

func (*NotificationService) RepoPKByName added in v0.1.3

func (s *NotificationService) RepoPKByName(ctx context.Context, owner, name string) (int64, error)

RepoPKByName resolves a repository pk for the repo-scoped notification endpoints. Visibility is the caller's concern.

func (*NotificationService) SetSubscription added in v0.1.3

func (s *NotificationService) SetSubscription(ctx context.Context, userPK, id int64, subscribed, ignored bool) (*NotificationThread, error)

SetSubscription updates the thread's subscription flags and returns the thread as updated.

type NotificationStore added in v0.1.3

type NotificationStore interface {
	UpsertNotificationThread(ctx context.Context, r *store.NotificationThreadRow) error
	ListNotificationThreads(ctx context.Context, userPK, repoPK int64, all bool, limit, offset int) ([]*store.NotificationThreadRow, int, error)
	NotificationThreadByPK(ctx context.Context, pk int64) (*store.NotificationThreadRow, error)
	MarkNotificationThreadRead(ctx context.Context, pk int64) error
	MarkNotificationThreadsRead(ctx context.Context, userPK, repoPK int64) error
	SetNotificationThreadSubscription(ctx context.Context, pk int64, subscribed, ignored bool) error
	DeleteNotificationThread(ctx context.Context, pk int64) error

	RepoByOwnerName(ctx context.Context, owner, name string) (*store.RepoRow, error)
	GetIssueByNumber(ctx context.Context, repoPK, number int64) (*store.IssueRow, error)
	GetIssueByPK(ctx context.Context, pk int64) (*store.IssueRow, error)
	ListAssigneePKs(ctx context.Context, issuePK int64) ([]int64, error)
	ListIssueComments(ctx context.Context, issuePK int64, limit, offset int) ([]store.CommentRow, error)
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
}

NotificationStore is the slice of the store the notification service needs: the thread table itself plus the lookups that drive fan-out and assembly.

type NotificationThread added in v0.1.3

type NotificationThread struct {
	ID            int64
	Reason        string
	Unread        bool
	Subscribed    bool
	Ignored       bool
	UpdatedAt     time.Time
	CreatedAt     time.Time
	LastReadAt    *time.Time
	RepoPK        int64
	SubjectTitle  string
	SubjectNumber int64
	SubjectIsPull bool
}

NotificationThread is one user's view of one issue or pull request conversation, the unit the notifications API serves.

type OrgMember added in v0.1.3

type OrgMember struct {
	User *User
	Role string
}

OrgMember pairs an org member with the role they hold.

type PRInput

type PRInput struct {
	Title               string
	Body                *string
	Base                string
	Head                string
	Draft               bool
	MaintainerCanModify bool
}

PRInput is the create payload: the title and optional body, the base and head branch names, and the draft and maintainer flags. For M5 the head is a branch in the same repository; cross-repository forks arrive with their milestone.

type PRPatch added in v0.1.3

type PRPatch struct {
	Title               *string
	Body                *string
	BaseRef             *string
	State               *string // "open" | "closed"
	Draft               *bool
	MaintainerCanModify *bool
	Labels              *[]string // replace; nil = no change
	AssigneeLogins      *[]string // replace; nil = no change
	MilestoneNumber     *int64
	ClearMilestone      bool
}

PRPatch is the update payload for an existing pull request. Only non-nil pointer fields are applied so callers can patch a single field without knowing the current value of the others.

type PRQuery

type PRQuery struct {
	State     string
	Head      string
	Base      string
	Sort      string
	Direction string
	Page      int
	PerPage   int
	Cursor    string
	// AfterNumber is the number of the last pull request on the previous page,
	// the seek key the GraphQL connection cursors carry. The list orders by
	// number descending, so it seeds the keyset seek directly.
	AfterNumber int64
}

PRQuery narrows the list endpoint to a state (open, closed, all) and a page. Head filters on the head branch, either a bare branch name or GitHub's "owner:branch" form; Base filters on the base branch. Sort is created (the default), updated, popularity, or long-running, and Direction is asc or desc, defaulting to desc. Cursor, when set, is the opaque keyset token from the previous page's Link header, which switches the list to a number seek instead of OFFSET.

type PRService

type PRService struct {
	// contains filtered or unexported fields
}

PRService implements the pull request subsystem. It leans on the repo service for visibility and write authorization and on the issue service for the issue half of a pull request, so those rules live in one place. The git store backs the merge surface: the test merge behind mergeability, the three merge strategies, and the synthetic refs/pull/<n>/head and /merge refs.

func NewPRService

func NewPRService(st PullStore, repos *RepoService, issues *IssueService, gs *git.Store) *PRService

NewPRService builds a PRService over the store, the repo and issue services, and the git store.

func (*PRService) Commits

func (s *PRService) Commits(ctx context.Context, viewerPK int64, owner, name string, number int64) ([]git.Commit, error)

Commits returns a pull request's own commits, oldest first.

func (*PRService) CountPRs added in v0.1.3

func (s *PRService) CountPRs(ctx context.Context, viewerPK int64, owner, name, state string) (int, error)

CountPRs returns the total matching the state filter without fetching a page. The GraphQL connection pairs it with ListPRsPage the same way the issue connection pairs CountIssues with ListIssuesPage.

func (*PRService) CreatePR

func (s *PRService) CreatePR(ctx context.Context, actorPK int64, owner, name string, in PRInput) (*PullRequest, error)

CreatePR opens a pull request after authorizing write access. It validates the base and head branches resolve and differ, allocates the shared issue number, writes the issue row (is_pull) and the pull extension in one transaction, publishes the synthetic refs/pull/<n>/head ref at the head tip, and enqueues the mergeability recompute so mergeable transitions from null to a value.

func (*PRService) Diff

func (s *PRService) Diff(ctx context.Context, viewerPK int64, owner, name string, number int64) ([]byte, error)

Diff returns the pull request's unified diff, the .diff media body and what gh pr diff prints.

func (*PRService) Files

func (s *PRService) Files(ctx context.Context, viewerPK int64, owner, name string, number int64, ignoreWhitespace bool) ([]git.FileChange, error)

Files returns the per-file diff of a pull request over the three-dot range from the base branch tip to the head, the body of the files endpoint. ignoreWhitespace serves the "Hide whitespace" (?w=1) view: a separate diff whose own line offsets are display-only, so the review API still anchors on the canonical diff this method returns when the flag is false.

func (*PRService) GetPR

func (s *PRService) GetPR(ctx context.Context, viewerPK int64, owner, name string, number int64) (*PullRequest, error)

GetPR resolves one pull request by number for the viewer.

func (*PRService) GetPRByID

func (s *PRService) GetPRByID(ctx context.Context, viewerPK, dbID int64) (*PullRequest, error)

GetPRByID resolves a pull request by its public database id for the viewer, the path a PullRequest node id decodes to. A pull request in a repository the viewer cannot see is ErrPullNotFound, never leaked.

func (*PRService) ListPRs

func (s *PRService) ListPRs(ctx context.Context, viewerPK int64, owner, name string, q PRQuery) ([]*PullRequest, int, error)

ListPRs returns a page of the repository's pull requests plus the total matching the state filter, for the pagination headers.

func (*PRService) ListPRsPage added in v0.1.2

func (s *PRService) ListPRsPage(ctx context.Context, viewerPK int64, owner, name string, q PRQuery) ([]*PullRequest, bool, error)

ListPRsPage returns a keyset-paginated page of the repository's pull requests plus whether a further page exists, without the COUNT that ListPRs runs for the page-number Link header. It is the flat read path for cursor walks: a malformed cursor decodes to nil and starts from the newest, matching the issue list's degrade-to-first-page behavior.

func (*PRService) ListPRsVersion added in v0.1.3

func (s *PRService) ListPRsVersion(ctx context.Context, viewerPK int64, owner, name string, q PRQuery) (int, string, error)

ListPRsVersion returns the count and the latest updated_at marker of the filtered window, the seed the REST pulls list hashes into a version ETag, mirroring ListIssuesVersion.

func (*PRService) ListPRsWindow added in v0.1.3

func (s *PRService) ListPRsWindow(ctx context.Context, viewerPK int64, owner, name string, q PRQuery) ([]*PullRequest, error)

ListPRsWindow returns a page of the repository's pull requests without the COUNT ListPRs runs; the REST handler pairs it with ListPRsVersion, which already counted the window for the ETag seed.

func (*PRService) Merge

func (s *PRService) Merge(ctx context.Context, actorPK int64, owner, name string, number int64, in MergeInput) (*MergeResult, error)

Merge lands a pull request by the given method after authorizing write access. It guards the expected head sha, refuses a closed, merged, conflicting, or empty merge, writes the merge commit, advances the base branch to it, closes the issue, and records the merge, all so a re-read reports merged true.

func (*PRService) OnHeadPush

func (s *PRService) OnHeadPush(ctx context.Context, pusherPK, repoPK int64, branch, newSHA string) error

OnHeadPush refreshes the pull requests a push to a branch touches. A push to a head branch repoints that pull request's recorded head and its refs/pull/<n>/head ref, and emits the pull_request synchronize event the new head triggers; a push to a base branch leaves the head alone. Either way every affected open pull request is re-checked for mergeability. pusherPK names the pusher as the synchronize event's actor.

func (*PRService) PRRef added in v0.1.3

func (s *PRService) PRRef(ctx context.Context, pullDBID int64) (owner, name string, number int64, err error)

PRRef resolves a pull request's owner, repo name, and number from its public database id. It is used by GraphQL mutation resolvers that receive a PullRequest node ID and need to address the domain by coordinates.

func (*PRService) Patch

func (s *PRService) Patch(ctx context.Context, viewerPK int64, owner, name string, number int64) ([]byte, error)

Patch returns the pull request's commits as an mbox patch series, the .patch media body.

func (*PRService) PullForEvent

func (s *PRService) PullForEvent(ctx context.Context, repo *Repo, issuePK int64) (*PullRequest, error)

PullForEvent assembles a pull request by its issue pk for the webhook renderer. No visibility check applies: the event was authorized when it was recorded.

func (*PRService) RecomputeMergeability

func (s *PRService) RecomputeMergeability(ctx context.Context, issuePK int64) error

RecomputeMergeability resolves and persists a pull request's merge state: it test-merges the current base tip against the head, records mergeable, the mergeable_state string, the rebaseable flag, the diff stats, and the commit count, and on a clean merge publishes a real refs/pull/<n>/merge commit. It is the body of the recompute_mergeability worker; a merged pull request is left untouched.

func (*PRService) RemoveRequestedReviewers added in v0.1.3

func (s *PRService) RemoveRequestedReviewers(ctx context.Context, actorPK int64, owner, name string, number int64, logins []string) (*PullRequest, error)

RemoveRequestedReviewers drops the given logins from a pull request's requested reviewers and returns the refreshed pull request. Logins that were never requested are ignored, but an unknown login or the author is refused the same way the add side refuses them.

func (*PRService) RequestReviewers added in v0.1.3

func (s *PRService) RequestReviewers(ctx context.Context, actorPK int64, owner, name string, number int64, logins []string) (*PullRequest, error)

RequestReviewers adds the given logins as requested reviewers of a pull request and returns the refreshed pull request. An unknown login is refused the way GitHub refuses a non-collaborator, and requesting the author is refused outright; both are 422s on the wire. Re-requesting an existing reviewer is a no-op.

func (*PRService) SetDraft added in v0.1.3

func (s *PRService) SetDraft(ctx context.Context, actorPK int64, owner, name string, number int64, draft bool) (*PullRequest, error)

SetDraft marks a pull request as a draft (draft=true) or as ready for review (draft=false) after authorizing write access. A no-op when the flag is already the requested value.

func (*PRService) UpdateBranch added in v0.1.3

func (s *PRService) UpdateBranch(ctx context.Context, actorPK int64, owner, name string, number int64, expectedHeadSHA string) error

UpdateBranch merges the base branch's tip into a pull request's head branch, the body of PUT /pulls/{number}/update-branch. It needs write access, refuses a closed or merged pull request, guards the expected head sha when the caller pins one, and reports ErrNoBaseUpdates when the head already contains the base tip and ErrNotMergeable when the two sides conflict. On success the head branch advances to the merge commit and the usual head-push refresh runs, so the pull request's recorded head, synthetic refs, and mergeability follow.

func (*PRService) UpdatePR added in v0.1.3

func (s *PRService) UpdatePR(ctx context.Context, actorPK int64, owner, name string, number int64, p PRPatch) (*PullRequest, error)

UpdatePR applies the non-nil fields of patch to an existing open pull request. Issue-level fields (title, body, state, labels, assignees, milestone) are delegated to the issue service; pull-level fields (base branch, draft, maintainer-can-modify) are updated in one UPDATE directly.

type ProfileFields added in v0.1.3

type ProfileFields struct {
	Name            string
	Email           string
	Bio             string
	Location        string
	Company         string
	Blog            string
	TwitterUsername string
}

ProfileFields are the account profile fields the settings page can update.

type PullRequest

type PullRequest struct {
	PK      int64
	ID      int64
	IssueID int64
	Number  int64
	RepoPK  int64
	Repo    *Repo

	Title  string
	Body   *string
	State  string // open | closed
	Locked bool
	// ActiveLockReason mirrors the issue-side lock reason; nil when unlocked.
	ActiveLockReason *string
	User             *User
	Assignees        []*User
	Labels           []*Label
	Milestone        *Milestone
	CommentsCount    int
	// RequestedReviewers are the users whose review is currently requested,
	// in request order. A submitted review clears its author's request on
	// GitHub; here the set changes only through the request endpoints.
	RequestedReviewers []*User

	Base GitEndpoint
	Head GitEndpoint

	Draft               bool
	MaintainerCanModify bool

	Merged         bool
	MergedAt       *time.Time
	MergedBy       *User
	MergeCommitSHA *string
	Mergeable      *bool
	MergeableState string
	Rebaseable     *bool
	Additions      int
	Deletions      int
	ChangedFiles   int
	CommitsCount   int

	ClosedAt  *time.Time
	CreatedAt time.Time
	UpdatedAt time.Time
}

PullRequest is the domain view of a pull request: the issue it shares its number, title, body, and state with, plus the git coordinates and merge state the pull_requests extension carries. ID is the pull request's own public database id (pull_requests.db_id), the value a PullRequest node id decodes to; IssueID is the underlying issue row's db_id, which the REST id field renders, matching GitHub where a pull request and its issue share one id space.

Mergeable, Rebaseable, MergedBy, MergedAt, MergeCommitSHA, and ClosedAt are pointers because a pull request acquires them only over its lifetime; a nil Mergeable is the not-yet-computed state the API surfaces as null, the null-then-value contract the mergeability worker resolves.

type PullStore

type PullStore interface {
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	RepoByPK(ctx context.Context, pk int64) (*store.RepoRow, error)

	GetIssueByNumber(ctx context.Context, repoPK, number int64) (*store.IssueRow, error)
	GetIssueByPK(ctx context.Context, pk int64) (*store.IssueRow, error)
	IssuesByPKs(ctx context.Context, pks []int64) (map[int64]*store.IssueRow, error)
	LabelsByIssue(ctx context.Context, issuePK int64) ([]store.LabelRow, error)
	ListAssigneePKs(ctx context.Context, issuePK int64) ([]int64, error)
	GetMilestoneByPK(ctx context.Context, pk int64) (*store.MilestoneRow, error)
	LabelsByIssuePKs(ctx context.Context, issuePKs []int64) (map[int64][]store.LabelRow, error)
	AssigneesByIssuePKs(ctx context.Context, issuePKs []int64) (map[int64][]int64, error)
	UsersByPKs(ctx context.Context, pks []int64) (map[int64]*store.UserRow, error)
	MilestonesByPKs(ctx context.Context, pks []int64) (map[int64]*store.MilestoneRow, error)

	GetPullByIssuePK(ctx context.Context, issuePK int64) (*store.PullRow, error)
	GetPullByDBID(ctx context.Context, dbID int64) (*store.PullRow, error)
	ListPulls(ctx context.Context, repoPK int64, f store.PullFilter, limit, offset int) ([]store.PullRow, error)
	ListPullsPage(ctx context.Context, repoPK int64, f store.PullFilter, cursor *store.PullCursor, limit int) ([]store.PullRow, bool, error)
	CountPulls(ctx context.Context, repoPK int64, f store.PullFilter) (int, error)
	PullListVersion(ctx context.Context, repoPK int64, f store.PullFilter) (int, string, error)
	OpenPullsByHeadRef(ctx context.Context, repoPK int64, headRef string) ([]store.PullRow, error)
	ListReviewRequestPKs(ctx context.Context, pullPK int64) ([]int64, error)
	ReviewRequestsByPullPKs(ctx context.Context, pullPKs []int64) (map[int64][]int64, error)
	AddReviewRequests(ctx context.Context, pullPK int64, reviewerPKs []int64) error
	RemoveReviewRequests(ctx context.Context, pullPK int64, reviewerPKs []int64) error
	OpenPullsByBaseRef(ctx context.Context, repoPK int64, baseRef string) ([]store.PullRow, error)
	SetMergeability(ctx context.Context, issuePK int64, mergeable *bool, state string, rebaseable *bool, additions, deletions, changedFiles, commits int, checkedAt time.Time) error
	UpdatePullDraft(ctx context.Context, pullPK int64, draft bool) error

	WithTx(ctx context.Context, fn func(*store.Tx) error) error

	EnqueueJob(ctx context.Context, j *store.JobRow) (bool, error)
	InsertEvent(ctx context.Context, e *store.EventRow) error
}

PullStore is the slice of the store the pull request service needs: the pull extension reads and writes, the issue, user, repository, label, and milestone lookups it assembles a pull request from, the transaction entry point the create and merge paths run through, and the job enqueue the mergeability recompute and the webhook event ride on.

type PushBatch

type PushBatch struct {
	RepoPK     int64
	PusherPK   int64
	Protocol   string // "http" | "ssh"
	Updates    []RefUpdate
	ReceivedAt time.Time
}

PushBatch is the parsed post-receive batch the transport hands to OnPush: the repository, the authenticated pusher, the transport, and the moved refs.

type PushPayload

type PushPayload struct {
	RepoPK   int64       `json:"repo_pk"`
	PusherPK int64       `json:"pusher_pk"`
	Protocol string      `json:"protocol"`
	Updates  []RefUpdate `json:"updates"`
}

PushPayload is the parsed push a deliver_event job carries so the renderer can build the push webhook body and the PushEvent feed entry from the moved refs.

type Reaction

type Reaction struct {
	ID        int64
	User      *User
	Content   string
	CreatedAt time.Time
}

Reaction is the domain view of a single reaction.

type ReactionRollup

type ReactionRollup struct {
	TotalCount int
	Counts     map[string]int
}

ReactionRollup is the per-content reaction count GitHub embeds on reactable objects. Counts is keyed by reaction content (+1, heart, ...); TotalCount is their sum.

type RefUpdate

type RefUpdate struct {
	Ref    string // fully qualified, e.g. "refs/heads/main"
	OldSHA string // ZeroSHA on create
	NewSHA string // ZeroSHA on delete
}

RefUpdate is one moved reference from a push.

func (RefUpdate) Created

func (u RefUpdate) Created() bool

Created reports whether the update brought a new ref into existence.

func (RefUpdate) Deleted

func (u RefUpdate) Deleted() bool

Deleted reports whether the update removed a ref.

type Release added in v0.1.3

type Release struct {
	PK              int64
	ID              int64
	RepoPK          int64
	TagName         string
	TargetCommitish string
	Name            *string
	Body            *string
	Draft           bool
	Prerelease      bool
	Author          *User
	Assets          []*ReleaseAsset
	CreatedAt       time.Time
	PublishedAt     *time.Time
	UpdatedAt       time.Time
}

Release is the domain view of a repository release. Draft releases are only visible to collaborators with write access; non-draft published releases are publicly visible. Assets are populated by the service when needed.

type ReleaseAsset added in v0.1.3

type ReleaseAsset struct {
	PK            int64
	ID            int64
	ReleasePK     int64
	ReleaseID     int64 // public id of the owning release, for asset urls
	Name          string
	Label         *string
	ContentType   string
	Size          int64
	DownloadCount int64
	Uploader      *User
	State         string
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

ReleaseAsset is one downloadable file attached to a release. State is "uploaded" once the binary has been written; "open" while the upload is in progress. The binary lives on disk under DataDir/assets/{PK}.

type ReleaseFilter added in v0.1.3

type ReleaseFilter struct {
	IncludeDrafts bool
	Page          int
	PerPage       int
}

ReleaseFilter selects and orders a repository's release list.

type ReleaseInput added in v0.1.3

type ReleaseInput struct {
	TagName         string
	TargetCommitish string
	Name            *string
	Body            *string
	Draft           bool
	Prerelease      bool
	MakeLatest      string // "true"|"false"|"legacy"; handled outside the DB
}

ReleaseInput is the create/update payload for a release.

type ReleaseService added in v0.1.3

type ReleaseService struct {
	// contains filtered or unexported fields
}

ReleaseService manages releases and their assets.

func NewReleaseService added in v0.1.3

func NewReleaseService(st ReleaseStore, repos *RepoService, assetDir string) *ReleaseService

NewReleaseService builds a ReleaseService. assetDir is the directory where uploaded binary files are stored (one file per asset pk).

func (*ReleaseService) CreateRelease added in v0.1.3

func (s *ReleaseService) CreateRelease(ctx context.Context, actorPK int64, owner, name string, in ReleaseInput) (*Release, error)

CreateRelease creates a new release. The actor must have write access to the repository.

func (*ReleaseService) DeleteRelease added in v0.1.3

func (s *ReleaseService) DeleteRelease(ctx context.Context, actorPK int64, owner, name string, id int64) error

DeleteRelease removes a release from the repository.

func (*ReleaseService) DeleteReleaseAsset added in v0.1.3

func (s *ReleaseService) DeleteReleaseAsset(ctx context.Context, actorPK int64, owner, name string, assetID int64) error

DeleteReleaseAsset removes an asset and its binary file.

func (*ReleaseService) GenerateReleaseNotes added in v0.1.3

func (s *ReleaseService) GenerateReleaseNotes(ctx context.Context, actorPK int64, owner, name string, in GenerateNotesInput) (*GeneratedNotes, error)

GenerateReleaseNotes collects the commit range automatic release notes are written from. The actor must have write access. The tag usually does not exist yet (gh generates notes before creating the release), so resolution falls back from the tag to the requested target commitish to the default branch, and the previous tag defaults to the latest published release.

func (*ReleaseService) GetLatestRelease added in v0.1.3

func (s *ReleaseService) GetLatestRelease(ctx context.Context, actorPK int64, owner, name string) (*Release, error)

GetLatestRelease returns the latest non-draft, non-prerelease release.

func (*ReleaseService) GetRelease added in v0.1.3

func (s *ReleaseService) GetRelease(ctx context.Context, actorPK int64, owner, name string, id int64) (*Release, error)

GetRelease returns a single release by its GitHub id within the repository.

func (*ReleaseService) GetReleaseAsset added in v0.1.3

func (s *ReleaseService) GetReleaseAsset(ctx context.Context, actorPK int64, owner, name string, assetID int64) (*ReleaseAsset, error)

GetReleaseAsset returns a single release asset.

func (*ReleaseService) GetReleaseByTag added in v0.1.3

func (s *ReleaseService) GetReleaseByTag(ctx context.Context, actorPK int64, owner, name, tag string) (*Release, error)

GetReleaseByTag returns a release by its tag name.

func (*ReleaseService) ListReleaseAssets added in v0.1.3

func (s *ReleaseService) ListReleaseAssets(ctx context.Context, actorPK int64, owner, name string, releaseID int64) ([]*ReleaseAsset, error)

ListReleaseAssets returns all assets for a release.

func (*ReleaseService) ListReleases added in v0.1.3

func (s *ReleaseService) ListReleases(ctx context.Context, actorPK int64, owner, name string, page, perPage int) ([]*Release, error)

ListReleases returns a page of releases for a repository.

func (*ReleaseService) ReleaseForEvent added in v0.1.3

func (s *ReleaseService) ReleaseForEvent(ctx context.Context, releasePK int64) (*Release, error)

ReleaseForEvent loads a release by pk for the webhook renderer, with no visibility gate: the event was authorized when it was recorded.

func (*ReleaseService) ServeAsset added in v0.1.3

func (s *ReleaseService) ServeAsset(ctx context.Context, assetID int64) (string, error)

ServeAsset increments the download counter and returns the file path so the handler can serve it (http.ServeFile handles range requests and ETags).

func (*ReleaseService) UpdateRelease added in v0.1.3

func (s *ReleaseService) UpdateRelease(ctx context.Context, actorPK int64, owner, name string, id int64, in ReleaseInput) (*Release, error)

UpdateRelease edits an existing release.

func (*ReleaseService) UpdateReleaseAsset added in v0.1.3

func (s *ReleaseService) UpdateReleaseAsset(ctx context.Context, actorPK int64, owner, name string, assetID int64, assetName, label *string) (*ReleaseAsset, error)

UpdateReleaseAsset edits the name or label of an asset.

func (*ReleaseService) UploadReleaseAsset added in v0.1.3

func (s *ReleaseService) UploadReleaseAsset(ctx context.Context, actorPK int64, owner, name string, releaseID int64, assetName, label, contentType string, r io.Reader) (*ReleaseAsset, error)

UploadReleaseAsset writes the binary to disk and records the asset row. The caller must close r; the service reads from it until EOF.

type ReleaseStore added in v0.1.3

type ReleaseStore interface {
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
	UsersByPKs(ctx context.Context, pks []int64) (map[int64]*store.UserRow, error)

	EnqueueJob(ctx context.Context, j *store.JobRow) (bool, error)
	InsertEvent(ctx context.Context, e *store.EventRow) error

	GetReleaseByID(ctx context.Context, repoPK, dbID int64) (*store.ReleaseRow, error)
	GetReleaseByPK(ctx context.Context, pk int64) (*store.ReleaseRow, error)
	GetReleaseByTag(ctx context.Context, repoPK int64, tag string) (*store.ReleaseRow, error)
	GetLatestRelease(ctx context.Context, repoPK int64) (*store.ReleaseRow, error)
	ListReleases(ctx context.Context, repoPK int64, includeDrafts bool, limit, offset int) ([]store.ReleaseRow, error)
	InsertRelease(ctx context.Context, r *store.ReleaseRow) error
	UpdateRelease(ctx context.Context, r *store.ReleaseRow) error
	DeleteRelease(ctx context.Context, pk int64) error

	ListReleaseAssets(ctx context.Context, releasePK int64) ([]store.ReleaseAssetRow, error)
	GetReleaseAssetByID(ctx context.Context, dbID int64) (*store.ReleaseAssetRow, error)
	InsertReleaseAsset(ctx context.Context, a *store.ReleaseAssetRow) error
	UpdateReleaseAsset(ctx context.Context, a *store.ReleaseAssetRow) error
	IncrementAssetDownloadCount(ctx context.Context, pk int64) error
	DeleteReleaseAsset(ctx context.Context, pk int64) error
}

ReleaseStore is the store slice the release service needs.

type Repo

type Repo struct {
	PK      int64
	OwnerPK int64
	ID      int64
	Owner   *User

	Name          string
	Description   *string
	Homepage      *string
	Private       bool
	Fork          bool
	DefaultBranch string

	HasIssues    bool
	HasProjects  bool
	HasWiki      bool
	HasDownloads bool
	Archived     bool
	Disabled     bool
	IsTemplate   bool

	AllowSquashMerge         bool
	AllowMergeCommit         bool
	AllowRebaseMerge         bool
	AllowAutoMerge           bool
	DeleteBranchOnMerge      bool
	AllowUpdateBranch        bool
	WebCommitSignoffRequired bool

	// ForkOfPK is the internal pk of the repository this one was forked
	// from, nil for a non-fork. The REST handler resolves it to the
	// parent/source objects on the full repository shape.
	ForkOfPK *int64

	OpenIssuesCount int
	PushedAt        *time.Time
	CreatedAt       time.Time
	UpdatedAt       time.Time
	Topics          string // JSON array, e.g. '["go","api"]'
}

Repo is the domain view of a repository. It is the presenter's input for the Repository wire model and the handle the git-data reads work through.

ID is the public database id (repositories.db_id), the value rendered as the REST "id". PK is the internal primary key; the git store shards bare repositories by it, so the service carries it for git access. The presenter never reads PK. OwnerPK is the owning user's internal pk, which the REST handler compares against the actor to decide the permissions block; it is also not rendered. Owner is the resolved owning account, the presenter's input for the embedded SimpleUser.

func (*Repo) FullName

func (r *Repo) FullName() string

FullName is the owner/name pair GitHub renders as full_name and uses to build the repository's URLs.

type RepoCollaborator added in v0.1.3

type RepoCollaborator struct {
	User       *User
	Permission string
}

RepoCollaborator pairs a collaborator with the permission they hold.

type RepoInput added in v0.1.3

type RepoInput struct {
	Name          string
	Description   *string
	Homepage      *string
	Private       bool
	AutoInit      bool   // init with a README commit
	DefaultBranch string // default "main"

	HasIssues   *bool
	HasProjects *bool
	HasWiki     *bool
	IsTemplate  bool

	AllowSquashMerge    *bool
	AllowMergeCommit    *bool
	AllowRebaseMerge    *bool
	AllowAutoMerge      *bool
	DeleteBranchOnMerge *bool

	GitignoreTemplate string
	LicenseTemplate   string
}

RepoInput holds the caller-supplied fields for creating a new repository. The nil-able feature and merge flags mean "use the default" (issues, projects, wiki, and the three merge methods on; auto-merge and branch deletion off). GitignoreTemplate and LicenseTemplate name templates from init_templates.go; the API layer validates them before calling CreateRepo, and a non-empty template implies an initial commit even without AutoInit, matching GitHub.

type RepoPatch added in v0.1.3

type RepoPatch struct {
	Name          *string
	Description   *string
	Homepage      *string
	DefaultBranch *string
	Private       *bool
	HasIssues     *bool
	HasProjects   *bool
	HasWiki       *bool
	Archived      *bool
	IsTemplate    *bool

	AllowSquashMerge         *bool
	AllowMergeCommit         *bool
	AllowRebaseMerge         *bool
	AllowAutoMerge           *bool
	DeleteBranchOnMerge      *bool
	AllowUpdateBranch        *bool
	WebCommitSignoffRequired *bool
}

RepoPatch holds nullable editable fields for PATCH /repos/{owner}/{repo}. A nil field leaves the stored value unchanged.

type RepoService

type RepoService struct {
	// contains filtered or unexported fields
}

RepoService resolves repositories and reads their git data. It pairs the metadata store with the git object store: GetRepo authorizes and assembles the domain Repo, and the git-data methods open the repository's bare git store through the internal pk GetRepo carried.

func NewRepoService

func NewRepoService(st RepoStore, gs *git.Store) *RepoService

NewRepoService builds a RepoService over the metadata store and the git store. The push sink submits its jobs through a store-backed enqueuer built from the same store, so a push records its events in the durable queue.

func (*RepoService) Archive added in v0.1.3

func (s *RepoService) Archive(ctx context.Context, repo *Repo, ref, format, prefix string, w io.Writer) error

Archive streams an archive of the tree at ref to w as one git archive subprocess: format is "zip" or "tar", prefix the leading directory recorded for every entry. The revision resolves before anything streams, so a bad ref or an empty repository surfaces as ErrGitNotFound while the response can still say so.

func (*RepoService) AuthorizeWrite

func (s *RepoService) AuthorizeWrite(ctx context.Context, actorPK int64, owner, name string) (*Repo, error)

AuthorizeWrite resolves the repository for the actor and checks write access. Visibility is enforced by GetRepo, so the not-found-vs-forbidden distinction matches GitHub: invisible -> 404 (ErrRepoNotFound), visible-but-no-write -> 403 (ErrForbidden). The git transport calls it to gate receive-pack.

Write access follows the actor's effective role from RepoPermission: the owner is admin, a collaborator carries the role of their grant, and any other viewer the repository is visible to is pull-only. push, maintain, and admin may write; pull (or no access) may not.

func (*RepoService) Blame added in v0.1.3

func (s *RepoService) Blame(repo *Repo, ref, path string) ([]git.BlameLine, error)

Blame returns every source line of path at ref annotated with the commit that last changed it. It returns ErrGitNotFound when the path does not exist at the ref, and ErrEmptyRepo when the repository has no commits.

func (*RepoService) CodeownersErrors added in v0.1.3

func (s *RepoService) CodeownersErrors(repo *Repo) ([]CodeownerError, error)

CodeownersErrors validates the repository's CODEOWNERS file at the default branch and returns the syntax errors GitHub's endpoint reports: a rule with no owners and an owner token that is neither an @mention nor an email. A repository with no CODEOWNERS file (or an empty one) has no errors.

func (*RepoService) CommitDiff added in v0.1.3

func (s *RepoService) CommitDiff(ctx context.Context, repo *Repo, sha string) ([]byte, error)

CommitDiff returns the commit's plain unified diff against its first parent, or against the empty tree for a root commit: the body /commit/{sha}.diff serves. Unlike CommitPatch it is one uncapped git diff subprocess, so the text endpoint never hands out a silently shortened diff.

func (*RepoService) CommitFiles added in v0.1.3

func (s *RepoService) CommitFiles(ctx context.Context, repo *Repo, sha string, ignoreWhitespace bool) ([]git.FileChange, error)

CommitFiles returns the commit's per-file changes against its first parent, or against the empty tree for a root commit: the same parsed form the PR Files tab and the compare page consume, so the commit page renders through the shared diff component instead of one raw patch. ignoreWhitespace serves the "Hide whitespace" (?w=1) view, a separate diff with display-only offsets.

func (*RepoService) CommitFormatPatch added in v0.1.3

func (s *RepoService) CommitFormatPatch(ctx context.Context, repo *Repo, sha string) ([]byte, error)

CommitFormatPatch returns the commit as a format-patch mail, the body /commit/{sha}.patch serves.

func (*RepoService) CommitPatch added in v0.1.3

func (s *RepoService) CommitPatch(repo *Repo, sha string) (string, error)

CommitPatch returns the unified diff patch of sha against its first parent. For the initial commit (no parents) it returns an empty string. The caller renders it through the markup pipeline as a diff block.

func (*RepoService) CommunityProfile added in v0.1.3

func (s *RepoService) CommunityProfile(repo *Repo) (CommunityProfile, error)

CommunityProfile computes the repository's community-health profile from the file tree at its default branch. An empty repository (no head) reports the description check alone, the way a freshly created repository does on GitHub.

func (*RepoService) Compare added in v0.1.3

func (s *RepoService) Compare(ctx context.Context, repo *Repo, base, head string) (*CompareResult, error)

Compare resolves base and head as branch names and computes the three-dot comparison between them. ErrGitNotFound is returned when either branch does not exist in the repository. When the two branches share no common history, a CompareResult with empty Commits and Files is returned rather than an error.

The cost is three git subprocesses in the common case: the merge base, then the commit list and the file diff in parallel (independent reads of immutable objects). The per-file counts ChangedFiles already carries supply the additions/deletions totals, so no separate diff --numstat runs. The commit list is capped at MaxCompareCommits; when the cap bites, one extra rev-list --count establishes the honest TotalCommits.

func (*RepoService) CompareDiff added in v0.1.3

func (s *RepoService) CompareDiff(ctx context.Context, repo *Repo, base, head string, direct bool) ([]byte, error)

CompareDiff returns the raw unified diff of the compare range as text: head against the merge base in the canonical form, or the direct two-point diff when direct is set (the two-dot form). Both ends resolve as any commit-ish; an unresolvable end is ErrGitNotFound.

func (*RepoService) CompareDirect added in v0.1.3

func (s *RepoService) CompareDirect(ctx context.Context, repo *Repo, base, head string) (*CompareResult, error)

CompareDirect is Compare over the two-dot form: the files are the diff between the two trees themselves rather than between head and the merge base, so changes only on the base side show up reversed. The commit list is the same base..head walk both forms share. Unrelated histories still produce the direct diff; only the merge base is absent.

func (*RepoService) CompareOpts added in v0.1.3

func (s *RepoService) CompareOpts(ctx context.Context, repo *Repo, base, head string, direct, ignoreWhitespace bool) (*CompareResult, error)

CompareOpts is Compare/CompareDirect with the range form and the whitespace mode chosen by the caller, backing the compare page's ?w=1 "Hide whitespace" view. The whitespace-ignored files carry display-only line counts and offsets; callers that anchor on the diff pass ignoreWhitespace false.

func (*RepoService) ComparePatch added in v0.1.3

func (s *RepoService) ComparePatch(ctx context.Context, repo *Repo, base, head string) ([]byte, error)

ComparePatch returns the compare range's own commits (base..head) as an mbox patch series, the body /compare/{basehead}.patch serves.

func (*RepoService) Contents

func (s *RepoService) Contents(repo *Repo, path, ref string) (git.PathResult, error)

Contents resolves a path at a ref. An empty ref reads the head commit. A blob yields a file result with content; a tree yields a directory listing.

func (*RepoService) CreateBlob added in v0.1.3

func (s *RepoService) CreateBlob(repo *Repo, content []byte) (*git.CreateBlobResult, error)

CreateBlob stores a blob object in the repository and returns its SHA.

func (*RepoService) CreateGitCommit added in v0.1.3

func (s *RepoService) CreateGitCommit(repo *Repo, in git.CreateCommitInput) (*git.CreateCommitResult, error)

CreateGitCommit writes a new commit object to the repository without updating any branch.

func (*RepoService) CreateGitTag added in v0.1.3

func (s *RepoService) CreateGitTag(repo *Repo, in git.CreateTagInput) (*git.CreateTagResult, error)

CreateGitTag creates an annotated tag object in the repository.

func (*RepoService) CreateRef

func (s *RepoService) CreateRef(ctx context.Context, actorPK int64, owner, name, ref, sha string) (git.Ref, error)

CreateRef creates a fully qualified reference (refs/heads/x, refs/tags/x) at sha after authorizing write access. The repository is resolved through the visibility rule first, so a private repository the actor cannot see is ErrRepoNotFound (404) rather than ErrForbidden (403).

func (*RepoService) CreateRepo added in v0.1.3

func (s *RepoService) CreateRepo(ctx context.Context, viewerPK int64, ownerLogin string, inp RepoInput) (*Repo, error)

CreateRepo creates a new repository owned by ownerLogin under the authenticated actor (viewerPK). The actor must own the target account (or be a site admin).

func (*RepoService) CreateTree added in v0.1.3

func (s *RepoService) CreateTree(repo *Repo, baseTreeSHA string, entries []git.CreateTreeEntry) (*git.CreateTreeResult, error)

CreateTree builds a new tree object in the repository.

func (*RepoService) DefaultBranchRef

func (s *RepoService) DefaultBranchRef(repo *Repo) (git.Branch, error)

DefaultBranchRef resolves the repository's head branch. It returns ErrEmptyRepo when the repository has no commits, which the caller renders as a null default_branch ref rather than an error.

func (*RepoService) DeleteFile added in v0.1.3

func (s *RepoService) DeleteFile(repo *Repo, in WriteFileInput) (*WriteFileResult, error)

DeleteFile removes a file from the repository, creating a new commit.

func (*RepoService) DeleteRef added in v0.1.3

func (s *RepoService) DeleteRef(ctx context.Context, actorPK int64, owner, name, ref string) error

DeleteRef removes an existing reference after authorizing write access.

func (*RepoService) DeleteRepo added in v0.1.3

func (s *RepoService) DeleteRepo(ctx context.Context, viewerPK int64, owner, name string) error

DeleteRepo soft-deletes the repository identified by owner/name. Only the repository owner may delete it.

func (*RepoService) Dispatch added in v0.1.3

func (s *RepoService) Dispatch(ctx context.Context, actorPK int64, owner, name, eventType string, clientPayload json.RawMessage) error

Dispatch records a repository_dispatch event, the body of POST /repos/{owner}/{repo}/dispatches that CI uses to trigger a custom workflow. It needs write access; the caller-chosen event_type and the opaque client_payload ride along to the webhook fan-out, which delivers a repository_dispatch event to every subscribed hook. The dispatch never appears on the public activity timeline, matching GitHub.

func (*RepoService) ForkRepo added in v0.1.3

func (s *RepoService) ForkRepo(ctx context.Context, viewerPK int64, src *Repo, inp ForkInput) (*Repo, error)

ForkRepo forks src for the viewer: a new repository row marked as a fork of src plus a git-level copy of its refs and objects. Forking a repository the viewer already forked returns the existing fork rather than failing, the way GitHub answers a repeat fork with the same 202. A name collision with an unrelated repository is ErrRepoExists. The caller has already resolved src through the visibility gate, so no second check runs here.

func (*RepoService) ForksCount added in v0.1.3

func (s *RepoService) ForksCount(ctx context.Context, repoPK int64) (int, error)

ForksCount reports how many live repositories were forked from repoPK. It backs network_count (and the fork counters) on the single-repository shape.

func (*RepoService) GetBlob

func (s *RepoService) GetBlob(repo *Repo, sha string) (git.Blob, error)

GetBlob loads a blob by its object id.

func (*RepoService) GetBranch

func (s *RepoService) GetBranch(repo *Repo, name string) (git.Branch, error)

GetBranch resolves a single branch by short name.

func (*RepoService) GetCommit

func (s *RepoService) GetCommit(repo *Repo, rev string) (git.Commit, error)

GetCommit loads a single commit by any revision (a sha, a branch or tag name, HEAD, or an expression like HEAD~2).

func (*RepoService) GetGitTag added in v0.1.3

func (s *RepoService) GetGitTag(repo *Repo, sha string) (*git.GetTagResult, error)

GetGitTag reads an annotated tag object by its SHA.

func (*RepoService) GetRef

func (s *RepoService) GetRef(repo *Repo, name string) (git.Ref, error)

GetRef resolves a single reference. The name carries the suffix the REST API uses (heads/main, tags/v1.0) or is fully qualified.

func (*RepoService) GetRepo

func (s *RepoService) GetRepo(ctx context.Context, viewerPK int64, owner, name string) (*Repo, error)

GetRepo resolves a repository by owner login and name for the given viewer (the authenticated user's internal pk, or 0 when anonymous). A private repository the viewer does not own is reported as ErrRepoNotFound, the same as a repository that does not exist, so a private repo never leaks through the status code.

func (*RepoService) GetRepoByID

func (s *RepoService) GetRepoByID(ctx context.Context, viewerPK, dbID int64) (*Repo, error)

GetRepoByID resolves a repository by its public database id for the viewer, applying the same visibility rule as GetRepo: a private repository the viewer cannot see is ErrRepoNotFound, never leaked. The GraphQL mutations decode a repository node id to this database id, then act through the owner-login and name path the rest of the domain uses.

func (*RepoService) GetRepoByPK added in v0.1.3

func (s *RepoService) GetRepoByPK(ctx context.Context, viewerPK, repoPK int64) (*Repo, error)

GetRepoByPK resolves a repository by its internal primary key for the viewer, applying the same visibility rule as GetRepo. It is used when the caller has decoded a ref node ID (which embeds the internal PK) and needs the full Repo.

func (*RepoService) GetTree

func (s *RepoService) GetTree(repo *Repo, rev string, recursive bool) (git.Tree, error)

GetTree loads a tree by any revision, optionally walking the whole subtree.

func (*RepoService) LatestCommit added in v0.1.3

func (s *RepoService) LatestCommit(ctx context.Context, repo *Repo, rev, path string) (git.Commit, bool, error)

LatestCommit returns the newest commit at rev touching path (the whole tree when path is empty). ok is false when nothing matches: an unborn ref, a bad revision, or a path with no history. It runs one bounded git log -1 subprocess instead of an in-process history walk, so a tree page asking for its latest-commit bar does not pay for the repository's depth.

func (*RepoService) ListBranches

func (s *RepoService) ListBranches(repo *Repo) ([]git.Branch, error)

ListBranches lists the repository's branches in name order. An empty or uninitialized repository yields an empty slice, not an error.

func (*RepoService) ListCollaboratorRepos added in v0.1.3

func (s *RepoService) ListCollaboratorRepos(ctx context.Context, viewerPK, userPK int64) ([]*Repo, error)

ListCollaboratorRepos returns the non-deleted repositories userPK holds a direct collaborator grant on, filtered by the viewer's visibility. It backs the member type and the collaborator affiliation of the repository lists.

func (*RepoService) ListCommits

func (s *RepoService) ListCommits(repo *Repo, opts git.LogOpts) ([]git.Commit, error)

ListCommits walks commit history from opts.From (defaulting to the head branch), optionally filtered to a path.

func (*RepoService) ListForks added in v0.1.3

func (s *RepoService) ListForks(ctx context.Context, viewerPK, repoPK int64) ([]*Repo, error)

ListForks returns the live forks of repoPK the viewer can see, newest first, the order the forks endpoint serves by default.

func (*RepoService) ListPublicRepos added in v0.1.3

func (s *RepoService) ListPublicRepos(ctx context.Context, sinceDBID int64, limit int) ([]*Repo, error)

ListPublicRepos returns up to limit live public repositories with a db_id greater than sinceDBID, ascending by id. It backs the global GET /repositories listing, which walks every public repository by id; each row's owner is resolved for the URL builder, with a missing owner skipped rather than failing the page.

func (*RepoService) ListRefs

func (s *RepoService) ListRefs(repo *Repo) ([]git.Ref, error)

ListRefs lists every branch and tag ref, fully qualified, in name order.

func (*RepoService) ListRepos added in v0.1.3

func (s *RepoService) ListRepos(ctx context.Context, viewerPK, ownerPK int64) ([]*Repo, error)

ListRepos returns all non-deleted repositories owned by ownerPK, filtered by the viewer's visibility. Anonymous viewers and non-owner viewers see only public repos; the owner sees all.

func (*RepoService) ListReposByLogin added in v0.1.3

func (s *RepoService) ListReposByLogin(ctx context.Context, viewerPK int64, ownerLogin string) ([]*Repo, error)

ListReposByLogin returns all non-deleted repositories owned by ownerLogin, filtered by the viewer's visibility. The owner login is resolved to an internal PK via the store. ErrUserNotFound is returned when no such account exists.

func (*RepoService) ListTags

func (s *RepoService) ListTags(repo *Repo) ([]git.Tag, error)

ListTags lists the repository's tags in name order. An empty or uninitialized repository yields an empty slice, not an error.

func (*RepoService) ListTeamRepos added in v0.1.3

func (s *RepoService) ListTeamRepos(ctx context.Context, viewerPK, userPK int64) ([]*Repo, error)

ListTeamRepos returns the non-deleted repositories userPK can reach through a team grant, filtered by the viewer's visibility. It backs the organization_member affiliation of GET /user/repos.

func (*RepoService) MergeBranch added in v0.1.3

func (s *RepoService) MergeBranch(ctx context.Context, actorPK int64, owner, name, base, head, commitMessage string) (*Repo, git.Commit, error)

MergeBranch performs a server-side branch merge, the body of POST /repos/{owner}/{repo}/merges (PyGitHub repo.merge, release scripts). It merges head into the base branch and advances the base ref to the new merge commit. base must name a branch; head may be a branch name or any commit-ish (sha, tag). A base that already contains head is ErrNothingToMerge (204), an unresolvable base or head is ErrMergeMissing (404), and a merge that does not apply cleanly is ErrMergeConflict (409). On success it returns the repository and the new merge commit so the caller can render the commit object.

func (*RepoService) OnPush

func (s *RepoService) OnPush(ctx context.Context, b PushBatch) error

OnPush is the single database-sync entry point after a push. It advances the repository's pushed_at, records a push event for webhook delivery, and enqueues a search reindex when the default branch moved. The mergeability recompute per affected pull request lands with the pull-request milestone that introduces the pull_requests table; the dedupe key it will use is reserved by the enqueue helper below. The git objects and refs are already written by the time OnPush runs, so a failure here is a metadata-lag bug, not data loss.

func (*RepoService) RepoForEvent

func (s *RepoService) RepoForEvent(ctx context.Context, repoPK int64) (*Repo, error)

RepoForEvent assembles a repository by internal pk with no visibility check, the system path the webhook renderer loads an event's repository through. The event was already authorized when it was recorded, so the renderer does not re-gate it.

func (*RepoService) RepoPermission added in v0.1.3

func (s *RepoService) RepoPermission(ctx context.Context, viewerPK int64, repo *Repo) (string, error)

RepoPermission resolves the viewer's effective role on repo: "admin" for the owner, the collaborator grant otherwise (the legacy "read"/"write" names normalize to pull/push), and "pull" for any other viewer the repository is visible to. An empty role means no access.

func (*RepoService) RepoRedirect added in v0.1.3

func (s *RepoService) RepoRedirect(ctx context.Context, viewerPK int64, owner, name string) (*Repo, error)

RepoRedirect resolves a repository that used to live at owner/name, for the 301 the web front serves after a rename. The redirect table is only consulted after the direct lookup missed (the caller's GetRepo), and the target is gated by the same visibility rule, so a moved private repository never confirms its existence through a redirect.

func (*RepoService) SyntheticHeadPush added in v0.1.3

func (s *RepoService) SyntheticHeadPush(ctx context.Context, repoPK int64, defaultBranch string, pusherPK int64) (*PushPayload, bool, error)

SyntheticHeadPush builds the push a hook test fires: a single update of the repository's default branch, before and after both pinned to its current head, so the body renders against real refs without moving anything. ok is false when the default branch has no commit yet (an empty repository), where there is nothing to test against and GitHub sends no delivery. pusherPK names the actor who triggered the test.

func (*RepoService) UpdateRef

func (s *RepoService) UpdateRef(ctx context.Context, actorPK int64, owner, name, ref, sha string, force bool) (git.Ref, error)

UpdateRef moves an existing reference to sha after authorizing write access. Unless force is set the move must be a fast-forward.

func (*RepoService) UpdateRepo added in v0.1.3

func (s *RepoService) UpdateRepo(ctx context.Context, viewerPK int64, owner, name string, p RepoPatch) (*Repo, error)

UpdateRepo applies patch to the repository identified by owner/name for the given viewer. Only the repository owner may update settings.

func (*RepoService) WriteFile added in v0.1.3

func (s *RepoService) WriteFile(repo *Repo, in WriteFileInput) (*WriteFileResult, error)

WriteFile creates or updates a file in the repository, creating a new commit on top of the branch. Returns ErrConflict if CurrentBlobSHA is set but does not match the actual current blob.

type RepoStore

type RepoStore interface {
	RepoByOwnerName(ctx context.Context, owner, name string) (*store.RepoRow, error)
	RepoByPK(ctx context.Context, pk int64) (*store.RepoRow, error)
	RepoByDBID(ctx context.Context, dbID int64) (*store.RepoRow, error)
	RepoByRedirect(ctx context.Context, owner, name string) (*store.RepoRow, error)
	UpsertRepoRedirect(ctx context.Context, oldOwner, oldName string, repoPK int64) error
	ReposByOwner(ctx context.Context, ownerPK int64) ([]*store.RepoRow, error)
	ListPublicRepos(ctx context.Context, sinceDBID int64, limit int) ([]*store.RepoRow, error)
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	InsertRepo(ctx context.Context, r *store.RepoRow) error
	UpdateRepo(ctx context.Context, pk int64, p store.RepoPatch) (*store.RepoRow, error)
	SoftDeleteRepo(ctx context.Context, pk int64) error
	CountForks(ctx context.Context, pk int64) (int64, error)
	ForksOf(ctx context.Context, pk int64) ([]*store.RepoRow, error)
	ReposByCollaborator(ctx context.Context, userPK int64) ([]*store.RepoRow, error)
	ReposByTeamMember(ctx context.Context, userPK int64) ([]*store.RepoRow, error)
	CollaboratorByRepo(ctx context.Context, repoPK, userPK int64) (*store.CollaboratorRow, error)
	TouchRepoPushedAt(ctx context.Context, pk int64, at time.Time) error
	EnqueueJob(ctx context.Context, j *store.JobRow) (bool, error)
	InsertEvent(ctx context.Context, e *store.EventRow) error
}

RepoStore is the slice of the store the repo service needs. The write path (the post-receive sink) adds the repo-by-pk lookup, the pushed_at touch, and the job enqueue; enqueuing through the store keeps the domain on its single store dependency rather than importing the worker package.

type Review

type Review struct {
	PK               int64
	ID               int64
	PullPK           int64
	PullNumber       int64
	RepoPK           int64
	User             *User
	State            string
	Body             string
	CommitID         string
	DismissedMessage *string
	Comments         []*ReviewComment
	SubmittedAt      *time.Time
	CreatedAt        time.Time
	UpdatedAt        time.Time
}

Review is the domain view of one review. ID is the review's own public database id (the value a PullRequestReview node id decodes to). State is one of the Review* constants; SubmittedAt is nil while the review is still a pending draft.

type ReviewComment

type ReviewComment struct {
	PK               int64
	ID               int64
	ReviewPK         int64
	ReviewID         int64
	PullPK           int64
	PullNumber       int64
	RepoPK           int64
	User             *User
	Path             string
	Side             string
	Line             *int64
	StartLine        *int64
	StartSide        *string
	Position         *int64
	OriginalPosition *int64
	CommitID         string
	OriginalCommitID string
	InReplyTo        *int64
	DiffHunk         string
	SubjectType      string
	Body             string
	Resolved         bool
	CreatedAt        time.Time
	UpdatedAt        time.Time
}

ReviewComment is the domain view of one inline comment. Line and StartLine are file line numbers in the line/side model; Position is the legacy 1-based diff offset. Both are filled in: the service resolves whichever the caller omitted from the pull request's diff. InReplyTo is the root comment's id when this is a reply.

type ReviewCommentInput

type ReviewCommentInput struct {
	Path      string
	Body      string
	Side      string
	Line      *int64
	StartSide string
	StartLine *int64
	Position  *int64
}

ReviewCommentInput is one inline comment in a review batch or a standalone comment. A caller gives either the line/side anchor or the legacy position; the service resolves the other from the diff.

type ReviewInput

type ReviewInput struct {
	Event    string
	Body     string
	CommitID string
	Comments []ReviewCommentInput
}

ReviewInput is the submit payload: the event (empty opens a pending draft), the review body, an optional commit the review pins to, and the batch of inline comments to attach.

type ReviewService

type ReviewService struct {
	// contains filtered or unexported fields
}

ReviewService implements the code review subsystem. It leans on the repo service for visibility and write authorization, on the pull request service to resolve and load a pull request, and on the issue service for user assembly. It reads the pull request's diff through the git store so it can resolve a comment anchor between the line/side and legacy position models and reject one that is not in the diff.

func NewReviewService

func NewReviewService(st reviewStore, repos *RepoService, prs *PRService, issues *IssueService, gs *git.Store) *ReviewService

NewReviewService builds a ReviewService over the store, the repo, pull request, and issue services, and the git store.

func (*ReviewService) CreateComment

func (s *ReviewService) CreateComment(ctx context.Context, actorPK int64, owner, name string, number int64, in ReviewCommentInput) (*ReviewComment, error)

CreateComment adds a standalone inline comment, the POST pulls/{n}/comments path. A standalone comment rides its own submitted, bodyless COMMENTED review, so every comment still belongs to a review.

func (*ReviewService) CreateReview

func (s *ReviewService) CreateReview(ctx context.Context, actorPK int64, owner, name string, number int64, in ReviewInput) (*Review, error)

CreateReview opens a review on a pull request. With an event it submits immediately (approved, changes requested, or commented); without one it opens the author's single pending draft. It authorizes read access, forbids self-approval, requires a body where the event needs one, resolves every inline anchor against the diff, writes the review and its comments in one transaction, and enqueues the decision recompute.

func (*ReviewService) DeleteReview added in v0.1.3

func (s *ReviewService) DeleteReview(ctx context.Context, actorPK int64, reviewDBID int64) (*Review, error)

DeleteReview deletes a pending (PENDING state) review by its database ID. Only the review's author may delete their own pending draft.

func (*ReviewService) DeleteReviewComment added in v0.1.3

func (s *ReviewService) DeleteReviewComment(ctx context.Context, actorPK, commentDBID int64) error

DeleteReviewComment removes an inline review comment.

func (*ReviewService) DismissReview

func (s *ReviewService) DismissReview(ctx context.Context, actorPK int64, owner, name string, number, reviewDBID int64, message string) (*Review, error)

DismissReview drops a submitted review's approval or change request, recording a reason. It needs write access, the permission to override a reviewer.

func (*ReviewService) EditReviewComment added in v0.1.3

func (s *ReviewService) EditReviewComment(ctx context.Context, actorPK, commentDBID int64, body string) (*ReviewComment, error)

EditReviewComment updates the body of an inline review comment.

func (*ReviewService) GetComment

func (s *ReviewService) GetComment(ctx context.Context, viewerPK int64, owner, name string, commentDBID int64) (*ReviewComment, error)

GetComment resolves one inline comment by id for the viewer. The standalone pulls/comments/{id} route carries no pull number, so the owning pull request's number is resolved from the comment to build its urls.

func (*ReviewService) GetReview

func (s *ReviewService) GetReview(ctx context.Context, viewerPK int64, owner, name string, number, reviewDBID int64) (*Review, error)

GetReview resolves one review by id for the viewer.

func (*ReviewService) ListAllReviewComments added in v0.1.3

func (s *ReviewService) ListAllReviewComments(ctx context.Context, viewerPK int64, owner, name string) ([]*ReviewComment, error)

ListAllReviewComments returns all inline review comments in a repository.

func (*ReviewService) ListComments

func (s *ReviewService) ListComments(ctx context.Context, viewerPK int64, owner, name string, number int64) ([]*ReviewComment, error)

ListComments returns every inline comment on a pull request for the viewer.

func (*ReviewService) ListCommentsForReview added in v0.1.3

func (s *ReviewService) ListCommentsForReview(ctx context.Context, viewerPK int64, owner, name string, number, reviewDBID int64) ([]*ReviewComment, error)

ListCommentsForReview returns the inline comments attached to one review, the GET reviews/{review_id}/comments shape. A pending draft's comments stay private to the draft's author.

func (*ReviewService) ListReviews

func (s *ReviewService) ListReviews(ctx context.Context, viewerPK int64, owner, name string, number int64) ([]*Review, error)

ListReviews returns a pull request's submitted reviews for the viewer.

func (*ReviewService) RecomputeReviewDecision

func (s *ReviewService) RecomputeReviewDecision(ctx context.Context, issuePK int64) error

RecomputeReviewDecision resolves and caches a pull request's review decision and status check rollup, the body of the recompute_review_decision worker. A missing pull request is a no-op, the same tolerance the mergeability recompute has for a deleted row.

func (*ReviewService) ReplyComment

func (s *ReviewService) ReplyComment(ctx context.Context, actorPK int64, owner, name string, number, inReplyToDBID int64, body string) (*ReviewComment, error)

ReplyComment adds a reply under an existing comment's thread, the POST pulls/{n}/comments/{id}/replies path. The reply inherits the root's anchor.

func (*ReviewService) ResolveThread

func (s *ReviewService) ResolveThread(ctx context.Context, actorPK int64, owner, name string, number, rootDBID int64, resolved bool) (*ReviewThread, error)

ResolveThread resolves or unresolves a review thread by its root comment id. It needs write access, the permission to settle a conversation.

func (*ReviewService) ReviewCommentForEvent added in v0.1.3

func (s *ReviewService) ReviewCommentForEvent(ctx context.Context, commentPK int64) (*ReviewComment, error)

ReviewCommentForEvent loads one inline review comment by its internal pk for the delivery renderer.

func (*ReviewService) ReviewDecision

func (s *ReviewService) ReviewDecision(ctx context.Context, viewerPK int64, owner, name string, number int64) (*string, error)

ReviewDecision returns a pull request's derived review decision for the viewer, the value the GraphQL field and the pull request view surface.

func (*ReviewService) ReviewForEvent added in v0.1.3

func (s *ReviewService) ReviewForEvent(ctx context.Context, reviewPK int64) (*Review, error)

ReviewForEvent loads one review by its internal pk for the delivery renderer, off the visibility gate like every ForEvent loader.

func (*ReviewService) ReviewRef added in v0.1.3

func (s *ReviewService) ReviewRef(ctx context.Context, viewerPK, reviewDBID int64) (owner, name string, number int64, err error)

ReviewRef decodes a review's db id into the owner, repo, and pull number the submit and dismiss mutations address it by. It enforces the viewer's visibility through GetRepo, so a review in a private repository resolves as not found.

func (*ReviewService) ReviewThreads

func (s *ReviewService) ReviewThreads(ctx context.Context, viewerPK int64, owner, name string, number int64) ([]*ReviewThread, error)

ReviewThreads folds a pull request's inline comments into threads (a root and its replies) and marks each resolved and outdated, the shape the GraphQL reviewThreads connection renders. viewerPK gates repository visibility.

func (*ReviewService) SubmitReview

func (s *ReviewService) SubmitReview(ctx context.Context, actorPK int64, owner, name string, number, reviewDBID int64, event, body string) (*Review, error)

SubmitReview submits a previously opened pending review under an event, the path the reviews/{id}/events endpoint and gh pr review on a draft take.

func (*ReviewService) ThreadRef

func (s *ReviewService) ThreadRef(ctx context.Context, viewerPK, rootDBID int64) (owner, name string, number int64, err error)

ThreadRef decodes a review thread's root comment id into the owner, repo, and pull number the resolve and unresolve mutations address it by. It enforces the viewer's visibility through GetRepo, so a thread in a repository the viewer cannot see resolves as not found rather than leaking its existence.

func (*ReviewService) UpdateReview added in v0.1.3

func (s *ReviewService) UpdateReview(ctx context.Context, actorPK int64, owner, name string, number, reviewDBID int64, body string) (*Review, error)

UpdateReview replaces the summary body of a review, the PUT review shape. Only the review's author may edit it.

type ReviewThread

type ReviewThread struct {
	RootPK     int64
	ID         int64
	PullPK     int64
	Path       string
	Line       *int64
	IsResolved bool
	IsOutdated bool
	Comments   []*ReviewComment
}

ReviewThread is a conversation: a root comment and the replies chained under it. ID is the root comment's thread node id. IsResolved follows the root's resolved flag; IsOutdated is true when the anchored line is no longer present in the pull request's current diff.

type SearchService

type SearchService struct {
	// contains filtered or unexported fields
}

SearchService runs the three search surfaces over the store and git. Issue, repository, and code search are filtered index scans; the service also owns the code index, rebuilding a repository's documents from its head tree when the push worker asks or when a search finds the index behind the head. It reuses the repo and issue services to assemble the domain values it returns, so visibility and rendering stay defined in one place. The store scans already gate visibility by viewer, so a private repository never appears in another viewer's results.

func NewSearchService

func NewSearchService(st SearchStore, repos *RepoService, issues *IssueService, gs *git.Store) *SearchService

NewSearchService builds a SearchService over the store, the repo and issue services, and the git store code search reads blobs from.

func (*SearchService) ReindexRepoCode added in v0.1.3

func (s *SearchService) ReindexRepoCode(ctx context.Context, repoPK int64) error

ReindexRepoCode rebuilds the repository's code index when its head moved. The reindex_search worker calls it after a default-branch push; searches call the same path lazily through ensureCodeIndex, so the worker is an optimization (warm index before anyone searches), not a correctness requirement.

func (*SearchService) SearchCode

func (s *SearchService) SearchCode(ctx context.Context, viewerPK int64, raw string, page, perPage int) ([]CodeResult, int, bool, error)

SearchCode queries the code index over the repositories the query scopes to and returns the files whose path or content matches the free-text terms. It requires a repo:, user:, or org: qualifier, matching GitHub's rule that a code search cannot span every repository on the host. Before querying it brings each scoped repository's index up to its current head, so a search right after a push (or after a web edit that never went through the push path) still sees the new content. The bool result reports whether any scoped index is truncated, which becomes the envelope's incomplete_results.

func (*SearchService) SearchIssues

func (s *SearchService) SearchIssues(ctx context.Context, viewerPK int64, raw, sort, order string, page, perPage int) ([]IssueHit, int, error)

SearchIssues runs an issue/pull-request search for the viewer and returns the page of assembled issues plus the total match count for the envelope.

func (*SearchService) SearchRepositories

func (s *SearchService) SearchRepositories(ctx context.Context, viewerPK int64, raw, sort, order string, page, perPage int) ([]*Repo, int, error)

SearchRepositories runs a repository search for the viewer and returns the page of assembled repositories plus the total match count.

func (*SearchService) SearchUsers added in v0.1.3

func (s *SearchService) SearchUsers(ctx context.Context, raw, sort, order string, page, perPage int) ([]*User, int, error)

SearchUsers runs an account search over the users table and returns the page of matched accounts plus the total match count. The free-text terms match the login, name, and public email; the type: qualifier narrows to user or org accounts. Unlike code search it spans every account, since accounts are public; visibility never enters into it.

type SearchStore

type SearchStore interface {
	SearchIssues(ctx context.Context, q store.IssueSearch) ([]store.IssueRow, error)
	CountSearchIssues(ctx context.Context, q store.IssueSearch) (int, error)
	SearchRepositories(ctx context.Context, q store.RepoSearch) ([]store.RepoRow, error)
	CountSearchRepositories(ctx context.Context, q store.RepoSearch) (int, error)
	SearchCode(ctx context.Context, q store.CodeSearch) ([]store.CodeHit, error)
	CountSearchCode(ctx context.Context, q store.CodeSearch) (int, error)
	SearchUsers(ctx context.Context, q store.UserSearch) ([]store.UserRow, error)
	CountSearchUsers(ctx context.Context, q store.UserSearch) (int, error)
	CodeIndexHead(ctx context.Context, repoPK int64) (string, error)
	CodeIndexTruncated(ctx context.Context, repoPKs []int64) (bool, error)
	ReplaceCodeDocs(ctx context.Context, repoPK int64, headSHA string, truncated bool, docs []store.CodeDoc) error
	VisibleRepoPKs(ctx context.Context, viewerPK int64, ownerPKs []int64) ([]int64, error)
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	RepoByOwnerName(ctx context.Context, owner, name string) (*store.RepoRow, error)
}

SearchStore is the slice of the store the search service needs: the cross-repository issue, repository, and code scans, the code index the service maintains, the visible-repository lookup that scopes code search, and the login and owner/name resolution that turns qualifiers into the internal pks the scans filter on.

type SocialService added in v0.1.3

type SocialService struct {
	// contains filtered or unexported fields
}

SocialService manages stars, watches, and follows.

func NewSocialService added in v0.1.3

func NewSocialService(st SocialStore) *SocialService

NewSocialService builds a SocialService over the store.

func (*SocialService) ActorFollows added in v0.1.3

func (s *SocialService) ActorFollows(ctx context.Context, actorPK int64, login string) (bool, error)

ActorFollows reports whether the actor follows the named user.

func (*SocialService) DeleteSubscription added in v0.1.3

func (s *SocialService) DeleteSubscription(ctx context.Context, actorPK int64, owner, name string) error

DeleteSubscription removes the actor's subscription to owner/name. Removing an absent subscription is a no-op.

func (*SocialService) Follow added in v0.1.3

func (s *SocialService) Follow(ctx context.Context, actorPK int64, login string) error

Follow records that the actor follows the named user. Following oneself is rejected, matching GitHub, and a repeated follow is a no-op.

func (*SocialService) FollowersOfActor added in v0.1.3

func (s *SocialService) FollowersOfActor(ctx context.Context, actorPK int64) ([]*User, error)

FollowersOfActor lists the users following the authenticated actor.

func (*SocialService) FollowersOfLogin added in v0.1.3

func (s *SocialService) FollowersOfLogin(ctx context.Context, login string) ([]*User, error)

FollowersOfLogin lists the users following the named user. The handler pages the returned slice.

func (*SocialService) FollowingOfActor added in v0.1.3

func (s *SocialService) FollowingOfActor(ctx context.Context, actorPK int64) ([]*User, error)

FollowingOfActor lists the users the authenticated actor follows.

func (*SocialService) FollowingOfLogin added in v0.1.3

func (s *SocialService) FollowingOfLogin(ctx context.Context, login string) ([]*User, error)

FollowingOfLogin lists the users the named user follows. The handler pages the returned slice.

func (*SocialService) IsStarred added in v0.1.3

func (s *SocialService) IsStarred(ctx context.Context, actorPK int64, owner, name string) (bool, error)

IsStarred reports whether the actor has starred owner/name.

func (*SocialService) SetSubscription added in v0.1.3

func (s *SocialService) SetSubscription(ctx context.Context, actorPK int64, owner, name string, subscribed, ignored bool) (*Subscription, error)

SetSubscription sets the actor's subscription to owner/name, creating or replacing it, the way PUT /repos/{o}/{r}/subscription does.

func (*SocialService) StarRepo added in v0.1.3

func (s *SocialService) StarRepo(ctx context.Context, actorPK int64, owner, name string) error

StarRepo records that the actor starred owner/name. A repeated star is a no-op, matching the idempotent PUT.

func (*SocialService) Stargazers added in v0.1.3

func (s *SocialService) Stargazers(ctx context.Context, owner, name string) ([]*User, error)

Stargazers lists the users who starred owner/name. The handler pages the returned slice.

func (*SocialService) StarredByActor added in v0.1.3

func (s *SocialService) StarredByActor(ctx context.Context, actorPK int64) ([]*Repo, error)

StarredByActor lists the repositories the authenticated actor starred. The actor sees their own private starred repositories.

func (*SocialService) StarredByLogin added in v0.1.3

func (s *SocialService) StarredByLogin(ctx context.Context, viewerPK int64, login string) ([]*Repo, error)

StarredByLogin lists the repositories the named user starred, filtered by the viewer's visibility. The handler pages the returned slice.

func (*SocialService) Subscription added in v0.1.3

func (s *SocialService) Subscription(ctx context.Context, actorPK int64, owner, name string) (*Subscription, error)

Subscription returns the actor's subscription to owner/name, or ErrNotFound when the actor has set none.

func (*SocialService) SubscriptionsByActor added in v0.1.3

func (s *SocialService) SubscriptionsByActor(ctx context.Context, actorPK int64) ([]*Repo, error)

SubscriptionsByActor lists the repositories the authenticated actor watches.

func (*SocialService) SubscriptionsByLogin added in v0.1.3

func (s *SocialService) SubscriptionsByLogin(ctx context.Context, viewerPK int64, login string) ([]*Repo, error)

SubscriptionsByLogin lists the repositories the named user watches, filtered by the viewer's visibility. The handler pages the returned slice.

func (*SocialService) Unfollow added in v0.1.3

func (s *SocialService) Unfollow(ctx context.Context, actorPK int64, login string) error

Unfollow removes the actor's follow of the named user. Removing an absent follow is a no-op.

func (*SocialService) UnstarRepo added in v0.1.3

func (s *SocialService) UnstarRepo(ctx context.Context, actorPK int64, owner, name string) error

UnstarRepo removes the actor's star on owner/name. Removing an absent star is a no-op.

func (*SocialService) UserFollows added in v0.1.3

func (s *SocialService) UserFollows(ctx context.Context, followerLogin, targetLogin string) (bool, error)

UserFollows reports whether the named follower follows the named target. It backs GET /users/{u}/following/{target}.

func (*SocialService) Watchers added in v0.1.3

func (s *SocialService) Watchers(ctx context.Context, owner, name string) ([]*User, error)

Watchers lists the users watching owner/name. The handler pages the returned slice.

type SocialStore added in v0.1.3

type SocialStore interface {
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
	RepoByOwnerName(ctx context.Context, owner, name string) (*store.RepoRow, error)
	CollaboratorByRepo(ctx context.Context, repoPK, userPK int64) (*store.CollaboratorRow, error)

	InsertStar(ctx context.Context, userPK, repoPK int64) error
	DeleteStar(ctx context.Context, userPK, repoPK int64) error
	IsStarred(ctx context.Context, userPK, repoPK int64) (bool, error)
	StarCount(ctx context.Context, repoPK int64) (int, error)
	StargazersByRepo(ctx context.Context, repoPK int64, limit, offset int) ([]*store.UserRow, error)
	StarredByUser(ctx context.Context, userPK int64, limit, offset int) ([]*store.RepoRow, error)

	UpsertSubscription(ctx context.Context, userPK, repoPK int64, subscribed, ignored bool) error
	DeleteSubscription(ctx context.Context, userPK, repoPK int64) error
	SubscriptionByRepo(ctx context.Context, userPK, repoPK int64) (*store.SubscriptionRow, error)
	WatcherCount(ctx context.Context, repoPK int64) (int, error)
	WatchersByRepo(ctx context.Context, repoPK int64, limit, offset int) ([]*store.UserRow, error)
	SubscriptionsByUser(ctx context.Context, userPK int64, limit, offset int) ([]*store.RepoRow, error)

	InsertFollow(ctx context.Context, followerPK, targetPK int64) error
	DeleteFollow(ctx context.Context, followerPK, targetPK int64) error
	IsFollowing(ctx context.Context, followerPK, targetPK int64) (bool, error)
	FollowerCount(ctx context.Context, targetPK int64) (int, error)
	FollowingCount(ctx context.Context, followerPK int64) (int, error)
	FollowersByUser(ctx context.Context, targetPK int64, limit, offset int) ([]*store.UserRow, error)
	FollowingByUser(ctx context.Context, followerPK int64, limit, offset int) ([]*store.UserRow, error)
}

SocialStore is the slice of the store the SocialService depends on.

type StatusCheckRollup

type StatusCheckRollup struct {
	State      string // one of the Rollup* constants
	SHA        string
	Statuses   []*CommitStatus
	CheckRuns  []*CheckRun
	TotalCount int
}

StatusCheckRollup is the combined verdict across every status and check run on a head sha, the value the pull request and its head commit surface.

type StatusInput

type StatusInput struct {
	State       string
	Context     string
	TargetURL   string
	Description string
}

StatusInput is the create payload for a commit status.

type Subscription added in v0.1.3

type Subscription struct {
	Subscribed bool
	Ignored    bool
	CreatedAt  time.Time
	RepoOwner  string
	RepoName   string
}

Subscription is the domain view of a repository subscription, the input for the REST subscription model.

type TeamService added in v0.1.3

type TeamService struct {
	// contains filtered or unexported fields
}

TeamService manages teams, collaborators, and repository topics.

func NewTeamService added in v0.1.3

func NewTeamService(st TeamStore) *TeamService

NewTeamService creates a TeamService over st.

func (*TeamService) AddCollaborator added in v0.1.3

func (s *TeamService) AddCollaborator(ctx context.Context, repoPK, userPK int64, permission string) (id int64, created bool, err error)

AddCollaborator sets (or updates) a collaborator's permission. created reports whether the grant is new, the bit that decides between GitHub's 201 invitation response and the 204 for an existing collaborator; id is the grant's row id, which doubles as the invitation id.

func (*TeamService) AddOrgMember added in v0.1.3

func (s *TeamService) AddOrgMember(ctx context.Context, orgPK, userPK int64, role string) (string, error)

AddOrgMember adds or updates a user's org membership. Any role other than admin normalizes to member, GitHub's two-role vocabulary.

func (*TeamService) AddTeamMember added in v0.1.3

func (s *TeamService) AddTeamMember(ctx context.Context, teamPK, userPK int64, role string) error

AddTeamMember adds or updates a user's role in a team.

func (*TeamService) AddTeamRepo added in v0.1.3

func (s *TeamService) AddTeamRepo(ctx context.Context, teamPK, repoPK int64, permission string) error

AddTeamRepo grants a team access to a repo.

func (*TeamService) CreateTeam added in v0.1.3

func (s *TeamService) CreateTeam(ctx context.Context, orgPK int64, name, description, privacy, permission string) (*store.TeamRow, error)

CreateTeam creates a new team in an org.

func (*TeamService) DeleteTeam added in v0.1.3

func (s *TeamService) DeleteTeam(ctx context.Context, pk int64) error

DeleteTeam removes a team.

func (*TeamService) GetCollaboratorPermission added in v0.1.3

func (s *TeamService) GetCollaboratorPermission(ctx context.Context, repoPK, userPK int64) (string, error)

GetCollaboratorPermission returns the permission of userPK on repoPK.

func (*TeamService) GetOrgMembership added in v0.1.3

func (s *TeamService) GetOrgMembership(ctx context.Context, orgPK, userPK int64) (string, error)

GetOrgMembership returns the role of userPK in orgPK, or ErrNotFound.

func (*TeamService) GetTeamBySlug added in v0.1.3

func (s *TeamService) GetTeamBySlug(ctx context.Context, orgPK int64, slug string) (*store.TeamRow, error)

GetTeamBySlug returns a team by org pk and slug.

func (*TeamService) GetTeamMembership added in v0.1.3

func (s *TeamService) GetTeamMembership(ctx context.Context, teamPK, userPK int64) (string, error)

GetTeamMembership returns the role of userPK in teamPK, or ErrNotFound.

func (*TeamService) GetTeamRepoPermission added in v0.1.3

func (s *TeamService) GetTeamRepoPermission(ctx context.Context, teamPK, repoPK int64) (string, error)

GetTeamRepoPermission returns the permission level for a repo in a team.

func (*TeamService) ListCollaborators added in v0.1.3

func (s *TeamService) ListCollaborators(ctx context.Context, repoPK int64) ([]RepoCollaborator, error)

ListCollaborators returns a repo's collaborator grants with their users resolved, oldest grant first. A grant whose user has vanished is skipped.

func (*TeamService) ListOrgMembers added in v0.1.3

func (s *TeamService) ListOrgMembers(ctx context.Context, orgPK int64) ([]OrgMember, error)

ListOrgMembers returns an org's members with their users resolved, oldest first. A membership whose user has vanished is skipped.

func (*TeamService) ListTeams added in v0.1.3

func (s *TeamService) ListTeams(ctx context.Context, orgPK int64) ([]*store.TeamRow, error)

ListTeams returns an org's teams, oldest first.

func (*TeamService) ListUserOrgs added in v0.1.3

func (s *TeamService) ListUserOrgs(ctx context.Context, userPK int64) ([]OrgMember, error)

ListUserOrgs returns the organizations userPK belongs to, oldest membership first, each paired with the role held. The User of each entry is the org account (orgs share the users table). An org whose account has vanished is skipped.

func (*TeamService) RemoveCollaborator added in v0.1.3

func (s *TeamService) RemoveCollaborator(ctx context.Context, repoPK, userPK int64) error

RemoveCollaborator removes a collaborator from a repo.

func (*TeamService) RemoveOrgMember added in v0.1.3

func (s *TeamService) RemoveOrgMember(ctx context.Context, orgPK, userPK int64) error

RemoveOrgMember removes a user from an org.

func (*TeamService) RemoveTeamMember added in v0.1.3

func (s *TeamService) RemoveTeamMember(ctx context.Context, teamPK, userPK int64) error

RemoveTeamMember removes a user from a team.

func (*TeamService) RemoveTeamRepo added in v0.1.3

func (s *TeamService) RemoveTeamRepo(ctx context.Context, teamPK, repoPK int64) error

RemoveTeamRepo removes a repo from a team.

func (*TeamService) SetTopics added in v0.1.3

func (s *TeamService) SetTopics(ctx context.Context, repoPK int64, topics []string) error

SetTopics replaces the topics for a repo.

func (*TeamService) TeamCounts added in v0.1.3

func (s *TeamService) TeamCounts(ctx context.Context, teamPK int64) (members, repos int, err error)

TeamCounts returns how many members and repos a team has.

func (*TeamService) UpdateTeam added in v0.1.3

func (s *TeamService) UpdateTeam(ctx context.Context, pk int64, name, description, privacy, permission *string) (*store.TeamRow, error)

UpdateTeam applies partial updates to a team.

type TeamStore added in v0.1.3

type TeamStore interface {
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
	TeamBySlug(ctx context.Context, orgPK int64, slug string) (*store.TeamRow, error)
	TeamByPK(ctx context.Context, pk int64) (*store.TeamRow, error)
	InsertTeam(ctx context.Context, t *store.TeamRow) error
	UpdateTeam(ctx context.Context, pk int64, name, description, privacy, permission *string) (*store.TeamRow, error)
	DeleteTeam(ctx context.Context, pk int64) error
	UpsertTeamMember(ctx context.Context, teamPK, userPK int64, role string) error
	TeamMemberRole(ctx context.Context, teamPK, userPK int64) (string, error)
	DeleteTeamMember(ctx context.Context, teamPK, userPK int64) error
	UpsertTeamRepo(ctx context.Context, teamPK, repoPK int64, permission string) error
	TeamRepoPermission(ctx context.Context, teamPK, repoPK int64) (string, error)
	DeleteTeamRepo(ctx context.Context, teamPK, repoPK int64) error
	RepoByOwnerName(ctx context.Context, owner, name string) (*store.RepoRow, error)
	UpdateRepoTopics(ctx context.Context, repoPK int64, topicsJSON string) error
	CollaboratorByRepo(ctx context.Context, repoPK, userPK int64) (*store.CollaboratorRow, error)
	CollaboratorsByRepo(ctx context.Context, repoPK int64) ([]*store.CollaboratorRow, error)
	UpsertCollaborator(ctx context.Context, repoPK, userPK int64, permission string) error
	DeleteCollaborator(ctx context.Context, repoPK, userPK int64) error
	TeamsByOrg(ctx context.Context, orgPK int64) ([]*store.TeamRow, error)
	CountTeamMembers(ctx context.Context, teamPK int64) (int, error)
	CountTeamRepos(ctx context.Context, teamPK int64) (int, error)
	UpsertOrgMember(ctx context.Context, orgPK, userPK int64, role string) error
	OrgMemberRole(ctx context.Context, orgPK, userPK int64) (string, error)
	DeleteOrgMember(ctx context.Context, orgPK, userPK int64) error
	OrgMembersByOrg(ctx context.Context, orgPK int64) ([]*store.OrgMemberRow, error)
	OrgMembersByUser(ctx context.Context, userPK int64) ([]*store.OrgMemberRow, error)
}

TeamStore is the narrow store interface TeamService depends on.

type User

type User struct {
	ID              int64
	Login           string
	Type            string
	SiteAdmin       bool
	Name            *string
	Company         *string
	Blog            string
	Location        *string
	Email           *string
	Hireable        *bool
	Bio             *string
	TwitterUsername *string
	PublicRepos     int
	PublicGists     int
	Followers       int
	Following       int
	CreatedAt       time.Time
	UpdatedAt       time.Time
}

User is the domain view of an account. It is the presenter's input for both the SimpleUser and full User wire models. ID is the public database id (users.db_id), not the internal primary key.

type UserService

type UserService struct {
	// contains filtered or unexported fields
}

UserService resolves accounts into domain users. The REST layer holds it and passes the authenticated actor's user id to Viewer for GET /user.

func NewUserService

func NewUserService(st UserStore) *UserService

NewUserService builds a UserService over the store.

func (*UserService) ByLogin

func (s *UserService) ByLogin(ctx context.Context, login string) (*User, error)

ByLogin resolves a public profile by login.

func (*UserService) ListUsers added in v0.1.3

func (s *UserService) ListUsers(ctx context.Context, since int64, limit int) ([]*User, error)

ListUsers returns up to limit accounts with an id greater than since, ordered by id, backing GitHub's GET /users id-cursor pagination.

func (*UserService) PKByLogin added in v0.1.3

func (s *UserService) PKByLogin(ctx context.Context, login string) (int64, error)

PKByLogin returns the internal (store) primary key of the user with the given login, or ErrUserNotFound if no such user exists. This is used by REST handlers that need to call services accepting internal PKs.

func (*UserService) UpdateProfile added in v0.1.3

func (s *UserService) UpdateProfile(ctx context.Context, viewerPK int64, fields ProfileFields) error

UpdateProfile updates the authenticated viewer's profile fields. Only the fields named in fields are written; empty strings clear their column value.

func (*UserService) Viewer

func (s *UserService) Viewer(ctx context.Context, userPK int64) (*User, error)

Viewer resolves the authenticated user behind GET /user. The caller has already established that the actor is a user and passes its internal pk.

type UserStore

type UserStore interface {
	UserByPK(ctx context.Context, pk int64) (*store.UserRow, error)
	UserByLogin(ctx context.Context, login string) (*store.UserRow, error)
	UpdateProfile(ctx context.Context, userPK int64, u store.ProfileUpdate) error
	ListUsers(ctx context.Context, sinceDBID int64, limit int) ([]*store.UserRow, error)
}

UserStore is the slice of the store the user service needs.

type WriteFileInput added in v0.1.3

type WriteFileInput struct {
	Path           string
	Content        []byte // nil for delete
	Message        string
	AuthorName     string
	AuthorEmail    string
	Branch         string
	CurrentBlobSHA string // must match current blob if non-empty
}

WriteFileInput holds the inputs for the file-write domain operation.

type WriteFileResult added in v0.1.3

type WriteFileResult struct {
	CommitSHA string
	BlobSHA   string // empty on delete
}

WriteFileResult is returned by WriteFile and DeleteFile.

Jump to

Keyboard shortcuts

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