feat(api): support ref suffixes in compare (#38148)

Compare API requests with a `^` or `~N` revision suffix (for example
`compare/main...feature^`) were rejected with `400 Unsupported
comparison syntax: ref with suffix`. The fix resolves the suffix to a
commit before comparing, so `base...head^` and `~N` work on either side,
the same as git.

Only `^`/`~N` navigation is resolved. Pull request creation still
requires plain branch refs, and the web compare page keeps rejecting
suffixes since its branch selectors need separate UI work.

Closes #33943
This commit is contained in:
Eyüp Can Akman
2026-06-24 05:38:02 +00:00
committed by GitHub
parent 59d4825a95
commit ef927f9fa3
11 changed files with 246 additions and 34 deletions
+6 -11
View File
@@ -208,11 +208,6 @@ func (cpi *comparePageInfoType) parseCompareInfo(ctx *context.Context, comparePa
// 1 Parse compare router param
compareReq := common.ParseCompareRouterParam(compareParam)
// remove the check when we support compare with carets
if compareReq.BaseOriRefSuffix != "" {
return util.NewInvalidArgumentErrorf("unsupported comparison syntax: ref with suffix")
}
// 2 get repository and owner for head
headOwner, headRepo, err := common.GetHeadOwnerAndRepo(ctx, baseRepo, compareReq)
if err != nil {
@@ -241,18 +236,18 @@ func (cpi *comparePageInfoType) parseCompareInfo(ctx *context.Context, comparePa
baseRefName := util.IfZero(compareReq.BaseOriRef, baseRepo.GetPullRequestTargetBranch(ctx))
headRefName := util.IfZero(compareReq.HeadOriRef, headRepo.DefaultBranch)
baseRef := ctx.Repo.GitRepo.UnstableGuessRefByShortName(baseRefName)
if baseRef == "" {
return util.NewNotExistErrorf("no base ref: %s", baseRefName)
baseRef, err := common.ResolveRefWithSuffix(ctx.Repo.GitRepo, baseRefName, compareReq.BaseOriRefSuffix)
if err != nil {
return err
}
headGitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, headRepo)
if err != nil {
return err
}
headRef := headGitRepo.UnstableGuessRefByShortName(headRefName)
if headRef == "" {
return util.NewNotExistErrorf("no head ref: %s", headRefName)
headRef, err := common.ResolveRefWithSuffix(headGitRepo, headRefName, compareReq.HeadOriRefSuffix)
if err != nil {
return err
}
ctx.Data["BaseName"] = baseRepo.OwnerName