Skip to content

The words this contract uses

One forge's word for a thing is another forge's word for something else, and a contract over four of them has to pick. This page records the picks and, where the choice was close, what it cost.

It exists because a term doing two jobs is the cheapest way to teach a reader the wrong model. Nothing here is a style preference; each entry is a place someone has been confused, or would be.

Repository means the forge's container, not the git repository

forge.Repository is the container a forge keeps a codebase in. It has a description, a visibility, an activity timestamp and possibly a published site. The git repository it wraps is reached through Repository.Git, a GitRemote carrying the clone URL and default branch.

They are separable in fact rather than only in modelling. On GitLab and Bitbucket a container can exist, carry a description and publish a site with no git repository behind it at all — which is why GitRemote is its own type and why its zero value is meaningful:

if r.Git.CloneURL == "" {
    // A container with nothing behind it. Not an error, and not clonable.
}

Everywhere else in this estate, "repo" means the git one. gitlab.com/phpboyscout/go/repo owns cloning, branching and committing. It exports no Repository type of its own, so there is no symbol collision, and the package prefix carries the distinction at every call site. Inside this package, an unqualified "repository" means the container.

Why not call it a Project

GitLab models this exact split and calls the container a Project, which is the better word taken alone. It is not used here because on the other three forges it collides rather than clarifies:

Forge What "project" means there
GitLab The container. The meaning we would want.
GitHub A planning board — ProjectV2 in the SDK this module imports.
Bitbucket A grouping of repositories inside a workspace.
Gitea No such concept.

Neither of the colliding meanings is modelled here, so naming the type Project would not create an ambiguity a caller could trip over in code. It would create one they trip over in their own forge's UI, which is worse: the contract and the screen in front of them would disagree about what a project is.

So the name follows the three forges that use it, and mapping GitLab's Project onto it is the provider's job rather than the caller's.

Namespace is the owner, and it is a path

owner in a method signature and namespace in an enumeration are the same thing: the path segment above the repository. A user, an organisation, a GitLab group, a Bitbucket workspace.

It is always a path string, never an ID, because a path is what a human has and what a URL shows. Where a forge's API wants something else — GitLab's project creation takes a numeric namespace_id — resolving it is the provider's problem, not the caller's.

Pull request is the noun, merge request is an alias

PullRequests is the capability; MergeRequests is a true Go type alias for it, so GitLab users can write the word their forge uses and get the same type.

The alias renames the type and not its methods — Go does not allow that — so the methods carry no noun — Find, FindLastMerged, Create, Update, Close, ResolveMergedCommit — which is why they read differently from ReleasePublisher's. That capability spells its methods CreateRelease and AddReleaseAsset because a provider implementing both would otherwise need two methods called Create.

Asset means a file on a release, in one of two shapes

A release asset is either content the caller holds, or a location where the bytes already live. Which of the two a forge can natively hold is inverted across the family: GitLab's native asset is a link, while GitHub and Gitea take only bytes.

"Attached" means the asset is on the release. It does not mean the bytes are reachable — this contract never fetches a location to check.

Capability, provider, adapter

A capability is an optional interface a provider may implement, discovered with forge.As. A provider is what a caller holds: one implementation of forge.Provider plus whichever capabilities it satisfies. An adapter is the module that supplies one — forge-gitlab, forge-github, forge-gitea, forge-bitbucket, and direct which ships inside this repository.

"Provider" and "adapter" are not interchangeable. A provider is a value; an adapter is a module.

Endpoint is the address, and it is comparable

forge.Endpoint is where a provider talks to, as a value that compares equal when two callers mean the same instance. That is what lets forge/pool build each one once. It is not a URL and not a client.