diff --git a/app/models/build_list.rb b/app/models/build_list.rb
index ad749c2af..9448ec7c6 100644
--- a/app/models/build_list.rb
+++ b/app/models/build_list.rb
@@ -1,6 +1,6 @@
class BuildList < ActiveRecord::Base
- include Modules::Models::CommitAndVersion
- include Modules::Models::FileStoreClean
+ include CommitAndVersion
+ include FileStoreClean
include AbfWorker::ModelHelper
include Feed::BuildList
include BuildListObserver
@@ -164,7 +164,7 @@ class BuildList < ActiveRecord::Base
after_transition on: [:published, :fail_publish, :build_error, :tests_failed], do: :notify_users
after_transition on: :build_success, do: :notify_users,
- unless: -> { |build_list| build_list.auto_publish? || build_list.auto_publish_into_testing? }
+ unless: ->(build_list) { build_list.auto_publish? || build_list.auto_publish_into_testing? }
event :place_build do
transition waiting_for_response: :build_pending
diff --git a/app/models/comment.rb b/app/models/comment.rb
index d674c38dc..10cf7ff0c 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -17,7 +17,7 @@ class Comment < ActiveRecord::Base
scope :for_commit, ->(c) { where(commentable_id: c.id.hex, commentable_type: c.class) }
default_scope { order(:created_at) }
- after_create :subscribe_on_reply, unless: -> {|c| c.commit_comment?}
+ after_create :subscribe_on_reply, unless: ->(c) { c.commit_comment? }
after_create :subscribe_users
attr_accessible :body, :data
diff --git a/app/models/concerns/acts_like_member.rb b/app/models/concerns/acts_like_member.rb
new file mode 100644
index 000000000..a80088a59
--- /dev/null
+++ b/app/models/concerns/acts_like_member.rb
@@ -0,0 +1,37 @@
+module ActsLikeMember
+ extend ActiveSupport::Concern
+
+ included do
+ scope :not_member_of, ->(item) {
+ where("
+ #{table_name}.id NOT IN (
+ SELECT relations.actor_id
+ FROM relations
+ WHERE (
+ relations.actor_type = '#{self.to_s}'
+ AND relations.target_type = '#{item.class.to_s}'
+ AND relations.target_id = #{item.id}
+ )
+ )
+ ")
+ }
+ scope :search_order, -> { order('CHAR_LENGTH(#{table_name}.uname) ASC') }
+ scope :without, ->(a) { where("#{table_name}.id NOT IN (?)", a) }
+ scope :by_uname, ->(n) { where("#{table_name}.uname ILIKE ?", n) }
+ scope :search, ->(q) { by_uname("%#{q.to_s.strip}%") }
+ end
+
+ def to_param
+ uname
+ end
+
+ module ClassMethods
+ def find_by_insensitive_uname(uname)
+ find_by_uname(uname) || by_uname(uname).first
+ end
+
+ def find_by_insensitive_uname!(uname)
+ find_by_insensitive_uname(uname) or raise ActiveRecord::RecordNotFound
+ end
+ end
+end
diff --git a/app/models/concerns/autostart.rb b/app/models/concerns/autostart.rb
new file mode 100644
index 000000000..c9b66ee3c
--- /dev/null
+++ b/app/models/concerns/autostart.rb
@@ -0,0 +1,31 @@
+module Autostart
+ extend ActiveSupport::Concern
+
+ ONCE_A_12_HOURS = 0
+ ONCE_A_DAY = 1
+ ONCE_A_WEEK = 2
+
+ AUTOSTART_STATUSES = [ONCE_A_12_HOURS, ONCE_A_DAY, ONCE_A_WEEK]
+ HUMAN_AUTOSTART_STATUSES = {
+ ONCE_A_12_HOURS => :once_a_12_hours,
+ ONCE_A_DAY => :once_a_day,
+ ONCE_A_WEEK => :once_a_week
+ }
+
+ included do
+ validates :autostart_status, numericality: true,
+ inclusion: {in: AUTOSTART_STATUSES}, allow_blank: true
+
+ attr_accessible :autostart_status
+ end
+
+ def human_autostart_status
+ self.class.human_autostart_status(autostart_status)
+ end
+
+ module ClassMethods
+ def human_autostart_status(autostart_status)
+ I18n.t("layout.products.autostart_statuses.#{HUMAN_AUTOSTART_STATUSES[autostart_status]}")
+ end
+ end
+end
diff --git a/app/models/concerns/build_list_observer.rb b/app/models/concerns/build_list_observer.rb
index 8061a3c54..b99411764 100644
--- a/app/models/concerns/build_list_observer.rb
+++ b/app/models/concerns/build_list_observer.rb
@@ -32,5 +32,4 @@ module BuildListObserver
end
end
end
-
end
diff --git a/app/models/concerns/commit_and_version.rb b/app/models/concerns/commit_and_version.rb
new file mode 100644
index 000000000..e2a965841
--- /dev/null
+++ b/app/models/concerns/commit_and_version.rb
@@ -0,0 +1,33 @@
+module CommitAndVersion
+ extend ActiveSupport::Concern
+
+ included do
+
+ validate -> {
+ if project && (commit_hash.blank? || project.repo.commit(commit_hash).blank?)
+ errors.add :commit_hash, I18n.t('flash.build_list.wrong_commit_hash', commit_hash: commit_hash)
+ end
+ }
+
+ before_validation :set_commit_and_version
+ before_create :set_last_published_commit
+ end
+
+ protected
+
+ def set_commit_and_version
+ if project && project_version.present? && commit_hash.blank?
+ self.commit_hash = project.repo.commits(project_version).try(:first).try(:id)
+ elsif project_version.blank? && commit_hash.present?
+ self.project_version = commit_hash
+ end
+ end
+
+ def set_last_published_commit
+ return unless self.respond_to? :last_published_commit_hash # product?
+ last_commit = self.last_published.first.try :commit_hash
+ if last_commit && self.project.repo.commit(last_commit).present? # commit(nil) is not nil!
+ self.last_published_commit_hash = last_commit
+ end
+ end
+end
diff --git a/app/models/concerns/feed/issue.rb b/app/models/concerns/feed/issue.rb
index b5d090b1e..df0ee1a28 100644
--- a/app/models/concerns/feed/issue.rb
+++ b/app/models/concerns/feed/issue.rb
@@ -4,11 +4,11 @@ module Feed::Issue
included do
after_commit :new_issue_notifications, on: :create
- after_commit :send_assign_notifications, on: :create, if: Proc.new { |i| i.assignee }
+ after_commit :send_assign_notifications, on: :create, if: -> { |i| i.assignee }
after_commit -> { send_assign_notifications(:update) }, on: :update
after_commit :send_hooks, on: :create
- after_commit -> { send_hooks(:update) }, on: :update, if: Proc.new { |i| i.previous_changes['status'].present? }
+ after_commit -> { send_hooks(:update) }, on: :update, if: -> { |i| i.previous_changes['status'].present? }
end
private
diff --git a/app/models/concerns/file_store_clean.rb b/app/models/concerns/file_store_clean.rb
new file mode 100644
index 000000000..afced4ff9
--- /dev/null
+++ b/app/models/concerns/file_store_clean.rb
@@ -0,0 +1,49 @@
+module FileStoreClean
+ extend ActiveSupport::Concern
+
+ included do
+ def destroy
+ destroy_files_from_file_store if Rails.env.production?
+ super
+ end
+ later :destroy, queue: :clone_build
+
+ def sha1_of_file_store_files
+ raise NotImplementedError, "You should implement this method"
+ end
+
+ def destroy_files_from_file_store(args = sha1_of_file_store_files)
+ files = *args
+ token = User.find_by_uname('file_store').authentication_token
+ uri = URI APP_CONFIG['file_store_url']
+ Net::HTTP.start(uri.host, uri.port) do |http|
+ files.each do |sha1|
+ begin
+ req = Net::HTTP::Delete.new("/api/v1/file_stores/#{sha1}.json")
+ req.basic_auth token, ''
+ http.request(req)
+ rescue # Dont care about it
+ end
+ end
+ end
+ end
+
+ def later_destroy_files_from_file_store(args)
+ destroy_files_from_file_store(args)
+ end
+ later :later_destroy_files_from_file_store, queue: :clone_build
+ end
+
+ def self.file_exist_on_file_store?(sha1)
+ begin
+ resp = JSON(RestClient.get "#{APP_CONFIG['file_store_url']}/api/v1/file_stores.json", params: {hash: sha1})
+ rescue # Dont care about it
+ resp = []
+ end
+ if resp[0].respond_to?('[]') && resp[0]['file_name'] && resp[0]['sha1_hash']
+ true
+ else
+ false
+ end
+ end
+end
diff --git a/app/models/concerns/git.rb b/app/models/concerns/git.rb
new file mode 100644
index 000000000..64ee9947d
--- /dev/null
+++ b/app/models/concerns/git.rb
@@ -0,0 +1,241 @@
+require 'nokogiri'
+require 'open-uri'
+
+module Git
+ extend ActiveSupport::Concern
+
+ included do
+ has_attached_file :srpm
+
+ validates_attachment_size :srpm, less_than_or_equal_to: 500.megabytes
+ validates_attachment_content_type :srpm, content_type: ['application/octet-stream', "application/x-rpm", "application/x-redhat-package-manager"], message: I18n.t('layout.invalid_content_type')
+
+ after_create :create_git_repo
+ after_commit(on: :create) {|p| p.fork_git_repo unless p.is_root?} # later with resque
+ after_commit(on: :create) {|p| p.import_attached_srpm if p.srpm?} # later with resque # should be after create_git_repo
+ after_destroy :destroy_git_repo
+ # after_rollback -> { destroy_git_repo rescue true if new_record? }
+
+ later :import_attached_srpm, queue: :fork_import
+ later :fork_git_repo, queue: :fork_import
+ end
+
+ def repo
+ @repo ||= Grit::Repo.new(path) rescue Grit::Repo.new(GAP_REPO_PATH)
+ end
+
+ def path
+ build_path(name_with_owner)
+ end
+
+ def versions
+ repo.tags.map(&:name) + repo.branches.map(&:name)
+ end
+
+ def create_branch(new_ref, from_ref, user)
+ return false if new_ref.blank? || from_ref.blank? || !(from_commit = repo.commit(from_ref))
+ status, out, err = repo.git.native(:branch, {process_info: true}, new_ref, from_commit.id)
+ if status == 0
+ Resque.enqueue(GitHook, owner.uname, name, from_commit.id, GitHook::ZERO, "refs/heads/#{new_ref}", 'commit', "user-#{user.id}", nil)
+ return true
+ end
+ return false
+
+ end
+
+ def delete_branch(branch, user)
+ return false if default_branch == branch.name
+ message = repo.git.native(:branch, {}, '-D', branch.name)
+ if message.present?
+ Resque.enqueue(GitHook, owner.uname, name, GitHook::ZERO, branch.commit.id, "refs/heads/#{branch.name}", 'commit', "user-#{user.id}", message)
+ end
+ return message.present?
+ end
+
+ def update_file(path, data, options = {})
+ head = options[:head].to_s || default_branch
+ actor = get_actor(options[:actor])
+ filename = File.split(path).last
+ message = options[:message]
+ message = "Updated file #{filename}" if message.nil? or message.empty?
+
+ # can not write to unexisted branch
+ return false if repo.branches.select{|b| b.name == head}.size != 1
+
+ parent = repo.commits(head).first
+
+ index = repo.index
+ index.read_tree(parent.tree.id)
+
+ # can not create new file
+ return false if (index.current_tree / path).nil?
+
+ system "sudo chown -R rosa:rosa #{repo.path}" #FIXME Permission denied - /mnt/gitstore/git_projects/...
+ index.add(path, data)
+ if sha1 = index.commit(message, parents: [parent], actor: actor, last_tree: parent.tree.id, head: head)
+ Resque.enqueue(GitHook, owner.uname, name, sha1, sha1, "refs/heads/#{head}", 'commit', "user-#{options[:actor].id}", message)
+ end
+ sha1
+ end
+
+ def paginate_commits(treeish, options = {})
+ options[:page] = options[:page].try(:to_i) || 1
+ options[:per_page] = options[:per_page].try(:to_i) || 20
+
+ skip = options[:per_page] * (options[:page] - 1)
+ last_page = (skip + options[:per_page]) >= repo.commit_count(treeish)
+
+ [repo.commits(treeish, options[:per_page], skip), options[:page], last_page]
+ end
+
+ def tree_info(tree, treeish = nil, path = nil)
+ return [] unless tree
+ grouped = tree.contents.sort_by{|c| c.name.downcase}.group_by(&:class)
+ [
+ grouped[Grit::Tree],
+ grouped[Grit::Blob],
+ grouped[Grit::Submodule]
+ ].compact.flatten.map do |node|
+ node_path = File.join([path.present? ? path : nil, node.name].compact)
+ [
+ node,
+ node_path,
+ repo.log(treeish, node_path, max_count: 1).first
+ ]
+ end
+ end
+
+ def import_srpm(srpm_path = srpm.path, branch_name = 'import')
+ token = User.find_by_uname('rosa_system').authentication_token
+ opts = [srpm_path, path, branch_name, Rails.root.join('bin', 'file-store.rb'), token, APP_CONFIG['file_store_url']].join(' ')
+ system("#{Rails.root.join('bin', 'import_srpm.sh')} #{opts} >> /dev/null 2>&1")
+ end
+
+ def is_empty?
+ repo.branches.count == 0
+ end
+
+ def total_commits_count
+ return 0 if is_empty?
+ %x(cd #{path} && git rev-list --all | wc -l).to_i
+ end
+
+ protected
+
+ def build_path(dir)
+ File.join(APP_CONFIG['git_path'], 'git_projects', "#{dir}.git")
+ end
+
+ def import_attached_srpm
+ if srpm?
+ import_srpm # srpm.path
+ self.srpm = nil; save # clear srpm
+ end
+ end
+
+ def create_git_repo
+ if is_root?
+ Grit::Repo.init_bare(path)
+ write_hook
+ end
+ end
+
+ def fork_git_repo
+ dummy = Grit::Repo.new(path) rescue parent.repo.fork_bare(path, shared: false)
+ write_hook
+ end
+
+ def destroy_git_repo
+ FileUtils.rm_rf path
+ end
+
+ def write_hook
+ hook = "/home/#{APP_CONFIG['shell_user']}/gitlab-shell/hooks/post-receive"
+ hook_file = File.join(path, 'hooks', 'post-receive')
+ FileUtils.ln_sf hook, hook_file
+ end
+
+ def get_actor(actor = nil)
+ @last_actor = case actor.class.to_s
+ when 'Grit::Actor' then options[:actor]
+ when 'Hash' then Grit::Actor.new(actor[:name], actor[:email])
+ when 'String' then Grit::Actor.from_stirng(actor)
+ else begin
+ if actor.respond_to?(:name) and actor.respond_to?(:email)
+ Grit::Actor.new(actor.name, actor.email)
+ else
+ config = Grit::Config.new(repo)
+ Grit::Actor.new(config['user.name'], config['user.email'])
+ end
+ end
+ end
+ @last_actor
+ end
+
+ module ClassMethods
+ MAX_SRC_SIZE = 1024*1024*256
+
+ def process_hook(owner_uname, repo, newrev, oldrev, ref, newrev_type, user = nil, message = nil)
+ rec = GitHook.new(owner_uname, repo, newrev, oldrev, ref, newrev_type, user, message)
+ Modules::Observers::ActivityFeed::Git.create_notifications rec
+ end
+
+ def run_mass_import(url, srpms_list, visibility, owner, add_to_repository_id)
+ doc = Nokogiri::HTML(open(url))
+ links = doc.css("a[href$='.src.rpm']")
+ return if links.count == 0
+ filter = srpms_list.lines.map(&:chomp).map(&:strip).select(&:present?)
+
+ repository = Repository.find add_to_repository_id
+ platform = repository.platform
+ dir = Dir.mktmpdir 'mass-import-', APP_CONFIG['tmpfs_path']
+ links.each do |link|
+ begin
+ package = link.attributes['href'].value
+ package.chomp!; package.strip!
+
+ next if package.size == 0 || package !~ /^[\w\.\-]+$/
+ next if filter.present? && !filter.include?(package)
+
+ uri = URI "#{url}/#{package}"
+ srpm_file = "#{dir}/#{package}"
+ Net::HTTP.start(uri.host) do |http|
+ if http.request_head(uri.path)['content-length'].to_i < MAX_SRC_SIZE
+ f = open(srpm_file, 'wb')
+ http.request_get(uri.path) do |resp|
+ resp.read_body{ |segment| f.write(segment) }
+ end
+ f.close
+ end
+ end
+ if name = `rpm -q --qf '[%{Name}]' -p #{srpm_file}` and $?.success? and name.present?
+ next if owner.projects.exists?(name: name)
+ description = `rpm -q --qf '[%{Description}]' -p #{srpm_file}`.scrub('')
+
+ project = owner.projects.build(
+ name: name,
+ description: description,
+ visibility: visibility,
+ is_package: false # See: Hook for #attach_to_personal_repository
+ )
+ project.owner = owner
+ if project.save
+ repository.projects << project rescue nil
+ project.update_attributes(is_package: true)
+ project.import_srpm srpm_file, platform.name
+ end
+ end
+ rescue => e
+ f.close if defined?(f)
+ Airbrake.notify_or_ignore(e, link: link.to_s, url: url, owner: owner)
+ ensure
+ File.delete srpm_file if srpm_file
+ end
+ end
+ rescue => e
+ Airbrake.notify_or_ignore(e, url: url, owner: owner)
+ ensure
+ FileUtils.remove_entry_secure dir if dir
+ end
+ end
+end
diff --git a/app/models/concerns/markdown.rb b/app/models/concerns/markdown.rb
new file mode 100644
index 000000000..bb8a51691
--- /dev/null
+++ b/app/models/concerns/markdown.rb
@@ -0,0 +1,190 @@
+# This module is based on
+# https://github.com/gitlabhq/gitlabhq/blob/397c3da9758c03a215a308c011f94261d9c61cfa/lib/gitlab/markdown.rb
+
+# Custom parser for GitLab-flavored Markdown
+#
+# It replaces references in the text with links to the appropriate items in
+# GitLab.
+#
+# Supported reference formats are:
+# * @foo for team members
+# * for issues & pull requests:
+# * #123
+# * abf#123
+# * abf/rosa-build#123
+# * 123456 for commits
+#
+# It also parses Emoji codes to insert images. See
+# http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
+#
+# Examples
+#
+# >> gfm("Hey @david, can you fix this?")
+# => "Hey @david, can you fix this?"
+#
+# >> gfm("Commit 35d5f7c closes #1234")
+# => "Commit 35d5f7c closes #1234"
+#
+# >> gfm(":trollface:")
+# => "
+module Markdown
+ include IssuesHelper
+
+ attr_reader :html_options
+
+ # Public: Parse the provided text with GitLab-Flavored Markdown
+ #
+ # text - the source text
+ # html_options - extra options for the reference links as given to link_to
+ #
+ # Note: reference links will only be generated if @project is set
+ def gfm(text, html_options = {})
+ return text if text.nil?
+
+ # Duplicate the string so we don't alter the original, then call to_str
+ # to cast it back to a String instead of a SafeBuffer. This is required
+ # for gsub calls to work as we need them to.
+ text = text.dup.to_str
+
+ @html_options = html_options
+
+ # Extract pre blocks so they are not altered
+ # from http://github.github.com/github-flavored-markdown/
+ text.gsub!(%r{
.*?
|.*?
}m) { |match| extract_piece(match) }
+ # Extract links with probably parsable hrefs
+ text.gsub!(%r{.*?}m) { |match| extract_piece(match) }
+ # Extract images with probably parsable src
+ text.gsub!(%r{}m) { |match| extract_piece(match) }
+
+ # TODO: add popups with additional information
+
+ text = parse(text)
+
+ # Insert pre block extractions
+ text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
+ insert_piece($1)
+ end
+
+ sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class)
+ end
+
+ private
+
+ def extract_piece(text)
+ @extractions ||= {}
+
+ md5 = Digest::MD5.hexdigest(text)
+ @extractions[md5] = text
+ "{gfm-extraction-#{md5}}"
+ end
+
+ def insert_piece(id)
+ @extractions[id]
+ end
+
+ # Private: Parses text for references and emoji
+ #
+ # text - Text to parse
+ #
+ # Note: reference links will only be generated if @project is set
+ #
+ # Returns parsed text
+ def parse(text)
+ parse_references(text) if @project
+ parse_emoji(text)
+
+ text
+ end
+
+ REFERENCE_PATTERN = %r{
+ (?[\W\/])? # Prefix
+ ( # Reference
+ @(?[a-zA-Z][a-zA-Z0-9_\-\.]*) # User/Group uname
+ |(?(?:[a-zA-Z0-9\-_]*\/)?(?:[a-zA-Z0-9\-_]*)?\#[0-9]+) # Issue ID
+ |(?[\h]{6,40}) # Commit ID
+ )
+ (?\W)? # Suffix
+ }x.freeze
+
+ TYPES = [:user, :issue, :commit].freeze
+
+ def parse_references(text)
+ # parse reference links
+ text.gsub!(REFERENCE_PATTERN) do |match|
+ prefix = $~[:prefix]
+ suffix = $~[:suffix]
+ type = TYPES.select{|t| !$~[t].nil?}.first
+ identifier = $~[type]
+
+ # Avoid HTML entities
+ if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';'
+ match
+ elsif ref_link = reference_link(type, identifier)
+ "#{prefix}#{ref_link}#{suffix}"
+ else
+ match
+ end
+ end
+ end
+
+ EMOJI_PATTERN = %r{(:(\S+):)}.freeze
+
+ def parse_emoji(text)
+ # parse emoji
+ text.gsub!(EMOJI_PATTERN) do |match|
+ if valid_emoji?($2)
+ image_tag(image_path("emoji/#{$2}.png"), class: 'emoji', title: $1, alt: $1, size: "20x20")
+ else
+ match
+ end
+ end
+ end
+
+ # Private: Checks if an emoji icon exists in the image asset directory
+ #
+ # emoji - Identifier of the emoji as a string (e.g., "+1", "heart")
+ #
+ # Returns boolean
+ def valid_emoji?(emoji)
+ Emoji.names.include? emoji
+ end
+
+ # Private: Dispatches to a dedicated processing method based on reference
+ #
+ # reference - Object reference ("@1234", "!567", etc.)
+ # identifier - Object identifier (Issue ID, SHA hash, etc.)
+ #
+ # Returns string rendered by the processing method
+ def reference_link(type, identifier)
+ send("reference_#{type}", identifier)
+ end
+
+ def reference_user(identifier)
+ member = User.where(uname: identifier).first || Group.where(uname: identifier).first
+ if member
+ link_to("@#{identifier}", "/#{identifier}", html_options.merge(title: member.fullname, class: "gfm gfm-member #{html_options[:class]}"))
+ end
+ end
+
+ def reference_issue(identifier)
+ if issue = Issue.find_by_hash_tag(identifier, current_ability, @project)
+ if issue.pull_request
+ title = "#{PullRequest.model_name.human}: #{issue.title}"
+ url = project_pull_request_path(issue.project, issue.pull_request)
+ else
+ title = "#{Issue.model_name.human}: #{issue.title}"
+ url = project_issue_path(issue.project.owner, issue.project.name, issue.serial_id)
+ end
+ link_to(identifier, url, html_options.merge(title: title, class: "gfm gfm-issue #{html_options[:class]}"))
+ end
+ end
+
+ def reference_commit(identifier)
+ if commit = @project.repo.commit(identifier)
+ link_to shortest_hash_id(commit.id), commit_path(@project, commit.id)
+ title = GitPresenters::CommitAsMessagePresenter.present(commit, project: @project) do |presenter|
+ link_to(identifier, commit_path(@project, commit), html_options.merge(title: presenter.caption, class: "gfm gfm-commit #{html_options[:class]}"))
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/owner.rb b/app/models/concerns/owner.rb
new file mode 100644
index 000000000..c7d2d489a
--- /dev/null
+++ b/app/models/concerns/owner.rb
@@ -0,0 +1,8 @@
+module Owner
+ extend ActiveSupport::Concern
+
+ included do
+ validates :owner, presence: true
+ after_create -> { relations.create actor_id: owner.id, actor_type: owner.class.to_s, role: 'admin' }
+ end
+end
diff --git a/app/models/concerns/personal_repository.rb b/app/models/concerns/personal_repository.rb
new file mode 100644
index 000000000..ed03d9094
--- /dev/null
+++ b/app/models/concerns/personal_repository.rb
@@ -0,0 +1,37 @@
+module PersonalRepository
+ extend ActiveSupport::Concern
+
+ included do
+ after_create :create_personal_repository, unless: :system?
+ end
+
+ def create_personal_repository
+ begin
+ pl = own_platforms.build
+ pl.owner = self
+ pl.name = "#{self.uname}_personal"
+ pl.description = "#{self.uname}_personal"
+ pl.platform_type = 'personal'
+ pl.distrib_type = APP_CONFIG['distr_types'].first
+ pl.visibility = 'open'
+ pl.save!
+
+ rep = pl.repositories.build
+ rep.name = 'main'
+ rep.description = 'main'
+ rep.save!
+ rescue Exception => e
+ pl.now_destroy rescue false
+ raise e
+ end
+ return true
+ end
+
+ def personal_platform
+ own_platforms.personal.first
+ end
+
+ def personal_repository
+ personal_platform.repositories.first
+ end
+end
diff --git a/app/models/concerns/regeneration_status.rb b/app/models/concerns/regeneration_status.rb
new file mode 100644
index 000000000..69920a599
--- /dev/null
+++ b/app/models/concerns/regeneration_status.rb
@@ -0,0 +1,44 @@
+module RegenerationStatus
+ extend ActiveSupport::Concern
+
+ READY = 0
+ WAITING_FOR_REGENERATION = 100
+ REGENERATING = 200
+
+ HUMAN_STATUSES = {
+ READY => :ready,
+ WAITING_FOR_REGENERATION => :waiting_for_regeneration,
+ REGENERATING => :regenerating
+ }
+
+ HUMAN_REGENERATION_STATUSES = {
+ AbfWorker::BaseObserver::COMPLETED => :completed,
+ AbfWorker::BaseObserver::FAILED => :failed,
+ AbfWorker::BaseObserver::CANCELED => :canceled
+ }.freeze
+
+ included do
+ after_update :cleanup_file_store
+
+ def sha1_of_file_store_files
+ files = []
+ files << last_regenerated_log_sha1 if last_regenerated_log_sha1.present?
+ files
+ end
+
+ def human_regeneration_status
+ self.class::HUMAN_REGENERATION_STATUSES[last_regenerated_status] || :no_data
+ end
+
+ def human_status
+ self.class::HUMAN_STATUSES[status] || :no_data
+ end
+
+ def cleanup_file_store
+ old_log_sha1 = last_regenerated_log_sha1_was
+ if old_log_sha1.present? && old_log_sha1 != last_regenerated_log_sha1
+ later_destroy_files_from_file_store([old_log_sha1])
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/time_living.rb b/app/models/concerns/time_living.rb
new file mode 100644
index 000000000..05f522573
--- /dev/null
+++ b/app/models/concerns/time_living.rb
@@ -0,0 +1,29 @@
+module TimeLiving
+ extend ActiveSupport::Concern
+
+ included do
+
+ validates :time_living, numericality: { only_integer: true }, presence: true
+
+ validate -> {
+ # MIN_TIME_LIVING <= time_living <= MAX_TIME_LIVING or
+ # 2 min <= time_living <= 12 hours
+ # time_living in seconds
+ min = self.class.const_defined?(:MIN_TIME_LIVING) ? self.class::MIN_TIME_LIVING : 120
+ max = self.class.const_defined?(:MAX_TIME_LIVING) ? self.class::MAX_TIME_LIVING : 43200
+ if min > time_living.to_i || time_living.to_i > max
+ errors.add :time_living,
+ I18n.t('flash.time_living.numericality_error', min: (min / 60), max: (max / 60))
+ end
+ }
+
+ before_validation :convert_time_living
+ attr_accessible :time_living
+ end
+
+ protected
+
+ def convert_time_living
+ self.time_living = time_living.to_i * 60 if time_living_was.to_i != time_living.to_i
+ end
+end
diff --git a/lib/modules/models/url_helper.rb b/app/models/concerns/url_helper.rb
similarity index 78%
rename from lib/modules/models/url_helper.rb
rename to app/models/concerns/url_helper.rb
index c374899c3..318c1e7b8 100644
--- a/lib/modules/models/url_helper.rb
+++ b/app/models/concerns/url_helper.rb
@@ -1,7 +1,7 @@
-module Modules::Models::UrlHelper
+module UrlHelper
def default_url_options
host ||= EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
protocol ||= APP_CONFIG['mailer_https_url'] ? 'https' : 'http' rescue 'http'
- {host: host, protocol: protocol}
+ { host: host, protocol: protocol }
end
end
diff --git a/lib/modules/models/web_hooks.rb b/app/models/concerns/web_hooks.rb
similarity index 96%
rename from lib/modules/models/web_hooks.rb
rename to app/models/concerns/web_hooks.rb
index 1911a30fc..0a75a5c0b 100644
--- a/lib/modules/models/web_hooks.rb
+++ b/app/models/concerns/web_hooks.rb
@@ -1,4 +1,4 @@
-module Modules::Models::WebHooks
+module WebHooks
class << self
protected
@@ -45,10 +45,11 @@ module Modules::Models::WebHooks
password :password
boolean :ssl, :message_without_join, :no_colors, :long_url, :notice
end
+
add_hook :jabber do
string :user
end
+
SCHEMA.freeze
NAMES.freeze
-
end
diff --git a/app/models/concerns/wiki.rb b/app/models/concerns/wiki.rb
new file mode 100644
index 000000000..47e852dfe
--- /dev/null
+++ b/app/models/concerns/wiki.rb
@@ -0,0 +1,31 @@
+module Wiki
+ extend ActiveSupport::Concern
+
+ included do
+ after_save :create_wiki
+ after_destroy :destroy_wiki
+ end
+
+ def wiki_path
+ build_path(wiki_repo_name)
+ end
+
+ def wiki_repo_name
+ File.join owner.uname, "#{name}.wiki"
+ end
+
+ protected
+
+ def create_wiki
+ if has_wiki && !FileTest.exist?(wiki_path)
+ Grit::Repo.init_bare(wiki_path)
+ wiki = Gollum::Wiki.new(wiki_path, {base_path: Rails.application.routes.url_helpers.project_wiki_index_path(owner, self)})
+ wiki.write_page('Home', :markdown, I18n.t("wiki.seed.welcome_content"),
+ {name: owner.name, email: owner.email, message: 'Initial commit'})
+ end
+ end
+
+ def destroy_wiki
+ FileUtils.rm_rf wiki_path
+ end
+end
diff --git a/app/models/group.rb b/app/models/group.rb
index 71ad3fa54..f6e3574fe 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -1,6 +1,6 @@
class Group < Avatar
- include Modules::Models::ActsLikeMember
- include Modules::Models::PersonalRepository
+ include ActsLikeMember
+ include PersonalRepository
belongs_to :owner, class_name: 'User'
diff --git a/app/models/hook.rb b/app/models/hook.rb
index 755e4147c..5d2c16ec8 100644
--- a/app/models/hook.rb
+++ b/app/models/hook.rb
@@ -1,6 +1,6 @@
class Hook < ActiveRecord::Base
- include Modules::Models::WebHooks
- include Modules::Models::UrlHelper
+ include WebHooks
+ include UrlHelper
include Rails.application.routes.url_helpers
belongs_to :project
@@ -121,7 +121,7 @@ class Hook < ActiveRecord::Base
def cleanup_data
if self.name.present? && fields = SCHEMA[self.name.to_sym]
new_data = {}
- fields.each{ |type, field| new_data[field] = self.data[field] }
+ fields.each { |type, field| new_data[field] = self.data[field] }
self.data = new_data
end
end
@@ -140,7 +140,7 @@ class Hook < ActiveRecord::Base
modified << diff.a_path
end
end
- {removed: removed, added: added, modified: modified}
+ { removed: removed, added: added, modified: modified }
end
end
diff --git a/app/models/platform.rb b/app/models/platform.rb
index 7cf7449b0..2cf877c8a 100644
--- a/app/models/platform.rb
+++ b/app/models/platform.rb
@@ -2,9 +2,9 @@ class Platform < ActiveRecord::Base
extend FriendlyId
friendly_id :name
- include Modules::Models::FileStoreClean
- include Modules::Models::RegenerationStatus
- include Modules::Models::Owner
+ include FileStoreClean
+ include RegenerationStatus
+ include Owner
include EventLoggable
AUTOMATIC_METADATA_REGENERATIONS = %w(day week)
@@ -32,10 +32,10 @@ class Platform < ActiveRecord::Base
has_many :mass_builds, foreign_key: :save_to_platform_id
validates :description, presence: true
- validates :visibility, presence: true, inclusion: {in: VISIBILITIES}
- validates :automatic_metadata_regeneration, inclusion: {in: AUTOMATIC_METADATA_REGENERATIONS}, allow_blank: true
+ validates :visibility, presence: true, inclusion: { in: VISIBILITIES }
+ validates :automatic_metadata_regeneration, inclusion: { in: AUTOMATIC_METADATA_REGENERATIONS }, allow_blank: true
validates :name, uniqueness: {case_sensitive: false}, presence: true, format: { with: /\A#{NAME_PATTERN}\z/ }
- validates :distrib_type, presence: true, inclusion: {in: APP_CONFIG['distr_types']}
+ validates :distrib_type, presence: true, inclusion: { in: APP_CONFIG['distr_types'] }
validate -> {
if released_was && !released
errors.add(:released, I18n.t('flash.platform.released_status_can_not_be_changed'))
@@ -79,7 +79,7 @@ class Platform < ActiveRecord::Base
end
event :regenerate do
- transition ready: :waiting_for_regeneration, if: -> { |p| p.main? }
+ transition ready: :waiting_for_regeneration, if: ->(p) { p.main? }
end
event :start_regeneration do
diff --git a/app/models/platform_arch_setting.rb b/app/models/platform_arch_setting.rb
index 6d0dbd9fc..f9c1314aa 100644
--- a/app/models/platform_arch_setting.rb
+++ b/app/models/platform_arch_setting.rb
@@ -2,7 +2,7 @@ class PlatformArchSetting < ActiveRecord::Base
DEFAULT_TIME_LIVING = 43200 # seconds, 12 hours
MIN_TIME_LIVING = 600 # seconds, 10 minutes
MAX_TIME_LIVING = 360000 # seconds, 100 hours, 4 day and 4 hours
- include Modules::Models::TimeLiving
+ include TimeLiving
belongs_to :arch
belongs_to :platform
diff --git a/app/models/product.rb b/app/models/product.rb
index a920545df..25fa00542 100644
--- a/app/models/product.rb
+++ b/app/models/product.rb
@@ -1,6 +1,6 @@
class Product < ActiveRecord::Base
- include Modules::Models::TimeLiving
- include Modules::Models::Autostart
+ include TimeLiving
+ include Autostart
include EventLoggable
belongs_to :platform
@@ -25,7 +25,7 @@ class Product < ActiveRecord::Base
def full_clone(attrs = {})
dup.tap do |c|
attrs.each {|k,v| c.send("#{k}=", v)}
- c.time_living = c.time_living.to_i / 60 # see: Modules::Models::TimeLiving#convert_time_living
+ c.time_living = c.time_living.to_i / 60 # see: TimeLiving#convert_time_living
c.platform_id = nil
c.product_build_lists = []
c.updated_at = nil; c.created_at = nil
@@ -33,7 +33,7 @@ class Product < ActiveRecord::Base
end
class << self
- Modules::Models::Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
+ Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
define_method "autostart_iso_builds_#{human_autostart_status}" do
autostart_iso_builds autostart_status
end
diff --git a/app/models/product_build_list.rb b/app/models/product_build_list.rb
index 67313c4e2..364f820fb 100644
--- a/app/models/product_build_list.rb
+++ b/app/models/product_build_list.rb
@@ -1,8 +1,8 @@
class ProductBuildList < ActiveRecord::Base
- include Modules::Models::CommitAndVersion
- include Modules::Models::TimeLiving
- include Modules::Models::FileStoreClean
- include Modules::Models::UrlHelper
+ include CommitAndVersion
+ include TimeLiving
+ include FileStoreClean
+ include UrlHelper
include AbfWorker::ModelHelper
include EventLoggable
diff --git a/app/models/project.rb b/app/models/project.rb
index 910c5cba8..c793124ed 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1,9 +1,9 @@
class Project < ActiveRecord::Base
- include Modules::Models::Autostart
- include Modules::Models::Owner
- include Modules::Models::Git
- include Modules::Models::Wiki
- include Modules::Models::UrlHelper
+ include Autostart
+ include Owner
+ include Git
+ include Wiki
+ include UrlHelper
include EventLoggable
VISIBILITIES = ['open', 'hidden']
@@ -238,11 +238,11 @@ class Project < ActiveRecord::Base
format_id = ProjectTag::FORMATS["#{tag_file_format(format)}"]
project_tag = project_tags.where(tag_name: tag.name, format_id: format_id).first
- return project_tag.sha1 if project_tag && project_tag.commit_id == tag.commit.id && Modules::Models::FileStoreClean.file_exist_on_file_store?(project_tag.sha1)
+ return project_tag.sha1 if project_tag && project_tag.commit_id == tag.commit.id && FileStoreClean.file_exist_on_file_store?(project_tag.sha1)
archive = archive_by_treeish_and_format tag.name, format
sha1 = Digest::SHA1.file(archive[:path]).hexdigest
- unless Modules::Models::FileStoreClean.file_exist_on_file_store? sha1
+ unless FileStoreClean.file_exist_on_file_store? sha1
token = User.find_by_uname('rosa_system').authentication_token
begin
resp = JSON `curl --user #{token}: -POST -F 'file_store[file]=@#{archive[:path]};filename=#{name}-#{tag.name}.#{tag_file_format(format)}' #{APP_CONFIG['file_store_url']}/api/v1/upload`
@@ -297,7 +297,7 @@ class Project < ActiveRecord::Base
end
class << self
- Modules::Models::Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
+ Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
define_method "autostart_build_lists_#{human_autostart_status}" do
autostart_build_lists autostart_status
end
diff --git a/app/models/project_import.rb b/app/models/project_import.rb
index a34949833..ae1872a6a 100644
--- a/app/models/project_import.rb
+++ b/app/models/project_import.rb
@@ -7,5 +7,5 @@ class ProjectImport < ActiveRecord::Base
scope :by_name, ->(name) { where("#{table_name}.name ILIKE ?", name) }
- after_initialize -> {|r| r.file_mtime ||= Time.current - 10.years } # default
+ after_initialize ->(r) { r.file_mtime ||= Time.current - 10.years } # default
end
diff --git a/app/models/project_tag.rb b/app/models/project_tag.rb
index 267bf39f2..3a116408d 100644
--- a/app/models/project_tag.rb
+++ b/app/models/project_tag.rb
@@ -1,5 +1,5 @@
class ProjectTag < ActiveRecord::Base
- include Modules::Models::FileStoreClean
+ include FileStoreClean
FORMATS = {
'zip' => 0,
diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb
index 29250a897..1e98c5629 100644
--- a/app/models/pull_request.rb
+++ b/app/models/pull_request.rb
@@ -7,7 +7,7 @@ class PullRequest < ActiveRecord::Base
:created_at, :updated_at, :comments, :status=, to: :issue, allow_nil: true
validates :from_project, :to_project, presence: true
- validate :uniq_merge, if: -> { |pull| pull.to_project.present? }
+ validate :uniq_merge, if: ->(pull) { pull.to_project.present? }
validates_each :from_ref, :to_ref do |record, attr, value|
check_ref record, attr, value
end
diff --git a/app/models/repository_status.rb b/app/models/repository_status.rb
index 8b1359fc6..1f783d499 100644
--- a/app/models/repository_status.rb
+++ b/app/models/repository_status.rb
@@ -1,6 +1,6 @@
class RepositoryStatus < ActiveRecord::Base
- include Modules::Models::FileStoreClean
- include Modules::Models::RegenerationStatus
+ include FileStoreClean
+ include RegenerationStatus
WAITING_FOR_RESIGN = 300
PUBLISH = 400
diff --git a/app/models/user.rb b/app/models/user.rb
index 321362706..e4309a079 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,6 +1,6 @@
class User < Avatar
- include Modules::Models::PersonalRepository
- include Modules::Models::ActsLikeMember
+ include PersonalRepository
+ include ActsLikeMember
include Feed::User
include EventLoggable
diff --git a/lib/modules/models/acts_like_member.rb b/lib/modules/models/acts_like_member.rb
deleted file mode 100644
index 372f4eed4..000000000
--- a/lib/modules/models/acts_like_member.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-module Modules
- module Models
- module ActsLikeMember
- extend ActiveSupport::Concern
-
- included do
- scope :not_member_of, -> {|item|
- where("
- #{table_name}.id NOT IN (
- SELECT relations.actor_id
- FROM relations
- WHERE (
- relations.actor_type = '#{self.to_s}'
- AND relations.target_type = '#{item.class.to_s}'
- AND relations.target_id = #{item.id}
- )
- )
- ")
- }
- scope :search_order, { order('CHAR_LENGTH(#{table_name}.uname) ASC') }
- scope :without, ->(a) { where("#{table_name}.id NOT IN (?)", a) }
- scope :by_uname, ->(n) { where("#{table_name}.uname ILIKE ?", n) }
- scope :search, ->(q) { by_uname("%#{q.to_s.strip}%") }
- end
-
- def to_param
- uname
- end
-
- module ClassMethods
- def find_by_insensitive_uname(uname)
- find_by_uname(uname) || by_uname(uname).first
- end
-
- def find_by_insensitive_uname!(uname)
- find_by_insensitive_uname(uname) or raise ActiveRecord::RecordNotFound
- end
- end
- end
- end
-end
-
diff --git a/lib/modules/models/autostart.rb b/lib/modules/models/autostart.rb
deleted file mode 100644
index 397989b9a..000000000
--- a/lib/modules/models/autostart.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-module Modules
- module Models
- module Autostart
- extend ActiveSupport::Concern
-
- ONCE_A_12_HOURS = 0
- ONCE_A_DAY = 1
- ONCE_A_WEEK = 2
-
- AUTOSTART_STATUSES = [ONCE_A_12_HOURS, ONCE_A_DAY, ONCE_A_WEEK]
- HUMAN_AUTOSTART_STATUSES = {
- ONCE_A_12_HOURS => :once_a_12_hours,
- ONCE_A_DAY => :once_a_day,
- ONCE_A_WEEK => :once_a_week
- }
-
- included do
- validates :autostart_status, numericality: true,
- inclusion: {in: AUTOSTART_STATUSES}, allow_blank: true
-
- attr_accessible :autostart_status
- end
-
- def human_autostart_status
- self.class.human_autostart_status(autostart_status)
- end
-
- module ClassMethods
- def human_autostart_status(autostart_status)
- I18n.t("layout.products.autostart_statuses.#{HUMAN_AUTOSTART_STATUSES[autostart_status]}")
- end
- end
- end
- end
-end
\ No newline at end of file
diff --git a/lib/modules/models/commit_and_version.rb b/lib/modules/models/commit_and_version.rb
deleted file mode 100644
index fac090b08..000000000
--- a/lib/modules/models/commit_and_version.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-module Modules
- module Models
- module CommitAndVersion
- extend ActiveSupport::Concern
-
- included do
-
- validate -> {
- if project && (commit_hash.blank? || project.repo.commit(commit_hash).blank?)
- errors.add :commit_hash, I18n.t('flash.build_list.wrong_commit_hash', commit_hash: commit_hash)
- end
- }
-
- before_validation :set_commit_and_version
- before_create :set_last_published_commit
- end
-
- protected
-
- def set_commit_and_version
- if project && project_version.present? && commit_hash.blank?
- self.commit_hash = project.repo.commits(project_version).try(:first).try(:id)
- elsif project_version.blank? && commit_hash.present?
- self.project_version = commit_hash
- end
- end
-
- def set_last_published_commit
- return unless self.respond_to? :last_published_commit_hash # product?
- last_commit = self.last_published.first.try :commit_hash
- if last_commit && self.project.repo.commit(last_commit).present? # commit(nil) is not nil!
- self.last_published_commit_hash = last_commit
- end
- end
- end
- end
-end
diff --git a/lib/modules/models/file_store_clean.rb b/lib/modules/models/file_store_clean.rb
deleted file mode 100644
index 68b1ae2c3..000000000
--- a/lib/modules/models/file_store_clean.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-module Modules
- module Models
- module FileStoreClean
- extend ActiveSupport::Concern
-
- included do
- def destroy
- destroy_files_from_file_store if Rails.env.production?
- super
- end
- later :destroy, queue: :clone_build
-
- def sha1_of_file_store_files
- raise NotImplementedError, "You should implement this method"
- end
-
- def destroy_files_from_file_store(args = sha1_of_file_store_files)
- files = *args
- token = User.find_by_uname('file_store').authentication_token
- uri = URI APP_CONFIG['file_store_url']
- Net::HTTP.start(uri.host, uri.port) do |http|
- files.each do |sha1|
- begin
- req = Net::HTTP::Delete.new("/api/v1/file_stores/#{sha1}.json")
- req.basic_auth token, ''
- http.request(req)
- rescue # Dont care about it
- end
- end
- end
- end
-
- def later_destroy_files_from_file_store(args)
- destroy_files_from_file_store(args)
- end
- later :later_destroy_files_from_file_store, queue: :clone_build
- end
-
- def self.file_exist_on_file_store?(sha1)
- begin
- resp = JSON(RestClient.get "#{APP_CONFIG['file_store_url']}/api/v1/file_stores.json", params: {hash: sha1})
- rescue # Dont care about it
- resp = []
- end
- if resp[0].respond_to?('[]') && resp[0]['file_name'] && resp[0]['sha1_hash']
- true
- else
- false
- end
- end
-
- end
- end
-end
diff --git a/lib/modules/models/git.rb b/lib/modules/models/git.rb
deleted file mode 100644
index a1d56afa3..000000000
--- a/lib/modules/models/git.rb
+++ /dev/null
@@ -1,246 +0,0 @@
-require 'nokogiri'
-require 'open-uri'
-
-module Modules
- module Models
- module Git
- extend ActiveSupport::Concern
-
- included do
- has_attached_file :srpm
-
- validates_attachment_size :srpm, less_than_or_equal_to: 500.megabytes
- validates_attachment_content_type :srpm, content_type: ['application/octet-stream', "application/x-rpm", "application/x-redhat-package-manager"], message: I18n.t('layout.invalid_content_type')
-
- after_create :create_git_repo
- after_commit(on: :create) {|p| p.fork_git_repo unless p.is_root?} # later with resque
- after_commit(on: :create) {|p| p.import_attached_srpm if p.srpm?} # later with resque # should be after create_git_repo
- after_destroy :destroy_git_repo
- # after_rollback -> { destroy_git_repo rescue true if new_record? }
-
- later :import_attached_srpm, queue: :fork_import
- later :fork_git_repo, queue: :fork_import
- end
-
- def repo
- @repo ||= Grit::Repo.new(path) rescue Grit::Repo.new(GAP_REPO_PATH)
- end
-
- def path
- build_path(name_with_owner)
- end
-
- def versions
- repo.tags.map(&:name) + repo.branches.map(&:name)
- end
-
- def create_branch(new_ref, from_ref, user)
- return false if new_ref.blank? || from_ref.blank? || !(from_commit = repo.commit(from_ref))
- status, out, err = repo.git.native(:branch, {process_info: true}, new_ref, from_commit.id)
- if status == 0
- Resque.enqueue(GitHook, owner.uname, name, from_commit.id, GitHook::ZERO, "refs/heads/#{new_ref}", 'commit', "user-#{user.id}", nil)
- return true
- end
- return false
-
- end
-
- def delete_branch(branch, user)
- return false if default_branch == branch.name
- message = repo.git.native(:branch, {}, '-D', branch.name)
- if message.present?
- Resque.enqueue(GitHook, owner.uname, name, GitHook::ZERO, branch.commit.id, "refs/heads/#{branch.name}", 'commit', "user-#{user.id}", message)
- end
- return message.present?
- end
-
- def update_file(path, data, options = {})
- head = options[:head].to_s || default_branch
- actor = get_actor(options[:actor])
- filename = File.split(path).last
- message = options[:message]
- message = "Updated file #{filename}" if message.nil? or message.empty?
-
- # can not write to unexisted branch
- return false if repo.branches.select{|b| b.name == head}.size != 1
-
- parent = repo.commits(head).first
-
- index = repo.index
- index.read_tree(parent.tree.id)
-
- # can not create new file
- return false if (index.current_tree / path).nil?
-
- system "sudo chown -R rosa:rosa #{repo.path}" #FIXME Permission denied - /mnt/gitstore/git_projects/...
- index.add(path, data)
- if sha1 = index.commit(message, parents: [parent], actor: actor, last_tree: parent.tree.id, head: head)
- Resque.enqueue(GitHook, owner.uname, name, sha1, sha1, "refs/heads/#{head}", 'commit', "user-#{options[:actor].id}", message)
- end
- sha1
- end
-
- def paginate_commits(treeish, options = {})
- options[:page] = options[:page].try(:to_i) || 1
- options[:per_page] = options[:per_page].try(:to_i) || 20
-
- skip = options[:per_page] * (options[:page] - 1)
- last_page = (skip + options[:per_page]) >= repo.commit_count(treeish)
-
- [repo.commits(treeish, options[:per_page], skip), options[:page], last_page]
- end
-
- def tree_info(tree, treeish = nil, path = nil)
- return [] unless tree
- grouped = tree.contents.sort_by{|c| c.name.downcase}.group_by(&:class)
- [
- grouped[Grit::Tree],
- grouped[Grit::Blob],
- grouped[Grit::Submodule]
- ].compact.flatten.map do |node|
- node_path = File.join([path.present? ? path : nil, node.name].compact)
- [
- node,
- node_path,
- repo.log(treeish, node_path, max_count: 1).first
- ]
- end
- end
-
- def import_srpm(srpm_path = srpm.path, branch_name = 'import')
- token = User.find_by_uname('rosa_system').authentication_token
- opts = [srpm_path, path, branch_name, Rails.root.join('bin', 'file-store.rb'), token, APP_CONFIG['file_store_url']].join(' ')
- system("#{Rails.root.join('bin', 'import_srpm.sh')} #{opts} >> /dev/null 2>&1")
- end
-
- def is_empty?
- repo.branches.count == 0
- end
-
- def total_commits_count
- return 0 if is_empty?
- %x(cd #{path} && git rev-list --all | wc -l).to_i
- end
-
- protected
-
- def build_path(dir)
- File.join(APP_CONFIG['git_path'], 'git_projects', "#{dir}.git")
- end
-
- def import_attached_srpm
- if srpm?
- import_srpm # srpm.path
- self.srpm = nil; save # clear srpm
- end
- end
-
- def create_git_repo
- if is_root?
- Grit::Repo.init_bare(path)
- write_hook
- end
- end
-
- def fork_git_repo
- dummy = Grit::Repo.new(path) rescue parent.repo.fork_bare(path, shared: false)
- write_hook
- end
-
- def destroy_git_repo
- FileUtils.rm_rf path
- end
-
- def write_hook
- hook = "/home/#{APP_CONFIG['shell_user']}/gitlab-shell/hooks/post-receive"
- hook_file = File.join(path, 'hooks', 'post-receive')
- FileUtils.ln_sf hook, hook_file
- end
-
- def get_actor(actor = nil)
- @last_actor = case actor.class.to_s
- when 'Grit::Actor' then options[:actor]
- when 'Hash' then Grit::Actor.new(actor[:name], actor[:email])
- when 'String' then Grit::Actor.from_stirng(actor)
- else begin
- if actor.respond_to?(:name) and actor.respond_to?(:email)
- Grit::Actor.new(actor.name, actor.email)
- else
- config = Grit::Config.new(repo)
- Grit::Actor.new(config['user.name'], config['user.email'])
- end
- end
- end
- @last_actor
- end
-
- module ClassMethods
- MAX_SRC_SIZE = 1024*1024*256
-
- def process_hook(owner_uname, repo, newrev, oldrev, ref, newrev_type, user = nil, message = nil)
- rec = GitHook.new(owner_uname, repo, newrev, oldrev, ref, newrev_type, user, message)
- Modules::Observers::ActivityFeed::Git.create_notifications rec
- end
-
- def run_mass_import(url, srpms_list, visibility, owner, add_to_repository_id)
- doc = Nokogiri::HTML(open(url))
- links = doc.css("a[href$='.src.rpm']")
- return if links.count == 0
- filter = srpms_list.lines.map(&:chomp).map(&:strip).select(&:present?)
-
- repository = Repository.find add_to_repository_id
- platform = repository.platform
- dir = Dir.mktmpdir 'mass-import-', APP_CONFIG['tmpfs_path']
- links.each do |link|
- begin
- package = link.attributes['href'].value
- package.chomp!; package.strip!
-
- next if package.size == 0 || package !~ /^[\w\.\-]+$/
- next if filter.present? && !filter.include?(package)
-
- uri = URI "#{url}/#{package}"
- srpm_file = "#{dir}/#{package}"
- Net::HTTP.start(uri.host) do |http|
- if http.request_head(uri.path)['content-length'].to_i < MAX_SRC_SIZE
- f = open(srpm_file, 'wb')
- http.request_get(uri.path) do |resp|
- resp.read_body{ |segment| f.write(segment) }
- end
- f.close
- end
- end
- if name = `rpm -q --qf '[%{Name}]' -p #{srpm_file}` and $?.success? and name.present?
- next if owner.projects.exists?(name: name)
- description = `rpm -q --qf '[%{Description}]' -p #{srpm_file}`.scrub('')
-
- project = owner.projects.build(
- name: name,
- description: description,
- visibility: visibility,
- is_package: false # See: Hook for #attach_to_personal_repository
- )
- project.owner = owner
- if project.save
- repository.projects << project rescue nil
- project.update_attributes(is_package: true)
- project.import_srpm srpm_file, platform.name
- end
- end
- rescue => e
- f.close if defined?(f)
- Airbrake.notify_or_ignore(e, link: link.to_s, url: url, owner: owner)
- ensure
- File.delete srpm_file if srpm_file
- end
- end
- rescue => e
- Airbrake.notify_or_ignore(e, url: url, owner: owner)
- ensure
- FileUtils.remove_entry_secure dir if dir
- end
-
- end
- end
- end
-end
diff --git a/lib/modules/models/markdown.rb b/lib/modules/models/markdown.rb
deleted file mode 100644
index 4483fcb64..000000000
--- a/lib/modules/models/markdown.rb
+++ /dev/null
@@ -1,193 +0,0 @@
-# This module is based on
-# https://github.com/gitlabhq/gitlabhq/blob/397c3da9758c03a215a308c011f94261d9c61cfa/lib/gitlab/markdown.rb
-module Modules
- module Models
- # Custom parser for GitLab-flavored Markdown
- #
- # It replaces references in the text with links to the appropriate items in
- # GitLab.
- #
- # Supported reference formats are:
- # * @foo for team members
- # * for issues & pull requests:
- # * #123
- # * abf#123
- # * abf/rosa-build#123
- # * 123456 for commits
- #
- # It also parses Emoji codes to insert images. See
- # http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
- #
- # Examples
- #
- # >> gfm("Hey @david, can you fix this?")
- # => "Hey @david, can you fix this?"
- #
- # >> gfm("Commit 35d5f7c closes #1234")
- # => "Commit 35d5f7c closes #1234"
- #
- # >> gfm(":trollface:")
- # => "
- module Markdown
- include IssuesHelper
-
- attr_reader :html_options
-
- # Public: Parse the provided text with GitLab-Flavored Markdown
- #
- # text - the source text
- # html_options - extra options for the reference links as given to link_to
- #
- # Note: reference links will only be generated if @project is set
- def gfm(text, html_options = {})
- return text if text.nil?
-
- # Duplicate the string so we don't alter the original, then call to_str
- # to cast it back to a String instead of a SafeBuffer. This is required
- # for gsub calls to work as we need them to.
- text = text.dup.to_str
-
- @html_options = html_options
-
- # Extract pre blocks so they are not altered
- # from http://github.github.com/github-flavored-markdown/
- text.gsub!(%r{.*?
|.*?
}m) { |match| extract_piece(match) }
- # Extract links with probably parsable hrefs
- text.gsub!(%r{.*?}m) { |match| extract_piece(match) }
- # Extract images with probably parsable src
- text.gsub!(%r{}m) { |match| extract_piece(match) }
-
- # TODO: add popups with additional information
-
- text = parse(text)
-
- # Insert pre block extractions
- text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
- insert_piece($1)
- end
-
- sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class)
- end
-
- private
-
- def extract_piece(text)
- @extractions ||= {}
-
- md5 = Digest::MD5.hexdigest(text)
- @extractions[md5] = text
- "{gfm-extraction-#{md5}}"
- end
-
- def insert_piece(id)
- @extractions[id]
- end
-
- # Private: Parses text for references and emoji
- #
- # text - Text to parse
- #
- # Note: reference links will only be generated if @project is set
- #
- # Returns parsed text
- def parse(text)
- parse_references(text) if @project
- parse_emoji(text)
-
- text
- end
-
- REFERENCE_PATTERN = %r{
- (?[\W\/])? # Prefix
- ( # Reference
- @(?[a-zA-Z][a-zA-Z0-9_\-\.]*) # User/Group uname
- |(?(?:[a-zA-Z0-9\-_]*\/)?(?:[a-zA-Z0-9\-_]*)?\#[0-9]+) # Issue ID
- |(?[\h]{6,40}) # Commit ID
- )
- (?\W)? # Suffix
- }x.freeze
-
- TYPES = [:user, :issue, :commit].freeze
-
- def parse_references(text)
- # parse reference links
- text.gsub!(REFERENCE_PATTERN) do |match|
- prefix = $~[:prefix]
- suffix = $~[:suffix]
- type = TYPES.select{|t| !$~[t].nil?}.first
- identifier = $~[type]
-
- # Avoid HTML entities
- if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';'
- match
- elsif ref_link = reference_link(type, identifier)
- "#{prefix}#{ref_link}#{suffix}"
- else
- match
- end
- end
- end
-
- EMOJI_PATTERN = %r{(:(\S+):)}.freeze
-
- def parse_emoji(text)
- # parse emoji
- text.gsub!(EMOJI_PATTERN) do |match|
- if valid_emoji?($2)
- image_tag(image_path("emoji/#{$2}.png"), class: 'emoji', title: $1, alt: $1, size: "20x20")
- else
- match
- end
- end
- end
-
- # Private: Checks if an emoji icon exists in the image asset directory
- #
- # emoji - Identifier of the emoji as a string (e.g., "+1", "heart")
- #
- # Returns boolean
- def valid_emoji?(emoji)
- Emoji.names.include? emoji
- end
-
- # Private: Dispatches to a dedicated processing method based on reference
- #
- # reference - Object reference ("@1234", "!567", etc.)
- # identifier - Object identifier (Issue ID, SHA hash, etc.)
- #
- # Returns string rendered by the processing method
- def reference_link(type, identifier)
- send("reference_#{type}", identifier)
- end
-
- def reference_user(identifier)
- member = User.where(uname: identifier).first || Group.where(uname: identifier).first
- if member
- link_to("@#{identifier}", "/#{identifier}", html_options.merge(title: member.fullname, class: "gfm gfm-member #{html_options[:class]}"))
- end
- end
-
- def reference_issue(identifier)
- if issue = Issue.find_by_hash_tag(identifier, current_ability, @project)
- if issue.pull_request
- title = "#{PullRequest.model_name.human}: #{issue.title}"
- url = project_pull_request_path(issue.project, issue.pull_request)
- else
- title = "#{Issue.model_name.human}: #{issue.title}"
- url = project_issue_path(issue.project.owner, issue.project.name, issue.serial_id)
- end
- link_to(identifier, url, html_options.merge(title: title, class: "gfm gfm-issue #{html_options[:class]}"))
- end
- end
-
- def reference_commit(identifier)
- if commit = @project.repo.commit(identifier)
- link_to shortest_hash_id(commit.id), commit_path(@project, commit.id)
- title = GitPresenters::CommitAsMessagePresenter.present(commit, project: @project) do |presenter|
- link_to(identifier, commit_path(@project, commit), html_options.merge(title: presenter.caption, class: "gfm gfm-commit #{html_options[:class]}"))
- end
- end
- end
- end
- end
-end
diff --git a/lib/modules/models/owner.rb b/lib/modules/models/owner.rb
deleted file mode 100644
index d9e8a6423..000000000
--- a/lib/modules/models/owner.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-module Modules
- module Models
- module Owner
- extend ActiveSupport::Concern
-
- included do
- validates :owner, presence: true
- after_create -> { relations.create actor_id: owner.id, actor_type: owner.class.to_s, role: 'admin' }
- end
-
- end
- end
-end
diff --git a/lib/modules/models/personal_repository.rb b/lib/modules/models/personal_repository.rb
deleted file mode 100644
index 2a4ba43fd..000000000
--- a/lib/modules/models/personal_repository.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-module Modules
- module Models
- module PersonalRepository
- extend ActiveSupport::Concern
-
- included do
- after_create :create_personal_repository, unless: :system?
- end
-
- def create_personal_repository
- begin
- pl = own_platforms.build
- pl.owner = self
- pl.name = "#{self.uname}_personal"
- pl.description = "#{self.uname}_personal"
- pl.platform_type = 'personal'
- pl.distrib_type = APP_CONFIG['distr_types'].first
- pl.visibility = 'open'
- pl.save!
-
- rep = pl.repositories.build
- rep.name = 'main'
- rep.description = 'main'
- rep.save!
- rescue Exception => e
- pl.now_destroy rescue false
- raise e
- end
- return true
- end
-
- def personal_platform
- own_platforms.personal.first
- end
-
- def personal_repository
- personal_platform.repositories.first
- end
-
- module ClassMethods
- end
- end
- end
-end
diff --git a/lib/modules/models/regeneration_status.rb b/lib/modules/models/regeneration_status.rb
deleted file mode 100644
index 80e12341a..000000000
--- a/lib/modules/models/regeneration_status.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-module Modules
- module Models
- module RegenerationStatus
- extend ActiveSupport::Concern
-
- READY = 0
- WAITING_FOR_REGENERATION = 100
- REGENERATING = 200
-
- HUMAN_STATUSES = {
- READY => :ready,
- WAITING_FOR_REGENERATION => :waiting_for_regeneration,
- REGENERATING => :regenerating
- }
-
- HUMAN_REGENERATION_STATUSES = {
- AbfWorker::BaseObserver::COMPLETED => :completed,
- AbfWorker::BaseObserver::FAILED => :failed,
- AbfWorker::BaseObserver::CANCELED => :canceled
- }.freeze
-
- included do
- after_update :cleanup_file_store
-
- def sha1_of_file_store_files
- files = []
- files << last_regenerated_log_sha1 if last_regenerated_log_sha1.present?
- files
- end
-
- def human_regeneration_status
- self.class::HUMAN_REGENERATION_STATUSES[last_regenerated_status] || :no_data
- end
-
- def human_status
- self.class::HUMAN_STATUSES[status] || :no_data
- end
-
- def cleanup_file_store
- old_log_sha1 = last_regenerated_log_sha1_was
- if old_log_sha1.present? && old_log_sha1 != last_regenerated_log_sha1
- later_destroy_files_from_file_store([old_log_sha1])
- end
- end
- end
- end
- end
-end
\ No newline at end of file
diff --git a/lib/modules/models/time_living.rb b/lib/modules/models/time_living.rb
deleted file mode 100644
index fde28e5e8..000000000
--- a/lib/modules/models/time_living.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-module Modules
- module Models
- module TimeLiving
- extend ActiveSupport::Concern
-
- included do
-
- validates :time_living, numericality: {
- only_integer: true
- }, presence: true
-
- validate -> {
- # MIN_TIME_LIVING <= time_living <= MAX_TIME_LIVING or
- # 2 min <= time_living <= 12 hours
- # time_living in seconds
- min = self.class.const_defined?(:MIN_TIME_LIVING) ? self.class::MIN_TIME_LIVING : 120
- max = self.class.const_defined?(:MAX_TIME_LIVING) ? self.class::MAX_TIME_LIVING : 43200
- if min > time_living.to_i || time_living.to_i > max
- errors.add :time_living,
- I18n.t('flash.time_living.numericality_error', min: (min / 60), max: (max / 60))
- end
- }
-
- before_validation :convert_time_living
- attr_accessible :time_living
- end
-
- protected
-
- def convert_time_living
- self.time_living = time_living.to_i * 60 if time_living_was.to_i != time_living.to_i
- end
- end
- end
-end
diff --git a/lib/modules/models/wiki.rb b/lib/modules/models/wiki.rb
deleted file mode 100644
index 033df0881..000000000
--- a/lib/modules/models/wiki.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-module Modules
- module Models
- module Wiki
- extend ActiveSupport::Concern
-
- included do
- after_save :create_wiki
- after_destroy :destroy_wiki
- end
-
- def wiki_path
- build_path(wiki_repo_name)
- end
-
- def wiki_repo_name
- File.join owner.uname, "#{name}.wiki"
- end
-
- protected
-
- def create_wiki
- if has_wiki && !FileTest.exist?(wiki_path)
- Grit::Repo.init_bare(wiki_path)
- wiki = Gollum::Wiki.new(wiki_path, {base_path: Rails.application.routes.url_helpers.project_wiki_index_path(owner, self)})
- wiki.write_page('Home', :markdown, I18n.t("wiki.seed.welcome_content"),
- {name: owner.name, email: owner.email, message: 'Initial commit'})
- end
- end
-
- def destroy_wiki
- FileUtils.rm_rf wiki_path
- end
-
- module ClassMethods
- end
- end
- end
-end