Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
639d23d
Fix duplicate script declaration error in pull request merge box
silverwind Feb 25, 2026
c04bf2e
Suppress djlint H025 false positive in pull merge box template
silverwind Feb 25, 2026
f7dcbd8
Read merge form data from element props instead of window.config.page…
silverwind Feb 26, 2026
6399e84
Merge remote-tracking branch 'origin/main' into fixmerge
silverwind Feb 27, 2026
71501fb
Move merge form JSON construction from template to Go
silverwind Feb 27, 2026
3cdf645
Apply suggestion from @silverwind
silverwind Feb 27, 2026
54dc981
Merge branch 'main' into fixmerge
silverwind Feb 27, 2026
83d9f38
Clean up merge form: pass params directly, remove unused code
silverwind Feb 27, 2026
365689a
Simplify merge form: remove params struct, read ctx.Data directly
silverwind Feb 27, 2026
66725dc
Reduce ctx.Data reads in merge form builder
silverwind Feb 27, 2026
db46564
Remove ctx.Data reads: pass values through typed params
silverwind Feb 27, 2026
4811c47
Remove obsolete ctx.Data sets and simplify merge style logic
silverwind Feb 27, 2026
6170a80
Remove ctx.Data round-trips in prepareViewPullInfo
silverwind Feb 27, 2026
1509ca3
DRY up merge form: embed struct, inline closure, deduplicate checks
silverwind Feb 27, 2026
1268eec
Pass pre-computed blocked-by flags to merge form builder
silverwind Feb 27, 2026
1898288
Add e2e tests for pull request merge box
silverwind Feb 27, 2026
ad0c12c
Optimize pull merge box e2e tests
silverwind Feb 27, 2026
b059455
Shorten e2e test names and use lowercase
silverwind Feb 27, 2026
33e154a
Remove redundant recovery check in status checks e2e test
silverwind Feb 27, 2026
96e8b2a
fix lint
silverwind Feb 27, 2026
93fae30
Fix type assertion panic when HeadTarget is template.HTML
silverwind Mar 1, 2026
4e72424
Remove unused apiCreateFile and extract preparePullViewReviewAndMergeAll
silverwind Mar 1, 2026
ff3e554
Remove unused clickDropdownItem utility function
silverwind Mar 1, 2026
885897b
Merge branch 'main' into fixmerge
silverwind Mar 1, 2026
a826a20
Add comments explaining merge permission logic
silverwind Mar 1, 2026
3e02cd4
Restore stillCanManualMerge closure
silverwind Mar 1, 2026
5ff665d
Rename merge form fields for clarity
silverwind Mar 6, 2026
f626aa0
Merge remote-tracking branch 'origin/main' into fixmerge
silverwind Mar 6, 2026
0affa9c
fmt
silverwind Mar 6, 2026
3d66fd3
Merge origin/main into fixmerge
silverwind Apr 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions modules/templates/util_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ func NewSliceUtils() *SliceUtils {
return &SliceUtils{}
}

func (su *SliceUtils) Pack(args ...any) []any {
return args
}

func (su *SliceUtils) Contains(s, v any) bool {
if s == nil {
return false
Expand Down
154 changes: 72 additions & 82 deletions templates/repo/issue/view_content/pull_merge_box.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -220,89 +220,77 @@
{{$hasPendingPullRequestMergeTip = ctx.Locale.Tr "repo.pulls.auto_merge_has_pending_schedule" .PendingPullRequestMerge.Doer.Name $createdPRMergeStr}}
{{end}}
<div class="divider"></div>
<script type="module">
const defaultMergeTitle = {{.DefaultMergeMessage}};
const defaultSquashMergeTitle = {{.DefaultSquashMergeMessage}};
const defaultMergeMessage = {{.DefaultMergeBody}};
const defaultSquashMergeMessage = {{.DefaultSquashMergeBody}};
const mergeForm = {
'baseLink': {{.Issue.Link}},
'textCancel': {{ctx.Locale.Tr "cancel"}},
'textDeleteBranch': {{ctx.Locale.Tr "repo.branch.delete" .HeadTarget}},
'textAutoMergeButtonWhenSucceed': {{ctx.Locale.Tr "repo.pulls.auto_merge_button_when_succeed"}},
'textAutoMergeWhenSucceed': {{ctx.Locale.Tr "repo.pulls.auto_merge_when_succeed"}},
'textAutoMergeCancelSchedule': {{ctx.Locale.Tr "repo.pulls.auto_merge_cancel_schedule"}},
'textClearMergeMessage': {{ctx.Locale.Tr "repo.pulls.clear_merge_message"}},
'textClearMergeMessageHint': {{ctx.Locale.Tr "repo.pulls.clear_merge_message_hint"}},
'textMergeCommitId': {{ctx.Locale.Tr "repo.pulls.merge_commit_id"}},

'canMergeNow': {{$canMergeNow}},
'allOverridableChecksOk': {{not $notAllOverridableChecksOk}},
'emptyCommit': {{.Issue.PullRequest.IsEmpty}},
'pullHeadCommitID': {{.PullHeadCommitID}},
'isPullBranchDeletable': {{.IsPullBranchDeletable}},
'defaultMergeStyle': {{.MergeStyle}},
'defaultDeleteBranchAfterMerge': {{$prUnit.PullRequestsConfig.DefaultDeleteBranchAfterMerge}},
'mergeMessageFieldPlaceHolder': {{ctx.Locale.Tr "repo.editor.commit_message_desc"}},
'defaultMergeMessage': defaultMergeMessage,

'hasPendingPullRequestMerge': {{.HasPendingPullRequestMerge}},
'hasPendingPullRequestMergeTip': {{$hasPendingPullRequestMergeTip}},
};

const generalHideAutoMerge = mergeForm.canMergeNow && mergeForm.allOverridableChecksOk; // if this pr can be merged now, then hide the auto merge
mergeForm['mergeStyles'] = [
{
'name': 'merge',
'allowed': {{$prUnit.PullRequestsConfig.AllowMerge}},
'textDoMerge': {{ctx.Locale.Tr "repo.pulls.merge_pull_request"}},
'mergeTitleFieldText': defaultMergeTitle,
'mergeMessageFieldText': defaultMergeMessage,
'hideAutoMerge': generalHideAutoMerge,
},
{
'name': 'rebase',
'allowed': {{$prUnit.PullRequestsConfig.AllowRebase}},
'textDoMerge': {{ctx.Locale.Tr "repo.pulls.rebase_merge_pull_request"}},
'hideMergeMessageTexts': true,
'hideAutoMerge': generalHideAutoMerge,
},
{
'name': 'rebase-merge',
'allowed': {{$prUnit.PullRequestsConfig.AllowRebaseMerge}},
'textDoMerge': {{ctx.Locale.Tr "repo.pulls.rebase_merge_commit_pull_request"}},
'mergeTitleFieldText': defaultMergeTitle,
'mergeMessageFieldText': defaultMergeMessage,
'hideAutoMerge': generalHideAutoMerge,
},
{
'name': 'squash',
'allowed': {{$prUnit.PullRequestsConfig.AllowSquash}},
'textDoMerge': {{ctx.Locale.Tr "repo.pulls.squash_merge_pull_request"}},
'mergeTitleFieldText': defaultSquashMergeTitle,
'mergeMessageFieldText': {{.GetCommitMessages}} + defaultSquashMergeMessage,
'hideAutoMerge': generalHideAutoMerge,
},
{
'name': 'fast-forward-only',
'allowed': {{and $prUnit.PullRequestsConfig.AllowFastForwardOnly (eq .Issue.PullRequest.CommitsBehind 0)}},
'textDoMerge': {{ctx.Locale.Tr "repo.pulls.fast_forward_only_merge_pull_request"}},
'hideMergeMessageTexts': true,
'hideAutoMerge': generalHideAutoMerge,
},
{
'name': 'manually-merged',
'allowed': {{$prUnit.PullRequestsConfig.AllowManualMerge}},
'textDoMerge': {{ctx.Locale.Tr "repo.pulls.merge_manually"}},
'hideMergeMessageTexts': true,
'hideAutoMerge': true,
}
];
window.config.pageData.pullRequestMergeForm = mergeForm;
</script>

{{$generalHideAutoMerge := and $canMergeNow (not $notAllOverridableChecksOk)}}
{{$showGeneralMergeForm = true}}
<div id="pull-request-merge-form"></div>
<div id="pull-request-merge-form" data-merge-form="{{JsonUtils.EncodeToString (dict
"baseLink" .Issue.Link
"textCancel" (ctx.Locale.Tr "cancel")
"textDeleteBranch" (ctx.Locale.Tr "repo.branch.delete" .HeadTarget)
"textAutoMergeButtonWhenSucceed" (ctx.Locale.Tr "repo.pulls.auto_merge_button_when_succeed")
"textAutoMergeWhenSucceed" (ctx.Locale.Tr "repo.pulls.auto_merge_when_succeed")
"textAutoMergeCancelSchedule" (ctx.Locale.Tr "repo.pulls.auto_merge_cancel_schedule")
"textClearMergeMessage" (ctx.Locale.Tr "repo.pulls.clear_merge_message")
"textClearMergeMessageHint" (ctx.Locale.Tr "repo.pulls.clear_merge_message_hint")
"textMergeCommitId" (ctx.Locale.Tr "repo.pulls.merge_commit_id")
"canMergeNow" $canMergeNow
"allOverridableChecksOk" (not $notAllOverridableChecksOk)
"emptyCommit" .Issue.PullRequest.IsEmpty
"pullHeadCommitID" .PullHeadCommitID
"isPullBranchDeletable" .IsPullBranchDeletable
"defaultMergeStyle" .MergeStyle
"defaultDeleteBranchAfterMerge" $prUnit.PullRequestsConfig.DefaultDeleteBranchAfterMerge
"mergeMessageFieldPlaceHolder" (ctx.Locale.Tr "repo.editor.commit_message_desc")
"defaultMergeMessage" .DefaultMergeBody
"hasPendingPullRequestMerge" .HasPendingPullRequestMerge
"hasPendingPullRequestMergeTip" $hasPendingPullRequestMergeTip
"mergeStyles" (SliceUtils.Pack
(dict
"name" "merge"
"allowed" $prUnit.PullRequestsConfig.AllowMerge
"textDoMerge" (ctx.Locale.Tr "repo.pulls.merge_pull_request")
"mergeTitleFieldText" .DefaultMergeMessage
"mergeMessageFieldText" .DefaultMergeBody
"hideAutoMerge" $generalHideAutoMerge
)
(dict
"name" "rebase"
"allowed" $prUnit.PullRequestsConfig.AllowRebase
"textDoMerge" (ctx.Locale.Tr "repo.pulls.rebase_merge_pull_request")
"hideMergeMessageTexts" true
"hideAutoMerge" $generalHideAutoMerge
)
(dict
"name" "rebase-merge"
"allowed" $prUnit.PullRequestsConfig.AllowRebaseMerge
"textDoMerge" (ctx.Locale.Tr "repo.pulls.rebase_merge_commit_pull_request")
"mergeTitleFieldText" .DefaultMergeMessage
"mergeMessageFieldText" .DefaultMergeBody
"hideAutoMerge" $generalHideAutoMerge
)
(dict
"name" "squash"
"allowed" $prUnit.PullRequestsConfig.AllowSquash
"textDoMerge" (ctx.Locale.Tr "repo.pulls.squash_merge_pull_request")
"mergeTitleFieldText" .DefaultSquashMergeMessage
"mergeMessageFieldText" (printf "%s%s" .GetCommitMessages .DefaultSquashMergeBody)
"hideAutoMerge" $generalHideAutoMerge
)
(dict
"name" "fast-forward-only"
"allowed" (and $prUnit.PullRequestsConfig.AllowFastForwardOnly (eq .Issue.PullRequest.CommitsBehind 0))
"textDoMerge" (ctx.Locale.Tr "repo.pulls.fast_forward_only_merge_pull_request")
"hideMergeMessageTexts" true
"hideAutoMerge" $generalHideAutoMerge
)
(dict
"name" "manually-merged"
"allowed" $prUnit.PullRequestsConfig.AllowManualMerge
"textDoMerge" (ctx.Locale.Tr "repo.pulls.merge_manually")
"hideMergeMessageTexts" true
"hideAutoMerge" true
)
)
)}}"></div>
{{else}}
{{/* no merge style was set in repo setting: not or ($prUnit.PullRequestsConfig.AllowMerge ...) */}}
<div class="divider"></div>
Expand Down Expand Up @@ -402,5 +390,7 @@
{{end}}
</div>
</div>
{{/* djlint:off H025 */}}
</div>
{{/* djlint:on */}}
{{end}}
4 changes: 2 additions & 2 deletions web_src/js/components/PullRequestMergeForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import {computed, onMounted, onUnmounted, shallowRef, watch} from 'vue';
import {SvgIcon} from '../svg.ts';
import {toggleElem} from '../utils/dom.ts';

const {pageData} = window.config;
const props = defineProps<{elRoot: HTMLElement}>();

const mergeForm = pageData.pullRequestMergeForm;
const mergeForm = JSON.parse(props.elRoot.getAttribute('data-merge-form')!);

const mergeTitleFieldValue = shallowRef('');
const mergeMessageFieldValue = shallowRef('');
Expand Down
20 changes: 2 additions & 18 deletions web_src/js/features/repo-issue-pull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,13 @@ function initRepoPullRequestCommitStatus(el: HTMLElement) {
}

function initRepoPullRequestMergeForm(box: HTMLElement) {
const el = box.querySelector('#pull-request-merge-form');
const el = box.querySelector<HTMLElement>('#pull-request-merge-form');
if (!el) return;

const view = createApp(PullRequestMergeForm);
const view = createApp(PullRequestMergeForm, {elRoot: el});
view.mount(el);
}

function executeScripts(elem: HTMLElement) {
for (const oldScript of elem.querySelectorAll('script')) {
// TODO: that's the only way to load the data for the merge form. In the future
// we need to completely decouple the page data and embedded script
// eslint-disable-next-line github/no-dynamic-script-tag
const newScript = document.createElement('script');
for (const attr of oldScript.attributes) {
if (attr.name === 'type' && attr.value === 'module') continue;
newScript.setAttribute(attr.name, attr.value);
}
newScript.text = oldScript.text;
document.body.append(newScript);
}
}

export function initRepoPullMergeBox(el: HTMLElement) {
initRepoPullRequestCommitStatus(el);
initRepoPullRequestUpdate(el);
Expand Down Expand Up @@ -124,7 +109,6 @@ export function initRepoPullMergeBox(el: HTMLElement) {
}
document.removeEventListener('visibilitychange', onVisibilityChange);
const newElem = createElementFromHTML(await resp.text());
executeScripts(newElem);
el.replaceWith(newElem);
};

Expand Down