Documentation
¶
Overview ¶
Package gitlab is the forgeapi client for GitLab: gitlab.com and self-managed instances, served by the same code. Client is its one exported type, so no wire type of this product, the merge request included, reaches a forgeapi signature.
Reads use this family's GraphQL documents where the instance accepts them and REST where it does not. Client.ConnectionCaps states how a connection decides, and each method states what its own path costs.
Index ¶
- type Client
- func (c *Client) BudgetState() forgeapi.BudgetState
- func (c *Client) Close()
- func (c *Client) CloseIssue(ctx context.Context, repo forgeapi.RepoRef, issue forgeapi.IssueRef) (forgeapi.Issue, error)
- func (c *Client) ClosePR(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef) (forgeapi.PullRequest, error)
- func (c *Client) CommitStatus(ctx context.Context, repo forgeapi.RepoRef, ref string) (forgeapi.CommitChecks, error)
- func (c *Client) ConnectionCaps(ctx context.Context) (forgeapi.ConnectionCaps, error)
- func (c *Client) CreateIssue(ctx context.Context, repo forgeapi.RepoRef, req forgeapi.NewIssue) (forgeapi.Issue, error)
- func (c *Client) CreatePR(ctx context.Context, repo forgeapi.RepoRef, req forgeapi.NewPullRequest) (forgeapi.PullRequest, error)
- func (c *Client) CreateRelease(ctx context.Context, repo forgeapi.RepoRef, req forgeapi.NewRelease) (forgeapi.Release, error)
- func (c *Client) GrantCaps(ctx context.Context) (forgeapi.GrantCaps, error)
- func (c *Client) ListIssues(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Issue], error)
- func (c *Client) ListLabels(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Label], error)
- func (c *Client) ListMyIssues(ctx context.Context, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Issue], error)
- func (c *Client) ListMyPRs(ctx context.Context, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.PullRequest], error)
- func (c *Client) ListPRs(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.PullRequest], error)
- func (c *Client) ListReleases(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Release], error)
- func (c *Client) ListRepos(ctx context.Context, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Repository], error)
- func (c *Client) ListRuns(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Run], error)
- func (c *Client) MergePR(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef, ...) (forgeapi.MergeOutcome, error)
- func (c *Client) MergeStatus(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef) (forgeapi.MergeStatus, error)
- func (c *Client) ReadPR(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef) (forgeapi.PullRequest, error)
- func (c *Client) ReopenPR(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef) (forgeapi.PullRequest, error)
- func (c *Client) RepoAffordances(ctx context.Context, repo forgeapi.RepoRef) (forgeapi.RepoAffordances, error)
- func (c *Client) RerunFailedChecks(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef, headSHA string) error
- func (c *Client) Whoami(ctx context.Context) (forgeapi.Account, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is one GitLab connection: where the instance is, what the credential is trusted with, and what the budget allows.
It is the concrete type New returns, so a consumer declares the narrowest role interface it actually uses against it rather than receiving an interface this package chose. What it holds is unexported, because the state behind an operation is nobody else's contract.
func New ¶
New builds a client for one connection.
It performs no I/O. Every capability this instance's version decides is resolved by the accessor that needs it, so an instance that is down fails at the operation rather than at construction, and a consumer can build its clients before it can reach anything.
What it does refuse at entry is a client it cannot run honestly, and every refusal carries a code of its own, because a consumer names the remedy for the refusal it got rather than showing a generic warning: no credential source, which is forgeapi.CodeAnonymousRefused rather than a client that sends anonymous requests; no web base URL, a half-present certificate pair, a forgeapi.Connection.Proxy URL net/url refuses or carrying no scheme this library proxies over, or a malformed forgeapi.Header entry, which is forgeapi.CodeConnectionInvalid; an extra header whose name this library or the HTTP stack writes itself, which is forgeapi.CodeHeaderReserved naming it; a plaintext URL without forgeapi.WithPlaintextHTTP, which is forgeapi.CodePlaintextRefused; a private-range or single-label host without forgeapi.WithPrivateAddresses, which is forgeapi.CodePrivateAddressRefused; a negative value passed to any budget option, forgeapi.WithRetries and forgeapi.WithMutationReserve included, which is forgeapi.CodeBudgetInvalid; and a forgeapi.RotationCursor that is not well formed, which is forgeapi.CodeCursorInvalid.
func (*Client) BudgetState ¶
func (c *Client) BudgetState() forgeapi.BudgetState
BudgetState implements forgeapi.Governor. It is the read-only view of this connection's governor: the remaining budget the instance last reported, when it renews, and what the last call cost. This product reports remaining and reset through its rate-limit headers and prices a document by the complexity the endpoint reports, which is what LastCost carries after a document read. The headers report the credential's own quota rather than this client's share of it, so it moves when another application spends and the governor's reserve is held against that shared pool.
forgeapi.BudgetState.RotationCursor is empty on this family and nothing rotates: the folded verdict here is one scalar selected by a document the list already sends, so no row costs a read of its own and there is no per-interval cap for a rotation to spread.
It performs no I/O and is safe to call concurrently with operations; it is never written from outside. See forgeapi.BudgetState.
func (*Client) Close ¶
func (c *Client) Close()
Close implements forgeapi.Core: it releases this client's pool, the idle connections of the transport the library built for the connection, at once, which a caller that disconnects or re-addresses the connection wants; otherwise they close after that transport's idle timeout. A transport supplied through forgeapi.WithWireTransport stays its author's to release. A call in flight keeps its connection until it returns. Close adds no closed state: a call after it dials afresh, and a further Close releases that connection too.
func (*Client) CloseIssue ¶
func (c *Client) CloseIssue(ctx context.Context, repo forgeapi.RepoRef, issue forgeapi.IssueRef) (forgeapi.Issue, error)
CloseIssue implements forgeapi.Issues.
func (*Client) ClosePR ¶
func (c *Client) ClosePR(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef) (forgeapi.PullRequest, error)
ClosePR implements forgeapi.PullRequests.
func (*Client) CommitStatus ¶
func (c *Client) CommitStatus(ctx context.Context, repo forgeapi.RepoRef, ref string) (forgeapi.CommitChecks, error)
CommitStatus implements forgeapi.Checks.
This read addresses one commit, so its fold is COMPLETE and bounded by forgeapi.Budget.StatusPages, and a fold that reaches that bound reports forgeapi.PartialPaginationCap with the verdict at forgeapi.CheckUnknown.
The fold is computed HERE rather than taken from any field upstream sends, and it DE-DUPLICATES to the latest row per context. This product's statuses route answers the historical rows, several per context where a check has been retried, so a fold over the rows as they arrive reports a superseded failure as live. There is no combined-status route to ask instead, so the de-duplication is this family's own: within one context the row with the greatest identifier is the live one, and the contexts keep the order upstream first mentioned them in.
func (*Client) ConnectionCaps ¶
ConnectionCaps implements forgeapi.Capabilities.
It is connection setup, and it is where everything this connection learns once about its instance is learned: TWO requests on the first call, the metadata read and the one bounded schema question that settles whether this instance accepts the documents this family ships, and zero on every later call because both answers are held with the client. The family is established from the header the metadata read carries rather than from its body, and the capability is answered from the version the body reports.
Those two requests are priced HERE rather than on the operations that need what they learn. That is what lets every operation publish an exact figure: a merge -state read is one request, a pull-request list is one per page, and a re-run costs the same on a connection that has just been opened as on one that has been used, because no operation resolves a connection property of its own.
A metadata read the credential cannot make is not a failure here, and that is a decision rather than a swallow: the header still names the product, so the family IS established, and the capability it could not read is reported unknown with the status in its evidence. An unknown renders a disabled control with its reason, where an error at this accessor would make every other operation unreachable on a connection whose public reads work. A response carrying no such header is REFUSED with forgeapi.CodeFamilyUndetected, because every route, enumeration table and error mapping below this point is one family's.
func (*Client) CreateIssue ¶
func (c *Client) CreateIssue(ctx context.Context, repo forgeapi.RepoRef, req forgeapi.NewIssue) (forgeapi.Issue, error)
CreateIssue implements forgeapi.Issues. It is ONE request: this product's creation takes label NAMES, so nothing has to resolve them to identifiers first.
func (*Client) CreatePR ¶
func (c *Client) CreatePR(ctx context.Context, repo forgeapi.RepoRef, req forgeapi.NewPullRequest) (forgeapi.PullRequest, error)
CreatePR implements forgeapi.PullRequests.
It is ONE request, which is what this product's own creation takes: the labels a caller names go on the wire as NAMES, so nothing has to resolve them to identifiers first, and the draft flag is the title prefix this product marks a draft with rather than a field of its own.
func (*Client) CreateRelease ¶
func (c *Client) CreateRelease(ctx context.Context, repo forgeapi.RepoRef, req forgeapi.NewRelease) (forgeapi.Release, error)
CreateRelease implements forgeapi.Releases.
The two flags this product has no field for are not sent and not faked: it has no draft release and no prerelease mark, so a caller asking for either gets a published release and the answer says so, which is what the operation's own per-forge block publishes.
func (*Client) GrantCaps ¶
GrantCaps implements forgeapi.Capabilities at no request, from the permission pair the last pull-request document reported: able to push answers yes, otherwise UNKNOWN, and before any document has run, yes by default, since any reader can read the merge state and only its recalculation is refusable by role. After a forgeapi.CodeScopeInsufficient refusal it answers UNKNOWN: this product checks a token's own permissions first, and the pair reports only the owner's.
func (*Client) ListIssues ¶
func (c *Client) ListIssues(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Issue], error)
ListIssues implements forgeapi.Issues.
It asks for the label DETAILS, which is part of the question rather than an option: without that parameter a row's labels arrive as bare names, and the normalized label carries a colour and a description a consumer renders.
func (*Client) ListLabels ¶
func (c *Client) ListLabels(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Label], error)
ListLabels implements forgeapi.Labels.
func (*Client) ListMyIssues ¶
func (c *Client) ListMyIssues(ctx context.Context, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Issue], error)
ListMyIssues implements forgeapi.Issues.
It is Client.ListMyPRs asking for the other collection: the instance-wide issue list narrowed to what the credential created, or under forgeapi.WithOwner that group's own issue list, both with the open state and the label details. The scope, the price and the unresolved-owner answer are that call's own. Each row carries its own forgeapi.Issue.Repo, recovered from the row's own full reference, because the rows span projects and the numeric project id beside it is not a canonical selector.
func (*Client) ListMyPRs ¶
func (c *Client) ListMyPRs(ctx context.Context, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.PullRequest], error)
ListMyPRs implements forgeapi.PullRequests over REST: the instance-wide merge-request list narrowed to what the credential created, or under forgeapi.WithOwner that group's own, subgroups included, addressed as [Client.scopedRoute] answers. Rows span projects, so each row's forgeapi.PullRequest.Repo comes from its own full reference, and each distinct fork costs one GET /projects/:id ([Client.resolveForks]). A REST row carries no head pipeline and a merge status listing may leave stale, so its verdict and block reason are unknown; Client.ReadPR names them where documents answer.
func (*Client) ListPRs ¶
func (c *Client) ListPRs(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.PullRequest], error)
ListPRs implements forgeapi.PullRequests.
It reads the list document rather than the REST list, and the reason here is staleness rather than absence: this product documents that listing may not proactively refresh the merge status because doing so is expensive, and the parameter that asks for a refresh guarantees nothing and can be ignored outright for a caller below a certain project role. A stale value is worse than a missing one, because nothing on the wire tells the two apart.
It is ONE request per page on both of its arms. A connection whose setup found the documents refused reads the REST list instead, from its first call, and on that path the block reason and the armed auto-merge are reported unknown rather than trusted, because this product documents that list as able to serve a merge status nothing refreshed. A document refused at RUNTIME on a connection whose setup question was answered is that call's failure and marks the connection, so the next call reads REST and no call spends two requests where its row publishes one.
Three action fields come from the document by name: the detailed merge status fills forgeapi.ActionState.MergeBlocked, the auto-merge flag fills forgeapi.ActionState.AutoMergeArmed, and the head pipeline's status fills forgeapi.ActionState.Checks. The measurement took that last one as ONE SCALAR: the document returns a nullable head pipeline whose status is a single enum member, so there is no collection to page and the bounded-fold rule every other list obeys has nothing to bound here. A row therefore never reads forgeapi.CheckUnknown for a pagination cap, forgeapi.PartialPaginationCap never arrives from this field, and the six per-state counts stay zero because one scalar cannot supply them. A row carries that marker only where its label connection names a further page. The pipeline's own SHA is not this pull request's head either, so it never fills forgeapi.PullRequest.HeadSHA, which reads the diff head instead.
func (*Client) ListReleases ¶
func (c *Client) ListReleases(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Release], error)
ListReleases implements forgeapi.Releases.
func (*Client) ListRepos ¶
func (c *Client) ListRepos(ctx context.Context, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Repository], error)
ListRepos implements forgeapi.Repos.
Without an owner scope it asks for the projects the credential is a MEMBER of, which is this operation's published question read against a product whose unfiltered project list is every project the instance makes visible. On a hosted instance that list is millions of rows in no order a consumer asked for, so sending no filter would answer a different question at a price no page bound reaches; the sibling family answers the same operation from the credential's own repositories for the same reason.
func (*Client) ListRuns ¶
func (c *Client) ListRuns(ctx context.Context, repo forgeapi.RepoRef, opts ...forgeapi.ListOption) (forgeapi.Page[forgeapi.Run], error)
ListRuns implements forgeapi.Checks.
A run is a pipeline, the row the re-run resolves its pipeline from: its state is the status folded through the merge request's head-pipeline table, its branch the ref as this product spells it, a refs/ path on the pipelines a merge request or a workload starts, and its name the pipeline's own, empty unless configured. It is not gated on forgeapi.CapRerunChecks, the re-run verb's, since every project carries the route.
func (*Client) MergePR ¶
func (c *Client) MergePR(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef, req forgeapi.MergeRequest) (forgeapi.MergeOutcome, error)
MergePR implements forgeapi.Merges.
Two family facts decide this method. The head commit is not merely prudent here: a group or instance setting can make it compulsory and the request is refused without it, which is why it is a required field rather than an option. And this product exposes no per-request strategy selector at all (its project merge method is read-only display text), so a forgeapi.MergeRequest.Strategy is refused here; what it does accept is a squash intent it can then not apply, which is reported rather than swallowed.
The auto-merge arm is DISARMED unless the caller asks for it, and the field it uses when asked is this product's current one rather than the pipeline-shaped parameter it deprecated. That is the defect this replaces: a merge that arms auto-merge by default completes later, unattended, on a pull request the user asked to merge now.
Where the project merges through a train, the request is accepted and the merge enqueued rather than refused, which is a success state and not a refusal to merge. The witness for it is the answer's OWN auto-merge state, because no merge response of this product carries a queue position and the only fields that would name the train are a deprecated experiment connection the schema gate refuses. So the queue verdict is forgeapi.QueueNone and the position unknown, and an answer whose state this family cannot read is reported as an unknown outcome rather than as a merge.
func (*Client) MergeStatus ¶
func (c *Client) MergeStatus(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef) (forgeapi.MergeStatus, error)
MergeStatus implements forgeapi.Merges.
It reads the single-merge-request document, whose selection carries the state and the merged timestamp this family derives the merged answer from and the merge request's own web URL. It follows no page of checks, which on this product is doubly true: this operation returns none, and the measurement found that the document serves one scalar head-pipeline status with no collection to page at all. A caller wanting the folded verdict calls Client.ReadPR on the same merge request.
It is ONE request, on the same two arms Client.ReadPR has and for the same reason: it reaches that document, and a connection whose setup found the documents refused reads the REST record instead. Neither arm is a page of a fold, and neither spends a discovery, which is what makes this row the exactly one request it publishes.
Queue is forgeapi.QueueNone: the only fields that could answer otherwise are the merge-train connection and its cars, both of which carry a deprecation reason, so a document selecting either fails the schema gate. Whether the project merges through a train at all is a repository affordance, read by Client.RepoAffordances.
func (*Client) ReadPR ¶
func (c *Client) ReadPR(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef) (forgeapi.PullRequest, error)
ReadPR implements forgeapi.PullRequests.
It reads the single-merge-request document, whose field set is its own, and its two absence answers are separated by the envelope rather than by the status: a resolved project with no merge request is forgeapi.CodePRNotFound, a null project is forgeapi.CodeRepoOrPRNotVisible, and the degraded REST path reports the union because there the status is all there is.
It is ONE request on both of its arms, and neither arm is a page of a fold: the fold on a single-pull-request read is COMPLETE elsewhere and bounded by forgeapi.Budget.StatusPages, and the measurement found that this family has no collection to fold at all, only the scalar head-pipeline status ListPRs above reads; its label connection is cut and marked as a ListPRs row's is. The second arm is the REST read a connection whose setup found the documents refused takes instead, from its first call, so the discovery is the connection's cost rather than this call's.
func (*Client) ReopenPR ¶
func (c *Client) ReopenPR(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef) (forgeapi.PullRequest, error)
ReopenPR implements forgeapi.PullRequests.
func (*Client) RepoAffordances ¶
func (c *Client) RepoAffordances(ctx context.Context, repo forgeapi.RepoRef) (forgeapi.RepoAffordances, error)
RepoAffordances implements forgeapi.Capabilities.
Two of its answers are three-valued for this product's sake: whether issues are enabled varies with the caller's permission, and push is reported as a role integer, from which no permission and no visibility are not the same answer. Whether merging goes through a train is read here from the project's own setting, because inferring it from a refusal would report a queue-protected merge request as unmergeable.
forgeapi.RepoAffordances.Ev is empty, which is the expectation table's own row: measured anonymously, this product's project record carries none of the four keys the three capabilities would name a source for, so the evidence map would state a source for values the record did not supply.
func (*Client) RerunFailedChecks ¶
func (c *Client) RerunFailedChecks(ctx context.Context, repo forgeapi.RepoRef, pr forgeapi.PRRef, headSHA string) error
RerunFailedChecks implements forgeapi.PullRequests.
It is TWO requests: the pipeline carrying the head the caller pinned has to be resolved before it can be retried, because this product's retry verb is addressed by a server-allocated pipeline id rather than by a commit.
Those two are all of them, on a fresh connection as on a used one. The capability this operation is gated on is the CONNECTION's, resolved and priced at setup by Client.ConnectionCaps, so this call reads the verdict it holds and sends nothing to obtain one.
The head pin binds and costs no request of its own: the resolving read is filtered BY the caller's SHA, which this product declares as a parameter of that route, and a SHA no pipeline carries means the merge request has moved since the caller's row was rendered. That is refused rather than retried, because a re-run can carry deployment side effects and a row displaying one commit's red status must not act on another's. An empty SHA means the forge reported no head, and the re-run then proceeds against the FIRST pipeline the instance returns, which is the one case where the pin is unavailable rather than waived.
The verb retries the failed and canceled jobs of that pipeline rather than the whole pipeline, which is what this operation publishes.
func (*Client) Whoami ¶
Whoami implements forgeapi.Identity.
forgeapi.Account.Scopes is nil on this product and that is a cannot-supply rather than an omission: the identity route carries no scope list, and the route that does describes one token rather than the connection's grant, so a scope set read there would answer a different question from the one this field asks.