Documentation
¶
Overview ¶
Package forge defines gu's provider-neutral view of a code-hosting service. Views depend on this package alone; they never import a provider package.
Index ¶
- Constants
- Variables
- func ParseTarget(target string) (kind string, id int, err error)
- func SplitPath(full string) (namespace, project string)
- func SuggestionBody(s Suggestion, style SuggestionStyle) string
- type Caps
- type DiffComment
- type DiffRefs
- type FieldPatch
- type Forge
- type Issue
- type IssueFilter
- type Job
- type MRFilter
- type Membership
- type MergeRequest
- type MyWorkFilter
- type Namespace
- type Note
- type Pipeline
- type PipelineFilter
- type Ref
- type Repo
- type Role
- type Side
- type Suggestion
- type SuggestionStyle
- type Thread
- type TreeEntry
- type User
- type WorkItem
Constants ¶
const ( StatusSuccess = "success" StatusFailed = "failed" StatusRunning = "running" StatusPending = "pending" StatusCanceled = "canceled" StatusSkipped = "skipped" StatusManual = "manual" )
Pipeline statuses, normalised across providers.
const ( KindIssue = "issue" KindMR = "mr" )
Kinds of work item.
const ( EntryDir = "dir" EntryFile = "file" )
Entry kinds in a repository tree.
Variables ¶
var ErrNotPositioned = errors.New("this comment cannot be anchored to the diff")
ErrNotPositioned is returned when a comment cannot be anchored to the diff — the merge request's refs are unknown, or the provider refused the position.
It is a distinct error rather than a silent fallback because a comment that was meant to sit on line 42 and instead appears at the bottom of the discussion is a different comment, and the author should be told which they got.
var ErrReadOnly = errors.New("read-only mode: relaunch without --read-only to make changes")
ErrReadOnly is returned by every mutating method when gu runs read-only.
Functions ¶
func ParseTarget ¶
ParseTarget splits an address — "issue/12" or "mr/42" — into its kind and number.
The format is this package's, named in Forge's own documentation, so both providers parse it through here rather than each keeping its own copy of the same three lines.
func SuggestionBody ¶
func SuggestionBody(s Suggestion, style SuggestionStyle) string
SuggestionBody renders a suggestion as the comment body a provider expects.
The fence is four backticks because a suggestion routinely contains code with three, and a fence the content can close is a suggestion that arrives truncated.
Types ¶
type Caps ¶
type Caps struct {
Suggestions bool
MultiLineSuggestions bool
SuggestionStyle SuggestionStyle
}
Caps says what a provider will accept, so the UI can offer only what will work rather than posting something that comes back rejected.
type DiffComment ¶
type DiffComment struct {
Body string
OldPath, NewPath string
Side Side
Line, StartLine int
Refs DiffRefs
}
DiffComment is a review comment anchored to a place in the diff.
Line is the last line of the range and StartLine the first, zero for a single line — the shape both providers use, and the shape a multi-line suggestion needs.
type DiffRefs ¶
type DiffRefs struct {
BaseSHA, HeadSHA, StartSHA string
}
DiffRefs are the commits a merge request's diff is computed from.
GitLab wants all three to position a comment; GitHub positions against the head commit alone. They travel together because they come from one place and are useless apart.
func (DiffRefs) Positioned ¶
Positioned reports whether the refs will carry a comment's position. The head commit is the one both providers need.
type FieldPatch ¶
FieldPatch is a partial update. A nil field means "leave unchanged", which is why every field is a pointer or a nilable slice.
type Forge ¶
type Forge interface {
// Capabilities reports what this provider will accept, so the UI can offer
// only what will work rather than posting something that comes back
// rejected.
Capabilities() Caps
// Whoami identifies the authenticated user.
Whoami(ctx context.Context) (User, error)
// Namespaces lists children of parent; parent "" lists top-level ones.
Namespaces(ctx context.Context, parent string) ([]Namespace, error)
// Repos lists projects directly inside namespace.
Repos(ctx context.Context, namespace string) ([]Repo, error)
// Issues lists issues in a project.
Issues(ctx context.Context, ref Ref, f IssueFilter) ([]Issue, error)
// Issue fetches one issue by its number.
Issue(ctx context.Context, ref Ref, id int) (Issue, error)
// GroupIssues lists issues across every project in a group, which is what
// a group-level board shows.
GroupIssues(ctx context.Context, group string, f IssueFilter) ([]Issue, error)
// MergeRequests lists merge requests or pull requests in a project.
MergeRequests(ctx context.Context, ref Ref, f MRFilter) ([]MergeRequest, error)
// MergeRequest fetches one merge request by its number.
MergeRequest(ctx context.Context, ref Ref, mr int) (MergeRequest, error)
// MergeRequestDiff returns a merge request as a unified diff.
MergeRequestDiff(ctx context.Context, ref Ref, mr int) (string, error)
// Threads lists the discussions on an issue or merge request. target is
// "issue/<id>" or "mr/<id>".
Threads(ctx context.Context, ref Ref, target string) ([]Thread, error)
// Tree lists the entries directly under a path in a repository. path ""
// is the root; ref "" is the default branch.
Tree(ctx context.Context, ref Ref, path, rev string) ([]TreeEntry, error)
// FileContent returns a file's bytes.
FileContent(ctx context.Context, ref Ref, path, rev string) ([]byte, error)
// MyWork lists the current user's issues and merge requests across every
// project they can see, in whichever roles the filter asks for.
MyWork(ctx context.Context, f MyWorkFilter) ([]WorkItem, error)
// Starred lists the current user's starred projects.
Starred(ctx context.Context) ([]Repo, error)
// Pipelines lists CI runs in a project.
Pipelines(ctx context.Context, ref Ref, f PipelineFilter) ([]Pipeline, error)
// Jobs lists the steps of one pipeline.
Jobs(ctx context.Context, ref Ref, pipelineID int) ([]Job, error)
// JobLog returns a job's log. The caller closes it.
JobLog(ctx context.Context, ref Ref, jobID int) (io.ReadCloser, error)
// Comment posts a note. target is "issue/<id>" or "mr/<id>".
Comment(ctx context.Context, ref Ref, target, body string) error
// CreateThread starts a new discussion, rather than replying to the main
// one. Review comments want their own thread.
CreateThread(ctx context.Context, ref Ref, target, body string) error
// CreateDiffThread starts a discussion anchored to a place in the diff,
// which is where a review comment belongs and the only place a suggestion
// can be posted. It returns ErrNotPositioned when the anchor cannot be
// honoured, so the caller can fall back to an ordinary thread and say so.
CreateDiffThread(ctx context.Context, ref Ref, mr int, c DiffComment) error
// SetFields applies a partial update to an issue or merge request.
SetFields(ctx context.Context, ref Ref, target string, patch FieldPatch) error
// RetryPipeline re-runs a pipeline's failed and canceled jobs.
RetryPipeline(ctx context.Context, ref Ref, pipelineID int) error
// Merge merges a merge request.
Merge(ctx context.Context, ref Ref, mr int) error
// Rebase brings a merge request up to date with its target branch,
// through the provider's API rather than any local git.
Rebase(ctx context.Context, ref Ref, mr int) error
}
Forge is the provider-neutral API surface. This iteration implements the read methods plus Comment and SetFields; pipelines, merging and rebasing arrive with later slices and will extend this interface.
func Multi ¶
Multi aggregates the given forges, keyed by profile name. With fewer than two it returns the single forge unchanged rather than paying for the fan-out.
func ReadOnly ¶
ReadOnly returns f wrapped so that every mutating method fails with ErrReadOnly. The guard lives here rather than in the UI so that a view added later cannot bypass it by forgetting a check — this is the fail-closed placement. Read methods are promoted from the embedded Forge and pass through untouched.
type Issue ¶
type Issue struct {
// Ref names the project the issue belongs to. It matters for listings
// that span projects, where a card has to say where it came from.
Ref Ref
ID int
Title string
Description string
State string // "opened" | "closed"
// Status is the provider work-item status, empty when it has none.
Status string
Author string
Assignees []string
Labels []string
Milestone string
// The rest is what a provider's own sidebar shows. Anything a provider
// does not have stays zero rather than being faked.
Epic string
Weight int
DueDate string
Upvotes int
Downvotes int
Comments int
UpdatedAt time.Time
WebURL string
Raw json.RawMessage
}
Issue is an issue on either provider.
type IssueFilter ¶
type IssueFilter struct {
State string // "" means all
Labels []string
Search string
// WithStatus asks for the provider work-item status (GitLab's To do /
// In progress / Done). It costs an extra request, so only the board —
// which groups by it — sets it.
WithStatus bool
}
IssueFilter narrows an issue listing.
type Job ¶
type Job struct {
ID int
Name string
Stage string
Status string
AllowFailure bool
Duration time.Duration
FinishedAt time.Time
WebURL string
Raw json.RawMessage
}
Job is one step of a pipeline.
type Membership ¶
type Membership string
Membership is how a note's author relates to the project, as the provider reports it. It is empty when the provider does not say, which is not the same as having no standing.
const ( MemberOwner Membership = "owner" MemberMaintainer Membership = "maintainer" MemberDeveloper Membership = "developer" MemberReporter Membership = "reporter" MemberMember Membership = "member" MemberContributor Membership = "contributor" )
The standings both providers can be mapped onto. GitLab reports an access level; GitHub an author association.
type MergeRequest ¶
type MergeRequest struct {
ID int
Title string
Description string
State string // "opened" | "merged" | "closed"
Author string
SourceBranch string
TargetBranch string
Draft bool
Labels []string
Assignees []string
Reviewers []string
Milestone string
Mergeable bool
Conflicts bool
Upvotes int
Downvotes int
Comments int
UpdatedAt time.Time
WebURL string
// Refs are the commits the diff is taken against. A review comment has to
// name them to be positioned, so without them a comment can only be posted
// unanchored — and a suggestion cannot be posted at all.
Refs DiffRefs
Raw json.RawMessage
}
MergeRequest models a GitLab merge request and a GitHub pull request as one type. Collapsing them is what makes cross-provider stacks possible.
type MyWorkFilter ¶
MyWorkFilter selects which of the current user's work to list. Empty slices mean "all of them", so the zero filter is every kind in every role.
func (MyWorkFilter) WantsKind ¶
func (f MyWorkFilter) WantsKind(kind string) bool
WantsKind reports whether the filter covers a kind of work item.
func (MyWorkFilter) WantsRole ¶
func (f MyWorkFilter) WantsRole(role Role) bool
WantsRole reports whether the filter covers a role.
type Note ¶
type Note struct {
ID int
Author string
// AuthorName is the display name, empty when the provider gives only a
// login. It is what an avatar takes its initials from.
AuthorName string
AvatarURL string
Membership Membership
Body string
CreatedAt time.Time
// System marks a note the provider generated — "changed the milestone",
// "added 1 commit" — rather than something a person wrote. These are the
// history a detail page draws as a timeline.
System bool
Resolved bool
}
Note is one comment on an issue or merge request, or one event in its history.
type Pipeline ¶
type Pipeline struct {
ID int
Status string
Ref string // the branch or tag it ran on
SHA string
Source string
WebURL string
CreatedAt time.Time
UpdatedAt time.Time
Raw json.RawMessage
}
Pipeline is one CI run: a GitLab pipeline or a GitHub Actions workflow run.
type PipelineFilter ¶
PipelineFilter narrows a pipeline listing.
type Ref ¶
type Ref struct {
Profile string
Host string
Namespace string // "atomic-blend/backend"
Project string // "auth"
}
Ref is the universal identity of a project. Profile is part of the key because two profiles routinely share a host: gitlab.com serves both the personal and the work account, distinguished only by CLI config directory.
type Repo ¶
type Repo struct {
Ref Ref
Name string
Description string
LastActivity time.Time
Starred bool
WebURL string
}
Repo is a GitLab project or a GitHub repository.
type Role ¶
type Role string
Role is how the current user relates to a work item. A single item can match more than one; the first matching role in the query order wins.
type Suggestion ¶
type Suggestion struct {
// Replacement is the new text, one entry per line, without newlines.
Replacement []string
Above int
Below int
// Note is the reviewer's own words, put above the block.
Note string
}
Suggestion is a proposed replacement for a span of lines, which the author can apply from the web UI with one click.
Above and Below say how many lines either side of the anchor the block replaces. GitLab expresses a multi-line suggestion that way; GitHub does it with the comment's own line range. The neutral form carries both so neither provider's shape leaks into the caller.
type SuggestionStyle ¶
type SuggestionStyle int
SuggestionStyle is how a provider spells a multi-line suggestion.
const ( // GitHubSuggestions carry no span: the comment's line range says how much // is replaced. GitHubSuggestions SuggestionStyle = iota // GitLabSuggestions carry the span in the fence itself. GitLabSuggestions )
The two spellings.
type Thread ¶
type Thread struct {
ID string
// Resolvable threads are review conversations; a plain comment is not.
Resolvable bool
Resolved bool
Notes []Note
}
Thread is a discussion: a single comment, or a resolvable conversation.
func (Thread) LastActivity ¶
LastActivity is when the thread was most recently added to.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package github implements forge.Forge against the GitHub REST API.
|
Package github implements forge.Forge against the GitHub REST API. |
|
Package gitlab implements forge.Forge against the GitLab REST API.
|
Package gitlab implements forge.Forge against the GitLab REST API. |