strip: added functionality to stip choosen commits on repo settings

This commit is contained in:
Bartłomiej Wołyńczyk 2017-04-03 12:49:12 +02:00
parent 93bb2a8b36
commit 57f66c793e
4 changed files with 295 additions and 0 deletions

View file

@ -29,5 +29,18 @@ def includeme(config):
name='repo_maintenance_execute',
pattern='/{repo_name:.*?[^/]}/maintenance/execute', repo_route=True)
# Strip
config.add_route(
name='strip',
pattern='/{repo_name:.*?[^/]}/strip', repo_route=True)
config.add_route(
name='strip_check',
pattern='/{repo_name:.*?[^/]}/strip_check', repo_route=True)
config.add_route(
name='strip_execute',
pattern='/{repo_name:.*?[^/]}/strip_execute', repo_route=True)
# Scan module for configuration decorators.
config.scan()

View file

@ -0,0 +1,110 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2011-2017 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
from pyramid.view import view_config
from rhodecode.apps._base import RepoAppView
from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator,
NotAnonymous)
log = logging.getLogger(__name__)
class StripView(RepoAppView):
def load_default_context(self):
c = self._get_local_tmpl_context()
# TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
c.repo_info = self.db_repo
self._register_global_c(c)
return c
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator('repository.admin')
@view_config(
route_name='strip', request_method='GET',
renderer='rhodecode:templates/admin/repos/repo_edit.mako')
def strip(self):
c = self.load_default_context()
c.active = 'strip'
c.strip_limit = 10
return self._get_template_context(c)
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator('repository.admin')
@view_config(
route_name='strip_check', request_method='POST',
renderer='json', xhr=True
)
def strip_check(self):
from rhodecode.lib.vcs.backends.base import EmptyCommit
data = {}
rp = self.request.POST
for i in range(1, 11):
chset = 'changeset_id-%d'%(i,)
check = rp.get(chset)
if check:
data[i] = self.db_repo.get_changeset(rp[chset])
if isinstance(data[i], EmptyCommit):
data[i] = {'rev': None, 'commit': rp[chset]}
else:
data[i] = {'rev': data[i].raw_id, 'branch': data[i].branch, 'author': data[i].author,
'comment': data[i].message}
else:
break
return data
@LoginRequired()
@NotAnonymous()
@HasRepoPermissionAnyDecorator('repository.admin')
@view_config(
route_name='strip_execute', request_method='POST',
renderer='json', xhr=True
)
def strip_execute(self):
from rhodecode.model.scm import ScmModel
from rhodecode.lib.ext_json import json
c = self.load_default_context()
user = self._rhodecode_user
rp = self.request.POST
data = {}
for idx in rp:
commit = json.loads(rp[idx])
#If someone put two times the same branch
if commit['branch'] in data.keys():
continue
try:
ScmModel().strip(repo=c.repo_info,
commit_id=commit['rev'], branch=commit['branch'])
log.info('Stripped commit %s from repo `%s` by %s' % (commit['rev'], c.repo_info.repo_name, user))
data[commit['rev']] = True
except Exception, e:
data[commit['rev']] = False
log.debug('Stripped commit %s from repo `%s` failed by %s, exeption %s' % (commit['rev'],
c.repo_info.repo_name, user, e.message))
return data

View file

@ -74,6 +74,9 @@
<li class="${'active' if c.active=='maintenance' else ''}">
<a href="${h.route_path('repo_maintenance', repo_name=c.repo_name)}">${_('Maintenance')}</a>
</li>
<li class="${'active' if c.active=='strip' else ''}">
<a href="${h.route_path('strip', repo_name=c.repo_name)}">${_('Strip')}</a>
</li>
## TODO: dan: replace repo navigation with navlist registry like with
## admin menu. First must find way to allow runtime configuration
## it to account for the c.repo_info.repo_type != 'svn' call above

View file

@ -0,0 +1,169 @@
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">${_('Strip')}</h3>
</div>
<div class="panel-body">
%if c.repo_info.repo_type != 'svn':
<p>
<h4>${_('Please provide up to %s commits commits to strip')%c.strip_limit}</h4>
</p>
<p>
${_('In the first step commits will be verified for existance in the repository')}. </br>
${_('In the second step, correct commits will be available for stripping')}.
</p>
${h.secure_form(h.route_path('strip_check', repo_name=c.repo_info.repo_name), method='post')}
<div id="change_body" class="field">
<div id="box-1" class="inputx locked_input">
<input class="text" id="changeset_id-1" name="changeset_id-1" size="59"
placeholder="${_('Enter full 40 character commit sha')}" type="text" value="">
<div id = "plus_icon-1" class="btn btn-default plus_input_button">
<i class="icon-plus" onclick="addNew(1);return false">${_('Add another commit')}</i>
</div>
</div>
</div>
<div id="results" style="display:none; padding: 10px 0px;"></div>
<div class="buttons">
<button class="btn btn-small btn-primary" onclick="check_changsets();return false">
${_('Check commits')}
</button>
</div>
<div id="results" style="display:none; padding: 10px 0px;"></div>
${h.end_form()}
%else:
<p>
<h4>${_('Sorry this functionality is not available for SVN repository')}</h4>
</p>
%endif
</div>
</div>
<script>
var plus_leaf = 1;
addNew = function(number){
if (number >= ${c.strip_limit}){
return;
}
var minus = '<i id="i_minus_icon-'+(number+1)+'" class="icon-minus" onclick="delOld('+(number+1)+');return false">${_('Remove')}</i>';
$('#plus_icon-'+number).detach();
number++;
var input = '<div id="box-'+number+'" class="inputx locked_input">'+
'<input class="text" id="changeset_id-'+number+'" name="changeset_id-'+number+'" size="59" type="text" value="">'+
'<div id="plus_icon-'+number+'" class="btn btn-default plus_input_button">'+
'<i id="i_plus_icon-'+(number)+'" class="icon-plus" onclick="addNew('+number+');return false">${_('Add another commit')}</i>'+
'</div>'+
'<div id="minus_icon-'+number+'" class="btn btn-default minus_input_button">'+
minus +
'</div>' +
'</div>';
$('#change_body').append(input);
plus_leaf++;
}
function re_index(number){
for(var i=number;i<=plus_leaf;i++){
var check = $('#box-'+i);
if (check.length == 0){
var change = $('#box-'+(i+1));
change.attr('id','box-'+i);
var plus = $('#plus_icon-'+(i+1));
var i_plus = $('#i_plus_icon-'+(i+1));
if (plus.length != 0){
plus.attr('id','plus_icon-'+i);
i_plus.attr('id','i_plus_icon-'+i);
i_plus.attr('onclick','addNew('+i+');return false');
plus_leaf--;
}
var minus = $('#minus_icon-'+(i+1));
var i_minus = $('#i_minus_icon-'+(i+1));
minus.attr('id','minus_icon-'+i);
i_minus.attr('id','i_minus_icon-'+i);
i_minus.attr('onclick','delOld('+i+');return false');
}
}
}
delOld = function(number){
$('#box-'+number).remove();
number = number - 1;
var box = $('#box-'+number);
var plus = '<div id="plus_icon-'+number+'" class="btn btn-default plus_input_button">'+
'<i id="i_plus_icon-'+number+'" class="icon-plus" onclick="addNew('+number +');return false">${_('Add another commit')}</i></div>';
var minus = $('#minus_icon-'+number);
if(number +1 == plus_leaf){
minus.detach();
box.append(plus);
box.append(minus);
}
re_index(number+1);
}
var result_data;
check_changsets = function() {
var postData = $('form').serialize();
$('#results').show();
$('#results').html('<h4>${_('Checking commits')}...</h4>');
var url = "${h.route_path('strip_check', repo_name=c.repo_info.repo_name)}";
var btn = $('button');
btn.attr('disabled', 'disabled');
btn.addClass('disabled');
var success = function (data) {
result_data = {};
var i = 0;
result ='';
$.each(data, function(index, value){
i= index;
var box = $('#box-'+index);
if (value.rev){
result_data[index] = JSON.stringify(value);
msg = '${_("author")}: ' + value.author + ' ${_("comment")}: ' + value.comment;
result += '<h4>' +value.rev+ '${_(' commit verified positive')}</br> '+ msg + '</h4>';
}
else{
result += '<h4>' +value.commit+ '${_('commit verified negative')}' + '</h4>';
}
box.remove();
});
var box = $('#box-'+(parseInt(i)+1));
box.remove();
$('#results').html(result);
};
btn.html('Strip');
btn.removeAttr('disabled');
btn.removeClass('disabled');
btn.attr('onclick','strip();return false;');
ajaxPOST(url, postData, success, null);
};
strip = function(){
var url = "${h.route_path('strip_execute', repo_name=c.repo_info.repo_name)}";
var success = function(data){
result = '';
$.each(data, function(index, value){
if(data[index]){
result += '<h4>' +index+ '${_(' commit striped successful')}' + '</h4>';
}
else{
result += '<h4>' +index+ '${_(' commit striped failed')}' + '</h4>';
}
});
$('#results').html(result);
};
ajaxPOST(url, result_data, success, null);
var btn = $('button');
btn.attr('disabled', 'disabled');
btn.addClass('disabled');
};
</script>