Skip to content

Commit

Permalink
[api][webui] make maintained projects a model
Browse files Browse the repository at this point in the history
This fixes some database issues. Brought to you from OhgottOhgottOhgott-Releases....
  • Loading branch information
adrianschroeter committed Sep 17, 2014
1 parent 78f9e47 commit 34c1679
Show file tree
Hide file tree
Showing 15 changed files with 121 additions and 85 deletions.
8 changes: 5 additions & 3 deletions src/api/app/controllers/webui/project_controller.rb
Expand Up @@ -285,8 +285,10 @@ def find_packages_info
end

def find_maintenance_infos
pm = @project.api_obj.maintenance_project
@project_maintenance_project = pm.name if pm
@project.api_obj.maintenance_projects.each do |pm|
# FIXME: skip the non official ones
@project_maintenance_project = pm.maintenance_project.name
end

@is_maintenance_project = @project.api_obj.is_maintenance?
if @is_maintenance_project
Expand All @@ -298,7 +300,7 @@ def find_maintenance_infos

@maintained_projects = []
@project.api_obj.maintained_projects.each do |mp|
@maintained_projects << mp.name
@maintained_projects << mp.project.name
end
end
@is_incident_project = @project.api_obj.is_maintenance_incident?
Expand Down
49 changes: 26 additions & 23 deletions src/api/app/helpers/branch_package.rb
Expand Up @@ -270,35 +270,38 @@ def determine_details_about_package_to_branch(p)
logger.info "sources will get copied from devel package #{p[:copy_from_devel].project.name}/#{p[:copy_from_devel].name}" unless p[:copy_from_devel] == p[:package]
end

incident_pkg = nil
if (!p[:copy_from_devel] or p[:copy_from_devel] == p[:package]) \
and p[:package].is_a? Package \
and p[:link_target_project].is_a?(Project) and p[:link_target_project].is_maintenance_release? \
and mp = p[:link_target_project].maintenance_project
# no defined devel area or no package inside, but we branch from a release are: check in open incidents

path = "/search/package/id?match=(linkinfo/@package=\"#{CGI.escape(p[:package].name)}\"+and+linkinfo/@project=\"#{CGI.escape(p[:link_target_project].name)}\""
path += "+and+starts-with(@project,\"#{CGI.escape(mp.name)}%3A\"))"
answer = Suse::Backend.post path, nil
data = REXML::Document.new(answer.body)
incident_pkg = nil
data.elements.each('collection/package') do |e|
ipkg = Package.find_by_project_and_name(e.attributes['project'], e.attributes['name'])
if ipkg.nil?
logger.error "read permission or data inconsistency, backend delivered package as linked package where no database object exists: #{e.attributes['project']} / #{e.attributes['name']}"
else
# is incident ?
if ipkg.project.is_maintenance_incident? and ipkg.project.is_unreleased?
# is a newer incident ?
if incident_pkg.nil? or ipkg.project.name.gsub(/.*:/, '').to_i > incident_pkg.project.name.gsub(/.*:/, '').to_i
incident_pkg = ipkg
and p[:link_target_project].is_a?(Project) \
and p[:link_target_project].is_maintenance_release? \
and p[:link_target_project].maintenance_projects.count
p[:link_target_project].maintenance_projects.each do |mp|
# no defined devel area or no package inside, but we branch from a release are: check in open incidents

path = "/search/package/id?match=(linkinfo/@package=\"#{CGI.escape(p[:package].name)}\"+and+linkinfo/@project=\"#{CGI.escape(p[:link_target_project].name)}\""
path += "+and+starts-with(@project,\"#{CGI.escape(mp.maintenance_project.name)}%3A\"))"
answer = Suse::Backend.post path, nil
data = REXML::Document.new(answer.body)
data.elements.each('collection/package') do |e|
ipkg = Package.find_by_project_and_name(e.attributes['project'], e.attributes['name'])
if ipkg.nil?
logger.error "read permission or data inconsistency, backend delivered package as linked package where no database object exists: #{e.attributes['project']} / #{e.attributes['name']}"
else
# is incident ?
if ipkg.project.is_maintenance_incident? and ipkg.project.is_unreleased?
# is a newer incident ?
if incident_pkg.nil? or ipkg.project.name.gsub(/.*:/, '').to_i > incident_pkg.project.name.gsub(/.*:/, '').to_i
incident_pkg = ipkg
end
end
end
end
end
if incident_pkg
p[:copy_from_devel] = incident_pkg
logger.info "sources will get copied from incident package #{p[:copy_from_devel].project.name}/#{p[:copy_from_devel].name}"
end
end
if incident_pkg
p[:copy_from_devel] = incident_pkg
logger.info "sources will get copied from incident package #{p[:copy_from_devel].project.name}/#{p[:copy_from_devel].name}"
elsif not @copy_from_devel and p[:package].is_a? Package and (p[:package].develpackage or p[:package].project.develproject)
p[:package] = p[:package].resolve_devel_package
p[:link_target_project] = p[:package].project
Expand Down
2 changes: 1 addition & 1 deletion src/api/app/helpers/maintenance_helper.rb
Expand Up @@ -242,7 +242,7 @@ def get_updateinfo_id(sourcePackage, targetRepo)
# expand a possible defined update info template in release target of channel
projectFilter = nil
if p = sourcePackage.project.find_parent and p.is_maintenance?
projectFilter = p.maintained_projects
projectFilter = p.maintained_projects.map{|mp| mp.project}
end
# prefer a channel in the source project to avoid double hits exceptions
ct = ChannelTarget.find_by_repo(targetRepo, [sourcePackage.project]) || ChannelTarget.find_by_repo(targetRepo, projectFilter)
Expand Down
2 changes: 1 addition & 1 deletion src/api/app/models/channel_binary.rb
Expand Up @@ -21,7 +21,7 @@ def create_channel_package(pkg, maintenanceProject)
return if Package.exists_by_project_and_name(pkg.project.name, name)

# do we need to take care about a maintained list from upper project?
if maintenanceProject and not maintenanceProject.maintained_projects.include? cp.project
if maintenanceProject and MaintainedProject.where(maintenance_project: maintenanceProject, project: cp.project).count < 1
# not a maintained project here
return
end
Expand Down
4 changes: 4 additions & 0 deletions src/api/app/models/maintained_project.rb
@@ -0,0 +1,4 @@
class MaintainedProject < ActiveRecord::Base
belongs_to :project, foreign_key: :project_id
belongs_to :maintenance_project, :class_name => "Project", foreign_key: :maintenance_project_id
end
45 changes: 9 additions & 36 deletions src/api/app/models/project.rb
Expand Up @@ -58,10 +58,11 @@ class ForbiddenError < APIException
# optional
has_one :maintenance_incident, dependent: :delete, foreign_key: :db_project_id

# self-reference between devel projects and maintenance projects
has_many :maintained_projects, :class_name => 'Project', :foreign_key => 'maintenance_project_id'
belongs_to :maintenance_project, :class_name => 'Project'
# projects can maintain other projects
has_many :maintained_projects, :class_name => 'MaintainedProject', foreign_key: :maintenance_project_id, :dependent => :delete_all
has_many :maintenance_projects, :class_name => 'MaintainedProject', foreign_key: :project_id, :dependent => :delete_all

# develproject is history, use develpackage instead. FIXME3.0: clean this up
has_many :develprojects, :class_name => 'Project', :foreign_key => 'develproject_id'
belongs_to :develproject, :class_name => 'Project'

Expand Down Expand Up @@ -679,25 +680,19 @@ def update_linked_projects(xmlhash)
end

def update_maintained_prjs_from_xml(xmlhash)
#--- maintenance-related parts ---#

# First check all current maintained project relations
olds = maintained_projects.pluck(:name)
olds = {}
self.maintained_projects.each{|mp| olds[mp.project.name]=mp}

# Set this project as the maintenance project for all maintained projects found in the XML
xmlhash.get('maintenance').elements('maintains') do |maintains|
pn = maintains['project']
next if olds.delete(pn)
maintained_project = Project.find_by_name!(pn)
maintained_project.maintenance_project = self
maintained_project.save!
MaintainedProject.create(project: maintained_project, maintenance_project: self)
end

olds.each do |pn|
maintained_project = Project.find_by_name!(pn)
maintained_project.maintenance_project = nil
maintained_project.save!
end
maintained_projects.delete(project: olds.values)
end

def check_for_empty_repo_list(list, error_prefix)
Expand Down Expand Up @@ -1023,28 +1018,6 @@ def set_project_type(project_type_name)
return true
end

def maintenance_project
return Project.find_by_id(maintenance_project_id)
end

def set_maintenance_project(project)
check_write_access!

if project.class == Project
self.maintenance_project_id = project.id
self.save!
return true
elsif project.is_a? String
prj = Project.find_by_name(project)
if prj
self.maintenance_project_id = prj.id
self.save!
return true
end
end
return false
end

def add_repository_with_targets(repoName, source_repo, add_target_repos = [])
trepo = self.repositories.create :name => repoName
source_repo.repository_architectures.each do |ra|
Expand Down Expand Up @@ -1393,7 +1366,7 @@ def release_targets_ng
next
end

pkg_name, rt_name = pkg.name.split('.', 2)
rt_name = pkg.name.split('.', 2).last
next unless rt_name
if pkg.is_patchinfo?
# We found a patchinfo that is specific to (at least) one release target!
Expand Down
6 changes: 3 additions & 3 deletions src/api/app/views/models/_project.xml.builder
Expand Up @@ -66,10 +66,10 @@ xml.project(project_attributes) do
end
end

unless my_model.maintained_projects.empty?
unless MaintainedProject.where(maintenance_project_id: my_model.id).empty?
xml.maintenance do |maintenance|
my_model.maintained_projects.each do |mp|
maintenance.maintains(:project => mp.name)
MaintainedProject.where(maintenance_project_id: my_model.id).each do |mp|
maintenance.maintains(:project => mp.project.name)
end
end
end
Expand Down
39 changes: 39 additions & 0 deletions src/api/db/migrate/20140916135426_project_maintains.rb
@@ -0,0 +1,39 @@
class ProjectMaintains < ActiveRecord::Migration

class OldProject < ActiveRecord::Base
self.table_name = 'projects'
end

def self.up

create_table :maintained_projects do |t|
t.references :project, null: false
t.integer :maintenance_project_id, null: false
end
execute("alter table maintained_projects add foreign key (project_id) references projects(id)")
execute("alter table maintained_projects add foreign key (maintenance_project_id) references projects(id)")
add_index :maintained_projects, [:project_id, :maintenance_project_id], :unique => true, :name => "uniq_index"

s = OldProject.find_by_sql "SELECT id,maintenance_project_id FROM projects WHERE NOT ISNULL(maintenance_project_id)"
s.each do |e|
next unless Project.find_by_id e.maintenance_project_id # broken data anyway
MaintainedProject.create(project_id: e.id, maintenance_project_id: e.maintenance_project_id)
end

remove_column :projects, :maintenance_project_id
end


def self.down
add_column :projects, :maintenance_project_id, :integer

MaintainedProject.all.each do |pm|
p = Project.find_by_id(pm.maintenance_project_id)
p.maintenance_project_id = pm.project_id
p.save
end

drop_table :maintained_projects
end

end
15 changes: 13 additions & 2 deletions src/api/db/structure.sql
Expand Up @@ -617,6 +617,17 @@ CREATE TABLE `linked_projects` (
UNIQUE KEY `linked_projects_index` (`db_project_id`,`linked_db_project_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `maintained_projects` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`project_id` int(11) NOT NULL,
`maintenance_project_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_index` (`project_id`,`maintenance_project_id`),
KEY `maintenance_project_id` (`maintenance_project_id`),
CONSTRAINT `maintained_projects_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`),
CONSTRAINT `maintained_projects_ibfk_2` FOREIGN KEY (`maintenance_project_id`) REFERENCES `projects` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `maintenance_incidents` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`db_project_id` int(11) DEFAULT NULL,
Expand Down Expand Up @@ -787,14 +798,12 @@ CREATE TABLE `projects` (
`remoteurl` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`remoteproject` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`type_id` int(11) NOT NULL,
`maintenance_project_id` int(11) DEFAULT NULL,
`develproject_id` int(11) DEFAULT NULL,
`delta` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `projects_name_index` (`name`(255)),
KEY `updated_at_index` (`updated_at`),
KEY `devel_project_id_index` (`develproject_id`),
KEY `index_db_projects_on_maintenance_project_id` (`maintenance_project_id`),
KEY `type_id` (`type_id`),
CONSTRAINT `projects_ibfk_1` FOREIGN KEY (`type_id`) REFERENCES `db_project_types` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Expand Down Expand Up @@ -1572,6 +1581,8 @@ INSERT INTO schema_migrations (version) VALUES ('20140908125426');

INSERT INTO schema_migrations (version) VALUES ('20140908135426');

INSERT INTO schema_migrations (version) VALUES ('20140916135426');

INSERT INTO schema_migrations (version) VALUES ('21');

INSERT INTO schema_migrations (version) VALUES ('22');
Expand Down
5 changes: 3 additions & 2 deletions src/api/lib/xpath_engine.rb
Expand Up @@ -103,8 +103,9 @@ def initialize
'LEFT JOIN db_project_types pt ON projects.type_id = pt.id']},
'title' => {:cpart => 'projects.title'},
'description' => {:cpart => 'projects.description'},
'maintenance/maintains/@project' => {:cpart => 'maintained.name', :joins => [
'LEFT JOIN projects AS maintained ON projects.id = maintained.maintenance_project_id']},
'maintenance/maintains/@project' => {:cpart => 'maintains_prj.name', :joins => [
'LEFT JOIN maintained_projects AS maintained_prj ON projects.id = maintained_prj.maintenance_project_id',
'LEFT JOIN projects AS maintains_prj ON maintained_prj.project_id = maintains_prj.id']},
'person/@userid' => {:cpart => 'users.login', :joins => [
'LEFT JOIN relationships AS rpr ON projects.id = rpr.project_id',
'LEFT JOIN users ON users.id = rpr.user_id']},
Expand Down
9 changes: 9 additions & 0 deletions src/api/test/fixtures/maintained_projects.yml
@@ -0,0 +1,9 @@
BaseDistro:
project: BaseDistro
maintenance_project: My_Maintenance
BaseDistro2.0_LinkedUpdateProject:
project: BaseDistro2.0_LinkedUpdateProject
maintenance_project: My_Maintenance
BaseDistro3:
project: BaseDistro3
maintenance_project: My_Maintenance
3 changes: 0 additions & 3 deletions src/api/test/fixtures/projects.yml
Expand Up @@ -14,7 +14,6 @@ BaseDistro:
updated_at: 2005-01-01 01:00:01.000000000 Z
type_id: 1
delta: 1
maintenance_project: My_Maintenance
BaseDistro2.0:
name: BaseDistro2.0
title: This is another base distro
Expand All @@ -32,7 +31,6 @@ BaseDistro2.0_LinkedUpdateProject:
updated_at: 2005-01-01 01:00:01.000000000 Z
type_id: 4
delta: 1
maintenance_project: My_Maintenance
BaseDistro3:
name: BaseDistro3
title: This is another base distro, without update project
Expand All @@ -41,7 +39,6 @@ BaseDistro3:
updated_at: 2005-01-01 01:00:01.000000000 Z
type_id: 4
delta: 1
maintenance_project: My_Maintenance
BaseDistro_Update:
name: BaseDistro:Update
title: This is an update project for the base distro
Expand Down
11 changes: 7 additions & 4 deletions src/api/test/functional/maintenance_test.rb
Expand Up @@ -26,11 +26,14 @@ def test_create_maintenance_project

put '/source/home:tom:maintenance/_meta', '<project name="home:tom:maintenance" kind="maintenance" > <title/> <description/> <maintenance><maintains project="kde4"/></maintenance> </project>'
assert_response :success
get '/source/home:tom:maintenance/_meta'
assert_response :success
assert_xml_tag :tag => 'maintains', :attributes => { project: 'kde4' }

get '/search/project', :match => '[maintenance/maintains/@project="kde4"]'
assert_response :success
assert_xml_tag :tag => 'collection', :children => { count: 1 }
assert_xml_tag :child => { tag: 'project', attributes: { name: 'home:tom:maintenance' } }
assert_xml_tag :tag => 'maintains', :attributes => { project: 'kde4' }

# cleanup
delete '/source/home:tom:maintenance'
Expand Down Expand Up @@ -486,9 +489,9 @@ def test_mbranch_and_maintenance_per_package_request
get "/source/#{incidentProject}/BaseDistro3.Channel/_meta"
assert_response 404 # not a maintained project
# make Channel project a maintained project and try again.
prj = Project.find_by_name('My:Maintenance')
prj.maintained_projects << Project.find_by_name('Channel')
prj.save
mprj = Project.find_by_name('My:Maintenance')
MaintainedProject.create(project: Project.find_by_name('Channel'), maintenance_project: mprj)

post "/source/#{incidentProject}?cmd=addchannels", nil
assert_response :success
get "/source/#{incidentProject}/BaseDistro3.Channel/_meta"
Expand Down
2 changes: 1 addition & 1 deletion src/api/test/unit/code_quality_test.rb
Expand Up @@ -71,7 +71,7 @@ def setup
'BinaryRelease::update_binary_releases_via_json' => 122.54,
'BranchPackage#find_packages_to_branch' => 239.64,
'BranchPackage#create_branch_packages' => 210.91,
'BranchPackage#determine_details_about_package_to_branch' => 196.38,
'BranchPackage#determine_details_about_package_to_branch' => 207.47,
'BranchPackage#check_for_update_project' => 110.23,
'BsRequest#change_review_state' => 203.53,
'BsRequest#apply_default_reviewers' => 129.52,
Expand Down
6 changes: 0 additions & 6 deletions src/api/test/unit/project_test.rb
Expand Up @@ -264,12 +264,6 @@ def test_create_maintenance_project_and_maintained_project
maintenance_project = Project.new(:name => 'Maintenance:Project')
assert_equal true, maintenance_project.set_project_type('maintenance')
assert_equal 'maintenance', maintenance_project.project_type()

# Create a project for which maintenance is done (i.e. a maintained project)
maintained_project = Project.new(:name => 'Maintained:Project')
assert_equal true, maintained_project.set_maintenance_project(maintenance_project)
assert_equal true, maintained_project.set_maintenance_project(maintenance_project.name)
assert_equal maintenance_project, maintained_project.maintenance_project()
end


Expand Down

0 comments on commit 34c1679

Please sign in to comment.