Defer breaking changes from !3063 to 4.0
Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.
Summary
!3063 (closed) carried fixes for places where this library and the GitLab API disagree. Where the right fix would remove an exported name, change a method's signature or change a field's type, it did the half that keeps v3 source compatible and left the rest for 4.0. It was closed on 2026-10-21 without merging, and its fixes go out again as small merge requests, one topic each, that keep the same split. The one exception is the pipeline cancellation role: after the review, !3063 (closed) gave the two CIRestrictPipelineCancellationRole fields a type of their own. That change goes out again in a merge request of its own, and if it is dropped there, it comes back to this list. One change of behavior, what a nil options pointer sends, is made opt-in instead, in !3065 (merged), which the review split out of !3063 (closed), and its default follows in 4.0. This issue tracks the rest, as the review of !3063 asked.
Why deferred
Each change below removes an exported name, changes a method's signature, changes a field's type or changes what a request sends by default, so it breaks existing callers and has to wait for a major version.
What 4.0 does
1. Methods that return a type their endpoint does not send
Each gets a V2 sibling with the right return type, and the original is deprecated in its favour. In 4.0 the original name takes the V2 signature and the V2 method is removed.
| Deprecated method | Returns today | V2 returns |
|---|---|---|
DeploymentsService.ApproveOrRejectProjectDeployment |
nothing (the approval is discarded) | *DeploymentApproval |
GeoSitesService.RepairGeoSite |
*GeoSite |
*GeoSiteStatus |
MergeRequestsService.CreateMergeRequestPipeline |
*PipelineInfo |
*Pipeline |
ProjectsService.CreateProjectForkRelation |
*ProjectForkRelation |
*Project |
ProjectsService.ShareProjectWithGroup |
nothing (the link is discarded) | *ProjectGroupLink |
UsersService.CreateServiceAccountUser |
*User |
*ServiceAccount |
ProjectForkRelation, which no GitLab entity exposes, is removed with them. CreateMergeRequestPipelineV2 also takes the route's async option.
2. Methods that take no options although their routes do
In 4.0 the base method takes the options struct. The WithOptions sibling stays, deprecated, and is removed in 5.0:
WorkItemsService.GetWorkItemandGetWorkItemWithOptions(from !3063 (closed))ProjectMembersService.DeleteProjectMemberandDeleteProjectMemberWithOptions(from !3063 (closed))JobsService.CancelJob,DraftNotesService.PublishAllDraftNotesandJobsService.GetJobArtifacts, whose siblings already follow the same pattern and would follow the same schedule
The three siblings already on main carry Deprecated notes that tie them to 4.0, and the two from !3063 (closed) carried the same. This schedule makes those notes wrong: each should either say 5.0, or come out until 4.0 deprecates the sibling.
3. A field typed narrower than what GitLab sends
GeoSiteStatus.Namespaces is a []string where GitLab sends namespace objects. The fix from !3063 (closed) keeps the full paths there and puts the objects in NamespaceDetails. In 4.0 the field takes the object type and NamespaceDetails is removed.
Epic.Labels needs nothing here: the fix from !3063 (closed) keeps the names there and puts the objects in LabelDetails, which is the shape Issue and MergeRequest already have.
Commit.ExtendedTrailers needs nothing here either: GitLab sends a list of values for each trailer, which the old map[string]string could not decode, so !3082 (merged) changed it to map[string][]string on main (v3.40.3). SubmoduleCommit.ExtendedTrailerValues, which !3085 (merged) added for the same key, already works and is released, so as the review of !3082 asked, it is to be deprecated on main, and 4.0 renames it ExtendedTrailers to match.
4. Fields current GitLab does not send, and option fields no current route declares
!3063 (closed) deprecated each of these with a note saying why, and what to read instead where GitLab sends the value under another name, except the two Skype options, which !3113 (merged) deprecated on main. The notes from !3063 (closed) go out again with the small merge requests, and in 4.0 the fields are removed:
AuditEvent.EventTypeContributionEvent.Title,ProjectEvent.Title,ProjectEvent.DataEpic.UserNotesCountGroup.DuoAvailabilityIntegration.GroupMentionEvents,Integration.GroupConfidentialMentionEventsIssue.IssueLinkID, which GitLab sends only on the issue links route, decoded there intoIssueRelationLicenseTemplate.FeaturedNote.Attachment,Note.ExpiresAt,Note.FileName,Note.Title,NoteAuthor.Email,NoteResolvedBy.EmailPendingInvite.IDPipelineTrigger.DeletedAtProject.BuildCoverageRegex,Project.CIOptInJWT,Project.OperationsAccessLevelCreateProjectOptions.BuildCoverageRegex,CreateProjectOptions.OperationsAccessLevel,EditProjectOptions.BuildCoverageRegex,EditProjectOptions.OperationsAccessLevelReleaseLink.External, which GitLab removed from the release link API in 16.0User.CanCreateOrganization,User.ExternUID,User.Provider,User.SkypeCreateUserOptions.Skype,ModifyUserOptions.SkypeWeightEvent.ResourceID,WeightEvent.ResourceType,WeightEvent.State
Older releases, all out of maintenance, did send some of these, for example Project.BuildCoverageRegex up to 15.2, Project.CIOptInJWT from 15.2 to 15.11, Project.OperationsAccessLevel and ReleaseLink.External up to 15.11, Note.Attachment up to 17.10, and User.Skype up to 18.1.
5. Structs that decode more than one entity
Group, Project and Issue each decode a narrow Grape entity and one or more wider ones that inherit it:
BasicGroupDetailson the job token groups allowlist,Entities::Groupon the group listings, andGroupDetailon the routes that answer with one groupBasicProjectDetailson a project listing withsimpleor without authentication,ProjectDetailson a single project read without authentication, andProjector an entity inheriting it otherwiseIssueBasicwhere other APIs render an issue (a milestone's issues, the issues a merge request closes, search), andIssueon the issues API's own routes
User decodes six. !3063 (closed) put the new fields on the one struct, with comments saying when GitLab sends each, and the merge requests that carry them again do the same. In 4.0 a route that answers with a narrower entity returns a struct shaped like it. BasicUser already has the shape of UserBasic, but BasicProject has the shape of the smaller ProjectIdentity rather than BasicProjectDetails, and no struct has the shape of Entities::Group or IssueBasic, so Project, Group and Issue each still need another struct.
6. A nil options pointer sends null by default
A nil *Options held in an any is not nil, so a POST, PUT or PATCH request given one sends the JSON literal null as its body, and a request with any other method has a query already on its URL replaced with an empty one. JobsService.CancelJob and DraftNotesService.PublishAllDraftNotes do this on their own, through their WithOptions siblings. !3065 (merged) adds the client option WithNilOptionsOmitted(), off by default, which makes such a pointer mean no options. As the review of !3063 asked, 4.0 makes that the default, where the option has no effect, and 5.0 removes the option.
Not part of this
GetMergeRequestChanges and ChangeApprovalConfiguration return *MergeRequest for endpoints that answer with MergeRequestChanges and ApprovalState. GitLab deprecated both endpoints and both methods are already deprecated here. They stay as they are: deprecated routes live a long time in GitLab, and callers may target older instances.
Next steps
- Add this issue to the 4.0 milestone once there is one.
- Land each item in the 4.0 release branch, together with the removal of the deprecation notes it retires.
Related: !3063 (closed), !3065 (merged)