diff --git a/Gemfile b/Gemfile index 4076c4e09..7076e5e1b 100644 --- a/Gemfile +++ b/Gemfile @@ -18,7 +18,7 @@ gem "yui-compressor", "0.9.5" # Higher versions depends on Platform gem which co gem 'rails3-jquery-autocomplete' gem 'ancestry', '~> 1.2.4' -gem 'paperclip', "~> 2.3" +gem 'paperclip', "~> 2.5" gem "will_paginate", "~> 3.0.2" gem 'meta-tags', '~> 1.2.4', :require => 'meta_tags' gem "russian" @@ -43,7 +43,7 @@ gem 'unicorn', '~> 4.1.1' group :production do gem "airbrake", '~> 3.0.5' - # gem 'newrelic_rpm', '~> 3.1.1' + gem 'newrelic_rpm' gem 'bluepill', :require => false end diff --git a/Gemfile.lock b/Gemfile.lock index 9819287e4..5fee68804 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -61,7 +61,7 @@ GEM capistrano (>= 1.0.0) capistrano_colors (0.5.5) chronic (0.6.6) - cocaine (0.2.0) + cocaine (0.2.1) columnize (0.3.5) daemons (1.1.4) delayed_job (2.1.4) @@ -127,6 +127,7 @@ GEM net-ssh-gateway (1.1.0) net-ssh (>= 1.99.1) nokogiri (1.5.0) + newrelic_rpm (3.3.1) omniauth (1.0.1) hashie (~> 1.2) rack @@ -134,7 +135,7 @@ GEM omniauth (~> 1.0) rack-openid (~> 1.3.1) orm_adapter (0.0.5) - paperclip (2.4.5) + paperclip (2.5.0) activerecord (>= 2.3.0) activesupport (>= 2.3.2) cocaine (>= 0.0.2) @@ -251,9 +252,10 @@ DEPENDENCIES jammit meta-tags (~> 1.2.4) mysql2 (<= 0.2.9) + newrelic_rpm omniauth (~> 1.0.1) omniauth-openid (~> 1.0.1) - paperclip (~> 2.3) + paperclip (~> 2.5) pg (~> 0.11.0) rails (= 3.0.11) rails-xmlrpc (~> 0.3.6) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4a64259cd..494f54ae1 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,8 +1,10 @@ # coding: UTF-8 class ApplicationController < ActionController::Base protect_from_forgery + layout :layout_by_resource + before_filter :set_locale before_filter lambda { EventLog.current_controller = self }, :only => [:create, :destroy, :open_id, :auto_build, :cancel, :publish, :change_visibility] # :update after_filter lambda { EventLog.current_controller = nil } @@ -14,26 +16,39 @@ class ApplicationController < ActionController::Base end protected - def get_owner + + def set_locale + I18n.locale = check_locale( get_user_locale || request.env['HTTP_ACCEPT_LANGUAGE'] ) + end + + def get_user_locale + user_signed_in? ? current_user.language : nil + end + + def check_locale(locale) + User::LANGUAGES.include?(locale.to_s) ? locale : :en + end + + def get_owner # params['user_id'] && User.find_by_id(params['user_id']) || # params['group_id'] && Group.find_by_id(params['group_id']) || current_user - if self.class.method_defined? :parent - if parent and (parent.is_a? User or parent.is_a? Group) - return parent - else - return current_user - end + if self.class.method_defined? :parent + if parent and (parent.is_a? User or parent.is_a? Group) + return parent else - params['user_id'] && User.find_by_id(params['user_id']) || - params['group_id'] && Group.find_by_id(params['group_id']) || current_user + return current_user end + else + params['user_id'] && User.find_by_id(params['user_id']) || + params['group_id'] && Group.find_by_id(params['group_id']) || current_user end + end - def layout_by_resource - if devise_controller? - "sessions" - else - "application" - end + def layout_by_resource + if devise_controller? + "sessions" + else + "application" end + end end diff --git a/app/controllers/build_lists_controller.rb b/app/controllers/build_lists_controller.rb index fc650a4b3..29d869151 100644 --- a/app/controllers/build_lists_controller.rb +++ b/app/controllers/build_lists_controller.rb @@ -39,6 +39,7 @@ class BuildListsController < ApplicationController Arch.where(:id => params[:arches]).each do |arch| Platform.main.where(:id => params[:bpls]).each do |bpl| @build_list = @project.build_lists.build(params[:build_list]) + @build_list.commit_hash = @project.git_repository.commits(@build_list.project_version.match(/(.+)_latest$/).to_a.last || @build_list.project_version).first.id @build_list.bpl = bpl; @build_list.arch = arch; @build_list.user = current_user flash_options = {:project_version => @build_list.project_version, :arch => arch.name, :bpl => bpl.name, :pl => @build_list.pl} if @build_list.save @@ -80,7 +81,13 @@ class BuildListsController < ApplicationController end def publish_build - @build_list.status = (params[:status].to_i == 0 ? BuildList::BUILD_PUBLISHED : BuildList::FAILED_PUBLISH) + if params[:status].to_i == 0 # ok + @build_list.status = BuildList::BUILD_PUBLISHED + @build_list.package_version = "#{params[:version]}-#{params[:release]}" + system("cd #{@build_list.project.git_repository.path} && git tag #{@build_list.package_version} #{@build_list.commit_hash}") # TODO REDO through grit + else + @build_list.status = BuildList::FAILED_PUBLISH + end @build_list.notified_at = Time.current @build_list.save @@ -113,9 +120,9 @@ class BuildListsController < ApplicationController @build_list.notified_at = Time.current @build_list.save - @build_list.delay.publish if @build_list.auto_publish # && @build_list.can_publish? - render :nothing => true, :status => 200 + + @build_list.delay.publish if @build_list.auto_publish # && @build_list.can_publish? end def circle_build diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index e20aa3af1..6f699a602 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,7 +1,7 @@ class CommentsController < ApplicationController before_filter :authenticate_user! - before_filter :set_commentable, :only => [:index, :edit, :create] - before_filter :find_project, :only => [:index] + before_filter :set_commentable, :only => [:index, :edit, :create, :update, :destroy] + #before_filter :find_project, :only => [:index, :edit] before_filter :find_comment, :only => [:edit, :update, :destroy] authorize_resource :only => [:show, :edit, :update, :destroy] @@ -12,11 +12,12 @@ class CommentsController < ApplicationController end def create - @comment = @commentable.comments.build(params[:comment]) + @comment = @commentable.comments.build(params[:comment]) if @commentable.class == Issue + @comment = Comment.new(params[:comment].merge(:commentable_id => @commentable.id, :commentable_type => @commentable.class.name)) if @commentable.class == Grit::Commit @comment.user = current_user if @comment.save flash[:notice] = I18n.t("flash.comment.saved") - redirect_to :back + redirect_to commentable_path else flash[:error] = I18n.t("flash.comment.save_error") render :action => 'new' @@ -24,15 +25,19 @@ class CommentsController < ApplicationController end def edit - @issue = @commentable - @project = @issue.project + @update_url = case @commentable.class.name + when "Issue" + project_issue_comment_path(@project, @commentable, @comment) + when "Grit::Commit" + project_commit_comment_path(@project, @commentable, @comment) + end + @commentable_path = commentable_path end def update if @comment.update_attributes(params[:comment]) flash[:notice] = I18n.t("flash.comment.saved") - #redirect_to :back - redirect_to [@comment.commentable.project, @comment.commentable] + redirect_to commentable_path else flash[:error] = I18n.t("flash.comment.save_error") render :action => 'new' @@ -43,7 +48,7 @@ class CommentsController < ApplicationController @comment.destroy flash[:notice] = t("flash.comment.destroyed") - redirect_to :back + redirect_to commentable_path end private @@ -55,18 +60,31 @@ class CommentsController < ApplicationController # end #end #nil - return Issue.find(params[:issue_id]) + if params[:issue_id].present? + return Issue.find_by_serial_id_and_project_id(params[:issue_id], params[:project_id]) + elsif params[:commit_id].present? + return @project.git_repository.commit(params[:commit_id]) + end end def set_commentable + find_project @commentable = find_commentable end def find_comment @comment = Comment.find(params[:id]) + @comment.project = @project if @comment.commentable_type == 'Grit::Commit' end def find_project - @project = @comment.commentable.project + @project = Project.find(params[:project_id]) end + + protected + + def commentable_path + @commentable.class == Issue ? [@project, @commentable] : commit_path(@project, @commentable.id) + end + end diff --git a/app/controllers/git/blobs_controller.rb b/app/controllers/git/blobs_controller.rb index 1182412ea..eb788d211 100644 --- a/app/controllers/git/blobs_controller.rb +++ b/app/controllers/git/blobs_controller.rb @@ -5,6 +5,16 @@ class Git::BlobsController < Git::BaseController def show @blob = @tree / @path + + if params[:raw] + image_url = Rails.root.to_s + "/" + @path + + response.headers['Cache-Control'] = "public, max-age=#{12.hours.to_i}" + response.headers['Content-Type'] = @blob.mime_type + response.headers['Content-Disposition'] = 'inline' + + render(:text => open(image_url).read) and return + end end def blame @@ -42,4 +52,4 @@ class Git::BlobsController < Git::BaseController @commit = @git_repository.log(@treeish, @path).first # TODO WTF nil ? end end -end \ No newline at end of file +end diff --git a/app/controllers/git/commits_controller.rb b/app/controllers/git/commits_controller.rb index 04b1a94dc..021d60cee 100644 --- a/app/controllers/git/commits_controller.rb +++ b/app/controllers/git/commits_controller.rb @@ -23,4 +23,4 @@ class Git::CommitsController < Git::BaseController end end -end \ No newline at end of file +end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 3f1a6f4ec..99f13be95 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -30,7 +30,10 @@ class IssuesController < ApplicationController @issue = Issue.new(params[:issue]) @issue.user_id = @user_id @issue.project_id = @project.id + if @issue.save + @issue.subscribe_creator(current_user.id) + flash[:notice] = I18n.t("flash.issue.saved") redirect_to project_issues_path(@project) else @@ -41,12 +44,12 @@ class IssuesController < ApplicationController def edit @user_id = @issue.user_id - @user_uname = @issue.user.uname + @user_uname = @issue.assign_uname end def update @user_id = params[:user_id].blank? ? @issue.user_id : params[:user_id] - @user_uname = params[:user_uname].blank? ? @issue.user.uname : params[:user_uname] + @user_uname = params[:user_uname].blank? ? @issue.assign_uname : params[:user_uname] if @issue.update_attributes( params[:issue].merge({:user_id => @user_id}) ) flash[:notice] = I18n.t("flash.issue.saved") diff --git a/app/controllers/platforms_controller.rb b/app/controllers/platforms_controller.rb index 3ce47f9a7..9c9563e02 100644 --- a/app/controllers/platforms_controller.rb +++ b/app/controllers/platforms_controller.rb @@ -113,7 +113,7 @@ class PlatformsController < ApplicationController @cloned = @platform.make_clone(:name => params[:platform]['name'], :description => params[:platform]['description'], :owner_id => current_user.id, :owner_type => current_user.class.to_s) if @cloned.persisted? - flash[:notice] = 'Клонирование успешно' + flash[:notice] = I18n.t("flash.platform.clone_success") redirect_to @cloned else flash[:error] = @cloned.errors.full_messages.join('. ') diff --git a/app/controllers/settings/notifiers_controller.rb b/app/controllers/settings/notifiers_controller.rb new file mode 100644 index 000000000..03df52237 --- /dev/null +++ b/app/controllers/settings/notifiers_controller.rb @@ -0,0 +1,22 @@ +class Settings::NotifiersController < ApplicationController + layout "sessions" + + before_filter :authenticate_user! + + load_and_authorize_resource :user + load_and_authorize_resource :class => Settings::Notifier, :through => :user, :singleton => true, :shallow => true + + def show + end + + def update + if @notifier.update_attributes(params[:settings_notifier]) + flash[:notice] = I18n.t("flash.settings.saved") + redirect_to [@user, @notifier] + else + flash[:notice] = I18n.t("flash.settings.save_error") + redirect_to [@user, @notifier] + end + end + +end diff --git a/app/helpers/git_helper.rb b/app/helpers/git_helper.rb index 8dd3624ad..286fba6f2 100644 --- a/app/helpers/git_helper.rb +++ b/app/helpers/git_helper.rb @@ -40,4 +40,9 @@ module GitHelper blob.data.split("\n").collect{|line| "
#{line.present? ? h(line) : "
"}
"}.join end -end \ No newline at end of file + def choose_render_way(blob) + return :image if blob.mime_type.match(/image/) + return :text if blob.mime_type.match(/text|xml|json/) + :binary + end +end diff --git a/app/helpers/settings/notifiers_helper.rb b/app/helpers/settings/notifiers_helper.rb new file mode 100644 index 000000000..295af1e51 --- /dev/null +++ b/app/helpers/settings/notifiers_helper.rb @@ -0,0 +1,2 @@ +module Settings::NotifiersHelper +end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 2c43482e1..39ceffa17 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,7 +1,7 @@ # coding: UTF-8 class UserMailer < ActionMailer::Base - default :from => APP_CONFIG['no-reply-email'] + default :from => APP_CONFIG['do-not-reply-email'] def new_user_notification(user) @user = user @@ -18,6 +18,14 @@ class UserMailer < ActionMailer::Base end end + def new_comment_reply_notification(comment, user) + @user = user + @comment = comment + mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_comment_reply_notification")) do |format| + format.html + end + end + def new_issue_notification(issue, user) @user = user @issue = issue diff --git a/app/models/ability.rb b/app/models/ability.rb index 1b7509a2b..7709990ee 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -1,8 +1,8 @@ # If rules goes one by one CanCan joins them by 'OR' sql operator # If rule has multiple conditions CanCan joins them by 'AND' sql operator -# WARNING: +# WARNING: # - put cannot rules _after_ can rules and not before! -# - beware inner joins. Use sub queries against them! +# - beware inner joins. Use sub queries against them! class Ability include CanCan::Ability @@ -28,6 +28,8 @@ class Ability else # Registered user rights can [:show, :autocomplete_user_uname], User + can [:show, :update], Settings::Notifier, :user_id => user.id + can [:read, :create], Group can [:update, :manage_members], Group do |group| group.objects.exists?(:object_type => 'User', :object_id => user.id, :role => 'admin') # or group.owner_id = user.id @@ -44,8 +46,9 @@ class Ability can(:fork, Project) {|project| can? :read, project} can(:destroy, Project) {|project| owner? project} - can :create, AutoBuildList - can [:index, :destroy], AutoBuildList, :project_id => user.own_project_ids + # TODO: Turn on AAA when it will be updated + #can :create, AutoBuildList + #can [:index, :destroy], AutoBuildList, :project_id => user.own_project_ids can :read, BuildList, :project => {:visibility => 'open'} can :read, BuildList, :project => {:owner_type => 'User', :owner_id => user.id} @@ -89,9 +92,10 @@ class Ability can([:update, :destroy], Issue) {|issue| issue.user_id == user.id or local_admin?(issue.project)} cannot :manage, Issue, :project => {:has_issues => false} # switch off issues - can(:create, Comment) {|comment| can? :read, comment.commentable.project} - can(:update, Comment) {|comment| comment.user_id == user.id or local_admin?(comment.commentable.project)} - cannot :manage, Comment, :commentable => {:project => {:has_issues => false}} # switch off issues + can(:create, Comment) {|comment| can? :read, comment.project || comment.commentable.project} + can(:update, Comment) {|comment| comment.user_id == user.id or local_admin?(comment.project || comment.commentable.project)} + #cannot :manage, Comment, :commentable => {:project => {:has_issues => false}} # switch off issues + cannot(:manage, Comment) {|comment| comment.commentable_type == 'Issue' && !comment.commentable.project.has_issues} # switch off issues end end diff --git a/app/models/build_list/item.rb b/app/models/build_list/item.rb index a06e3b89e..ec49f740c 100644 --- a/app/models/build_list/item.rb +++ b/app/models/build_list/item.rb @@ -1,11 +1,15 @@ class BuildList::Item < ActiveRecord::Base + belongs_to :build_list attr_protected :build_list_id - STATUSES = [BuildServer::SUCCESS, BuildServer::DEPENDENCIES_ERROR, BuildServer::BUILD_ERROR, BuildServer::BUILD_STARTED] + GIT_ERROR = 5 + + STATUSES = [BuildServer::SUCCESS, BuildServer::DEPENDENCIES_ERROR, BuildServer::BUILD_ERROR, BuildServer::BUILD_STARTED, GIT_ERROR] HUMAN_STATUSES = { nil => :unknown, + GIT_ERROR => :git_error, BuildServer::DEPENDENCIES_ERROR => :dependencies_error, BuildServer::SUCCESS => :success, BuildServer::BUILD_STARTED => :build_started, diff --git a/app/models/comment.rb b/app/models/comment.rb index 439fd0733..8ba9c05d0 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,20 +1,30 @@ class Comment < ActiveRecord::Base belongs_to :commentable, :polymorphic => true belongs_to :user + attr_accessor :project validates :body, :user_id, :commentable_id, :commentable_type, :presence => true - after_create :deliver_new_comment_notification + # FIXME + after_create :subscribe_on_reply, :unless => "commentable_type == 'Grit::Commit'" + after_create :deliver_new_comment_notification, :unless => "commentable_type == 'Grit::Commit'" protected def deliver_new_comment_notification - recipients = self.commentable.project.relations.by_role('admin').where(:object_type => 'User').map { |rel| rel.read_attribute(:object_id) } - recipients = recipients | [self.commentable.user_id] - recipients = recipients | [self.commentable.project.owner_id] if self.commentable.project.owner_type == 'User' - recipients.each do |recipient_id| - recipient = User.find(recipient_id) - UserMailer.delay.new_comment_notification(self, recipient) + subscribes = self.commentable.subscribes + subscribes.each do |subscribe| + if self.user_id != subscribe.user_id && User.find(subscribe.user).notifier.new_comment_reply && User.find(subscribe.user).notifier.can_notify + if self.commentable.comments.exists?(:user_id => subscribe.user.id) + UserMailer.delay.new_comment_reply_notification(self, subscribe.user) + else + UserMailer.delay.new_comment_notification(self, subscribe.user) + end + end end end + + def subscribe_on_reply + self.commentable.subscribes.create(:user_id => self.user_id) if !self.commentable.subscribes.exists?(:user_id => self.user_id) + end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 9ae96f439..efeffbf13 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -4,7 +4,13 @@ class Issue < ActiveRecord::Base belongs_to :project belongs_to :user - has_many :comments, :as => :commentable + has_many :comments, :as => :commentable, + :finder_sql => proc { "comments.commentable_id = '#{self.id}' " + + " AND comments.commentable_type = '#{self.class.name}'"} + #'SELECT comments.* FROM comments ' + + #'WHERE comments.commentable_id = \'#{self.id}\' ' + + #' AND comments.commentable_type = \'#{self.class.name}\' ' + + #'ORDER BY comments.created_at' has_many :subscribes, :as => :subscribeable validates :title, :body, :project_id, :presence => true @@ -16,6 +22,7 @@ class Issue < ActiveRecord::Base after_create :deliver_new_issue_notification after_create :deliver_issue_assign_notification after_update :deliver_issue_assign_notification + after_update :subscribe_issue_assigned_user def assign_uname user.uname if user @@ -25,6 +32,12 @@ class Issue < ActiveRecord::Base serial_id.to_s end + def subscribe_creator(creator_id) + if !self.subscribes.exists?(:user_id => creator_id) + self.subscribes.create(:user_id => creator_id) + end + end + protected def set_serial_id @@ -36,12 +49,12 @@ class Issue < ActiveRecord::Base recipients = collect_recipient_ids recipients.each do |recipient_id| recipient = User.find(recipient_id) - UserMailer.delay.new_issue_notification(self, recipient)#.deliver + UserMailer.delay.new_issue_notification(self, recipient) if User.find(recipient).notifier.can_notify && User.find(recipient).notifier.new_issue end end def deliver_issue_assign_notification - UserMailer.delay.issue_assign_notification(self, self.user) if self.user_id_was != self.user_id + UserMailer.delay.issue_assign_notification(self, self.user) if self.user_id_was != self.user_id && self.user.notifier.issue_assign && self.user.notifier.can_notify end def subscribe_users @@ -56,7 +69,21 @@ class Issue < ActiveRecord::Base recipients = self.project.relations.by_role('admin').where(:object_type => 'User').map { |rel| rel.read_attribute(:object_id) } recipients = recipients | [self.user_id] if self.user_id recipients = recipients | [self.project.owner_id] if self.project.owner_type == 'User' + + # filter by notification settings + recipients = recipients.select do |recipient| + User.find(recipient).notifier.new_issue && User.find(recipient).notifier.can_notify + end + recipients end + def subscribe_issue_assigned_user + if self.user_id_was != self.user_id + self.subscribes.where(:user_id => self.user_id_was).first.destroy unless self.user_id_was.blank? + if self.user.notifier.issue_assign && !self.subscribes.exists?(:user_id => self.user_id) + self.subscribes.create(:user_id => self.user_id) + end + end + end end diff --git a/app/models/product.rb b/app/models/product.rb index 36337f4f9..84afdfb35 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -9,7 +9,7 @@ class Product < ActiveRecord::Base has_attached_file :tar - validates_attachment_content_type :tar, :content_type => ["application/gnutar", "application/x-compressed", "application/x-gzip", "application/x-bzip2", "application/x-tar"], :message => I18n.t('layout.products.invalid_content_type') + validates_attachment_content_type :tar, :content_type => ["application/gnutar", "application/x-compressed", "application/x-gzip", "application/x-bzip2", "application/x-tar"], :message => I18n.t('layout.invalid_content_type') validates :name, :presence => true, :uniqueness => {:scope => :platform_id} scope :recent, order("name ASC") diff --git a/app/models/project.rb b/app/models/project.rb index 85ee5d513..8f8600ee3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -9,6 +9,7 @@ class Project < ActiveRecord::Base has_many :build_lists, :dependent => :destroy has_many :auto_build_lists, :dependent => :destroy + # has_many :project_imports, :dependent => :destroy has_many :project_to_repositories, :dependent => :destroy has_many :repositories, :through => :project_to_repositories @@ -20,6 +21,8 @@ class Project < ActiveRecord::Base validates :owner, :presence => true validate { errors.add(:base, :can_have_less_or_equal, :count => MAX_OWN_PROJECTS) if owner.projects.size >= MAX_OWN_PROJECTS } # validate {errors.add(:base, I18n.t('flash.project.save_warning_ssh_key')) if owner.ssh_key.blank?} + validates_attachment_size :srpm, :less_than => 500.megabytes + validates_attachment_content_type :srpm, :content_type => ['application/octet-stream'], :message => I18n.t('layout.invalid_content_type') # "application/x-rpm", "application/x-redhat-package-manager" ? #attr_accessible :category_id, :name, :description, :visibility attr_readonly :name @@ -36,10 +39,13 @@ class Project < ActiveRecord::Base after_destroy :destroy_git_repo after_destroy :destroy_wiki + after_save {|p| p.delay.import_srpm if p.srpm?} # should be after create_git_repo # after_rollback lambda { destroy_git_repo rescue true if new_record? } has_ancestry + has_attached_file :srpm + include Modules::Models::Owner def auto_build @@ -59,10 +65,13 @@ class Project < ActiveRecord::Base bl.pl = platform bl.bpl = platform bl.update_type = 'recommended' - bl.arch = Arch.find_by_name('i586') - bl.project_version = "latest_#{platform.name}" + bl.arch = Arch.find_by_name('x86_64') # Return i586 after mass rebuild + # FIXME: Need to set "latest_#{platform.name}" + bl.project_version = "latest_mandriva2011" bl.build_requires = false # already set as db default bl.user = user + bl.auto_publish = true # already set as db default + bl.include_repos = [platform.repositories.find_by_name('main').id] end end @@ -71,7 +80,7 @@ class Project < ActiveRecord::Base res = tags.select{|tag| tag.name =~ /^v\./} return res if res and res.size > 0 tags - end + end def collected_project_versions project_versions.collect{|tag| tag.name.gsub(/^\w+\./, "")} end @@ -127,7 +136,7 @@ class Project < ActiveRecord::Base return true else raise "Failed to create project #{name} (repo #{repository.name}) inside platform #{repository.platform.name} in path #{path} with code #{result}." - end + end end def xml_rpc_destroy(repository) @@ -143,6 +152,20 @@ class Project < ActiveRecord::Base @platforms ||= repositories.map(&:platform).uniq end + def import_srpm(branch_name = 'import') + if srpm? + system("#{Rails.root.join('bin', 'import_srpm.sh')} #{srpm.path} #{path} #{branch_name} >> /dev/null 2>&1") + self.srpm = nil; save # clear srpm + end + end + + class << self + def commit_comments(commit, project) + comments = Comment.where(:commentable_id => commit.id, :commentable_type => 'Grit::Commit').order(:created_at) + comments.each {|x| x.project = project} + end + end + protected def build_path(dir) diff --git a/app/models/repository.rb b/app/models/repository.rb index 13c4e2a02..b9246f86a 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -48,7 +48,7 @@ class Repository < ActiveRecord::Base return true else raise "Failed to create repository #{name} inside platform #{platform.name} with code #{result}." - end + end end def xml_rpc_destroy diff --git a/app/models/settings.rb b/app/models/settings.rb new file mode 100644 index 000000000..f6af89076 --- /dev/null +++ b/app/models/settings.rb @@ -0,0 +1,5 @@ +module Settings + def self.table_name_prefix + 'settings_' + end +end diff --git a/app/models/settings/notifier.rb b/app/models/settings/notifier.rb new file mode 100644 index 000000000..af21fd811 --- /dev/null +++ b/app/models/settings/notifier.rb @@ -0,0 +1,5 @@ +class Settings::Notifier < ActiveRecord::Base + belongs_to :user + + validates :user_id, :presence => true +end diff --git a/app/models/user.rb b/app/models/user.rb index affe00818..ae724821f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,9 +1,13 @@ class User < ActiveRecord::Base ROLES = ['admin'] + LANGUAGES_FOR_SELECT = [['Russian', 'ru'], ['English', 'en']] + LANGUAGES = LANGUAGES_FOR_SELECT.map(&:last) devise :database_authenticatable, :registerable, :omniauthable, # :token_authenticatable, :encryptable, :timeoutable :recoverable, :rememberable, :validatable #, :trackable, :confirmable, :lockable + has_one :notifier, :class_name => 'Settings::Notifier' #:notifier + has_many :authentications, :dependent => :destroy has_many :build_lists, :dependent => :destroy @@ -26,11 +30,15 @@ class User < ActiveRecord::Base validate { errors.add(:uname, :taken) if Group.where('uname LIKE ?', uname).present? } validates :ssh_key, :uniqueness => true, :allow_blank => true validates :role, :inclusion => {:in => ROLES}, :allow_blank => true + validates :language, :inclusion => {:in => LANGUAGES}, :allow_blank => true - attr_accessible :email, :password, :password_confirmation, :remember_me, :login, :name, :ssh_key, :uname + attr_accessible :email, :password, :password_confirmation, :remember_me, :login, :name, :ssh_key, :uname, :language attr_readonly :uname, :own_projects_count + attr_readonly :uname attr_accessor :login + after_create :create_settings_notifier + def admin? role == 'admin' end @@ -75,5 +83,11 @@ class User < ActiveRecord::Base clean_up_passwords result end + + private + + def create_settings_notifier + self.create_notifier + end end diff --git a/app/views/build_lists/show.html.haml b/app/views/build_lists/show.html.haml index 9c7e779c5..1cd64f1e8 100644 --- a/app/views/build_lists/show.html.haml +++ b/app/views/build_lists/show.html.haml @@ -21,7 +21,9 @@ %b = t("activerecord.attributes.build_list.container_path") \: - - if @build_list.container_path.present? + - if @build_list.status == BuildList::BUILD_PUBLISHED + = t("layout.build_lists.container_published") + - elsif @build_list.container_path.present? - container_url = "http://#{request.host_with_port}/downloads#{@build_list.container_path}" = link_to container_url, container_url %p diff --git a/app/views/comments/_form.html.haml b/app/views/comments/_form.html.haml index 4078f495e..3600e8d2b 100644 --- a/app/views/comments/_form.html.haml +++ b/app/views/comments/_form.html.haml @@ -7,4 +7,4 @@ = image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save")) = t("layout.save") %span.text_button_padding= t("layout.or") - = link_to t("layout.cancel"), [@issue.project, @issue], :class => "text_button_padding link_button" + = link_to t("layout.cancel"), @commentable_path , :class => "text_button_padding link_button" diff --git a/app/views/comments/_list.html.haml b/app/views/comments/_list.html.haml new file mode 100644 index 000000000..25e6e13ee --- /dev/null +++ b/app/views/comments/_list.html.haml @@ -0,0 +1,33 @@ +%a{ :name => "comments" } +.block#block-list + .content + %h2.title + = t("layout.issues.comments_header") + .inner + %ul.list + - list.each do |comment| + %li + .left + = link_to comment.user.uname, user_path(comment.user.uname) + .item + = comment.body + %br + %br + - if commentable.class == Issue + - edit_path = edit_project_issue_comment_path(project, commentable, comment) + - delete_path = project_issue_comment_path(project, commentable, comment) + - elsif commentable.class == Grit::Commit + - edit_path = edit_project_commit_comment_path(project, commentable, comment) + - delete_path = project_commit_comment_path(project, commentable, comment) + = link_to t("layout.edit"), edit_path if can? :update, comment + = link_to image_tag("web-app-theme/icons/cross.png", :alt => t("layout.delete")) + " " + t("layout.delete"), delete_path, :method => "delete", :class => "button", :confirm => t("layout.comments.confirm_delete") if can? :delete, comment + +.block + .content + %h2.title + = t("layout.comments.new_header") + .inner + - new_path = project_issue_comments_path(project, commentable) if commentable.class == Issue + - new_path = project_commit_comments_path(project, commentable) if commentable.class == Grit::Commit + = form_for :comment, :url => new_path, :method => :post, :html => { :class => :form } do |f| + = render :partial => "comments/form", :locals => {:f => f} diff --git a/app/views/comments/edit.html.haml b/app/views/comments/edit.html.haml index 516ddd476..eb586af80 100644 --- a/app/views/comments/edit.html.haml +++ b/app/views/comments/edit.html.haml @@ -1,10 +1,10 @@ .block .secondary-navigation %ul.wat-cf - %li.first= link_to t("layout.issues.list"), project_issue_path(@project, @issue) + %li.first= link_to t(@comment.commentable_type == 'Grit::Commit' ? "layout.git.repositories.commits" : "layout.issues.list"), @commentable_path .content %h2.title - = t("layout.issues.edit_header") + = t("layout.#{@comment.commentable_type == 'Grit::Commit' ? 'comments' : 'issues'}.edit_header") .inner - = form_for @comment, :url => project_issue_comment_path(@project, @issue, @comment), :html => { :class => :form } do |f| + = form_for @comment, :url => @update_url, :html => { :class => :form } do |f| = render :partial => "form", :locals => {:f => f} diff --git a/app/views/devise/registrations/edit.html.haml b/app/views/devise/registrations/edit.html.haml index 75d6fcfa0..b983f1836 100644 --- a/app/views/devise/registrations/edit.html.haml +++ b/app/views/devise/registrations/edit.html.haml @@ -39,6 +39,12 @@ - else = resource.role + .group.wat-cf + .left + = f.label :language, :class => "label" + .right + = f.select :language, User::LANGUAGES_FOR_SELECT + / .group.wat-cf / .left / = f.label :current_password, :class => "label" @@ -68,3 +74,5 @@ %span.text_button_padding = link_to t('layout.back'), :back, :class => "text_button_padding link_button" + .group.navform.wat-cf + = link_to t('layout.settings.notifier'), user_settings_notifier_path(current_user)#, :class => "text_button_padding link_button" diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index aeddc6958..5c9d0de5d 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -37,6 +37,12 @@ .right = f.password_field :password_confirmation, :class => "text_field" + .group.wat-cf + .left + = f.label :language, :class => "label" + .right + = f.select :language, User::LANGUAGES_FOR_SELECT + .group.navform.wat-cf %button.button{ :type => "submit" } #{image_tag("web-app-theme/icons/tick.png", :alt => t("devise.registrations.sign_up_header"))} #{t("devise.registrations.sign_up_header")} diff --git a/app/views/devise/shared/_links.haml b/app/views/devise/shared/_links.haml index f3c6883ac..958f5ec3c 100644 --- a/app/views/devise/shared/_links.haml +++ b/app/views/devise/shared/_links.haml @@ -1,13 +1,13 @@ - if controller_name != 'sessions' - = link_to "Войти", new_session_path(resource_name), :class => "text_button_padding link_button" + = link_to t("layout.devise.shared_links.sign_in"), new_session_path(resource_name), :class => "text_button_padding link_button" - if devise_mapping.registerable? && controller_name != 'registrations' - = link_to "Зарегистрироваться", new_registration_path(resource_name), :class => "text_button_padding link_button" + = link_to t("layout.devise.shared_links.sign_up"), new_registration_path(resource_name), :class => "text_button_padding link_button" - if devise_mapping.recoverable? && controller_name != 'passwords' - = link_to "Забыли пароль?", new_password_path(resource_name), :class => "text_button_padding link_button" + = link_to t("layout.devise.shared_links.forgot_password"), new_password_path(resource_name), :class => "text_button_padding link_button" - if devise_mapping.confirmable? && controller_name != 'confirmations' - = link_to "Не получили инструкции по подтверждению?", new_confirmation_path(resource_name), :class => "text_button_padding link_button" + = link_to t("layout.devise.shared_links.confirm_again"), new_confirmation_path(resource_name), :class => "text_button_padding link_button" - if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' - = link_to "Не получили инструкции по разблокировке?", new_unlock_path(resource_name), :class => "text_button_padding link_button" + = link_to t("layout.devise.shared_links.unlock"), new_unlock_path(resource_name), :class => "text_button_padding link_button" - if devise_mapping.omniauthable? - resource_class.omniauth_providers.each do |provider| - = link_to "Войти через #{provider.to_s.classify}", omniauth_authorize_path(resource_name, provider), :class => "text_button_padding link_button" \ No newline at end of file + = link_to t("layout.devise.shared_links.sign_in_through", :provider => provider.to_s.classify), omniauth_authorize_path(resource_name, provider), :class => "text_button_padding link_button" diff --git a/app/views/git/blobs/show.html.haml b/app/views/git/blobs/show.html.haml index 2059f0a03..04b3a19b3 100644 --- a/app/views/git/blobs/show.html.haml +++ b/app/views/git/blobs/show.html.haml @@ -13,6 +13,7 @@ .content .inner %h3= render_path + %h3= @blob.mime_type .blob_header .size #{(@blob.size / 1024.0).round(3)} Kb @@ -22,13 +23,33 @@ - else #{link_to "Raw", raw_path(@project, @treeish, @path)} #{link_to "Blame", blame_path(@project, @treeish, @path)} #{link_to "History", commits_path(@project, @treeish, @path)} .clear - %table.table.blob - %tr - %td.lines - :plain -
#{render_line_numbers(@blob.data.split("\n").length)}
- %td.blob - :plain -
#{render_blob(@blob)}
+ - case choose_render_way(@blob) + - when :image + %table.table.blob + %tr + %td.lines + %td.blob + :plain +
+
+
+ - when :text + %table.table.blob + %tr + %td.lines + :plain +
#{render_line_numbers(@blob.data.split("\n").length)}
+ %td.blob + :plain +
#{render_blob(@blob)}
+ - when :binary + %table.table.blob + %tr + %td.lines + %td.blob + :plain +
+
#{ link_to @blob.basename, raw_path(@project, @treeish, @path) }
+
-- content_for :sidebar, render(:partial => 'git/shared/sidebar') \ No newline at end of file +- content_for :sidebar, render(:partial => 'git/shared/sidebar') diff --git a/app/views/git/commits/show.html.haml b/app/views/git/commits/show.html.haml index e5d39833e..8f3ec67f8 100644 --- a/app/views/git/commits/show.html.haml +++ b/app/views/git/commits/show.html.haml @@ -26,3 +26,5 @@ %p= t 'layout.git.repositories.commit_diff_too_big' - content_for :sidebar, render(:partial => 'git/shared/sidebar') + += render :partial => "comments/list", :locals => {:list => Project.commit_comments(@commit, @project), :project => @project, :commentable => @commit} diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index ea6a25a13..9f1c6306d 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -19,4 +19,4 @@ = render :partial => 'issues/list' .actions-bar.wat-cf .actions - = will_paginate @issues, :param_name => :issue_page + = will_paginate @issues#, :param_name => :issue_page diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 49b229b5c..a8d1c3e6e 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -29,28 +29,4 @@ - else = link_to t('layout.issues.subscribe_btn'), project_issue_subscribes_path(@project, @issue), :method => :post -%a{ :name => "comments" } -.block#block-list - .content - %h2.title - = t("layout.issues.comments_header") - .inner - %ul.list - - @issue.comments.each do |comment| - %li - .left - = link_to comment.user.uname, user_path(comment.user.uname) - .item - = comment.body - %br - %br - = link_to t("layout.edit"), edit_project_issue_comment_path(@project, @issue.id, comment) if can? :update, comment - = link_to image_tag("web-app-theme/icons/cross.png", :alt => t("layout.delete")) + " " + t("layout.delete"), project_issue_comment_path(@project, @issue.id, comment), :method => "delete", :class => "button", :confirm => t("layout.comments.confirm_delete") if can? :delete, comment - -.block - .content - %h2.title - = t("layout.comments.new_header") - .inner - = form_for :comment, :url => project_issue_comments_path(@project, @issue), :method => :post, :html => { :class => :form } do |f| - = render :partial => "comments/form", :locals => {:f => f} += render :partial => "comments/list", :locals => {:list => @issue.comments.order(:created_at), :project => @project, :commentable => @issue} diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 2fc1915cc..0f318764e 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -16,6 +16,9 @@ .group = f.label :has_wiki, t("activerecord.attributes.project.has_wiki"), :class => :label = f.check_box :has_wiki +.group + = f.label :srpm, t("activerecord.attributes.project.srpm"), :class => :label + = f.file_field :srpm, :class => 'file_field' .group.navform.wat-cf %button.button{:type => "submit"} diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index ba3c5c14f..1017c5329 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -8,7 +8,7 @@ .content %h2.title= t("layout.projects.edit_header") .inner - = form_for @project, :html => { :class => :form } do |f| + = form_for @project, :html => { :class => :form, :multipart => true } do |f| = render :partial => "form", :locals => {:f => f} - content_for :sidebar, render('sidebar') diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index f9304bdd8..6e5ec7973 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -9,7 +9,7 @@ .content %h2.title= t("layout.projects.new_header") .inner - = form_for [get_owner, @project], :html => { :class => :form } do |f| + = form_for [get_owner, @project], :html => { :class => :form, :multipart => true } do |f| = render :partial => "form", :locals => {:f => f} -# content_for :sidebar, render('sidebar') diff --git a/app/views/settings/notifiers/_form.html.haml b/app/views/settings/notifiers/_form.html.haml new file mode 100644 index 000000000..2631874bc --- /dev/null +++ b/app/views/settings/notifiers/_form.html.haml @@ -0,0 +1,29 @@ +.group + = f.label :can_notify, t('activerecord.attributes.settings.notifier.can_notify'), :class => :label + = f.check_box :can_notify#, :class => 'text_field' + +.group + = f.label :new_comment, t('activerecord.attributes.settings.notifier.new_comment'), :class => :label + = f.check_box :new_comment, :class => 'notify_cbx' + +.group + = f.label :new_comment_reply, t('activerecord.attributes.settings.notifier.new_comment_reply'), :class => :label + = f.check_box :new_comment_reply, :class => 'notify_cbx' + +.group + = f.label :new_issue, t('activerecord.attributes.settings.notifier.new_issue'), :class => :label + = f.check_box :new_issue, :class => 'notify_cbx' + +.group + = f.label :issue_assign, t('activerecord.attributes.settings.notifier.issue_assign'), :class => :label + = f.check_box :issue_assign, :class => 'notify_cbx' + +.group.navform.wat-cf + %button.button{:type => "submit"} + = image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save")) + = t("layout.save") + %span.text_button_padding= t("layout.or") + = link_to t("layout.cancel"), user_settings_notifier_path(@user), :class => "text_button_padding link_button" + +:javascript + disableNotifierCbx($('#settings_notifier_can_notify')); diff --git a/app/views/settings/notifiers/show.html.haml b/app/views/settings/notifiers/show.html.haml new file mode 100644 index 000000000..97f82b931 --- /dev/null +++ b/app/views/settings/notifiers/show.html.haml @@ -0,0 +1,5 @@ +#block-signup.block + %h2= title t("layout.settings.notifiers.edit_header") + .content + = form_for @notifier, :url => user_settings_notifier_path(@user), :html => { :class => :form } do |f| + = render :partial => "form", :locals => {:f => f} diff --git a/app/views/user_mailer/issue_assign_notification.en.haml b/app/views/user_mailer/issue_assign_notification.en.haml new file mode 100644 index 000000000..83c33e8ac --- /dev/null +++ b/app/views/user_mailer/issue_assign_notification.en.haml @@ -0,0 +1,7 @@ +%p== Hello, #{@user.name}. + + +%p You have been assigned to issue #{ link_to @issue.title, [@issue.project, @issue] } + + +%p== Support team «ROSA Build System» diff --git a/app/views/user_mailer/issue_assign_notification.haml b/app/views/user_mailer/issue_assign_notification.ru.haml similarity index 100% rename from app/views/user_mailer/issue_assign_notification.haml rename to app/views/user_mailer/issue_assign_notification.ru.haml diff --git a/app/views/user_mailer/new_comment_notification.en.haml b/app/views/user_mailer/new_comment_notification.en.haml new file mode 100644 index 000000000..7c02852bc --- /dev/null +++ b/app/views/user_mailer/new_comment_notification.en.haml @@ -0,0 +1,9 @@ +%p== Hello, #{@user.name}. + + +%p To the issue #{ link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] } added a comment. + +%p "#{ @comment.body }" + + +%p== Support team «ROSA Build System» diff --git a/app/views/user_mailer/new_comment_notification.haml b/app/views/user_mailer/new_comment_notification.ru.haml similarity index 91% rename from app/views/user_mailer/new_comment_notification.haml rename to app/views/user_mailer/new_comment_notification.ru.haml index 88692f64e..315a56b88 100644 --- a/app/views/user_mailer/new_comment_notification.haml +++ b/app/views/user_mailer/new_comment_notification.ru.haml @@ -3,5 +3,7 @@ %p К задаче #{ link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] } был добавлен новый комментарий. +%p "#{ @comment.body }" + %p== Команда поддержки «ROSA Build System» diff --git a/app/views/user_mailer/new_comment_reply_notification.en.haml b/app/views/user_mailer/new_comment_reply_notification.en.haml new file mode 100644 index 000000000..9324062f2 --- /dev/null +++ b/app/views/user_mailer/new_comment_reply_notification.en.haml @@ -0,0 +1,9 @@ +%p== Hello, #{@user.name}. + + +%p Your comment into issue #{ link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] } has been answered. + +%p "#{ @comment.body }" + + +%p== Support team «ROSA Build System» diff --git a/app/views/user_mailer/new_comment_reply_notification.ru.haml b/app/views/user_mailer/new_comment_reply_notification.ru.haml new file mode 100644 index 000000000..48ff0ab4b --- /dev/null +++ b/app/views/user_mailer/new_comment_reply_notification.ru.haml @@ -0,0 +1,9 @@ +%p== Здравствуйте, #{@user.name}. + + +%p На Ваш комментарий в задаче #{ link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] } был дан ответ. + +%p "#{ @comment.body }" + + +%p== Команда поддержки «ROSA Build System» diff --git a/app/views/user_mailer/new_issue_notification.en.haml b/app/views/user_mailer/new_issue_notification.en.haml new file mode 100644 index 000000000..f814fa617 --- /dev/null +++ b/app/views/user_mailer/new_issue_notification.en.haml @@ -0,0 +1,7 @@ +%p== Hello, #{@user.name}. + + +%p To project #{ link_to @issue.project.name, project_path(@issue.project) } has been added an issue #{ link_to @issue.title, [@issue.project, @issue] } + + +%p== Support team «ROSA Build System» diff --git a/app/views/user_mailer/new_issue_notification.haml b/app/views/user_mailer/new_issue_notification.ru.haml similarity index 100% rename from app/views/user_mailer/new_issue_notification.haml rename to app/views/user_mailer/new_issue_notification.ru.haml diff --git a/app/views/user_mailer/new_user_notification.en.haml b/app/views/user_mailer/new_user_notification.en.haml new file mode 100644 index 000000000..d1a0722bf --- /dev/null +++ b/app/views/user_mailer/new_user_notification.en.haml @@ -0,0 +1,12 @@ +%p== Hello, #{@user.name}. + + +%p You have been sign up to project «ROSA Build System» and now can sign in. + + +%p + ==Your email : #{@user.email} + %br/ + ==Your password: #{@user.password} + +%p== Support team «ROSA Build System» diff --git a/app/views/user_mailer/new_user_notification.haml b/app/views/user_mailer/new_user_notification.ru.haml similarity index 100% rename from app/views/user_mailer/new_user_notification.haml rename to app/views/user_mailer/new_user_notification.ru.haml diff --git a/bin/import_srpm.sh b/bin/import_srpm.sh new file mode 100755 index 000000000..6b3bd1512 --- /dev/null +++ b/bin/import_srpm.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# import_srpm.sh: Import SRPM packages to git repo + +# Input data +srpm_path=$1 +git_path=$2 +git_branch=$3 +name=$(rpm -q --qf '[%{Name}]' -p $srpm_path) +version=$(rpm -q --qf '[%{Version}]' -p $srpm_path) +tmp_dir=/tmp/$name-$version-$RANDOM + +# Clone destination repo +mkdir -p $tmp_dir +git clone $git_path $tmp_dir + +# Switch to import branch +cd $tmp_dir +git branch --track $git_branch origin/$git_branch # Try track remote +git branch $git_branch # Try create local +git checkout $git_branch + +# Remove all files except .git +rm -rf $tmp_dir/* +mv $tmp_dir/.git $tmp_dir/git +rm -rf $tmp_dir/.* +mv $tmp_dir/git $tmp_dir/.git + +# Unpack srpm +rpm2cpio $srpm_path > srpm.cpio +cpio -idv < srpm.cpio +rm -f srpm.cpio + +# Commit and push changes +git add -A . +git commit -m "Automatic import for version $version" +git push origin HEAD + +# Cleanup +rm -rf $tmp_dir diff --git a/bin/mount_downloads.sh b/bin/mount_downloads.sh index 6bb68f669..11c2f45ca 100755 --- a/bin/mount_downloads.sh +++ b/bin/mount_downloads.sh @@ -2,9 +2,20 @@ for f in `ls /srv/rosa_build/shared/downloads` do - if [ -d /home/share/platforms/$f ] - then - sudo umount /srv/rosa_build/shared/downloads/$f 2>&1 >> /dev/null - sudo mount --bind /home/share/platforms/$f /srv/rosa_build/shared/downloads/$f - fi + if [ -d /home/share ] + then + # Staging case + if [ -d /home/share/platforms/$f ] + then + sudo umount /srv/rosa_build/shared/downloads/$f 2>&1 >> /dev/null + sudo mount --bind /home/share/platforms/$f /srv/rosa_build/shared/downloads/$f + fi + else + # Production case + if [ -d /share/platforms/$f ] + then + sudo umount /srv/rosa_build/shared/downloads/$f 2>&1 >> /dev/null + sudo mount --bind /share/platforms/$f /srv/rosa_build/shared/downloads/$f + fi + fi done diff --git a/config/application.rb b/config/application.rb index 090e206c5..901d86784 100644 --- a/config/application.rb +++ b/config/application.rb @@ -32,7 +32,7 @@ module Rosa # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] - config.i18n.default_locale = :ru + config.i18n.default_locale = :en config.action_view.javascript_expansions[:defaults] = %w() diff --git a/config/deploy.rb b/config/deploy.rb index d8234e321..b03d867e4 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -1,15 +1,17 @@ $:.unshift(File.expand_path('./lib', ENV['rvm_path'])) set :rvm_type, :user + require 'rvm/capistrano' require 'bundler/capistrano' require 'delayed/recipes' require 'airbrake/capistrano' + set :whenever_command, "bundle exec whenever" # require "whenever/capistrano" -set :default_stage, "staging" -# set :stages, %w(production staging pingwinsoft ui) # auto readed require 'capistrano/ext/multistage' +set :default_stage, "staging" +# set :stages, %w(production staging pingwinsoft) # auto readed # main details ssh_options[:forward_agent] = true @@ -21,20 +23,15 @@ set :user, "rosa" set :use_sudo, false set :keep_releases, 3 +set :scm, :git set :repository, "git@github.com:warpc/rosa-build.git" -# set :git_shallow_clone, 1 -set :scm, "git" -# set :deploy_via, :copy -# set :copy_cache, true +set :deploy_via, :remote_cache require 'lib/recipes/nginx' require 'lib/recipes/unicorn' require 'lib/recipes/bluepill' -namespace :deploy do - # task :restart, :roles => :app, :except => { :no_release => true } do - # run "touch #{current_release}/tmp/restart.txt" - # end +namespace :deploy do task :stub_xml_rpc do path = File.join(release_path, 'config', 'environment.rb') code = %Q{\nrequire 'stub_xml_rpc'\n} @@ -42,25 +39,34 @@ namespace :deploy do run %Q{echo "#{code}" >> #{path}} end - task :symlink_all, :roles => :web do + task :symlink_all, :roles => :app do run "mkdir -p #{fetch :shared_path}/config" + + # Setup DB run "cp -n #{fetch :release_path}/config/database.yml.sample #{fetch :shared_path}/config/database.yml" - run "cp -n #{fetch :release_path}/config/application.yml.sample #{fetch :shared_path}/config/application.yml" run "ln -nfs #{fetch :shared_path}/config/database.yml #{fetch :release_path}/config/database.yml" + + # Setup application + run "cp -n #{fetch :release_path}/config/deploy/application.#{fetch :stage}.yml #{fetch :shared_path}/config/application.yml" run "ln -nfs #{fetch :shared_path}/config/application.yml #{fetch :release_path}/config/application.yml" + # It will survive downloads folder between deployments run "mkdir -p #{fetch :shared_path}/downloads" run "ln -nfs #{fetch :shared_path}/downloads/ #{fetch :release_path}/public/downloads" end + + task :symlink_pids, :roles => :app do + run "cd #{fetch :shared_path}/tmp && ln -nfs ../pids pids" + end end after "deploy:update_code", "deploy:symlink_all", "deploy:migrate" -after "deploy:restart", "delayed_job:restart", "bluepill:restart", "deploy:cleanup" +after "deploy:restart","bluepill:stop", "delayed_job:restart", "deploy:cleanup", "bluepill:start" +after "deploy:setup", "deploy:symlink_pids" require 'cape' namespace :rake_tasks do Cape do - # mirror_rake_tasks mirror_rake_tasks 'db:seeds' end end diff --git a/config/deploy/application.production.yml b/config/deploy/application.production.yml new file mode 100644 index 000000000..450faf330 --- /dev/null +++ b/config/deploy/application.production.yml @@ -0,0 +1,15 @@ +production: + root_path: /share + nginx_log: /srv/rosa_build/shared/log/nginx.access.log + do-not-reply-email: do-not-reply@rosalab.ru + project_name: ABF + repo_project_name: ABF + build_server_ip: 127.0.0.1 + build_server_port: 12555 + build_server_path: /xmlrpc + product_builder_ip: + mdv: 192.168.122.19 + nau5: 192.168.122.203 + product_builder_port: 12554 + product_builder_path: /xmlrpc + distr_types: ['mdv'] \ No newline at end of file diff --git a/config/deploy/application.staging.yml b/config/deploy/application.staging.yml new file mode 100644 index 000000000..6e9ae1cac --- /dev/null +++ b/config/deploy/application.staging.yml @@ -0,0 +1,15 @@ +production: + root_path: /share + nginx_log: /srv/rosa_build/shared/log/nginx.access.log + do-not-reply-email: do-not-reply@rosalab.ru + project_name: ABF + repo_project_name: ABF + build_server_ip: 127.0.0.1 + build_server_port: 12555 + build_server_path: /xmlrpc + product_builder_ip: + mdv: 192.168.122.19 + nau5: 192.168.122.203 + product_builder_port: 12554 + product_builder_path: /xmlrpc + distr_types: ['mdv', 'nau5'] diff --git a/config/deploy/ui.rb b/config/deploy/ui.rb deleted file mode 100644 index 824b9075b..000000000 --- a/config/deploy/ui.rb +++ /dev/null @@ -1,15 +0,0 @@ -set :branch, "ui" - -set :domain, "abf.warpc.ru" # "195.19.76.12" -set :port, 1822 - -role :app, domain -role :web, domain -role :db, domain, :primary => true - -set :application, "rosa_build_#{stage}" -set :deploy_to, "/srv/#{application}" - -# set :unicorn_port, 8082 - -before "deploy:restart", "deploy:stub_xml_rpc" diff --git a/config/environments/production.rb b/config/environments/production.rb index f29b78fce..0d9247b3a 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -36,7 +36,7 @@ Rosa::Application.configure do # Disable delivery errors, bad email addresses will be ignored # config.action_mailer.raise_delivery_errors = false - config.action_mailer.default_url_options = { :host => 'npp-build.rosalab.ru' } + config.action_mailer.default_url_options = { :host => 'rosa-build.rosalab.ru' } # Enable threaded mode # config.threadsafe! diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index 5e4e43321..7f0e522af 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -20,6 +20,8 @@ en: passwords: send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' updated: 'Your password was changed successfully. You are now signed in.' + button: 'Submit' + edit_button: 'Change my password' confirmations: send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' confirmed: 'Your account was successfully confirmed. You are now signed in.' @@ -27,6 +29,11 @@ en: signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.' updated: 'You updated your account successfully.' destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' + sign_up_header: 'Signup' + edit_password_description: Leave blank if you don't want to change it + current_password_description: 'We need your current password to confirm your changes' + cancel: 'Cancel my account' + cancel_confirmation: 'Are you sure?' unlocks: send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' unlocked: 'Your account was successfully unlocked. You are now signed in.' diff --git a/config/locales/en.yml b/config/locales/en.yml index a747bfa69..0708026ca 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,5 +1,705 @@ -# Sample localization file for English. Add more files in this directory for other locales. -# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. - en: - hello: "Hello world" + will_paginate: + previous_label: ‹ Previous + next_label: Next › + page_gap: ... + + datatables: + previous_label: ‹ Prev. + next_label: Next ›b r + first_label: « First + last_label: Last » + empty_label: No data accessible + info_label: Records displayed from _START_ to _END_ total _TOTAL_ + info_empty_label: Records displayed from 0 to 0 total 0 + filtered_label: (filtered of _MAX_) + + layout: + logged_in_as: You logged as + logout: Logout + user_list: User list + edit: Edit + show: View + cancel: Cancel + create: Create + delete: Erase + save: Save + search: Search + clone: Clone + search_by_name: Filter by name + are_you_sure: "Sure?" + login: Login + or: or + yes_: Yes + no_: No + true_: True + false_: False + publish: Publish + add: Add + upload: Upload + not_access: Access denied! + owner: Owner + confirm: Sure? + back: Back + settings: + notifier: Notifier setting + notifiers: + edit_header: Notifier setting + processing: working ... + invalid_content_type: incorrect type + + devise: + shared_links: + sign_in: Sign in + sign_up: Sign up + forgot_password: Forgot your password? + confirm_again: Do not receive the confirmation link? + unlock: Do not receive unlock instructions? + sign_in_through: Sign in by %{provider} + + downloads: + title: Downloads statistic + message: Automatically updated every 5 minutes + refresh_btn: Refresh + + auto_build_lists: + header: Automated build projects + message: All projects build under user repository and architecture i586 + project: Project + action: Action + automate_btn: Automate + cancel_btn: Cancel + not_automated: Not automated + already_automated: Automated + + weekdays: + Monday: Monday + Tuesday: Tuesday + Wednesday: Wednesday + Thursday: Thursday + Friday: Friday + Saturday: Saturday + Sunday: Sunday + + menu: + categories: Catalogue + containers: Containers + downloads: Statistics + event_logs: Event log + build_lists: Task monitoring + groups: Groups + platforms: Platforms + products: Products + projects: Projects + repositories: Repositories + rights: Rights + roles: Roles + users: Users + personal_repository: My repository + auto_build_lists: Automated build + + sessions: + sign_in_header: Sign in + + private_users: + list: List + new: New pair + list_header: Pair login/password + confirm_delete: Are you sure to delete this pair login/password? + confirm_regenerate: Are you sure to regenerate this pair login/password? + regenerate_btn: Regenerate + warning_message: Warning - Old data set as invalid when new data obtaining + + categories: + list: List + new: Create + edit: Edit + platforms: By platform + list_header: Catalogue + new_header: New category + edit_header: Edit category + confirm_delete: Are you sure to delete this category? + + issues: + list: List + edit: Edit + comments_header: Comments + new: New task + list_header: List + confirm_delete: Are you sure to delete this task? + edit_header: Task edit + new_header: New task + statuses: + open: Opened + closed: Closed + any: Any + subscribe: Subscribe + subscribe_btn: Subscribe + unsubscribe_btn: Unsubscribe + + comments: + confirm_delete: Are you sure to delete the comment? + new_header: New comment + edit_header: Editing a comment + + platforms: + admin_id: Owner + build_all: Build all + list: List + new: Create + edit: Edit + new_header: New platform + edit_header: Edit + list_header: Platforms + list_header_main: General + list_header_personal: Personal + list_header_all: All + clone_header: Platform clone + show: Platform + projects: Projects + products: Products + location: Location + repositories: Repositories + back_to_the_list: ⇐To platform list + freeze: Freeze + unfreeze: Unfeeze + confirm_freeze: Are you sure to freeze this platform? + confirm_freeze: Are you sure to clone this platform? + confirm_unfreeze: Are you sure to defrost this platform? + released_suffix: (released) + confirm_delete: Are you sure to delete this platform? + current_platform_header: Current platform + owner: Owner + visibility: Visibility + platform_type: Platform type + distrib_type: Distribution kit type + private_users: Access data + confirm_clone: To clone? + clone: To clone + + event_logs: + list:List + list_header: Event log + + repositories: + list: List + list_header: Repositories + new: New repository + new_header: New repository + show: Repository + location: Location + projects: Projects + new_header: New repository + back_to_the_list: ⇐ List of repositories + confirm_delete: Are you sure to delete this repository? + current_repository_header: Current repository + + personal_repositories: + settings_header: Settings + change_visibility_from_hidden: Replace the status to "Opened" + change_visibility_from_open: Replace the status to "Private" + settings: Settings + show: My repository + private_users: Private repository users + + products: + list: List + new: New product + list_header: Products + clone: Clone + build: Build + new_header: New product + edit_header: Product editing + confirm_delete: Are you sure to delete this product? + + cron_tab_generator: + show: Show cron tab the generator + hide: Hide cron tab the generator + choose: Choose + every_minute: Every minute + every_hour: Every hour + every_day: Every day + every_month: Every month + every_weekday: Every weekdays + minutes: Minutes + hours: Hours + days: Days + months: Months + weekdays: weekdays + + projects: + add: Add + edit: Edit + list: List + list_header: Projects + edit_header: Edit the project + show: Project + build: Build + new_build: New build %{project_name} + confirm_delete: Are you sure to delete this project? + new: New project + new_header: New project + new_header: New project + location: Location + git_repo_location: Path to git repo + current_project_header: Current project + current_build_lists: Current builds + build_button: Start build + add_collaborators: Add collaborators + members: Members + collaborators: Collaborators + groups: Groups + edit_collaborators: Edit collaborators + issues: Issues + + collaborators: + back_to_proj: Back to project + edit: Edit list + add: Add/Remove + list: List + edit_roles: Edit roles + roles_header: Roles to + add_role: Add/Remove a role + input_username: Enter an username + input_groupname: Enter a groupname + + members: + back_to_group: Back to group + edit: Edit list + roles: Roles + add_member: Add member + input_username: Username + + groups: + list: List + new: Create + edit: Edit + members: Members + new_header: New group + edit_header: Edit + list_header: Groups + show: Group + back_to_the_list: ⇐ List of groups + confirm_delete: Are you sure to remove this group? + edit_members: Edit members + + users: + list: List + new: Create + edit: Edit + new_header: New user + edit_header: Edit + list_header: Users + groups: Groups + show: User + back_to_the_list: ⇐ List of users + confirm_delete: Are you sure to remove this user? + own_projects: My projects + part_projects: Participate projects + filter_header: Filter + + git: + repositories: + empty: Empty repository + source: Source + commits: Commits + commit_diff_too_big: Sorry, commit too big! + tags: Tags + branches: Branches + project_versions: Versions + + product_build_lists: + statuses: + '0': 'build' + '1': 'build error' + '2': 'build in progress' + + build_lists: + filter_header: Filter + current: Curent + created_at_start: "Build start from:" + created_at_end: "Build start to:" + notified_at_start: "Last update time by BS from:" + notified_at_end: " Last update time by BS to:" + bs_id_search: 'Id search' + project_name_search: Project name search + bs_id_not_set: Id isn’t set + items_header: Build items + no_items_data: No data + show: Show + cancel_button_header: Action + cancel_button: Cancel + cancel_success: 'Build canceled' + cancel_fail: 'Errors on build cancelling!' + publish_success: 'Build on publish queue' + publish_fail: 'Errors on publish queue!' + container_published: 'Container in a repository' + + build_server_status: + header: Build server status + client_count: Clients count + count_new_task: New task count + count_build_task: Build task count + + items: + statuses: + build_started: Build started + build_error: Build error + dependencies_error: Dependences not found + success: Build complete + unknown: Build waiting + git_error: Git error + + statuses: + build_error: Build error + build_published: Build published + build_publish: Build publishing + failed_publish: Publishing error + dependencies_fail: Dependences not found + waiting_for_response: Waiting for response + build_pending: Build pending + dependency_test_failed: Dependency test failed + binary_test_failed: Binary test failed + build_canceled: Build canceled + success: Build complete + build_started: Build started + platform_not_found: Platform not found + platform_pending: Platforn pending + project_not_found: Project not found + project_version_not_found: Project version not found + + flash: + settings: + saved: Settings saved success + save_error: Setting update error + + + subscribe: + saved: Subscription on notifications for this task is created + destroyed: Subscription on notifications for this task is cleaned + + exception_message: Access violation to this page! + + downloads: + statistics_refreshed: Statistics refreshed + + collaborators: + successfully_changed: Collaborators list successfully changed + error_in_changing: Collaborators list changing error + member_already_added: Member %s already added + group_already_added: Group already added + successfully_added: Member %s successfully added + error_in_adding: Member %s adding error + + members: + successfully_changed: Members list successfully changed + error_in_changing: Members list changing error + successfully_added: Member successfully added + error_in_adding: Member adding error + already_added: User already added + + auto_build_list: + success: Automated build success! + failed: Automated build failed! + cancel: Automated build canceled! + cancel_failed: Automated build canceling failed! + + category: + saved: Category saved + save_error: Category saves error + destroyed: Category deleted + + comment: + saved: Comment saved + save_error: Comment saves error + destroyed: Comment deleted + + issue: + saved: Task saved + save_error: Task saves error + destroyed: Task deleted + + project: + saved: Project saved + save_error: Project saves error + save_warning_ssh_key: Owner of the project must specify in profile a SSH key + destroyed: Project deleted + forked: Project forked + fork_error: Project fork error + + user: + saved: User saved + save_error: User data saves error + destroyed: User account deleted + + group: + saved: Group saved + save_error: Group saves error + destroyed: Group deleted + user_uname_exists: User already exists + + repository: + saved: Repository added + save_error: Repository adding error + destroyed: Repository deleted + project_added: Project added on repository + project_not_added: Project adding error. In this repository already is a project with such name. First remove the old project + project_removed: Project deleted + project_not_removed: Project deleting failed + + product: + saved: Product saved + save_error: Product saves error + build_started: Product build started + destroyed: Product deleted + + platform: + saved: Platform saved + save_error: Platform saves error + freezed: Platform freezed + freeze_error: Platform freezing error, try again + unfreezed: Platform unfreezed + unfreeze_error: Platform unfreezing error, try again + destroyed: Platform deleted + build_all_success: All project build in progress + + build_list: + saved: Project version '%{project_version}' build list, platform '%{bpl}', architecture '%{arch}' creation success + save_error: Project version '%{project_version}' build list, platform '%{bpl}', architecture '%{arch}' creation error + no_project_version_selected: Select any version of project + no_project_version_found: Project version '%{project_version}' not found + no_arch_or_platform_selected: At least one of architecture of platform must selected + wrong_platform: For the main repository its mail platform can be chosen only! + can_not_published: Build publishing with status "Build" available only + + attributes: + password: Password + password_confirmation: Confirmation + remember_me: Remember + name: Name + parent_platform_id: Parent platform + build_list: Build list + + activerecord: + models: + category: Category + repository: Repository + arch: Arch + container: Container + platform: Platform + group: Group + event_log: Event log + project: Project + rpm: RPM + user: User + private_user: Private user + product: Product + product_build_list: Product build list + build_list: Build list + build_list_item: Build list item + download: Statistics + auto_build_list: Auto rebuild list + settings: + notifier: Notifies setting + + attributes: + settings: + notifier: + can_notify: Notifications by e-mail + new_comment: New task comment notifications + new_comment_reply: New reply of comment notifications + new_issue: New task notifications + issue_assign: New task assignment notifications + + auto_build_list: + project_id: Project + project: Project + bpl_id: Repository for saving + bpl: Repository for saving + pl_id: Platform + pl: Platform + arch_id: Architecture + arch: Architecture + + comment: + body: Content + user: Author + + issue: + title: Title + body: Content + user: Assigned + user_id: Assigned + project: Project + status: Status + + private_user: + login: Login + password: Password + + category: + parent_id: Parent + name: Name + + repository: + name: Name + description: Description + platform_id: Platform + platform: Platform + created_at: Created + updated_at: Updated + owner: Owner + + product: + name: Name + platform_id: Platform + build_status: Build status + build_path: ISO path + created_at: Created + updated_at: Updated + ks: Content .ks.template + counter: Content .counter + build_script: Content build + menu: Content .menu.xml + tar: Tar.bz2 file + is_template: Template + system_wide: System + cron_tab: Cront tab + use_cron: Cron usage + + arch: + name: Name + created_at: Created + updated_at: Updated + + container: + name: Name + project_id: Project + project: Project + owner_id: Owner + owner: Owner + created_at: Created + updated_at: Updated + + platform: + name: Name + description: Description + parent_platform_id: Parent platform + parent: Parent platform + released: Released + created_at: Created + updated_at: Updated + distrib_type: Source type + visibility: Status + visibility_types: + open: Open + hidden: Hidden + + event_log: + kind: Event type + created_at: Event date and time + user: User + ip: User IP + protocol: Access protocol + description: Description + + project: + category_id: Category + name: Name + description: Descripton + owner: Owner + visibility: Visibility + repository_id: Repository + repository: Repository + created_at: Created + updated_at: Updated + has_issues: Tracker on + srpm: Import code from src.rpm + + rpm: + name: Name + arch_id: Arch + arch: Arch + project_id: Project + project: Project + created_at: Created + updated_at: Updated + + role: + name: Name + on: Slave + to: Master + use_default: By default + use_default_for_owner: Default by owner + + group: + name: Name + uname: Nickname + owner: Owner + created_at: Created + updated_at: Updated + + user: + name: User + login: Nickname or Email + email: Email + uname: Nickname + ssh_key: SSH key + current_password: Current password + role: Role + created_at: Created + updated_at: Updated + role: System role + language: Language + + product_build_list: + id: Id + product: Product + status: Status + notified_at: Notified at + + build_list: + bs_id: Id + name: Name + container_path: Container path + status: Status + project_id: Project + project: Project + arch_id: Architecture + arch: Architecture + is_circle: Recurrent + notified_at: Notified at + additional_repos: Additional repository + include_repos: Includes repository + updated_at: Updated + created_at: Created + pl: Packet list repository + pl_id: Packet list repository + bpl: Platform + bpl_id: Platform + update_type: Update type + build_requires: Dependable build requires + auto_publish: Automated publising + project_version: Version + user: User + + build_list/item: + name: Name + level: Level + status: Status + version: Version + build_list: Build list + + download: + name: Name + version: Version + distro: Source + platform: Platform + counter: Downloads + + notifications: + subjects: + new_comment_notification: New comment to your task + new_issue_notification: New task added to project + new_user_notification: Registered on project «%{ project_name }» + issue_assign_notification: New task assigned diff --git a/config/locales/ru.yml b/config/locales/ru.yml index efacd3794..ba3f3141f 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -41,7 +41,22 @@ ru: not_access: Нет доступа! owner: Владелец confirm: Уверены? + back: Назад + settings: + notifier: Настройки оповещений + notifiers: + edit_header: Настройки оповещений processing: Обрабатывается... + invalid_content_type: имеет неверный тип + + devise: + shared_links: + sign_in: Войти + sign_up: Зарегистрироваться + forgot_password: Забыли пароль? + confirm_again: Не получили инструкции по подтверждению? + unlock: Не получили инструкции по разблокировке? + sign_in_through: Войти через %{provider} downloads: title: Статистика закачек пакетов @@ -129,6 +144,7 @@ ru: comments: confirm_delete: Вы уверены, что хотите удалить комментарий? new_header: Новый комментарий + edit_header: Редактирование комментария platforms: admin_id: Владелец @@ -267,7 +283,6 @@ ru: new_header: Новый продукт edit_header: Редактирование продукта confirm_delete: Вы уверены, что хотите удалить этот продукт? - invalid_content_type: имеет неверный тип cron_tab_generator: show: Показать cron tab генератор @@ -391,6 +406,7 @@ ru: cancel_fail: 'При отмене сборки произошла ошибка!' publish_success: 'Сборка поставлена в очередь на публикацию.' publish_fail: 'При публикации сборки произошла ошибка!' + container_published: 'Контейнер размещен в репозитории' build_server_status: header: Статус сборочного сервера @@ -405,6 +421,7 @@ ru: dependencies_error: зависимости не найдены success: собран unknown: ожидает сборки + git_error: проблема с гит statuses: build_error: ошибка сборки @@ -422,9 +439,14 @@ ru: platform_not_found: платформа не найдена platform_pending: платформа в процессе создания project_not_found: проект не найден - project_version_not_found: версия не найден + project_version_not_found: версия не найдена flash: + settings: + saved: Настройки успешно сохранены + save_error: При обновлении настроек произошла ошибка + + subscribe: saved: Вы подписаны на оповещения для этой задачи destroyed: Подписка на оповещения для этой задачи убрана @@ -513,6 +535,7 @@ ru: unfreeze_error: Не удалось разморозить платформу, попробуйте еще раз destroyed: Платформа успешно удалена build_all_success: Все проекты успешно отправлены на сборку + clone_success: Клонирование успешно build_list: saved: Билд лист для версии '%{project_version}', платформы '%{bpl}' и архитектуры '%{arch}' создан успешно @@ -566,8 +589,18 @@ ru: build_list_item: Элемент сборочного листа download: Статистика auto_build_list: Автоматическая пересборка пакетов + settings: + notifier: Настройки оповещений attributes: + settings: + notifier: + can_notify: Включить оповещения по электронной почте + new_comment: Оповещать о новом комментарии в задаче + new_comment_reply: Оповещать о новом ответе на мой комментарий + new_issue: Оповещать о новых задачах в моих проектах + issue_assign: Оповещать, когда на меня выставляют задачу + auto_build_list: project_id: Проект project: Проект @@ -672,6 +705,7 @@ ru: updated_at: Обновлен has_issues: Включить трэкер has_wiki: Включить Wiki + srpm: Импортировать код из src.rpm rpm: name: Название @@ -707,6 +741,7 @@ ru: created_at: Создан updated_at: Обновлен role: Роль в системе + language: Язык product_build_list: id: Id diff --git a/config/routes.rb b/config/routes.rb index b868e46ea..8a6c0107e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,14 +1,17 @@ Rosa::Application.routes.draw do # XML RPC match 'api/xmlrpc' => 'rpc#xe_index' - + devise_for :users, :controllers => {:omniauth_callbacks => 'users/omniauth_callbacks'} do get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru' end - + resources :users do resources :groups, :only => [:new, :create, :index] get :autocomplete_user_uname, :on => :collection + namespace :settings do + resource :notifier, :only => [:show, :update] + end end resources :event_logs, :only => :index @@ -164,20 +167,24 @@ Rosa::Application.routes.draw do # Tree match '/projects/:project_id/git/tree/:treeish(/*path)', :controller => "git/trees", :action => :show, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :tree - + # Commits match '/projects/:project_id/git/commits/:treeish(/*path)', :controller => "git/commits", :action => :index, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :commits match '/projects/:project_id/git/commit/:id(.:format)', :controller => "git/commits", :action => :show, :defaults => { :format => :html }, :as => :commit - + # Commit Comments + match '/projects/:project_id/git/commit/:commit_id/comments/:id(.:format)', :controller => "comments", :action => :edit, :as => :edit_project_commit_comment, :via => :get + match '/projects/:project_id/git/commit/:commit_id/comments/:id(.:format)', :controller => "comments", :action => :update, :as => :project_commit_comment, :via => :put + match '/projects/:project_id/git/commit/:commit_id/comments/:id(.:format)', :controller => "comments", :action => :destroy, :via => :delete + match '/projects/:project_id/git/commit/:commit_id/comments(.:format)', :controller => "comments", :action => :create, :as => :project_commit_comments, :via => :post # Blobs match '/projects/:project_id/git/blob/:treeish/*path', :controller => "git/blobs", :action => :show, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :blob match '/projects/:project_id/git/commit/blob/:commit_hash/*path', :controller => "git/blobs", :action => :show, :project_name => /[0-9a-zA-Z_.\-]*/, :as => :blob_commit - + # Blame match '/projects/:project_id/git/blame/:treeish/*path', :controller => "git/blobs", :action => :blame, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :blame match '/projects/:project_id/git/commit/blame/:commit_hash/*path', :controller => "git/blobs", :action => :blame, :as => :blame_commit - - # Raw + + # Raw match '/projects/:project_id/git/raw/:treeish/*path', :controller => "git/blobs", :action => :raw, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :raw match '/projects/:project_id/git/commit/raw/:commit_hash/*path', :controller => "git/blobs", :action => :raw, :as => :raw_commit diff --git a/db/migrate/20111012223306_create_roles.rb b/db/migrate/20111012223306_create_roles.rb new file mode 100644 index 000000000..b5693219d --- /dev/null +++ b/db/migrate/20111012223306_create_roles.rb @@ -0,0 +1,14 @@ +class CreateRoles < ActiveRecord::Migration + def self.up + create_table :roles do |t| + t.integer :id + t.string :name + + t.timestamps + end + end + + def self.down + drop_table :roles + end +end diff --git a/db/migrate/20111019173246_create_role_lines.rb b/db/migrate/20111019173246_create_role_lines.rb new file mode 100644 index 000000000..84aa4e3de --- /dev/null +++ b/db/migrate/20111019173246_create_role_lines.rb @@ -0,0 +1,13 @@ +class CreateRoleLines < ActiveRecord::Migration + def self.up + create_table :role_lines do |t| + t.integer :role_id + t.integer :relation_id + t.timestamps + end + end + + def self.down + drop_table :role_lines + end +end diff --git a/db/migrate/20120111072106_create_settings_notifiers.rb b/db/migrate/20120111072106_create_settings_notifiers.rb new file mode 100644 index 000000000..b8517a9e9 --- /dev/null +++ b/db/migrate/20120111072106_create_settings_notifiers.rb @@ -0,0 +1,19 @@ +class CreateSettingsNotifiers < ActiveRecord::Migration + def self.up + create_table :settings_notifiers do |t| + t.integer :user_id, :null => false + + t.boolean :can_notify, :default => true + t.boolean :new_comment, :default => true + t.boolean :new_comment_reply, :default => true + t.boolean :new_issue, :default => true + t.boolean :issue_assign, :default => true + + t.timestamps + end + end + + def self.down + drop_table :settings_notifiers + end +end diff --git a/db/migrate/20120111080234_change_commentable_id.rb b/db/migrate/20120111080234_change_commentable_id.rb new file mode 100644 index 000000000..60c3c3268 --- /dev/null +++ b/db/migrate/20120111080234_change_commentable_id.rb @@ -0,0 +1,9 @@ +class ChangeCommentableId < ActiveRecord::Migration + def self.up + change_column :comments, :commentable_id, :string + end + + def self.down + change_column :comments, :commentable_id, :integer + end +end diff --git a/db/migrate/20120111135443_add_settings_notifier_to_all_users.rb b/db/migrate/20120111135443_add_settings_notifier_to_all_users.rb new file mode 100644 index 000000000..de018150a --- /dev/null +++ b/db/migrate/20120111135443_add_settings_notifier_to_all_users.rb @@ -0,0 +1,13 @@ +class AddSettingsNotifierToAllUsers < ActiveRecord::Migration + def self.up + User.all.each do |user| + user.create_notifier + end + end + + def self.down + User.all.each do |user| + user.notifier.destroy + end + end +end diff --git a/db/migrate/20120113121748_add_issue_status_default_value.rb b/db/migrate/20120113121748_add_issue_status_default_value.rb new file mode 100644 index 000000000..bbc58f3cc --- /dev/null +++ b/db/migrate/20120113121748_add_issue_status_default_value.rb @@ -0,0 +1,9 @@ +class AddIssueStatusDefaultValue < ActiveRecord::Migration + def self.up + change_column :issues, :status, :string, :default => 'open' + end + + def self.down + change_column :issues, :status, :string, :null => true + end +end diff --git a/db/migrate/20120113151305_add_package_version_to_build_lists.rb b/db/migrate/20120113151305_add_package_version_to_build_lists.rb new file mode 100644 index 000000000..d416e3fa5 --- /dev/null +++ b/db/migrate/20120113151305_add_package_version_to_build_lists.rb @@ -0,0 +1,9 @@ +class AddPackageVersionToBuildLists < ActiveRecord::Migration + def self.up + add_column :build_lists, :package_version, :string + end + + def self.down + remove_column :build_lists, :package_version + end +end diff --git a/db/migrate/20120113212924_add_commit_hash_to_build_lists.rb b/db/migrate/20120113212924_add_commit_hash_to_build_lists.rb new file mode 100644 index 000000000..504d49f9a --- /dev/null +++ b/db/migrate/20120113212924_add_commit_hash_to_build_lists.rb @@ -0,0 +1,9 @@ +class AddCommitHashToBuildLists < ActiveRecord::Migration + def self.up + add_column :build_lists, :commit_hash, :string + end + + def self.down + remove_column :build_lists, :commit_hash + end +end diff --git a/db/migrate/20120117110723_add_language_to_users.rb b/db/migrate/20120117110723_add_language_to_users.rb new file mode 100644 index 000000000..4bf0cec48 --- /dev/null +++ b/db/migrate/20120117110723_add_language_to_users.rb @@ -0,0 +1,9 @@ +class AddLanguageToUsers < ActiveRecord::Migration + def self.up + add_column :users, :language, :string, :default => 'en' + end + + def self.down + remove_column :users, :language + end +end diff --git a/db/migrate/20120124101727_add_srpm_columns_to_projects.rb b/db/migrate/20120124101727_add_srpm_columns_to_projects.rb new file mode 100644 index 000000000..3aa569326 --- /dev/null +++ b/db/migrate/20120124101727_add_srpm_columns_to_projects.rb @@ -0,0 +1,11 @@ +class AddSrpmColumnsToProjects < ActiveRecord::Migration + def self.up + change_table :projects do |t| + t.has_attached_file :srpm + end + end + + def self.down + drop_attached_file :projects, :srpm + end +end diff --git a/db/schema.rb b/db/schema.rb index 66760c9f1..4ed423246 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -72,6 +72,8 @@ ActiveRecord::Schema.define(:version => 20120126214447) do t.text "include_repos" t.integer "user_id" t.boolean "auto_publish", :default => true + t.string "package_version" + t.string "commit_hash" end add_index "build_lists", ["arch_id"], :name => "index_build_lists_on_arch_id" @@ -87,7 +89,7 @@ ActiveRecord::Schema.define(:version => 20120126214447) do end create_table "comments", :force => true do |t| - t.integer "commentable_id" + t.string "commentable_id" t.string "commentable_type" t.integer "user_id" t.text "body" @@ -159,13 +161,20 @@ ActiveRecord::Schema.define(:version => 20120126214447) do t.integer "user_id" t.string "title" t.text "body" - t.string "status" + t.string "status", :default => "open" t.datetime "created_at" t.datetime "updated_at" end add_index "issues", ["project_id", "serial_id"], :name => "index_issues_on_project_id_and_serial_id", :unique => true + create_table "permissions", :force => true do |t| + t.integer "right_id" + t.integer "role_id" + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "platforms", :force => true do |t| t.string "description" t.string "name" @@ -237,7 +246,7 @@ ActiveRecord::Schema.define(:version => 20120126214447) do t.integer "category_id" t.text "description" t.string "ancestry" - t.boolean "has_wiki" + t.boolean "has_wiki", :default => false t.boolean "has_issues", :default => true end @@ -263,6 +272,14 @@ ActiveRecord::Schema.define(:version => 20120126214447) do t.string "owner_type" end + create_table "rights", :force => true do |t| + t.string "name", :null => false + t.string "controller", :null => false + t.string "action", :null => false + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "rpms", :force => true do |t| t.string "name", :null => false t.integer "arch_id", :null => false @@ -274,6 +291,17 @@ ActiveRecord::Schema.define(:version => 20120126214447) do add_index "rpms", ["project_id", "arch_id"], :name => "index_rpms_on_project_id_and_arch_id" add_index "rpms", ["project_id"], :name => "index_rpms_on_project_id" + create_table "settings_notifiers", :force => true do |t| + t.integer "user_id", :null => false + t.boolean "can_notify", :default => true + t.boolean "new_comment", :default => true + t.boolean "new_comment_reply", :default => true + t.boolean "new_issue", :default => true + t.boolean "issue_assign", :default => true + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "subscribes", :force => true do |t| t.integer "subscribeable_id" t.string "subscribeable_type" @@ -284,9 +312,9 @@ ActiveRecord::Schema.define(:version => 20120126214447) do create_table "users", :force => true do |t| t.string "name" - t.string "email", :default => "", :null => false - t.string "encrypted_password", :limit => 128, :default => "", :null => false - t.string "password_salt", :default => "", :null => false + t.string "email", :default => "", :null => false + t.string "encrypted_password", :limit => 128, :default => "", :null => false + t.string "password_salt", :default => "", :null => false t.string "reset_password_token" t.string "remember_token" t.datetime "remember_created_at" @@ -296,6 +324,7 @@ ActiveRecord::Schema.define(:version => 20120126214447) do t.string "uname" t.string "role" t.integer "own_projects_count", :default => 0, :null => false + t.string "language", :default => "en" end add_index "users", ["email"], :name => "index_users_on_email", :unique => true diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake index d3c5cce79..88f65117d 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/import.rake @@ -5,8 +5,9 @@ namespace :import do desc "Load projects" task :projects => :environment do source = ENV['SOURCE'] || 'http://dl.dropbox.com/u/984976/package_list.txt' - owner = User.find_by_uname(ENV['OWNER_UNAME']) || Group.find_by_uname(ENV['OWNER_UNAME']) || User.first - platform = Platform.find_by_name(ENV['PLATFORM_NAME']) # 'mandriva2011' + #owner = User.find_by_uname(ENV['OWNER_UNAME']) || Group.find_by_uname(ENV['OWNER_UNAME']) || User.first + owner = Group.find_by_uname("npp_team") + platform = Platform.find_by_name("RosaNPP") # RosaNPP repo = platform.repositories.first rescue nil say "START import projects from '#{source}' for '#{owner.uname}'.#{repo ? " To repo '#{platform.name}/#{repo.name}'." : ''}" ask 'Press enter to continue' diff --git a/public/javascripts/application.js b/public/javascripts/application.js index b2617a1c7..2ab692666 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -1,3 +1,13 @@ +function disableNotifierCbx(global_cbx) { + if ($(global_cbx).attr('checked')) { + $('.notify_cbx').removeAttr('disabled'); + $('.notify_cbx').each(function(i,el) { $(el).prev().removeAttr('disabled'); }) + } else { + $('.notify_cbx').attr('disabled', 'disabled'); + $('.notify_cbx').each(function(i,el) { $(el).prev().attr('disabled', 'disabled'); }) + } +} + $(document).ready(function() { $('select#build_list_pl_id').change(function() { var platform_id = $(this).val(); @@ -29,4 +39,8 @@ $(document).ready(function() { } }); }); + + $('#settings_notifier_can_notify').click(function() { + disableNotifierCbx($(this)); + }); }); diff --git a/spec/controllers/build_lists_controller_spec.rb b/spec/controllers/build_lists_controller_spec.rb index a3e088c63..79035ac97 100644 --- a/spec/controllers/build_lists_controller_spec.rb +++ b/spec/controllers/build_lists_controller_spec.rb @@ -27,6 +27,8 @@ describe BuildListsController do end shared_examples_for 'create build list' do + before {test_git_commit(@project)} + it 'should be able to perform new action' do get :new, :project_id => @project.id response.should render_template(:new) @@ -36,6 +38,17 @@ describe BuildListsController do post :create, {:project_id => @project.id}.merge(@create_params) response.should redirect_to(@project) end + + it 'should save correct commit_hash for branch based build' do + post :create, {:project_id => @project.id}.merge(@create_params).deep_merge(:build_list => {:project_version => "master_latest"}) + @project.build_lists.last.commit_hash.should == @project.git_repository.commits('master').last.id + end + + it 'should save correct commit_hash for tag based build' do + system("cd #{@project.git_repository.path} && git tag 4.7.5.3") # TODO REDO through grit + post :create, {:project_id => @project.id}.merge(@create_params).deep_merge(:build_list => {:project_version => "4.7.5.3"}) + @project.build_lists.last.commit_hash.should == @project.git_repository.commits('4.7.5.3').last.id + end end shared_examples_for 'not create build list' do @@ -57,7 +70,7 @@ describe BuildListsController do platform = Factory(:platform_with_repos) @create_params = { :build_list => { - :project_version => 'v1.0', + :project_version => 'master_latest', :pl_id => platform.id, :update_type => 'security', :include_repos => [platform.repositories.first.id] @@ -299,14 +312,23 @@ describe BuildListsController do let(:build_list) { Factory(:build_list_core) } describe 'publish_build' do + before { test_git_commit(build_list.project); build_list.update_attribute :commit_hash, build_list.project.git_repository.commits('master').last.id } + def do_get(status) - get :publish_build, :id => build_list.bs_id, :status => status + get :publish_build, :id => build_list.bs_id, :status => status, :version => '4.7.5.3', :release => '1' build_list.reload end it { do_get(BuildServer::SUCCESS); response.should be_ok } + it 'should create correct git tag for correct commit' do + do_get(BuildServer::SUCCESS) + build_list.project.git_repository.tags.last.name.should == build_list.package_version + build_list.project.git_repository.commits(build_list.package_version).last.id.should == build_list.commit_hash + end it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildList::BUILD_PUBLISHED) } + it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :package_version).to('4.7.5.3-1') } it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :status).to(BuildList::FAILED_PUBLISH) } + it { lambda{ do_get(BuildServer::ERROR) }.should_not change(build_list, :package_version) } it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :notified_at) } end diff --git a/spec/controllers/comments_controller_for_commit_spec.rb b/spec/controllers/comments_controller_for_commit_spec.rb new file mode 100644 index 000000000..70daadb17 --- /dev/null +++ b/spec/controllers/comments_controller_for_commit_spec.rb @@ -0,0 +1,152 @@ +require 'spec_helper' + +shared_examples_for 'user with create comment rights for commits' do + it 'should be able to perform create action' do + post :create, @create_params + response.should redirect_to(commit_path(@project, @commit.id)) + end + + it 'should create subscribe object into db' do + lambda{ post :create, @create_params }.should change{ Comment.count }.by(1) + end +end + +shared_examples_for 'user with update own comment rights for commits' do + it 'should be able to perform update action' do + put :update, {:id => @own_comment.id}.merge(@update_params) + response.should redirect_to(commit_path(@project, @commit.id)) + end + + it 'should update subscribe body' do + put :update, {:id => @own_comment.id}.merge(@update_params) + @own_comment.reload.body.should == 'updated' + end +end + +shared_examples_for 'user with update stranger comment rights for commits' do + it 'should be able to perform update action' do + put :update, {:id => @comment.id}.merge(@update_params) + response.should redirect_to(commit_path(@project, @commit.id)) + end + + it 'should update comment title' do + put :update, {:id => @comment.id}.merge(@update_params) + @comment.reload.body.should == 'updated' + end +end + +shared_examples_for 'user without update stranger comment rights for commits' do + it 'should not be able to perform update action' do + put :update, {:id => @comment.id}.merge(@update_params) + response.should redirect_to(forbidden_path) + end + + it 'should not update comment title' do + put :update, {:id => @comment.id}.merge(@update_params) + @comment.reload.body.should_not == 'updated' + end +end + +shared_examples_for 'user without destroy comment rights for commits' do + it 'should not be able to perform destroy action' do + delete :destroy, :id => @comment.id, :commit_id => @commit.id, :project_id => @project.id + response.should redirect_to(forbidden_path) + end + + it 'should not reduce comments count' do + lambda{ delete :destroy, :id => @comment.id, :commit_id => @commit.id, :project_id => @project.id }.should change{ Comment.count }.by(0) + end +end + +#shared_examples_for 'user with destroy rights' do +# it 'should be able to perform destroy action' do +# delete :destroy, :id => @comment.id, :issue_id => @issue.serial_id, :project_id => @project.id +# response.should redirect_to([@project, @issue]) +# end +# +# it 'should reduce comments count' do +# lambda{ delete :destroy, :id => @comment.id, :issue_id => @issue.serial_id, :project_id => @project.id }.should change{ Comment.count }.by(-1) +# end +#end + +describe CommentsController do + before(:each) do + stub_rsync_methods + + @project = Factory(:project) + %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.git_repository.path}) # maybe FIXME ? + @commit = @project.git_repository.commits.first + + @comment = Factory(:comment) + @comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id) + @create_params = {:comment => {:body => 'I am a comment!'}, :project_id => @project.id, :commit_id => @commit.id} + @update_params = {:comment => {:body => 'updated'}, :project_id => @project.id, :commit_id => @commit.id} + + any_instance_of(Project, :versions => ['v1.0', 'v2.0']) + + @request.env['HTTP_REFERER'] = commit_path(@project, @commit.id) + end + + context 'for project admin user' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') + @own_comment = Factory(:comment, :user => @user) + @own_comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id) + end + + it_should_behave_like 'user with create comment rights for commits' + it_should_behave_like 'user with update stranger comment rights for commits' + it_should_behave_like 'user with update own comment rights for commits' + it_should_behave_like 'user without destroy comment rights for commits' + end + + context 'for project owner user' do + before(:each) do + @user = @project.owner + set_session_for(@user) + @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') + + @own_comment = Factory(:comment, :user => @user) + @own_comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id) + end + + it_should_behave_like 'user with create comment rights for commits' + it_should_behave_like 'user with update stranger comment rights for commits' + it_should_behave_like 'user with update own comment rights for commits' + it_should_behave_like 'user without destroy comment rights for commits' + end + + context 'for project reader user' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'reader') + + @own_comment = Factory(:comment, :user => @user) + @own_comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id) + end + + it_should_behave_like 'user with create comment rights for commits' + it_should_behave_like 'user without update stranger comment rights for commits' + it_should_behave_like 'user with update own comment rights for commits' + it_should_behave_like 'user without destroy comment rights for commits' + end + + context 'for project writer user' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'writer') + + @own_comment = Factory(:comment, :user => @user) + @own_comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id) + end + + it_should_behave_like 'user with create comment rights for commits' + it_should_behave_like 'user without update stranger comment rights for commits' + it_should_behave_like 'user with update own comment rights for commits' + it_should_behave_like 'user without destroy comment rights for commits' + end +end diff --git a/spec/controllers/comments_controller_spec.rb b/spec/controllers/comments_controller_spec.rb index c93ac57f0..d8cd8d002 100644 --- a/spec/controllers/comments_controller_spec.rb +++ b/spec/controllers/comments_controller_spec.rb @@ -49,12 +49,12 @@ end shared_examples_for 'user without destroy comment rights' do it 'should not be able to perform destroy action' do - delete :destroy, :id => @comment.id, :issue_id => @issue.id, :project_id => @project.id + delete :destroy, :id => @comment.id, :issue_id => @issue.serial_id, :project_id => @project.id response.should redirect_to(forbidden_path) end it 'should not reduce comments count' do - lambda{ delete :destroy, :id => @comment.id, :issue_id => @issue.id, :project_id => @project.id }.should change{ Issue.count }.by(0) + lambda{ delete :destroy, :id => @comment.id, :issue_id => @issue.serial_id, :project_id => @project.id }.should change{ Issue.count }.by(0) end end @@ -77,8 +77,8 @@ describe CommentsController do @issue = Factory(:issue, :project_id => @project.id) @comment = Factory(:comment, :commentable => @issue) - @create_params = {:comment => {:body => 'I am a comment!'}, :project_id => @project.id, :issue_id => @issue.id} - @update_params = {:comment => {:body => 'updated'}, :project_id => @project.id, :issue_id => @issue.id} + @create_params = {:comment => {:body => 'I am a comment!'}, :project_id => @project.id, :issue_id => @issue.serial_id} + @update_params = {:comment => {:body => 'updated'}, :project_id => @project.id, :issue_id => @issue.serial_id} any_instance_of(Project, :versions => ['v1.0', 'v2.0']) diff --git a/spec/controllers/settings/notifiers_controller_spec.rb b/spec/controllers/settings/notifiers_controller_spec.rb new file mode 100644 index 000000000..3ffcced81 --- /dev/null +++ b/spec/controllers/settings/notifiers_controller_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Settings::NotifiersController do + +end diff --git a/spec/factories/build_list_factory.rb b/spec/factories/build_list_factory.rb index 10c4fc3b5..751a6ea09 100644 --- a/spec/factories/build_list_factory.rb +++ b/spec/factories/build_list_factory.rb @@ -8,6 +8,7 @@ Factory.define(:build_list) do |p| p.build_requires true p.update_type 'security' p.include_repos {|bl| bl.pl.repositories.map(&:id)} + p.commit_hash '1234567890abcdef1234567890abcdef12345678' end Factory.define(:build_list_core, :parent => :build_list) do |p| diff --git a/spec/factories/settings_notifiers.rb b/spec/factories/settings_notifiers.rb new file mode 100644 index 000000000..d189db60e --- /dev/null +++ b/spec/factories/settings_notifiers.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :notifier do + end +end \ No newline at end of file diff --git a/spec/helpers/settings/notifiers_helper_spec.rb b/spec/helpers/settings/notifiers_helper_spec.rb new file mode 100644 index 000000000..9b16f8bda --- /dev/null +++ b/spec/helpers/settings/notifiers_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the Settings::NotifiersHelper. For example: +# +# describe Settings::NotifiersHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe Settings::NotifiersHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 8d004b3ed..ff86fcc9d 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -2,4 +2,118 @@ require "spec_helper" describe UserMailer do pending "add some examples to (or delete) #{__FILE__}" + + context 'On Issue create' do + before(:each) do + stub_rsync_methods + + @project = Factory(:project) + @issue_user = Factory(:user) + + any_instance_of(Project, :versions => ['v1.0', 'v2.0']) + + @issue = Factory(:issue, :project_id => @project.id, :user_id => @issue_user.id) + @email = UserMailer.new_issue_notification(@issue, @issue_user).deliver + end + + it 'should have correct subject' do + @email.subject.should == I18n.t("notifications.subjects.new_issue_notification") + end + + it 'should render receiver email' do + @email.to.should == [@issue_user.email] + end + + it 'should render the sender email' do + @email.from.should == [APP_CONFIG['do-not-reply-email']] + end + + it 'should assign user name' do + @email.body.encoded.should match(@issue_user.name) + end + + it 'should assign issue project name' do + @email.body.encoded.should match(@issue.project.name) + end + + it 'should assign issue title' do + @email.body.encoded.should match(@issue.title) + end + end + + context 'On Issue assign' do + before(:each) do + stub_rsync_methods + + @project = Factory(:project) + @issue_user = Factory(:user) + @user = Factory(:user) + + any_instance_of(Project, :versions => ['v1.0', 'v2.0']) + + @issue = Factory(:issue, :project_id => @project.id, :user_id => @issue_user.id) + @email = UserMailer.issue_assign_notification(@issue, @user).deliver + end + + it 'should have correct subject' do + @email.subject.should == I18n.t("notifications.subjects.issue_assign_notification") + end + + it 'should render receiver email' do + @email.to.should == [@user.email] + end + + it 'should render the sender email' do + @email.from.should == [APP_CONFIG['do-not-reply-email']] + end + + it 'should assign user name' do + @email.body.encoded.should match(@user.name) + end + + it 'should assign issue title' do + @email.body.encoded.should match(@issue.title) + end + end + + + context 'On Comment create' do + before(:each) do + stub_rsync_methods + + @project = Factory(:project) + @issue_user = Factory(:user) + @user = Factory(:user) + + any_instance_of(Project, :versions => ['v1.0', 'v2.0']) + + @issue = Factory(:issue, :project_id => @project.id, :user_id => @issue_user.id) + @comment = Factory(:comment, :commentable => @issue, :user_id => @user.id) + @email = UserMailer.new_comment_notification(@comment, @issue_user).deliver + end + + it 'should have correct subject' do + @email.subject.should == I18n.t("notifications.subjects.new_comment_notification") + end + + it 'should render receiver email' do + @email.to.should == [@issue_user.email] + end + + it 'should render the sender email' do + @email.from.should == [APP_CONFIG['do-not-reply-email']] + end + + it 'should assign user name' do + @email.body.encoded.should match(@issue_user.name) + end + + it 'should assign comment body' do + @email.body.encoded.should match(@comment.body) + end + + it 'should assign issue title' do + @email.body.encoded.should match(@issue.title) + end + end end diff --git a/spec/models/cancan_spec.rb b/spec/models/cancan_spec.rb index e245c19ff..bafc774d1 100644 --- a/spec/models/cancan_spec.rb +++ b/spec/models/cancan_spec.rb @@ -91,7 +91,7 @@ describe CanCan do @ability.should be_able_to(:read, @admin) end - it "shoud be able to read index AutoBuildList" do + pending "shoud be able to read index AutoBuildList" do @ability.should be_able_to(:index, AutoBuildList) end diff --git a/spec/models/comment_for_commit_spec.rb b/spec/models/comment_for_commit_spec.rb new file mode 100644 index 000000000..938c4db7e --- /dev/null +++ b/spec/models/comment_for_commit_spec.rb @@ -0,0 +1,135 @@ +require 'spec_helper' +require "cancan/matchers" + +def set_comments_data_for_commit + @ability = Ability.new(@user) + + @project = Factory(:project) + %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.git_repository.path}) # maybe FIXME ? + @commit = @project.git_repository.commits.first + + @comment = Factory(:comment, :user => @user) + @comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id) + + @stranger_comment = Factory(:comment, :user => @stranger) + @stranger_comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id, :project => @project) + + @create_params = {:commentable_type => @commit.class.name, :commentable_id => @commit.id, :user => @user, :project => @project} + + any_instance_of(Project, :versions => ['v1.0', 'v2.0']) +end + +describe Comment do + context 'for global admin user' do + before(:each) do + @user = Factory(:admin) + @stranger = Factory(:user) + + set_comments_data_for_commit + end + + it 'should create comment' do + @ability.should be_able_to(:create, Comment.new(@create_params)) + end + + pending "sends an e-mail" do + ActionMailer::Base.deliveries.last.to.include?(@stranger.email).should == true + end + + it 'should update comment' do + @ability.should be_able_to(:update, @comment) + end + + it 'should update stranger comment' do + @ability.should be_able_to(:update, @stranger_comment) + end + + it 'should destroy own comment' do + @ability.should be_able_to(:destroy, @comment) + end + + it 'should destroy stranger comment' do + @ability.should be_able_to(:destroy, @stranger_comment) + end + end + + context 'for project admin user' do + before(:each) do + @user = Factory(:user) + @stranger = Factory(:user) + + set_comments_data_for_commit + + @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') + end + + it 'should create comment' do + @ability.should be_able_to(:create, Comment.new(@create_params)) + end + + it 'should update comment' do + @ability.should be_able_to(:update, @comment) + end + + it 'should update stranger comment' do + @ability.should be_able_to(:update, @stranger_comment) + end + + it 'should not destroy comment' do + @ability.should_not be_able_to(:destroy, @comment) + end + end + + context 'for project owner user' do + before(:each) do + @user = Factory(:user) + @stranger = Factory(:user) + + set_comments_data_for_commit + + @project.update_attribute(:owner, @user) + @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') + end + + it 'should create comment' do + @ability.should be_able_to(:create, Comment.new(@create_params)) + end + + it 'should update comment' do + @ability.should be_able_to(:update, @comment) + end + + it 'should update stranger comment' do + @ability.should be_able_to(:update, @stranger_comment) + end + + it 'should not destroy comment' do + @ability.should_not be_able_to(:destroy, @comment) + end + end + + context 'for simple user' do + before(:each) do + @user = Factory(:user) + @stranger = Factory(:user) + + set_comments_data_for_commit + end + + it 'should create comment' do + @ability.should be_able_to(:create, Comment.new(@create_params)) + end + + it 'should update comment' do + @ability.should be_able_to(:update, @comment) + end + + it 'should not update stranger comment' do + @ability.should_not be_able_to(:update, @stranger_comment) + end + + it 'should not destroy comment' do + @ability.should_not be_able_to(:destroy, @comment) + end + end +end diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index 0b969c134..a8b8b41dc 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require "cancan/matchers" -def set_testable_data +def set_commentable_data @ability = Ability.new(@user) @project = Factory(:project) @@ -19,13 +19,17 @@ describe Comment do @user = Factory(:admin) @stranger = Factory(:user) - set_testable_data + set_commentable_data end it 'should create comment' do @ability.should be_able_to(:create, Comment.new(:commentable => @issue, :user => @user)) end + pending "sends an e-mail" do + ActionMailer::Base.deliveries.last.to.include?(@stranger.email).should == true + end + it 'should update comment' do @ability.should be_able_to(:update, @comment) end @@ -35,7 +39,7 @@ describe Comment do end it 'should destroy own comment' do - @ability.should be_able_to(:destroy, @comment) + @ability.should be_able_to(:destroy, @comment) end it 'should destroy stranger comment' do @@ -48,7 +52,7 @@ describe Comment do @user = Factory(:user) @stranger = Factory(:user) - set_testable_data + set_commentable_data @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') end @@ -75,7 +79,7 @@ describe Comment do @user = Factory(:user) @stranger = Factory(:user) - set_testable_data + set_commentable_data @project.update_attribute(:owner, @user) @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') @@ -103,7 +107,7 @@ describe Comment do @user = Factory(:user) @stranger = Factory(:user) - set_testable_data + set_commentable_data end it 'should create comment' do diff --git a/spec/models/settings/notifier_spec.rb b/spec/models/settings/notifier_spec.rb new file mode 100644 index 000000000..fb73cfe7d --- /dev/null +++ b/spec/models/settings/notifier_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Settings::Notifier do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a79b3ce74..095a7030f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -37,6 +37,11 @@ def stub_rsync_methods any_instance_of(Platform, :umount_directory_for_rsync => true) end +def test_git_commit(project) + project.git_repository.repo.index.add('test', 'TEST') + project.git_repository.repo.index.commit('Test commit') +end + Delayed::Worker.delay_jobs = false # Execute all jobs realtime # Add testing root_path diff --git a/spec/tests.git/HEAD b/spec/tests.git/HEAD new file mode 100644 index 000000000..df9ee5473 --- /dev/null +++ b/spec/tests.git/HEAD @@ -0,0 +1 @@ +bdc8b580b5b583aeb43efb19aac2ab8ce5566dff diff --git a/spec/tests.git/config b/spec/tests.git/config new file mode 100644 index 000000000..d38f8c6fe --- /dev/null +++ b/spec/tests.git/config @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = git://github.com/tpope/vim-ragtag.git +[branch "master"] + remote = origin + merge = refs/heads/master diff --git a/spec/tests.git/description b/spec/tests.git/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/spec/tests.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/spec/tests.git/hooks/applypatch-msg.sample b/spec/tests.git/hooks/applypatch-msg.sample new file mode 100755 index 000000000..8b2a2fe84 --- /dev/null +++ b/spec/tests.git/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +: diff --git a/spec/tests.git/hooks/commit-msg.sample b/spec/tests.git/hooks/commit-msg.sample new file mode 100755 index 000000000..b58d1184a --- /dev/null +++ b/spec/tests.git/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/spec/tests.git/hooks/post-commit.sample b/spec/tests.git/hooks/post-commit.sample new file mode 100755 index 000000000..22668216a --- /dev/null +++ b/spec/tests.git/hooks/post-commit.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script that is called after a successful +# commit is made. +# +# To enable this hook, rename this file to "post-commit". + +: Nothing diff --git a/spec/tests.git/hooks/post-receive.sample b/spec/tests.git/hooks/post-receive.sample new file mode 100755 index 000000000..7a83e17ab --- /dev/null +++ b/spec/tests.git/hooks/post-receive.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script for the "post-receive" event. +# +# The "post-receive" script is run after receive-pack has accepted a pack +# and the repository has been updated. It is passed arguments in through +# stdin in the form +# +# For example: +# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master +# +# see contrib/hooks/ for a sample, or uncomment the next line and +# rename the file to "post-receive". + +#. /usr/share/doc/git-core/contrib/hooks/post-receive-email diff --git a/spec/tests.git/hooks/post-update.sample b/spec/tests.git/hooks/post-update.sample new file mode 100755 index 000000000..ec17ec193 --- /dev/null +++ b/spec/tests.git/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/spec/tests.git/hooks/pre-applypatch.sample b/spec/tests.git/hooks/pre-applypatch.sample new file mode 100755 index 000000000..b1f187c2e --- /dev/null +++ b/spec/tests.git/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +: diff --git a/spec/tests.git/hooks/pre-commit.sample b/spec/tests.git/hooks/pre-commit.sample new file mode 100755 index 000000000..b187c4bb1 --- /dev/null +++ b/spec/tests.git/hooks/pre-commit.sample @@ -0,0 +1,46 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test "$(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0')" +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +exec git diff-index --check --cached $against -- diff --git a/spec/tests.git/hooks/pre-rebase.sample b/spec/tests.git/hooks/pre-rebase.sample new file mode 100755 index 000000000..f0f6da314 --- /dev/null +++ b/spec/tests.git/hooks/pre-rebase.sample @@ -0,0 +1,172 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +exit 0 + +<<\DOC_END +################################################################ + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/spec/tests.git/hooks/prepare-commit-msg.sample b/spec/tests.git/hooks/prepare-commit-msg.sample new file mode 100755 index 000000000..f093a02ec --- /dev/null +++ b/spec/tests.git/hooks/prepare-commit-msg.sample @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git a/spec/tests.git/hooks/update.sample b/spec/tests.git/hooks/update.sample new file mode 100755 index 000000000..71ab04edc --- /dev/null +++ b/spec/tests.git/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/spec/tests.git/index b/spec/tests.git/index new file mode 100644 index 000000000..29cca27d4 Binary files /dev/null and b/spec/tests.git/index differ diff --git a/spec/tests.git/info/exclude b/spec/tests.git/info/exclude new file mode 100644 index 000000000..a5196d1be --- /dev/null +++ b/spec/tests.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/spec/tests.git/logs/HEAD b/spec/tests.git/logs/HEAD new file mode 100644 index 000000000..f47abecdc --- /dev/null +++ b/spec/tests.git/logs/HEAD @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 bdc8b580b5b583aeb43efb19aac2ab8ce5566dff Alexander 1325695134 +0600 clone: from git://github.com/tpope/vim-ragtag.git +bdc8b580b5b583aeb43efb19aac2ab8ce5566dff bdc8b580b5b583aeb43efb19aac2ab8ce5566dff Alexander 1325695134 +0600 checkout: moving from master to bdc8b580b5b583aeb43efb19aac2ab8ce5566dff diff --git a/spec/tests.git/logs/refs/heads/master b/spec/tests.git/logs/refs/heads/master new file mode 100644 index 000000000..9219de536 --- /dev/null +++ b/spec/tests.git/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 bdc8b580b5b583aeb43efb19aac2ab8ce5566dff Alexander 1325695134 +0600 clone: from git://github.com/tpope/vim-ragtag.git diff --git a/spec/tests.git/objects/pack/pack-5185f74f028bf49d2611c9fea56570138a196143.idx b/spec/tests.git/objects/pack/pack-5185f74f028bf49d2611c9fea56570138a196143.idx new file mode 100644 index 000000000..46bd6036d Binary files /dev/null and b/spec/tests.git/objects/pack/pack-5185f74f028bf49d2611c9fea56570138a196143.idx differ diff --git a/spec/tests.git/objects/pack/pack-5185f74f028bf49d2611c9fea56570138a196143.pack b/spec/tests.git/objects/pack/pack-5185f74f028bf49d2611c9fea56570138a196143.pack new file mode 100644 index 000000000..593982972 Binary files /dev/null and b/spec/tests.git/objects/pack/pack-5185f74f028bf49d2611c9fea56570138a196143.pack differ diff --git a/spec/tests.git/packed-refs b/spec/tests.git/packed-refs new file mode 100644 index 000000000..b48a6248c --- /dev/null +++ b/spec/tests.git/packed-refs @@ -0,0 +1,5 @@ +# pack-refs with: peeled +30aefeac002db3ec08ff278bd76290645469611e refs/tags/v2.0 +^644c62ad7bc7d9a4a5f19f5e8c41ef910782178b +235e4467107467feacc50553bbeda15e9bf99f57 refs/tags/v1.11 +bdc8b580b5b583aeb43efb19aac2ab8ce5566dff refs/remotes/origin/master diff --git a/spec/tests.git/refs/heads/master b/spec/tests.git/refs/heads/master new file mode 100644 index 000000000..df9ee5473 --- /dev/null +++ b/spec/tests.git/refs/heads/master @@ -0,0 +1 @@ +bdc8b580b5b583aeb43efb19aac2ab8ce5566dff diff --git a/spec/tests.git/refs/remotes/origin/HEAD b/spec/tests.git/refs/remotes/origin/HEAD new file mode 100644 index 000000000..6efe28fff --- /dev/null +++ b/spec/tests.git/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/master