forked from mirrors/forgejo
feat: Retrieve default merge commit message for pull requests (#10022)
Closes #7719 Co-authored-by: kukolos <91948790+kukolos@users.noreply.github.com> Co-authored-by: 0ko <0ko@noreply.codeberg.org> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10022 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Reviewed-by: 0ko <0ko@noreply.codeberg.org> Co-authored-by: MayMeow <maymeow@noreply.codeberg.org> Co-committed-by: MayMeow <maymeow@noreply.codeberg.org>
This commit is contained in:
parent
b8e7d7c9d8
commit
2566924ff8
4 changed files with 118 additions and 1 deletions
|
|
@ -240,6 +240,11 @@
|
|||
},
|
||||
"teams.add_all_repos.modal.header": "Add all repositories",
|
||||
"teams.remove_all_repos.modal.header": "Remove all repositories",
|
||||
"pulls.manual_merge.helper": "Manual merge helper",
|
||||
"pulls.manual_merge.helpder.description": "Use this merge commit message when completing the merge manually.",
|
||||
"pulls.manual_merge.commit.title": "Merge commit title",
|
||||
"pulls.manual_merge.commit.body": "Merge commit body",
|
||||
"pulls.manual_merge.copy.button": "Copy merge commit message",
|
||||
"admin.auths.oauth2_quota_group_claim_name": "Claim name providing group names for this source to be used for quota management. (Optional)",
|
||||
"admin.auths.oauth2_quota_group_map": "Map claimed groups to quota groups. (Optional - requires claim name above)",
|
||||
"admin.auths.oauth2_quota_group_map_removal": "Remove users from synchronized quota groups if user does not belong to corresponding group.",
|
||||
|
|
|
|||
|
|
@ -390,7 +390,7 @@
|
|||
{{end}}
|
||||
|
||||
{{if and .Issue.PullRequest.HeadRepo (not .Issue.PullRequest.HasMerged) (not .Issue.IsClosed)}}
|
||||
{{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "ShowMergeInstructions" .ShowMergeInstructions "AutodetectManualMerge" .AutodetectManualMerge}}
|
||||
{{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "ShowMergeInstructions" .ShowMergeInstructions "AutodetectManualMerge" .AutodetectManualMerge "DefaultMergeMessage" .DefaultMergeMessage "DefaultMergeBody" .DefaultMergeBody "IsPullFilesConflicted" .IsPullFilesConflicted}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,35 @@
|
|||
<div class="divider"></div>
|
||||
<details class="collapsible">
|
||||
<summary class="tw-py-2"> {{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint"}} </summary>
|
||||
{{if .IsPullFilesConflicted}}
|
||||
{{$titleID := printf "manual-merge-title-%d" .PullRequest.ID}}
|
||||
{{$bodyID := printf "manual-merge-body-%d" .PullRequest.ID}}
|
||||
{{$copySourceID := printf "manual-merge-message-%d" .PullRequest.ID}}
|
||||
{{$fullMessage := .DefaultMergeMessage}}
|
||||
{{if .DefaultMergeBody}}
|
||||
{{$fullMessage = printf "%s\n\n%s" .DefaultMergeMessage .DefaultMergeBody}}
|
||||
{{end}}
|
||||
<div class="tw-mb-4">
|
||||
<h3 class="tw-flex tw-items-center tw-gap-2">{{svg "octicon-info" 16}} {{ctx.Locale.Tr "pulls.manual_merge.helper"}}</h3>
|
||||
<p class="tw-mb-2">{{ctx.Locale.Tr "pulls.manual_merge.helpder.description"}}</p>
|
||||
<div class="ui secondary segment tw-space-y-3">
|
||||
<div class="ui form">
|
||||
<div class="field">
|
||||
<label for="{{$titleID}}">{{ctx.Locale.Tr "pulls.manual_merge.commit.title"}}</label>
|
||||
<textarea id="{{$titleID}}" readonly rows="1">{{- .DefaultMergeMessage -}}</textarea>
|
||||
</div>
|
||||
{{if .DefaultMergeBody}}
|
||||
<div class="field">
|
||||
<label for="{{$bodyID}}">{{ctx.Locale.Tr "pulls.manual_merge.commit.body"}}</label>
|
||||
<textarea id="{{$bodyID}}" readonly rows="5">{{- .DefaultMergeBody -}}</textarea>
|
||||
</div>
|
||||
{{end}}
|
||||
<textarea id="{{$copySourceID}}" class="tw-hidden" aria-hidden="true" readonly>{{- $fullMessage -}}</textarea>
|
||||
<button class="secondary button" type="button" data-clipboard-target="#{{$copySourceID}}">{{svg "octicon-copy" 16}} {{ctx.Locale.Tr "pulls.manual_merge.copy.button"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div><h3>{{ctx.Locale.Tr "repo.pulls.cmd_instruction_checkout_title"}}</h3>{{ctx.Locale.Tr "repo.pulls.cmd_instruction_checkout_desc"}}</div>
|
||||
{{$localBranch := .PullRequest.HeadBranch}}
|
||||
{{if ne .PullRequest.HeadRepo.ID .PullRequest.BaseRepo.ID}}
|
||||
|
|
|
|||
83
tests/integration/pull_merge_instruction_test.go
Normal file
83
tests/integration/pull_merge_instruction_test.go
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
auth_model "forgejo.org/models/auth"
|
||||
issues_model "forgejo.org/models/issues"
|
||||
repo_model "forgejo.org/models/repo"
|
||||
"forgejo.org/models/unittest"
|
||||
user_model "forgejo.org/models/user"
|
||||
"forgejo.org/modules/gitrepo"
|
||||
api "forgejo.org/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPullMergeInstruction(t *testing.T) {
|
||||
onApplicationRun(t, func(t *testing.T, _ *url.URL) {
|
||||
session := loginUser(t, "user1")
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")
|
||||
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
|
||||
|
||||
// Use API to create a conflicting PR, mirroring TestCantMergeConflict
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", "user1", "repo1"), &api.CreatePullRequestOption{
|
||||
Head: "conflict",
|
||||
Base: "base",
|
||||
Title: "create a conflicting pr",
|
||||
}).AddTokenAuth(token)
|
||||
resp := session.MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var pr api.PullRequest
|
||||
DecodeJSON(t, resp, &pr)
|
||||
|
||||
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{
|
||||
Name: "user1",
|
||||
})
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{
|
||||
OwnerID: user1.ID,
|
||||
Name: "repo1",
|
||||
})
|
||||
|
||||
// Assert that the PR exists, is open, and is not mergeable (conflicted)
|
||||
prLoaded := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
|
||||
ID: pr.ID,
|
||||
HeadRepoID: repo1.ID,
|
||||
BaseRepoID: repo1.ID,
|
||||
HeadBranch: "conflict",
|
||||
BaseBranch: "base",
|
||||
}, "status = 0")
|
||||
assert.False(t, prLoaded.Mergeable(t.Context()), "PR should be marked as conflicted")
|
||||
|
||||
gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1)
|
||||
require.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
// Visit the PR page and check for the manual merge helper
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/user1/repo1/pulls/%d", pr.Index))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
// Check for "View command line instructions"
|
||||
summary := htmlDoc.doc.Find("details.collapsible summary").Text()
|
||||
assert.Contains(t, summary, "View command line instructions")
|
||||
|
||||
// Check for "Manual merge helper"
|
||||
helperTitle := htmlDoc.doc.Find("details.collapsible h3").Text()
|
||||
assert.Contains(t, helperTitle, "Manual merge helper")
|
||||
|
||||
// Check for the description
|
||||
helperDesc := htmlDoc.doc.Find("details.collapsible p").Text()
|
||||
assert.Contains(t, helperDesc, "Use this merge commit message when completing the merge manually.")
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue