Merge pull request #218 from abf/rosa-build:214-delete-and-restore-branches
#214: Delete/Restore branches
This commit is contained in:
commit
c33588f620
6
Gemfile
6
Gemfile
|
@ -59,6 +59,12 @@ gem 'rest-client', '~> 1.6.6'
|
|||
gem 'attr_encrypted', '1.2.1'
|
||||
gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
|
||||
|
||||
# AngularJS related stuff
|
||||
gem 'angularjs-rails'
|
||||
gem 'ng-rails-csrf'
|
||||
gem 'momentjs-rails'
|
||||
gem 'angular-i18n', '0.1.2'
|
||||
|
||||
group :assets do
|
||||
gem 'sass-rails', '~> 3.2.5'
|
||||
gem 'coffee-rails', '~> 3.2.2'
|
||||
|
|
120
Gemfile.lock
120
Gemfile.lock
|
@ -58,36 +58,37 @@ GEM
|
|||
json
|
||||
ancestry (1.3.0)
|
||||
activerecord (>= 2.3.14)
|
||||
angular-i18n (0.1.2)
|
||||
angularjs-rails (1.0.7)
|
||||
arel (3.0.2)
|
||||
attr_encrypted (1.2.1)
|
||||
encryptor (>= 1.1.1)
|
||||
bcrypt-ruby (3.0.1)
|
||||
better_errors (0.8.0)
|
||||
bcrypt-ruby (3.1.1)
|
||||
better_errors (0.9.0)
|
||||
coderay (>= 1.0.0)
|
||||
erubis (>= 2.6.6)
|
||||
binding_of_caller (0.7.1)
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
blankslate (3.1.2)
|
||||
bluepill (0.0.62)
|
||||
activesupport (>= 3.0.0)
|
||||
bluepill (0.0.66)
|
||||
activesupport (>= 3.0.0, < 4.0.0)
|
||||
daemons (~> 1.1.4)
|
||||
i18n (>= 0.5.0)
|
||||
state_machine (~> 1.1.0)
|
||||
bourne (1.4.0)
|
||||
mocha (~> 0.13.2)
|
||||
state_machine (~> 1.1)
|
||||
builder (3.0.4)
|
||||
callsite (0.0.11)
|
||||
cancan (1.6.7)
|
||||
cape (1.7.0)
|
||||
capistrano (2.14.2)
|
||||
capistrano (2.15.5)
|
||||
highline
|
||||
net-scp (>= 1.0.0)
|
||||
net-sftp (>= 2.0.0)
|
||||
net-ssh (>= 2.0.14)
|
||||
net-ssh-gateway (>= 1.1.0)
|
||||
capistrano_colors (0.5.5)
|
||||
charlock_holmes (0.6.9.2)
|
||||
charlock_holmes (0.6.9.4)
|
||||
chronic (0.6.7)
|
||||
chunky_png (1.2.7)
|
||||
chunky_png (1.2.8)
|
||||
cocaine (0.4.2)
|
||||
coderay (1.0.9)
|
||||
coffee-rails (3.2.2)
|
||||
|
@ -96,7 +97,7 @@ GEM
|
|||
coffee-script (2.2.0)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.6.2)
|
||||
coffee-script-source (1.6.3)
|
||||
compass (0.12.2)
|
||||
chunky_png (~> 1.2)
|
||||
fssm (>= 0.2.7)
|
||||
|
@ -106,7 +107,7 @@ GEM
|
|||
creole (0.5.0)
|
||||
daemons (1.1.9)
|
||||
debug_inspector (0.0.2)
|
||||
devise (2.2.3)
|
||||
devise (2.2.4)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (~> 3.1)
|
||||
|
@ -156,9 +157,9 @@ GEM
|
|||
activesupport (>= 3.1, < 4.1)
|
||||
haml (~> 3.1)
|
||||
railties (>= 3.1, < 4.1)
|
||||
hashie (1.2.0)
|
||||
highline (1.6.15)
|
||||
hike (1.2.1)
|
||||
hashie (2.0.5)
|
||||
highline (1.6.19)
|
||||
hike (1.2.3)
|
||||
hirb (0.7.1)
|
||||
httpauth (0.2.0)
|
||||
i18n (0.6.1)
|
||||
|
@ -176,11 +177,10 @@ GEM
|
|||
libv8 (3.3.10.4)
|
||||
macaddr (1.6.1)
|
||||
systemu (~> 2.5.0)
|
||||
mail (2.5.3)
|
||||
i18n (>= 0.4.0)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mailcatcher (0.5.11)
|
||||
mailcatcher (0.5.12)
|
||||
activesupport (~> 3.0)
|
||||
eventmachine (~> 1.0.0)
|
||||
haml (>= 3.1, < 5)
|
||||
|
@ -191,41 +191,44 @@ GEM
|
|||
thin (~> 1.5.0)
|
||||
meta-tags (1.2.6)
|
||||
actionpack
|
||||
meta_request (0.2.3)
|
||||
meta_request (0.2.7)
|
||||
callsite
|
||||
rack-contrib
|
||||
railties
|
||||
metaclass (0.0.1)
|
||||
mime-types (1.21)
|
||||
mocha (0.13.3)
|
||||
metaclass (~> 0.0.1)
|
||||
mime-types (1.23)
|
||||
mini_portile (0.5.1)
|
||||
mock_redis (0.6.2)
|
||||
multi_json (1.7.5)
|
||||
momentjs-rails (2.0.0.2)
|
||||
railties (>= 3.1)
|
||||
multi_json (1.7.7)
|
||||
multipart-post (1.2.0)
|
||||
mustache (0.99.4)
|
||||
net-scp (1.1.0)
|
||||
net-scp (1.1.2)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-sftp (2.1.1)
|
||||
net-sftp (2.1.2)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (2.6.6)
|
||||
net-ssh (2.6.8)
|
||||
net-ssh-gateway (1.2.0)
|
||||
net-ssh (>= 2.6.5)
|
||||
newrelic_rpm (3.5.5.38)
|
||||
nokogiri (1.5.9)
|
||||
ng-rails-csrf (0.1.0)
|
||||
nokogiri (1.6.0)
|
||||
mini_portile (~> 0.5.0)
|
||||
oauth2 (0.8.1)
|
||||
faraday (~> 0.8)
|
||||
httpauth (~> 0.1)
|
||||
jwt (~> 0.1.4)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.2)
|
||||
omniauth (1.1.3)
|
||||
hashie (~> 1.2)
|
||||
omniauth (1.1.4)
|
||||
hashie (>= 1.2, < 3)
|
||||
rack
|
||||
omniauth-facebook (1.4.1)
|
||||
omniauth-oauth2 (~> 1.1.0)
|
||||
omniauth-github (1.1.0)
|
||||
omniauth-github (1.1.1)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.1)
|
||||
omniauth-google-oauth2 (0.1.13)
|
||||
omniauth-google-oauth2 (0.2.0)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2
|
||||
omniauth-oauth2 (1.1.1)
|
||||
|
@ -283,13 +286,13 @@ GEM
|
|||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
raindrops (0.10.0)
|
||||
rake (10.0.4)
|
||||
rdiscount (2.0.7.1)
|
||||
raindrops (0.11.0)
|
||||
rake (10.1.0)
|
||||
rdiscount (2.1.6)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
redcarpet (2.2.2)
|
||||
redis (3.0.3)
|
||||
redis (3.0.4)
|
||||
redis-actionpack (3.2.3)
|
||||
actionpack (~> 3.2.3)
|
||||
redis-rack (~> 1.4.0)
|
||||
|
@ -297,7 +300,7 @@ GEM
|
|||
redis-activesupport (3.2.3)
|
||||
activesupport (~> 3.2.3)
|
||||
redis-store (~> 1.1.0)
|
||||
redis-namespace (1.2.1)
|
||||
redis-namespace (1.3.0)
|
||||
redis (~> 3.0.0)
|
||||
redis-rack (1.4.2)
|
||||
rack (~> 1.4.1)
|
||||
|
@ -324,7 +327,7 @@ GEM
|
|||
actionmailer (~> 3.0)
|
||||
rest-client (1.6.7)
|
||||
mime-types (>= 1.16)
|
||||
rr (1.0.4)
|
||||
rr (1.0.5)
|
||||
rspec (2.11.0)
|
||||
rspec-core (~> 2.11.0)
|
||||
rspec-expectations (~> 2.11.0)
|
||||
|
@ -338,7 +341,7 @@ GEM
|
|||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec (~> 2.11.0)
|
||||
ruby-haml-js (0.0.3)
|
||||
ruby-haml-js (0.0.4)
|
||||
execjs
|
||||
sprockets (>= 2.0.0)
|
||||
rubypython (0.5.3)
|
||||
|
@ -346,28 +349,27 @@ GEM
|
|||
ffi (~> 1.0.7)
|
||||
russian (0.6.0)
|
||||
i18n (>= 0.5.0)
|
||||
rvm-capistrano (1.2.7)
|
||||
rvm-capistrano (1.4.1)
|
||||
capistrano (>= 2.0.0)
|
||||
sanitize (2.0.3)
|
||||
nokogiri (>= 1.4.4, < 1.6)
|
||||
sass (3.2.7)
|
||||
sanitize (2.0.6)
|
||||
nokogiri (>= 1.4.4)
|
||||
sass (3.2.9)
|
||||
sass-rails (3.2.6)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
shotgun (0.9)
|
||||
rack (>= 1.0)
|
||||
shoulda (3.4.0)
|
||||
shoulda (3.5.0)
|
||||
shoulda-context (~> 1.0, >= 1.0.1)
|
||||
shoulda-matchers (~> 1.0, >= 1.4.1)
|
||||
shoulda-context (1.0.2)
|
||||
shoulda-matchers (1.5.4)
|
||||
shoulda-matchers (>= 1.4.1, < 3.0)
|
||||
shoulda-context (1.1.4)
|
||||
shoulda-matchers (2.2.0)
|
||||
activesupport (>= 3.0.0)
|
||||
bourne (~> 1.3)
|
||||
sinatra (1.3.6)
|
||||
sinatra (1.4.3)
|
||||
rack (~> 1.4)
|
||||
rack-protection (~> 1.3)
|
||||
tilt (~> 1.3, >= 1.3.3)
|
||||
rack-protection (~> 1.4)
|
||||
tilt (~> 1.3, >= 1.3.4)
|
||||
skinny (0.2.3)
|
||||
eventmachine (~> 1.0.0)
|
||||
thin (~> 1.5.0)
|
||||
|
@ -377,7 +379,7 @@ GEM
|
|||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sqlite3 (1.3.7)
|
||||
state_machine (1.1.2)
|
||||
state_machine (1.2.0)
|
||||
stringex (1.4.0)
|
||||
systemu (2.5.2)
|
||||
therubyracer (0.10.2)
|
||||
|
@ -386,9 +388,9 @@ GEM
|
|||
daemons (>= 1.0.9)
|
||||
eventmachine (>= 0.12.6)
|
||||
rack (>= 1.0.0)
|
||||
thor (0.17.0)
|
||||
tilt (1.3.6)
|
||||
treetop (1.4.12)
|
||||
thor (0.18.1)
|
||||
tilt (1.4.1)
|
||||
treetop (1.4.14)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
turbo-sprockets-rails3 (0.3.6)
|
||||
|
@ -407,7 +409,7 @@ GEM
|
|||
macaddr (~> 1.0)
|
||||
vegas (0.1.11)
|
||||
rack (>= 1.0.0)
|
||||
warden (1.2.1)
|
||||
warden (1.2.3)
|
||||
rack (>= 1.0)
|
||||
whenever (0.7.3)
|
||||
activesupport (>= 2.3.4)
|
||||
|
@ -424,6 +426,8 @@ DEPENDENCIES
|
|||
RedCloth
|
||||
airbrake (~> 3.1.2)
|
||||
ancestry (~> 1.3.0)
|
||||
angular-i18n (= 0.1.2)
|
||||
angularjs-rails
|
||||
attr_encrypted (= 1.2.1)
|
||||
better_errors
|
||||
binding_of_caller
|
||||
|
@ -453,7 +457,9 @@ DEPENDENCIES
|
|||
meta-tags (~> 1.2.5)
|
||||
meta_request
|
||||
mock_redis (= 0.6.2)
|
||||
momentjs-rails
|
||||
newrelic_rpm (~> 3.5.5.38)
|
||||
ng-rails-csrf
|
||||
omniauth
|
||||
omniauth-facebook
|
||||
omniauth-github
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
var RosaABF = angular.module('RosaABF', ['ngResource', 'ng-rails-csrf', 'angular-i18n']);
|
||||
|
||||
var DateTimeFormatter = function() {
|
||||
|
||||
var UtcFormatter = function(api_time) {
|
||||
return moment.utc(api_time * 1000).format('YYYY-MM-DD HH:mm:ss UTC');
|
||||
}
|
||||
|
||||
return {
|
||||
utc : UtcFormatter
|
||||
}
|
||||
}
|
||||
RosaABF.factory("DateTimeFormatter", DateTimeFormatter);
|
||||
|
||||
var LocalesHelper = function($locale) {
|
||||
var locales = {
|
||||
'ru' : 'ru-ru',
|
||||
'en' : 'en-us'
|
||||
}
|
||||
return {
|
||||
setLocale: function(locale) {
|
||||
$locale.id = locales[locale];
|
||||
}
|
||||
}
|
||||
}
|
||||
RosaABF.factory("LocalesHelper", ['$locale', LocalesHelper]);
|
|
@ -0,0 +1,70 @@
|
|||
RosaABF.controller('ProjectRefsController', ['$scope', '$http', 'ApiProject', function($scope, $http, ApiProject) {
|
||||
|
||||
$scope.singleton = ApiProject.singleton;
|
||||
$scope.branches = [];
|
||||
$scope.tags = [];
|
||||
|
||||
$scope.project_id = null;
|
||||
$scope.current_ref = null;
|
||||
$scope.project_resource = null;
|
||||
|
||||
$scope.init = function(project_id, ref, locale) {
|
||||
$scope.project_id = project_id;
|
||||
$scope.current_ref = ref;
|
||||
|
||||
$scope.project_resource = ApiProject.resource.get({id: $scope.project_id}, function(results) {
|
||||
$scope.project = new Project(results.project);
|
||||
$scope.getRefs();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$scope.getRefs = function() {
|
||||
|
||||
$scope.project_resource.$refs({id: $scope.project_id}, function(results) {
|
||||
$scope.tags = [];
|
||||
$scope.branches = [];
|
||||
_.each(results.refs_list, function(ref){
|
||||
var result = new ProjectRef(ref);
|
||||
if (result.isTag) {
|
||||
if (result.ref == $scope.current_ref) {
|
||||
$scope.tags.unshift(result);
|
||||
} else {
|
||||
$scope.tags.push(result);
|
||||
}
|
||||
} else {
|
||||
if (result.ref == $scope.current_ref) {
|
||||
$scope.branches.unshift(result);
|
||||
} else {
|
||||
$scope.branches.push(result);
|
||||
}
|
||||
}
|
||||
});
|
||||
$scope.updateBranchesCount();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$scope.updateBranchesCount = function() {
|
||||
$scope.singleton.project.branches_count = $scope.branches.length;
|
||||
}
|
||||
|
||||
$scope.destroy = function(branch) {
|
||||
$scope.project_resource.$delete_branch(
|
||||
{owner: $scope.project.owner.uname, project: $scope.project.name, ref: branch.ref},
|
||||
function() { // on success
|
||||
var i = $scope.branches.indexOf(branch);
|
||||
if(i != -1) { $scope.branches.splice(i, 1); }
|
||||
|
||||
$scope.updateBranchesCount();
|
||||
// Removes branch from "Current branch/tag:" select box
|
||||
$('#branch_selector option').filter(function() {
|
||||
return this.value.match('.*\/branches\/' + branch.ref + '$');
|
||||
}).remove();
|
||||
}, function () { // on error
|
||||
$scope.getRefs();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}]);
|
9
app/assets/javascripts/angularjs/controllers/project_repo_block_controller.js
vendored
Normal file
9
app/assets/javascripts/angularjs/controllers/project_repo_block_controller.js
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
RosaABF.controller('ProjectRepoBlockController', ['$scope', 'ApiProject', function($scope, ApiProject) {
|
||||
|
||||
$scope.singleton = ApiProject.singleton;
|
||||
|
||||
$scope.init = function(branches) {
|
||||
$scope.singleton.project.branches_count = branches;
|
||||
}
|
||||
|
||||
}]);
|
|
@ -0,0 +1,98 @@
|
|||
RosaABF.controller('PullRequestController',['$scope', '$http', 'ApiPullRequest', 'ApiProject', 'DateTimeFormatter', function($scope, $http, ApiPullRequest, ApiProject, DateTimeFormatter) {
|
||||
|
||||
$scope.project_id = null;
|
||||
$scope.project_resource = null;
|
||||
|
||||
$scope.serial_id = null;
|
||||
$scope.pull = null;
|
||||
$scope.pull_resource = null;
|
||||
|
||||
$scope.merged_at = null;
|
||||
$scope.closed_at = null;
|
||||
$scope.branch = null;
|
||||
|
||||
$scope.can_delete_branch = false;
|
||||
|
||||
$scope.init = function(project_id, serial_id) {
|
||||
$scope.project_id = project_id;
|
||||
$scope.serial_id = serial_id;
|
||||
$scope.getPullRequest();
|
||||
}
|
||||
|
||||
$scope.getPullRequest = function() {
|
||||
$scope.pull_resource = ApiPullRequest.resource.get(
|
||||
{project_id: $scope.project_id, serial_id: $scope.serial_id},
|
||||
function(results) {
|
||||
$scope.pull = results.pull_request;
|
||||
if ($scope.pull.merged_at) { $scope.merged_at = DateTimeFormatter.utc($scope.pull.merged_at); }
|
||||
if ($scope.pull.closed_at) { $scope.closed_at = DateTimeFormatter.utc($scope.pull.closed_at); }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// @param [from_ref] - sets only at first time
|
||||
$scope.getBranch = function(from_ref) {
|
||||
if (!$scope.project_resource) {
|
||||
$scope.project_resource = ApiProject.resource.get({id: $scope.project_id});
|
||||
}
|
||||
// Fix: at first load
|
||||
// Cannot read property 'from_ref' of null
|
||||
if (!from_ref) { from_ref = $scope.pull.from_ref.ref; }
|
||||
$scope.project_resource.$refs({id: $scope.project_id}, function(results) {
|
||||
var branch = null;
|
||||
_.each(results.refs_list, function(ref){
|
||||
var result = new ProjectRef(ref);
|
||||
if (!result.isTag && result.ref == from_ref) {
|
||||
branch = result;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
$scope.branch = branch;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.reopen = function() {
|
||||
$scope.pull.status = 'reopen';
|
||||
$scope.pull_resource.$update(function() {
|
||||
$scope.getPullRequest();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.close = function() {
|
||||
$scope.pull.status = 'close';
|
||||
$scope.pull_resource.$update(function() {
|
||||
$scope.getPullRequest();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.merge = function() {
|
||||
$scope.pull_resource.$merge(function() {
|
||||
$scope.getPullRequest();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deleteBranch = function() {
|
||||
$scope.project_resource.$delete_branch($scope.branch_params(),
|
||||
function() { $scope.branch = null; }, // success
|
||||
function() { $scope.getBranch(); } // error
|
||||
);
|
||||
}
|
||||
|
||||
$scope.restoreBranch = function() {
|
||||
$scope.project_resource.$restore_branch($scope.branch_params(),
|
||||
function() { $scope.getBranch(); }, // success
|
||||
function() { $scope.getBranch(); } // error
|
||||
);
|
||||
}
|
||||
|
||||
$scope.branch_params = function() {
|
||||
var project = $scope.pull.from_ref.project;
|
||||
return {
|
||||
owner: project.fullname.replace(/\/.*/, ''),
|
||||
project: project.name,
|
||||
ref: $scope.pull.from_ref.ref,
|
||||
sha: $scope.pull.from_ref.sha
|
||||
}
|
||||
}
|
||||
|
||||
}]);
|
|
@ -0,0 +1,7 @@
|
|||
RosaABF.controller('RosaABFController', ['$scope', 'LocalesHelper', function($scope, LocalesHelper) {
|
||||
|
||||
$scope.init = function(locale) {
|
||||
LocalesHelper.setLocale(locale);
|
||||
}
|
||||
|
||||
}]);
|
|
@ -0,0 +1,24 @@
|
|||
var _locales = {
|
||||
'ru-ru': {
|
||||
'project.total_branches': [
|
||||
'Всего %1 ветка',
|
||||
'Всего %1 ветки',
|
||||
'Всего %1 веток'
|
||||
],
|
||||
'project.total_tags': [
|
||||
'Всего %1 тег',
|
||||
'Всего %1 тега',
|
||||
'Всего %1 тегов'
|
||||
]
|
||||
},
|
||||
'en-us': {
|
||||
'project.total_branches': [
|
||||
'Total %1 branch',
|
||||
'Total %1 branches'
|
||||
],
|
||||
'project.total_tags': [
|
||||
'Total %1 tag',
|
||||
'Total %1 tags'
|
||||
]
|
||||
}
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
var Project = function(atts){
|
||||
var self = this;
|
||||
var initialSettings = atts || {};
|
||||
//initial settings if passed in
|
||||
for(var setting in initialSettings){
|
||||
if(initialSettings.hasOwnProperty(setting))
|
||||
self[setting] = initialSettings[setting];
|
||||
};
|
||||
|
||||
//with some logic...
|
||||
|
||||
//return the scope-safe instance
|
||||
return self;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
var ProjectRef = function(atts) {
|
||||
var self = this;
|
||||
var initialSettings = atts || {};
|
||||
//initial settings if passed in
|
||||
for(var setting in initialSettings){
|
||||
if(initialSettings.hasOwnProperty(setting))
|
||||
self[setting] = initialSettings[setting];
|
||||
};
|
||||
|
||||
|
||||
|
||||
//with some logic...
|
||||
self.isTag = self.object.type == 'tag';
|
||||
|
||||
self.path = function(project) {
|
||||
return '/' + project.fullname + '/tree/' + self.ref;
|
||||
}
|
||||
|
||||
self.diff_path = function(project, current_ref) {
|
||||
return '/' + project.fullname + '/diff/' + current_ref + '...' + self.ref;
|
||||
}
|
||||
|
||||
self.archive_path = function(project, type) {
|
||||
return '/' + project.fullname + '/archive/' + project.name + '-' + self.ref + '.' + type;
|
||||
}
|
||||
|
||||
//return the scope-safe instance
|
||||
return self;
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
RosaABF.factory("ApiProject", ['$resource', function($resource) {
|
||||
|
||||
var ProjectResource = $resource(
|
||||
'/api/v1/projects/:id.json',
|
||||
{id: '@project.id'},
|
||||
{
|
||||
refs: {
|
||||
url: '/api/v1/projects/:id/refs_list.json',
|
||||
method: 'GET',
|
||||
isArray : false
|
||||
},
|
||||
delete_branch: {
|
||||
url: '/:owner/:project/branches/:ref',
|
||||
method: 'DELETE',
|
||||
isArray : false
|
||||
},
|
||||
restore_branch: {
|
||||
url: '/:owner/:project/branches/:ref', // ?sha=<sha>
|
||||
method: 'PUT',
|
||||
isArray : false
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
resource : ProjectResource,
|
||||
singleton : {
|
||||
project : {
|
||||
branches_count : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}]);
|
|
@ -0,0 +1,25 @@
|
|||
RosaABF.factory("ApiPullRequest", ['$resource', function($resource) {
|
||||
|
||||
var PullRequestResource = $resource(
|
||||
'/api/v1/projects/:project_id/pull_requests/:serial_id.json',
|
||||
{
|
||||
project_id: '@pull_request.to_ref.project.id',
|
||||
serial_id: '@pull_request.number'
|
||||
},
|
||||
{
|
||||
update: {
|
||||
method: 'PUT',
|
||||
isArray : false
|
||||
},
|
||||
merge: {
|
||||
url: '/api/v1/projects/:project_id/pull_requests/:serial_id/merge.json',
|
||||
method: 'PUT',
|
||||
isArray: false
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
resource : PullRequestResource
|
||||
}
|
||||
}]);
|
|
@ -13,6 +13,16 @@
|
|||
//= require backbone_rails_sync
|
||||
//= require backbone_datalink
|
||||
//= require backbone/rosa
|
||||
|
||||
// require angular
|
||||
//= require unstable/angular
|
||||
// require angular-resource
|
||||
//= require unstable/angular-resource
|
||||
//= require ng-rails-csrf
|
||||
//= require angular-i18n
|
||||
//= require_tree ./angularjs
|
||||
//= require moment
|
||||
|
||||
//= require_self
|
||||
|
||||
function disableNotifierCbx(global_cbx) {
|
||||
|
|
|
@ -744,7 +744,7 @@ div.admin-role {
|
|||
padding-right: 10px;
|
||||
}
|
||||
|
||||
article a.right_floated {
|
||||
.right_floated {
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
class Api::V1::ProjectsController < Api::V1::BaseController
|
||||
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:get_id, :show, :refs] if APP_CONFIG['anonymous_access']
|
||||
skip_before_filter :authenticate_user!, :only => [:get_id, :show, :refs_list] if APP_CONFIG['anonymous_access']
|
||||
|
||||
load_and_authorize_resource :project
|
||||
|
||||
|
@ -23,6 +23,8 @@ class Api::V1::ProjectsController < Api::V1::BaseController
|
|||
end
|
||||
|
||||
def refs_list
|
||||
@refs = @project.repo.branches.sort_by(&:name) +
|
||||
@project.repo.tags.select{ |t| t.commit }.sort_by(&:name).reverse
|
||||
end
|
||||
|
||||
def update
|
||||
|
|
|
@ -78,7 +78,7 @@ class Api::V1::PullRequestsController < Api::V1::BaseController
|
|||
if (action = pull_params[:status]) && %w(close reopen).include?(pull_params[:status])
|
||||
if @pull.send("can_#{action}?")
|
||||
@pull.set_user_and_time current_user
|
||||
need_check = true if action == 'reopen'
|
||||
need_check = true if action == 'reopen' && @pull.valid?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
class Projects::Git::BaseController < Projects::BaseController
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:show, :index, :blame, :raw, :archive, :diff, :tags, :branches] if APP_CONFIG['anonymous_access']
|
||||
load_and_authorize_resource :project
|
||||
|
||||
load_and_authorize_resource :project
|
||||
before_filter :set_treeish_and_path
|
||||
before_filter :set_branch_and_tree
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
class Projects::Git::TreesController < Projects::Git::BaseController
|
||||
before_filter lambda{redirect_to @project if params[:treeish] == @project.default_branch and params[:path].blank?}, :only => :show
|
||||
skip_before_filter :set_branch_and_tree, :set_treeish_and_path, :only => :archive
|
||||
before_filter lambda { raise Grit::NoSuchPathError if params[:treeish] != @branch.try(:name) }, :only => [:branch, :destroy]
|
||||
|
||||
skip_authorize_resource :project, :only => [:destroy, :restore_branch]
|
||||
before_filter lambda { authorize!(:write, @project) }, :only => [:destroy, :restore_branch]
|
||||
|
||||
def show
|
||||
render('empty') and return if @project.is_empty?
|
||||
|
@ -28,14 +32,19 @@ class Projects::Git::TreesController < Projects::Git::BaseController
|
|||
end
|
||||
|
||||
def tags
|
||||
@tags = @project.repo.tags.select{ |t| t.commit }.sort_by(&:name).reverse
|
||||
render 'refs'
|
||||
end
|
||||
|
||||
def restore_branch
|
||||
@project.restore_branch @treeish, params[:sha] if @treeish.present? && params[:sha].present?
|
||||
render :nothing => true
|
||||
end
|
||||
|
||||
def destroy
|
||||
status = @branch && @project.delete_branch(@branch, current_user) ? 200 : 422
|
||||
render :nothing => true, :status => status
|
||||
end
|
||||
|
||||
def branches
|
||||
raise Grit::NoSuchPathError if params[:treeish] != @branch.try(:name) # get wrong branch name to nonempty project
|
||||
@branches = @project.repo.branches.sort_by(&:name).select{ |b| b.name != @branch.name }.unshift(@branch).compact if @branch
|
||||
render 'refs'
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -78,14 +78,6 @@ class Projects::PullRequestsController < Projects::BaseController
|
|||
redirect_to project_pull_request_path(@pull.to_project, @pull)
|
||||
end
|
||||
|
||||
def merge
|
||||
unless @pull.merge!(current_user)
|
||||
flash.now[:error] = t('flash.pull_request.save_error')
|
||||
flash.now[:warning] = @pull.errors.full_messages.join('. ')
|
||||
end
|
||||
redirect_to project_pull_request_path(@pull.to_project, @pull)
|
||||
end
|
||||
|
||||
def show
|
||||
load_diff_commits_data
|
||||
end
|
||||
|
|
|
@ -8,9 +8,9 @@ module PullRequestHelper
|
|||
(common_comments + pull_comments + commits).sort_by{ |c| c[0] }.map{ |c| c[1] }
|
||||
end
|
||||
|
||||
def pull_status_label pull
|
||||
def pull_status_label pull_status, options = {}
|
||||
statuses = {'ready' => 'success', 'closed' => 'important', 'merged' => 'important', 'blocked' => 'warning'}
|
||||
content_tag :span, t("projects.pull_requests.statuses.#{pull.status}"), :class => "state label-bootstrap label-#{statuses[pull.status]}"
|
||||
content_tag :span, t("projects.pull_requests.statuses.#{pull_status}"), options.merge(:class => "state label-bootstrap label-#{statuses[pull_status]}")
|
||||
end
|
||||
|
||||
def pull_status pull
|
||||
|
|
|
@ -15,7 +15,7 @@ class Ability
|
|||
# Shared rights between guests and registered users
|
||||
can [:show, :archive], Project, :visibility => 'open'
|
||||
can :get_id, Project, :visibility => 'open' # api
|
||||
can :archive, Project, :visibility => 'open'
|
||||
can(:refs_list, Project) {|project| can? :show, project}
|
||||
can :read, Issue, :project => {:visibility => 'open'}
|
||||
can [:read, :commits, :files], PullRequest, :to_project => {:visibility => 'open'}
|
||||
can :search, BuildList
|
||||
|
@ -74,7 +74,6 @@ class Ability
|
|||
can(:destroy, Project) {|project| project.owner_type == 'Group' and project.owner.actors.exists?(:actor_type => 'User', :actor_id => user.id, :role => 'admin')}
|
||||
can :remove_user, Project
|
||||
can :preview, Project
|
||||
can(:refs_list, Project) {|project| can? :read, project}
|
||||
|
||||
can([:read, :create, :edit, :destroy, :update], Hook) {|hook| can?(:edit, hook.project)}
|
||||
|
||||
|
|
|
@ -49,6 +49,10 @@ class PullRequest < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def cross_pull?
|
||||
from_project_id != to_project_id
|
||||
end
|
||||
|
||||
def check(do_transaction = true)
|
||||
if do_transaction && !valid?
|
||||
issue.set_close nil
|
||||
|
|
|
@ -109,7 +109,7 @@ class CommentPresenter < ApplicationPresenter
|
|||
statuses = {'open' => 'success', 'closed' => 'important'}
|
||||
content_tag :span, t("layout.issues.status.#{@referenced_issue.status}"), :class => "state label-bootstrap label-#{statuses[@referenced_issue.status]}"
|
||||
else
|
||||
pull_status_label @referenced_issue
|
||||
pull_status_label @referenced_issue.status
|
||||
end.html_safe
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
json.refs_list (@project.repo.branches + @project.repo.tags) do |grit|
|
||||
json.refs_list @refs do |grit|
|
||||
json.ref grit.name
|
||||
json.object do
|
||||
json.type (grit.class.name =~ /Tag/ ? 'tag' : 'commit')
|
||||
json.sha grit.commit.id
|
||||
json.authored_date grit.commit.authored_date.to_i
|
||||
end
|
||||
end
|
||||
json.url refs_list_api_v1_project_path(@project.id, :format => :json)
|
|
@ -2,14 +2,14 @@ json.number pull.serial_id
|
|||
json.(pull, :title, :status)
|
||||
json.to_ref do
|
||||
json.ref pull.to_ref
|
||||
json.sha pull.to_commit.id
|
||||
json.sha pull.to_commit.try(:id)
|
||||
json.project do
|
||||
json.partial! 'api/v1/projects/project', :project => pull.to_project
|
||||
end
|
||||
end
|
||||
json.from_ref do
|
||||
json.ref pull.from_ref
|
||||
json.sha pull.from_commit.id
|
||||
json.sha pull.from_commit.try(:id)
|
||||
json.project do
|
||||
json.partial! 'api/v1/projects/project', :project => pull.from_project
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
json.issue do
|
||||
json.pull_request do
|
||||
json.partial! 'pull', :pull => @pull
|
||||
json.body @pull.body
|
||||
json.closed_at pull.issue.closed_at.to_i if @pull.merged? || @pull.closed?
|
||||
json.closed_at @pull.issue.closed_at.to_i if @pull.merged? || @pull.closed?
|
||||
json.closed_by do
|
||||
json.partial! 'api/v1/shared/member', :member => @pull.issue.closer
|
||||
end if @pull.issue.closer
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
json.(member, :id, :name)
|
||||
json.(member, :id, :name, :uname)
|
||||
json.type member.class.name
|
||||
json.url member_path(member)
|
||||
json.url member_path(member)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
- if user_signed_in?
|
||||
= auto_discovery_link_tag :atom, atom_activity_feeds_path(:format => 'atom', :token => current_user.authentication_token), :title => t("layout.atom_link_tag_title", :nickname => current_user.uname, :app_name => APP_CONFIG['project_name'])
|
||||
|
||||
%body
|
||||
%body{'ng-app' => 'RosaABF', 'ng-controller' => 'RosaABFController', 'ng-init' => "init('#{I18n.locale}')"}
|
||||
.wrap{:class => content_for?(:sidebar) ? 'columns' : ''}
|
||||
%header
|
||||
.left
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- act = action_name.to_sym; contr = controller_name.to_sym; treeish = project.default_head(params[:treeish]); branch = @branch.try(:name) || project.default_head
|
||||
-http_url = git_repo_url(project.name_with_owner)
|
||||
-ssh_url = git_ssh_repo_url(project.name_with_owner)
|
||||
#description-top
|
||||
#description-top{'ng-controller' => 'ProjectRepoBlockController', 'ng-init' => "init(#{project.repo.branches.count})"}
|
||||
-if @commit
|
||||
%ul.nav.zip
|
||||
%li#menu-archive.dropdown
|
||||
|
@ -42,7 +42,7 @@
|
|||
%li{:class => ('selected' if act == :index && contr == :commits )}
|
||||
= link_to t('project_menu.commits'), commits_path(project, treeish)
|
||||
%li{:class => ('selected' if act == :branches && contr == :trees )}
|
||||
= link_to t('project_menu.branches', :count => project.repo.branches.count), branches_path(project, branch)
|
||||
= link_to t('project_menu.branches', :count => '{{singleton.project.branches_count}}'), branches_path(project, branch)
|
||||
%li.tags{:class => ('selected' if act == :tags && contr == :trees )}
|
||||
= link_to t('project_menu.tags', :count => project.repo.tags.count), tags_path(project)
|
||||
.both
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
- base = branch.name == @branch.name
|
||||
%tr{:class => (base ? 'base' : '')}
|
||||
%td.name= link_to branch.name, tree_path(@project, branch.name)
|
||||
%td.actions
|
||||
%ul.actions
|
||||
- if base
|
||||
%li.text= t('layout.projects.base_branch')
|
||||
- else
|
||||
%li
|
||||
= link_to t('layout.projects.compare'), diff_path(@project, "#{@branch.name}...#{branch.name}")
|
|
@ -1,10 +0,0 @@
|
|||
- subjects_name = action_name.to_s
|
||||
|
||||
%h3= t("layout.projects.#{subjects_name}")
|
||||
- if subject.blank?
|
||||
%p= t("layout.projects.no_#{subjects_name}")
|
||||
- elsif subject.count == 1
|
||||
%p= t("layout.projects.showing_#{subjects_name.singularize}")
|
||||
- else
|
||||
%p= t("layout.projects.showing_#{subjects_name}", :count => subject.count)
|
||||
.both
|
|
@ -1,8 +0,0 @@
|
|||
%li
|
||||
= link_to t('layout.projects.browse_code'), tree_path(@project, tag.name), :class => 'detail-link'
|
||||
- file_name = "#{@project.name}-#{tag.name}"
|
||||
- %w(zip tar.gz).each do |type|
|
||||
= link_to t('layout.projects.source_code', :type => type), archive_path(@project, file_name, type), :class => 'detail-link'
|
||||
%p.name
|
||||
%b= tag.name
|
||||
.date= tag.commit.authored_date.strftime('%d.%m.%Y')
|
|
@ -0,0 +1,34 @@
|
|||
-set_meta_tags :title => "#{title_object @project}"
|
||||
|
||||
= render 'submenu'
|
||||
= render 'repo_block', :project => @project
|
||||
|
||||
%div{'ng-controller' => 'ProjectRefsController',
|
||||
'ng-init' => "init('#{@project.id}','#{@branch.try(:name)}')"}
|
||||
|
||||
%h3= t('layout.projects.branches')
|
||||
%p{'ng-show' => '!branches.length'}= t('layout.projects.no_branches')
|
||||
%p{'ng-show' => 'branches.length > 0'} {{'project.total_branches' | i18n:'plural':branches.length}}
|
||||
.both
|
||||
%br
|
||||
|
||||
%input.mediumheight{'ng-model' => 'query.ref'}
|
||||
.both
|
||||
|
||||
%table#project-branches
|
||||
%tbody
|
||||
%tr{'ng-repeat' => 'branch in branches | filter:query', 'ng-class' => '{base: branch.ref == current_ref}'}
|
||||
%td.name
|
||||
%a{'ng-href' => '{{branch.path(project)}}' } {{branch.ref}}
|
||||
%td.actions
|
||||
%ul.actions
|
||||
%li.text{'ng-show' => 'branch.ref == current_ref'}
|
||||
= t('layout.projects.base_branch')
|
||||
- if can?(:write, @project)
|
||||
%li{'ng-hide' => 'branch.ref == current_ref'}
|
||||
%a{:href => '', 'ng-click' => 'destroy(branch)'}
|
||||
= t('layout.projects.delete_branch')
|
||||
%li{'ng-hide' => 'branch.ref == current_ref'}
|
||||
%a{'ng-href' => '{{branch.diff_path(project, current_ref)}}' }
|
||||
= t('layout.projects.compare')
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
-set_meta_tags :title => "#{title_object @project}"
|
||||
|
||||
= render 'submenu'
|
||||
= render 'repo_block', :project => @project
|
||||
= render 'header', :subject => (@branches || @tags)
|
||||
|
||||
- if @tags.present?
|
||||
%div#project-tags
|
||||
%ol.release-list
|
||||
= render :partial => 'tag', :collection => @tags
|
||||
- elsif @branches.present?
|
||||
%table#project-branches
|
||||
%tbody
|
||||
= render :partial => 'branch', :collection => @branches
|
|
@ -0,0 +1,27 @@
|
|||
-set_meta_tags :title => "#{title_object @project}"
|
||||
|
||||
= render 'submenu'
|
||||
= render 'repo_block', :project => @project
|
||||
|
||||
%div{'ng-controller' => 'ProjectRefsController', 'ng-init' => "init('#{@project.id}')"}
|
||||
|
||||
%h3= t('layout.projects.tags')
|
||||
%p{'ng-show' => '!tags.length'}= t('layout.projects.no_tags')
|
||||
%p{'ng-show' => 'tags.length > 0'} {{'project.total_tags' | i18n:'plural':tags.length}}
|
||||
.both
|
||||
%br
|
||||
|
||||
%input.mediumheight{'ng-model' => 'query.ref'}
|
||||
.both
|
||||
|
||||
#project-tags
|
||||
%ol.release-list
|
||||
%li{'ng-repeat' => 'tag in tags | filter:query'}
|
||||
%a.detail-link{'ng-href' => '{{tag.path(project)}}' }
|
||||
= t('layout.projects.browse_code')
|
||||
- %w(zip tar.gz).each do |type|
|
||||
%a.detail-link{'ng-href' => "{{tag.archive_path(project, '#{type}')}}" }
|
||||
= t('layout.projects.source_code', :type => type)
|
||||
%p.name
|
||||
%b {{tag.ref}}
|
||||
.date {{tag.object.authored_date * 1000 | date:'yyyy.MM.dd'}}
|
|
@ -1,14 +1,36 @@
|
|||
- if can?(:merge, @pull) && @pull.can_merging?
|
||||
%br
|
||||
=form_for PullRequest.new, :url => merge_project_pull_request_path(@project, @pull), :html => { :method => :put, :class => :form } do |f|
|
||||
=f.submit t 'projects.pull_requests.ready'
|
||||
-else
|
||||
.flash
|
||||
%div{:class => @pull.ready? ? 'notice' : 'alert'}
|
||||
=pull_status @pull
|
||||
%a.button{:href => '', 'ng-click' => 'merge()', 'ng-show' => "pull.status == 'ready'"}
|
||||
= t 'projects.pull_requests.ready'
|
||||
.both
|
||||
|
||||
.flash{'ng-show' => '!pull.mergeable'}
|
||||
.notice{'ng-show' => "pull.status == 'blocked'"}
|
||||
= t "projects.pull_requests.blocked"
|
||||
.alert{'ng-show' => "pull.status == 'merged'"}
|
||||
= t("projects.pull_requests.merged",
|
||||
:user => '{{pull.merged_by.uname}}',
|
||||
:to_ref => show_ref(@pull, 'to'),
|
||||
:from_ref => show_ref(@pull, 'from'),
|
||||
:time => '{{merged_at}}').html_safe
|
||||
.alert{'ng-show' => "pull.status == 'closed'"}
|
||||
= t("projects.pull_requests.closed",
|
||||
:user => '{{pull.closed_by.uname}}',
|
||||
:time => '{{closed_at}}')
|
||||
.both
|
||||
|
||||
|
||||
- if !@pull.cross_pull? && can?(:write, @project)
|
||||
%div{'ng-init' => "getBranch('#{@pull.from_ref}')", 'ng-show' => "pull.status == 'closed' || pull.status == 'merged'"}
|
||||
%a.button{:href => '', 'ng-click' => 'deleteBranch()', 'ng-show' => "branch && branch.object.sha == pull.from_ref.sha"}
|
||||
= t('layout.projects.delete_branch')
|
||||
%a.button{:href => '', 'ng-click' => 'restoreBranch()', 'ng-hide' => "branch"}
|
||||
= t('layout.projects.restore_branch')
|
||||
.both
|
||||
|
||||
|
||||
-if can? :update, @pull
|
||||
-if action = @pull.can_close? ? 'close' : ('reopen' if @pull.can_reopen?)
|
||||
%br
|
||||
=form_for :pull, :url => [@project, @pull], :html => { :id => 'do_pull_action',:method => :put, :class => :form } do |f|
|
||||
=hidden_field_tag "pull_request_action", action
|
||||
=f.submit t ".#{action}"
|
||||
%br
|
||||
%a.button{:href => '', 'ng-click' => 'reopen()', 'ng-show' => "pull.status == 'closed'"}
|
||||
= t '.reopen'
|
||||
%a.button{:href => '', 'ng-click' => 'close()', 'ng-show' => "pull.status == 'ready' || pull.status == 'open' || pull.status == 'blocked'"}
|
||||
= t '.close'
|
|
@ -1,19 +1,23 @@
|
|||
-ar = 'activerecord.attributes.pull_requests'
|
||||
-set_meta_tags :title => [title_object(@project), t('.title', :name => @pull.title.truncate(40), :user => @pull.user.try(:uname))]
|
||||
= render :partial => 'submenu'
|
||||
%h3.bpadding10
|
||||
=pull_status_label @pull
|
||||
=pull_header @pull
|
||||
#repo-wrapper
|
||||
=render 'nav_tabs'
|
||||
.tab-content.pull_diff_fix
|
||||
#discussion.tab-pane.active
|
||||
=render 'projects/issues/header'
|
||||
=render 'activity'
|
||||
%br
|
||||
=render "projects/comments/add", :project => @project, :commentable => @issue if current_user
|
||||
.pull_status
|
||||
=render 'status'
|
||||
=render 'diff_commits_tabs' unless @pull.already?
|
||||
=hidden_field_tag :preview_url, project_md_preview_path(@project)
|
||||
= render "projects/comments/markdown_help"
|
||||
|
||||
%div{'ng-controller' => 'PullRequestController', 'ng-init' => "init('#{@project.id}', '#{@pull.serial_id}')"}
|
||||
|
||||
%h3.bpadding10
|
||||
- PullRequest::STATUSES.each do |status|
|
||||
= pull_status_label status, {'ng-show' => "pull.status == '#{status}'"}
|
||||
= pull_header @pull
|
||||
#repo-wrapper
|
||||
=render 'nav_tabs'
|
||||
.tab-content.pull_diff_fix
|
||||
#discussion.tab-pane.active
|
||||
=render 'projects/issues/header'
|
||||
=render 'activity'
|
||||
%br
|
||||
=render "projects/comments/add", :project => @project, :commentable => @issue if current_user
|
||||
.pull_status
|
||||
=render 'status'
|
||||
=render 'diff_commits_tabs' unless @pull.already?
|
||||
=hidden_field_tag :preview_url, project_md_preview_path(@project)
|
||||
= render "projects/comments/markdown_help"
|
||||
|
|
|
@ -2,16 +2,14 @@ en:
|
|||
layout:
|
||||
projects:
|
||||
branches: Branches
|
||||
showing_branches: Showing %{count} branches
|
||||
showing_branch: Showing 1 branch
|
||||
delete_branch: Delete branch
|
||||
restore_branch: Restore branch
|
||||
no_branches: No branches
|
||||
base_branch: Base branch
|
||||
compare: Compare
|
||||
browse_code: Browse code
|
||||
source_code: Source code (%{type})
|
||||
tags: Tags
|
||||
showing_tags: Showing %{count} tags
|
||||
showing_tag: Showing 1 tag
|
||||
no_tags: No tags
|
||||
add: Add
|
||||
public_projects_list: Public projects list
|
||||
|
|
|
@ -2,16 +2,14 @@ ru:
|
|||
layout:
|
||||
projects:
|
||||
branches: Ветки
|
||||
showing_branches: Показано %{count} веток
|
||||
showing_branch: Показана 1 ветка
|
||||
no_branch: Нет веток
|
||||
delete_branch: Удалить ветку
|
||||
restore_branch: Востановить ветку
|
||||
no_branches: Нет веток
|
||||
base_branch: Текущая ветка
|
||||
compare: Сравнить
|
||||
browse_code: Просмотреть код
|
||||
source_code: Исходный код (%{type})
|
||||
tags: Теги
|
||||
showing_tags: Показано %{count} тегов
|
||||
showing_tag: Показан 1 тег
|
||||
no_tags: Нет тегов
|
||||
add: Добавить
|
||||
public_projects_list: Список публичных проектов
|
||||
|
|
|
@ -21,7 +21,7 @@ ru:
|
|||
ready: Данный пул реквест можно смержить автоматически.
|
||||
merged: |
|
||||
%{user} смержил <span class="label-bootstrap label-info font14">%{to_ref}</span>
|
||||
с <span class="label-bootstrap label-info font14">%{from_ref}</span> в %{time}'
|
||||
с <span class="label-bootstrap label-info font14">%{from_ref}</span> в %{time}
|
||||
closed: '%{user} закрыл пул реквест в %{time}'
|
||||
is_big: Этот пул реквест слишком большой! Мы показываем только последние %{count} коммитов.
|
||||
open: ''
|
||||
|
|
|
@ -310,7 +310,6 @@ Rosa::Application.routes.draw do
|
|||
resources :hooks, :except => :show
|
||||
resources :pull_requests, :except => :destroy do
|
||||
get :autocomplete_to_project, :on => :collection
|
||||
put :merge, :on => :member
|
||||
end
|
||||
post '/preview' => 'projects#preview', :as => 'md_preview'
|
||||
post 'refs_list' => 'projects#refs_list', :as => 'refs_list'
|
||||
|
@ -336,6 +335,8 @@ Rosa::Application.routes.draw do
|
|||
get '/tags' => "git/trees#tags", :as => :tags
|
||||
# Branches
|
||||
get '/branches/:treeish' => "git/trees#branches", :as => :branches
|
||||
delete '/branches/:treeish' => "git/trees#destroy", :as => :branches
|
||||
put '/branches/:treeish' => "git/trees#restore_branch", :as => :branches
|
||||
# Commits
|
||||
get '/commits/:treeish(/*path)' => "git/commits#index", :as => :commits, :format => false
|
||||
get '/commit/:id(.:format)' => "git/commits#show", :as => :commit
|
||||
|
|
|
@ -33,6 +33,20 @@ module Modules
|
|||
repo.tags.map(&:name) + repo.branches.map(&:name)
|
||||
end
|
||||
|
||||
# TODO: return something else instead of empty string on success and error
|
||||
def restore_branch(branch, sha)
|
||||
repo.git.native(:branch, {}, branch, sha)
|
||||
end
|
||||
|
||||
def delete_branch(branch, user)
|
||||
return false if default_branch == branch.name
|
||||
message = repo.git.native(:branch, {}, '-D', branch.name)
|
||||
if message.present?
|
||||
Resque.enqueue(GitHook,owner.uname, name, GitHook::ZERO, branch.commit.id, "refs/heads/#{branch.name}", 'commit', "user-#{user.id}", message)
|
||||
end
|
||||
return message.present?
|
||||
end
|
||||
|
||||
def update_file(path, data, options = {})
|
||||
head = options[:head].to_s || default_branch
|
||||
actor = get_actor(options[:actor])
|
||||
|
|
|
@ -7,7 +7,6 @@ describe Projects::Git::TreesController do
|
|||
stub_symlink_methods
|
||||
|
||||
@project = FactoryGirl.create(:project)
|
||||
@another_user = FactoryGirl.create(:user)
|
||||
@params = { :owner_name => @project.owner.uname,
|
||||
:project_name => @project.name,
|
||||
:treeish => "#{@project.name}-master"}
|
||||
|
@ -37,6 +36,17 @@ describe Projects::Git::TreesController do
|
|||
get :archive, @params.merge(:format => 'tar.gz')
|
||||
response.code.should == '401'
|
||||
end
|
||||
|
||||
it 'should not be able to perform destroy action' do
|
||||
delete :destroy, @params.merge(:treeish => 'master')
|
||||
response.should_not be_success
|
||||
end
|
||||
|
||||
it 'should not be able to perform restore_branch action' do
|
||||
put :restore_branch, @params.merge(:treeish => 'master')
|
||||
response.should_not be_success
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'for other user' do
|
||||
|
@ -60,6 +70,16 @@ describe Projects::Git::TreesController do
|
|||
response.should be_success
|
||||
end
|
||||
|
||||
it 'should not be able to perform destroy action' do
|
||||
delete :destroy, @params.merge(:treeish => 'master')
|
||||
response.should_not be_success
|
||||
end
|
||||
|
||||
it 'should not be able to perform restore_branch action' do
|
||||
put :restore_branch, @params.merge(:treeish => 'master')
|
||||
response.should_not be_success
|
||||
end
|
||||
|
||||
[:tags, :branches].each do |action|
|
||||
it "should be able to perform #{action} action" do
|
||||
get action, @params.merge(:treeish => 'master')
|
||||
|
@ -68,5 +88,28 @@ describe Projects::Git::TreesController do
|
|||
end
|
||||
end
|
||||
|
||||
context 'for writer user' do
|
||||
before(:each) do
|
||||
user = FactoryGirl.create(:user)
|
||||
@project.relations.create!(:actor_type => 'User', :actor_id => user.id, :role => 'writer')
|
||||
set_session_for user
|
||||
end
|
||||
|
||||
it 'should be able to perform destroy action' do
|
||||
delete :destroy, @params.merge(:treeish => 'conflicts')
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
it 'should not be able to perform destroy action for master branch' do
|
||||
delete :destroy, @params.merge(:treeish => 'master')
|
||||
response.should_not be_success
|
||||
end
|
||||
|
||||
it 'should be able to perform restore_branch action' do
|
||||
put :restore_branch, @params.merge(:treeish => 'conflicts')
|
||||
response.should be_success
|
||||
end
|
||||
end
|
||||
|
||||
after(:all) {clean_projects_dir}
|
||||
end
|
||||
|
|
|
@ -97,11 +97,6 @@ shared_examples_for 'user with pull request update rights' do
|
|||
response.should redirect_to(project_pull_request_path(@pull.to_project, @pull))
|
||||
end
|
||||
|
||||
it 'should be able to perform merge action' do
|
||||
put :merge, @update_params
|
||||
response.should redirect_to(project_pull_request_path(@pull.to_project, @pull))
|
||||
end
|
||||
|
||||
let(:pull) { @project.pull_requests.find(@pull) }
|
||||
it 'should update pull request status' do
|
||||
put :update, @update_params
|
||||
|
@ -135,11 +130,6 @@ shared_examples_for 'user without pull request update rights' do
|
|||
response.should redirect_to(controller.current_user ? forbidden_path : new_user_session_path)
|
||||
end
|
||||
|
||||
it 'should not be able to perform merge action' do
|
||||
put :merge, @update_params
|
||||
response.should redirect_to(controller.current_user ? forbidden_path : new_user_session_path)
|
||||
end
|
||||
|
||||
let(:pull) { @project.pull_requests.find(@pull) }
|
||||
it 'should not update pull request status' do
|
||||
put :update, @update_params
|
||||
|
|
|
@ -86,4 +86,55 @@ describe Project do
|
|||
lambda {FactoryGirl.create(:project, :name => "...\nbeatiful_name\n for project")}.should raise_error(ActiveRecord::RecordInvalid)
|
||||
end
|
||||
end
|
||||
|
||||
context 'manage branches' do
|
||||
let!(:project) { FactoryGirl.create(:project_with_commit) }
|
||||
let(:branch) { project.repo.branches.detect{|b| b.name == 'conflicts'} }
|
||||
let(:master) { project.repo.branches.detect{|b| b.name == 'master'} }
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
before { stub_redis }
|
||||
|
||||
context '#delete_branch' do
|
||||
it 'ensures that returns true on success' do
|
||||
project.delete_branch(branch, user).should be_true
|
||||
end
|
||||
|
||||
it 'ensures that branch has been deleted' do
|
||||
lambda { project.delete_branch(branch, user) }.should change{ project.repo.branches.count }.by(-1)
|
||||
end
|
||||
|
||||
it 'ensures that returns false on delete master' do
|
||||
project.delete_branch(master, user).should be_false
|
||||
end
|
||||
|
||||
it 'ensures that master has not been deleted' do
|
||||
lambda { project.delete_branch(master, user) }.should change{ project.repo.branches.count }.by(0)
|
||||
end
|
||||
|
||||
it 'ensures that returns false on delete wrong branch' do
|
||||
project.delete_branch(branch, user)
|
||||
project.delete_branch(branch, user).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context '#restore_branch' do
|
||||
before do
|
||||
project.delete_branch(branch, user)
|
||||
end
|
||||
|
||||
xit 'ensures that returns true on success' do
|
||||
project.restore_branch(branch.name, branch.commit.id).should be_true
|
||||
end
|
||||
|
||||
it 'ensures that branch has been restored' do
|
||||
lambda { project.restore_branch(branch.name, branch.commit.id) }.should change{ project.repo.branches.count }.by(1)
|
||||
end
|
||||
|
||||
xit 'ensures that returns false on restore wrong branch' do
|
||||
project.restore_branch(branch.name, GitHook::ZERO).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue