feature: initial implementation of squash functionality for git and hg; no enable/disable settings option yet
This commit is contained in:
parent
5e3cc80c7b
commit
802e8a8119
8 changed files with 206 additions and 88 deletions
|
|
@ -1498,6 +1498,10 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
||||||
|
|
||||||
if merge_possible:
|
if merge_possible:
|
||||||
log.debug("Pre-conditions checked, trying to merge.")
|
log.debug("Pre-conditions checked, trying to merge.")
|
||||||
|
|
||||||
|
controls = peppercorn.parse(self.request.POST.items())
|
||||||
|
squash_before_merge = str2bool(controls.get("squash_before_merge", "false"))
|
||||||
|
|
||||||
extras = vcs_operation_context(
|
extras = vcs_operation_context(
|
||||||
self.request.environ,
|
self.request.environ,
|
||||||
repo_name=pull_request.target_repo.repo_name,
|
repo_name=pull_request.target_repo.repo_name,
|
||||||
|
|
@ -1506,7 +1510,9 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
||||||
scm=pull_request.target_repo.repo_type,
|
scm=pull_request.target_repo.repo_type,
|
||||||
)
|
)
|
||||||
with pull_request.set_state(PullRequest.STATE_UPDATING):
|
with pull_request.set_state(PullRequest.STATE_UPDATING):
|
||||||
self._merge_pull_request(pull_request, self._rhodecode_db_user, extras)
|
self._merge_pull_request(
|
||||||
|
pull_request, self._rhodecode_db_user, extras, squash_commits=squash_before_merge
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
log.debug("Pre-conditions failed, NOT merging.")
|
log.debug("Pre-conditions failed, NOT merging.")
|
||||||
|
|
||||||
|
|
@ -1518,9 +1524,9 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _merge_pull_request(self, pull_request, user, extras):
|
def _merge_pull_request(self, pull_request, user, extras, squash_commits=False):
|
||||||
_ = self.request.translate
|
_ = self.request.translate
|
||||||
merge_resp = PullRequestModel().merge_repo(pull_request, user, extras=extras)
|
merge_resp = PullRequestModel().merge_repo(pull_request, user, extras=extras, squash_commits=squash_commits)
|
||||||
|
|
||||||
if merge_resp.executed:
|
if merge_resp.executed:
|
||||||
log.debug("The merge was successful, closing the pull request.")
|
log.debug("The merge was successful, closing the pull request.")
|
||||||
|
|
|
||||||
|
|
@ -1169,6 +1169,7 @@ class BaseRepository(object):
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
use_rebase=False,
|
use_rebase=False,
|
||||||
close_branch=False,
|
close_branch=False,
|
||||||
|
squash_commits=False,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Merge the revisions specified in `source_ref` from `source_repo`
|
Merge the revisions specified in `source_ref` from `source_repo`
|
||||||
|
|
@ -1222,6 +1223,7 @@ class BaseRepository(object):
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
use_rebase=use_rebase,
|
use_rebase=use_rebase,
|
||||||
close_branch=close_branch,
|
close_branch=close_branch,
|
||||||
|
squash_commits=squash_commits,
|
||||||
)
|
)
|
||||||
except RepositoryError as exc:
|
except RepositoryError as exc:
|
||||||
log.exception("Unexpected failure when running merge, dry-run=%s", dry_run)
|
log.exception("Unexpected failure when running merge, dry-run=%s", dry_run)
|
||||||
|
|
@ -1240,6 +1242,7 @@ class BaseRepository(object):
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
use_rebase=False,
|
use_rebase=False,
|
||||||
close_branch=False,
|
close_branch=False,
|
||||||
|
squash_commits=False,
|
||||||
):
|
):
|
||||||
"""Internal implementation of merge."""
|
"""Internal implementation of merge."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from celery.platforms import strargv
|
||||||
from zope.cachedescriptors.property import Lazy as LazyProperty
|
from zope.cachedescriptors.property import Lazy as LazyProperty
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
@ -842,7 +843,7 @@ class GitRepository(BaseRepository):
|
||||||
cmd.extend(["--no-tags", repository_path, branch_name])
|
cmd.extend(["--no-tags", repository_path, branch_name])
|
||||||
self.run_git_command(cmd, fail_on_stderr=False)
|
self.run_git_command(cmd, fail_on_stderr=False)
|
||||||
|
|
||||||
def _local_merge(self, merge_message, user_name, user_email, heads):
|
def _local_merge(self, merge_message, user_name, user_email, heads, squash_commits=False):
|
||||||
"""
|
"""
|
||||||
Merge the given head into the checked out branch.
|
Merge the given head into the checked out branch.
|
||||||
|
|
||||||
|
|
@ -853,6 +854,7 @@ class GitRepository(BaseRepository):
|
||||||
|
|
||||||
:param merge_message: The message to use for the merge commit.
|
:param merge_message: The message to use for the merge commit.
|
||||||
:param heads: the heads to merge.
|
:param heads: the heads to merge.
|
||||||
|
:param squash_commits: Use squash strategy to merge.
|
||||||
"""
|
"""
|
||||||
if self.bare:
|
if self.bare:
|
||||||
raise RepositoryError("Cannot merge into a bare git repository")
|
raise RepositoryError("Cannot merge into a bare git repository")
|
||||||
|
|
@ -863,40 +865,68 @@ class GitRepository(BaseRepository):
|
||||||
if self.is_empty():
|
if self.is_empty():
|
||||||
# TODO(skreft): do something more robust in this case.
|
# TODO(skreft): do something more robust in this case.
|
||||||
raise RepositoryError("Do not know how to merge into empty repositories yet")
|
raise RepositoryError("Do not know how to merge into empty repositories yet")
|
||||||
unresolved = None
|
|
||||||
|
|
||||||
# N.B.(skreft): the --no-ff option is used to enforce the creation of a
|
base_cmd = [
|
||||||
# commit message. We also specify the user who is doing the merge.
|
|
||||||
cmd = [
|
|
||||||
"-c",
|
"-c",
|
||||||
f'user.name="{user_name}"',
|
f'user.name="{user_name}"',
|
||||||
"-c",
|
"-c",
|
||||||
f"user.email={user_email}",
|
f"user.email={user_email}",
|
||||||
"merge",
|
|
||||||
"--no-ff",
|
|
||||||
"-m",
|
|
||||||
safe_str(merge_message),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
merge_cmd = cmd + heads
|
if squash_commits:
|
||||||
|
self._squash_merge(base_cmd, heads, merge_message)
|
||||||
|
else:
|
||||||
|
self._normal_merge(base_cmd, heads, merge_message)
|
||||||
|
|
||||||
|
def _normal_merge(self, base_cmd, heads, merge_message):
|
||||||
try:
|
try:
|
||||||
|
# N.B.(skreft): the --no-ff option is used to enforce the creation of a
|
||||||
|
# commit message. We also specify the user who is doing the merge.
|
||||||
|
merge_cmd = base_cmd + ["merge", "--no-ff", "-m", safe_str(merge_message)] + heads
|
||||||
|
|
||||||
|
log.debug("Merge command: %s", merge_cmd)
|
||||||
self.run_git_command(merge_cmd, fail_on_stderr=False)
|
self.run_git_command(merge_cmd, fail_on_stderr=False)
|
||||||
except RepositoryError:
|
except RepositoryError as e:
|
||||||
files = self.run_git_command(["diff", "--name-only", "--diff-filter", "U"], fail_on_stderr=False)[
|
log.warning("Merge failed with error: %s", e)
|
||||||
0
|
self._abort_merge()
|
||||||
].splitlines()
|
|
||||||
# NOTE(marcink): we add U notation for consistent with HG backend output
|
|
||||||
unresolved = [f"U {f}" for f in files]
|
|
||||||
|
|
||||||
# Cleanup any merge leftovers
|
def _squash_merge(self, base_cmd, heads, merge_message):
|
||||||
self._remote.invalidate_vcs_cache()
|
try:
|
||||||
self.run_git_command(["merge", "--abort"], fail_on_stderr=False)
|
squash_cmd = (
|
||||||
|
base_cmd
|
||||||
|
+ [
|
||||||
|
"merge",
|
||||||
|
"--squash",
|
||||||
|
]
|
||||||
|
+ heads
|
||||||
|
)
|
||||||
|
|
||||||
if unresolved:
|
log.debug("Squash command: %s", squash_cmd)
|
||||||
raise UnresolvedFilesInRepo(unresolved)
|
self.run_git_command(squash_cmd, fail_on_stderr=False)
|
||||||
else:
|
|
||||||
raise
|
commit_cmd = base_cmd + ["commit", "-m", safe_str(merge_message)]
|
||||||
|
|
||||||
|
log.debug("Commit after squash command: %s", commit_cmd)
|
||||||
|
self.run_git_command(commit_cmd, fail_on_stderr=False)
|
||||||
|
except RepositoryError as e:
|
||||||
|
log.warning("Squash failed with error: %s", e)
|
||||||
|
self._abort_merge()
|
||||||
|
|
||||||
|
def _abort_merge(self):
|
||||||
|
files = self.run_git_command(["diff", "--name-only", "--diff-filter", "U"], fail_on_stderr=False)[
|
||||||
|
0
|
||||||
|
].splitlines()
|
||||||
|
|
||||||
|
# NOTE(marcink): we add U notation for consistent with HG backend output
|
||||||
|
unresolved = [f"U {f}" for f in files]
|
||||||
|
|
||||||
|
# Cleanup merge state
|
||||||
|
self._remote.invalidate_vcs_cache()
|
||||||
|
self.run_git_command(["merge", "--abort"], fail_on_stderr=False)
|
||||||
|
|
||||||
|
if unresolved:
|
||||||
|
raise UnresolvedFilesInRepo(unresolved)
|
||||||
|
raise RepositoryError("Merge failed without unresolved files")
|
||||||
|
|
||||||
def _local_push(self, source_branch, repository_path, target_branch, enable_hooks=False, rc_scm_data=None):
|
def _local_push(self, source_branch, repository_path, target_branch, enable_hooks=False, rc_scm_data=None):
|
||||||
"""
|
"""
|
||||||
|
|
@ -961,10 +991,16 @@ class GitRepository(BaseRepository):
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
use_rebase=False,
|
use_rebase=False,
|
||||||
close_branch=False,
|
close_branch=False,
|
||||||
|
squash_commits=False,
|
||||||
):
|
):
|
||||||
log.debug(
|
if squash_commits:
|
||||||
"Executing merge_repo with %s strategy, dry_run mode:%s", "rebase" if use_rebase else "merge", dry_run
|
strategy = "squash and merge"
|
||||||
)
|
elif use_rebase:
|
||||||
|
strategy = "rebase"
|
||||||
|
else:
|
||||||
|
strategy = "merge"
|
||||||
|
|
||||||
|
log.debug("Executing merge_repo with '%s' strategy, dry_run mode: %s", strategy, dry_run)
|
||||||
from rhodecode.model.repo import RepoModel
|
from rhodecode.model.repo import RepoModel
|
||||||
|
|
||||||
if target_ref.commit_id != self.branches[target_ref.name]:
|
if target_ref.commit_id != self.branches[target_ref.name]:
|
||||||
|
|
@ -1026,7 +1062,9 @@ class GitRepository(BaseRepository):
|
||||||
merge_failure_reason = MergeFailureReason.NONE
|
merge_failure_reason = MergeFailureReason.NONE
|
||||||
metadata = {}
|
metadata = {}
|
||||||
try:
|
try:
|
||||||
shadow_repo._local_merge(merge_message, merger_name, merger_email, [source_ref.commit_id])
|
shadow_repo._local_merge(
|
||||||
|
merge_message, merger_name, merger_email, [source_ref.commit_id], squash_commits=squash_commits
|
||||||
|
)
|
||||||
merge_possible = True
|
merge_possible = True
|
||||||
|
|
||||||
# Need to invalidate the cache, or otherwise we
|
# Need to invalidate the cache, or otherwise we
|
||||||
|
|
|
||||||
|
|
@ -680,6 +680,7 @@ class MercurialRepository(BaseRepository):
|
||||||
use_rebase=False,
|
use_rebase=False,
|
||||||
close_commit_id=None,
|
close_commit_id=None,
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
|
squash_commits=False,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Merge the given source_revision into the checked out revision.
|
Merge the given source_revision into the checked out revision.
|
||||||
|
|
@ -711,11 +712,11 @@ class MercurialRepository(BaseRepository):
|
||||||
return source_ref_commit_id, True
|
return source_ref_commit_id, True
|
||||||
|
|
||||||
unresolved = None
|
unresolved = None
|
||||||
if use_rebase:
|
if use_rebase or squash_commits:
|
||||||
try:
|
try:
|
||||||
bookmark_name = f"rcbook{source_ref_commit_id}{target_ref_commit_id}"
|
bookmark_name = f"rcbook{source_ref_commit_id}{target_ref_commit_id}"
|
||||||
self.bookmark(bookmark_name, revision=source_ref.commit_id)
|
self.bookmark(bookmark_name, revision=source_ref.commit_id)
|
||||||
self._remote.rebase(source=source_ref_commit_id, dest=target_ref_commit_id)
|
self._remote.rebase(source=source_ref_commit_id, dest=target_ref_commit_id, collapse=squash_commits)
|
||||||
self._remote.invalidate_vcs_cache()
|
self._remote.invalidate_vcs_cache()
|
||||||
self._update(bookmark_name, clean=True)
|
self._update(bookmark_name, clean=True)
|
||||||
return self._identify(), True
|
return self._identify(), True
|
||||||
|
|
@ -809,10 +810,16 @@ class MercurialRepository(BaseRepository):
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
use_rebase=False,
|
use_rebase=False,
|
||||||
close_branch=False,
|
close_branch=False,
|
||||||
|
squash_commits=False,
|
||||||
):
|
):
|
||||||
log.debug(
|
if squash_commits:
|
||||||
"Executing merge_repo with %s strategy, dry_run mode:%s", "rebase" if use_rebase else "merge", dry_run
|
strategy = "squash and merge"
|
||||||
)
|
elif use_rebase:
|
||||||
|
strategy = "rebase"
|
||||||
|
else:
|
||||||
|
strategy = "merge"
|
||||||
|
|
||||||
|
log.debug("Executing merge_repo with '%s' strategy, dry_run mode: %s", strategy, dry_run)
|
||||||
from rhodecode.model.repo import RepoModel
|
from rhodecode.model.repo import RepoModel
|
||||||
|
|
||||||
if target_ref.commit_id not in self._heads():
|
if target_ref.commit_id not in self._heads():
|
||||||
|
|
@ -899,6 +906,7 @@ class MercurialRepository(BaseRepository):
|
||||||
use_rebase=use_rebase,
|
use_rebase=use_rebase,
|
||||||
close_commit_id=close_commit_id,
|
close_commit_id=close_commit_id,
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
|
squash_commits=squash_commits,
|
||||||
)
|
)
|
||||||
merge_possible = True
|
merge_possible = True
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1011,12 +1011,12 @@ class PullRequestModel(BaseModel):
|
||||||
|
|
||||||
return commit_ids
|
return commit_ids
|
||||||
|
|
||||||
def merge_repo(self, pull_request, user, extras):
|
def merge_repo(self, pull_request, user, extras, squash_commits=False):
|
||||||
repo_type = pull_request.source_repo.repo_type
|
repo_type = pull_request.source_repo.repo_type
|
||||||
log.debug("Merging pull request %s", pull_request)
|
log.debug("Merging pull request %s", pull_request)
|
||||||
|
|
||||||
extras["user_agent"] = "{}/internal-merge".format(repo_type)
|
extras["user_agent"] = "{}/internal-merge".format(repo_type)
|
||||||
merge_state = self._merge_pull_request(pull_request, user, extras)
|
merge_state = self._merge_pull_request(pull_request, user, extras, squash_commits=squash_commits)
|
||||||
if merge_state.executed:
|
if merge_state.executed:
|
||||||
log.debug("Merge was successful, updating the pull request comments.")
|
log.debug("Merge was successful, updating the pull request comments.")
|
||||||
self._comment_and_close_pr(pull_request, user, merge_state)
|
self._comment_and_close_pr(pull_request, user, merge_state)
|
||||||
|
|
@ -1027,7 +1027,7 @@ class PullRequestModel(BaseModel):
|
||||||
log.warning("Merge failed, not updating the pull request.")
|
log.warning("Merge failed, not updating the pull request.")
|
||||||
return merge_state
|
return merge_state
|
||||||
|
|
||||||
def _merge_pull_request(self, pull_request, user, extras, merge_msg=None):
|
def _merge_pull_request(self, pull_request, user, extras, merge_msg=None, squash_commits=False):
|
||||||
target_vcs = pull_request.target_repo.scm_instance()
|
target_vcs = pull_request.target_repo.scm_instance()
|
||||||
source_vcs = pull_request.source_repo.scm_instance()
|
source_vcs = pull_request.source_repo.scm_instance()
|
||||||
|
|
||||||
|
|
@ -1067,6 +1067,7 @@ class PullRequestModel(BaseModel):
|
||||||
message=message,
|
message=message,
|
||||||
use_rebase=use_rebase,
|
use_rebase=use_rebase,
|
||||||
close_branch=close_branch,
|
close_branch=close_branch,
|
||||||
|
squash_commits=squash_commits,
|
||||||
)
|
)
|
||||||
|
|
||||||
return merge_state
|
return merge_state
|
||||||
|
|
|
||||||
|
|
@ -521,6 +521,15 @@ input[type="submit"] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a[role="button"].btn {
|
||||||
|
&.disabled {
|
||||||
|
.border ( @border-thickness-buttons, @rcblue );
|
||||||
|
background-color: @rcblue;
|
||||||
|
color: white;
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
input[type="reset"] {
|
input[type="reset"] {
|
||||||
&:extend(.btn-default);
|
&:extend(.btn-default);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,70 +1,100 @@
|
||||||
|
|
||||||
<div class="pull-request-wrap">
|
<div class="pull-request-wrap">
|
||||||
|
|
||||||
% if c.pr_merge_possible:
|
% if c.pr_merge_possible:
|
||||||
<h2 class="merge-status">
|
<h2 class="merge-status">
|
||||||
<span class="merge-icon success"><i class="icon-ok"></i></span>
|
<span class="merge-icon success"><i class="icon-ok"></i></span>
|
||||||
${_('This pull request can be merged automatically.')}
|
${_('This pull request can be merged automatically.')}
|
||||||
</h2>
|
</h2>
|
||||||
% else:
|
% else:
|
||||||
<h2 class="merge-status">
|
<h2 class="merge-status">
|
||||||
<span class="merge-icon warning"><i class="icon-false"></i></span>
|
<span class="merge-icon warning"><i class="icon-false"></i></span>
|
||||||
${_('Merge is not currently possible because of below failed checks.')}
|
${_('Merge is not currently possible because of below failed checks.')}
|
||||||
</h2>
|
</h2>
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% if c.pr_merge_errors.items():
|
% if c.pr_merge_errors.items():
|
||||||
<ul>
|
<ul>
|
||||||
% for pr_check_key, pr_check_details in c.pr_merge_errors.items():
|
% for pr_check_key, pr_check_details in c.pr_merge_errors.items():
|
||||||
<% pr_check_type = pr_check_details['error_type'] %>
|
<% pr_check_type = pr_check_details['error_type'] %>
|
||||||
<li>
|
<li>
|
||||||
<div class="merge-message ${pr_check_type}" data-role="merge-message">
|
<div class="merge-message ${pr_check_type}" data-role="merge-message">
|
||||||
<span style="white-space: pre-line">- ${pr_check_details['message']}</span>
|
<span style="white-space: pre-line">- ${pr_check_details['message']}</span>
|
||||||
% if pr_check_key == 'todo':
|
% if pr_check_key == 'todo':
|
||||||
% for co in pr_check_details['details']:
|
% for co in pr_check_details['details']:
|
||||||
<a class="permalink" href="#comment-${co.comment_id}" onclick="Rhodecode.comments.scrollToComment($('#comment-${co.comment_id}'), 0, ${h.str_json(co.outdated)})"> #${co.comment_id}</a>${'' if loop.last else ','}
|
<a class="permalink" href="#comment-${co.comment_id}"
|
||||||
% endfor
|
onclick="Rhodecode.comments.scrollToComment($('#comment-${co.comment_id}'), 0, ${h.str_json(co.outdated)})">
|
||||||
% endif
|
#${co.comment_id}</a>${'' if loop.last else ','}
|
||||||
</div>
|
% endfor
|
||||||
</li>
|
% endif
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
% endfor
|
% endfor
|
||||||
</ul>
|
</ul>
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
<div class="pull-request-merge-actions">
|
<div class="pull-request-merge-actions">
|
||||||
% if c.allowed_to_merge:
|
% if c.allowed_to_merge:
|
||||||
## Merge info, show only if all errors are taken care of
|
## Merge info, show only if all errors are taken care of
|
||||||
% if not c.pr_merge_errors and c.pr_merge_info:
|
% if not c.pr_merge_errors and c.pr_merge_info:
|
||||||
<div class="pull-request-merge-info">
|
<div class="pull-request-merge-info">
|
||||||
<ul>
|
<ul>
|
||||||
% for pr_merge_key, pr_merge_details in c.pr_merge_info.items():
|
% for pr_merge_key, pr_merge_details in c.pr_merge_info.items():
|
||||||
<li>
|
<li>
|
||||||
- ${pr_merge_details['message']}
|
- ${pr_merge_details['message']}
|
||||||
</li>
|
</li>
|
||||||
% endfor
|
% endfor
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
${h.secure_form(h.route_path('pullrequest_merge', repo_name=c.repo_name, pull_request_id=c.pull_request.pull_request_id), id='merge_pull_request_form', request=request)}
|
${h.secure_form(h.route_path('pullrequest_merge', repo_name=c.repo_name,
|
||||||
<% merge_disabled = ' disabled' if c.pr_merge_possible is False else '' %>
|
pull_request_id=c.pull_request.pull_request_id), id='merge_pull_request_form', request=request,
|
||||||
|
style='display: flex; justify-content: flex-end;')}
|
||||||
|
<% merge_disabled = ' disabled' if c.pr_merge_possible is False else '' %>
|
||||||
|
|
||||||
% if c.allowed_to_close:
|
% if c.allowed_to_close:
|
||||||
## close PR action, injected later next to COMMENT button
|
## close PR action, injected later next to COMMENT button
|
||||||
% if c.pull_request_review_status == c.REVIEW_STATUS_APPROVED:
|
% if c.pull_request_review_status == c.REVIEW_STATUS_APPROVED:
|
||||||
<a id="close-pull-request-action" class="btn btn-approved-status" href="#close-as-approved" onclick="closePullRequest('${c.REVIEW_STATUS_APPROVED}'); return false;">
|
<a id="close-pull-request-action" class="btn btn-approved-status" href="#close-as-approved"
|
||||||
${_('Close with status {}').format(h.commit_status_lbl(c.REVIEW_STATUS_APPROVED))}
|
onclick="closePullRequest('${c.REVIEW_STATUS_APPROVED}'); return false;">
|
||||||
</a>
|
${_('Close with status {}').format(h.commit_status_lbl(c.REVIEW_STATUS_APPROVED))}
|
||||||
% else:
|
</a>
|
||||||
<a id="close-pull-request-action" class="btn btn-rejected-status" href="#close-as-rejected" onclick="closePullRequest('${c.REVIEW_STATUS_REJECTED}'); return false;">
|
% else:
|
||||||
${_('Close with status {}').format(h.commit_status_lbl(c.REVIEW_STATUS_REJECTED))}
|
<a id="close-pull-request-action" class="btn btn-rejected-status" href="#close-as-rejected"
|
||||||
</a>
|
onclick="closePullRequest('${c.REVIEW_STATUS_REJECTED}'); return false;">
|
||||||
|
${_('Close with status {}').format(h.commit_status_lbl(c.REVIEW_STATUS_REJECTED))}
|
||||||
|
</a>
|
||||||
|
% endif
|
||||||
% endif
|
% endif
|
||||||
% endif
|
<div class="btn-group btn-group-actions" style="margin-right: 5px;">
|
||||||
|
<input type="submit" id="merge_pull_request" value="${_('Merge Pull Request')}"
|
||||||
|
class="btn${merge_disabled}" ${merge_disabled}>
|
||||||
|
|
||||||
<input type="submit" id="merge_pull_request" value="${_('Merge and close Pull Request')}" class="btn${merge_disabled}"${merge_disabled}>
|
<a class="btn btn-primary btn-more-option${merge_disabled}" data-toggle="dropdown"
|
||||||
${h.end_form()}
|
id="pull_request_more_options" aria-pressed="false" role="button" title="${_('More merge options')}">
|
||||||
|
<i class="icon-down"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
% if not merge_disabled and c.rhodecode_db_repo.repo_type in ['git', 'hg']:
|
||||||
|
<div class="btn-action-switcher-container">
|
||||||
|
<ul class="btn-action-switcher" role="menu" style="min-width: 230px;">
|
||||||
|
<li>
|
||||||
|
<a id="squash_merge_pull_request" href="#">
|
||||||
|
% if c.rhodecode_db_repo.repo_type == 'git':
|
||||||
|
${_('Squash commits and merge.')}
|
||||||
|
% elif c.rhodecode_db_repo.repo_type == 'hg':
|
||||||
|
${_('Collapse commits and merge.')}
|
||||||
|
% endif
|
||||||
|
</a>
|
||||||
|
<input type="hidden" id="squash_merge_pull_request_value" name="squash_before_merge"
|
||||||
|
value="false">
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
% endif
|
||||||
|
</div>
|
||||||
|
${h.end_form()}
|
||||||
|
|
||||||
% if c.rhodecode_edition_id == 'EE':
|
% if c.rhodecode_edition_id == 'EE':
|
||||||
<div class="pull-request-settings"
|
<div class="pull-request-settings"
|
||||||
|
|
@ -87,16 +117,36 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
% elif c.rhodecode_user.username != h.DEFAULT_USER:
|
% elif c.rhodecode_user.username != h.DEFAULT_USER:
|
||||||
<a class="btn" href="#" onclick="refreshMergeChecks(); return false;">${_('refresh checks')}</a>
|
<a class="btn" href="#" onclick="refreshMergeChecks(); return false;">${_('refresh checks')}</a>
|
||||||
<input type="submit" value="${_('Merge and close Pull Request')}" class="btn disabled" disabled="disabled" title="${_('You are not allowed to merge this pull request.')}">
|
<input type="submit" value="${_('Merge and close Pull Request')}" class="btn disabled" disabled="disabled"
|
||||||
|
title="${_('You are not allowed to merge this pull request.')}">
|
||||||
% else:
|
% else:
|
||||||
<input type="submit" value="${_('Login to Merge this Pull Request')}" class="btn disabled" disabled="disabled">
|
<input type="submit" value="${_('Login to Merge this Pull Request')}" class="btn disabled" disabled="disabled">
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
$('#squash_merge_pull_request').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$('#squash_merge_pull_request_value').val("true");
|
||||||
|
|
||||||
|
$('#merge_pull_request_form').submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#merge_pull_request_form').submit(function () {
|
||||||
|
if (!$('#merge_pull_request').attr('disabled')) {
|
||||||
|
$('#merge_pull_request').attr('disabled', 'disabled');
|
||||||
|
}
|
||||||
|
if (!$('#pull_request_more_options').hasClass('disabled')) {
|
||||||
|
$('#pull_request_more_options').addClass('disabled');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
$("#close_branch_before_merging").on('change', function () {
|
$("#close_branch_before_merging").on('change', function () {
|
||||||
const $checkbox = $(this);
|
const $checkbox = $(this);
|
||||||
updateCloseBranchSetting(
|
updateCloseBranchSetting(
|
||||||
|
|
|
||||||
|
|
@ -975,6 +975,9 @@ window.setObserversData = ${c.pull_request_set_observers_data_json | n};
|
||||||
if (!$('#merge_pull_request').attr('disabled')) {
|
if (!$('#merge_pull_request').attr('disabled')) {
|
||||||
$('#merge_pull_request').attr('disabled', 'disabled');
|
$('#merge_pull_request').attr('disabled', 'disabled');
|
||||||
}
|
}
|
||||||
|
if (!$('#pull_request_more_options').hasClass('disabled')) {
|
||||||
|
$('#pull_request_more_options').addClass('disabled');
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue