From 284fccf212108e3c5b1d8841e48e424aa9ef9fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Schr=C3=B6ter?= Date: Mon, 2 Jan 2012 16:56:41 +0100 Subject: [PATCH] [api] fix and test branching&release of new packages --- src/api/app/controllers/source_controller.rb | 137 ++++++++++-------- .../fixtures/backend/binary/packageNew.spec | 30 ++++ src/api/test/functional/maintenance_test.rb | 50 ++++++- .../functional/request_controller_test.rb | 3 + 4 files changed, 156 insertions(+), 64 deletions(-) create mode 100644 src/api/test/fixtures/backend/binary/packageNew.spec diff --git a/src/api/app/controllers/source_controller.rb b/src/api/app/controllers/source_controller.rb index e5bf36cc1c4..6d30782920e 100644 --- a/src/api/app/controllers/source_controller.rb +++ b/src/api/app/controllers/source_controller.rb @@ -1229,6 +1229,19 @@ def index_branch # generic branch function for package based, project wide or request based branch def do_branch + # + # 1) BaseProject <-- 2) UpdateProject <-- 3) DevelProject/Package + # X) BranchProject + # + # 2/3) are optional + # + # X) is target_project with target_package, the project where new sources get created + # + # link_target_project points to 3) or to 2) in copy_from_devel case + # + # name of 1) may get used in package or repo names when using :extend_name + # + # set defaults unless params[:attribute] params[:attribute] = "OBS:Maintained" @@ -1249,9 +1262,6 @@ def do_branch unless params[:update_project_attribute] params[:update_project_attribute] = "OBS:UpdateProject" end - if not params[:update_project_attribute] - params[:update_project_attribute] = "OBS:UpdateProject" - end if target_project and not valid_project_name? target_project render_error :status => 400, :errorcode => "invalid_project_name", :message => "invalid project name '#{target_project}'" @@ -1290,9 +1300,10 @@ def do_branch end end - @packages.push({ :target_project => pkg.db_project, :package => pkg, :target_package => "#{pkg.name}.#{pkg.db_project.name}" }) + @packages.push({ :link_target_project => action.source.project, :package => pkg, :target_package => "#{pkg.name}.#{pkg.db_project.name}" }) end elsif params[:project] and params[:package] + pkg = nil if params[:missingok] prj = DbProject.get_by_name params[:project] if DbPackage.exists_by_project_and_name(params[:project], params[:package], follow_project_links=true, allow_remote_packages=true) @@ -1300,19 +1311,19 @@ def do_branch :message => "Branch call with missingok paramater but branch source (#{params[:project]}/#{params[:package]}) exists." return end - pkg = nil else pkg = DbPackage.get_by_project_and_name params[:project], params[:package] + prj = pkg.db_project if pkg end tpkg_name = params[:target_package] tpkg_name = params[:package] unless tpkg_name tpkg_name += ".#{params[:project]}" if extend_names if pkg # local package - @packages.push({ :target_project => pkg.db_project, :package => pkg, :rev => params[:rev], :target_package => tpkg_name }) + @packages.push({ :base_project => prj, :link_target_project => pkg.db_project, :package => pkg, :rev => params[:rev], :target_package => tpkg_name }) else # remote or not existing package - @packages.push({ :target_project => params[:project], :package => params[:package], :rev => params[:rev], :target_package => tpkg_name }) + @packages.push({ :base_project => prj, :link_target_project => (prj||params[:project]), :package => params[:package], :rev => params[:rev], :target_package => tpkg_name }) end else extend_names = true @@ -1327,23 +1338,23 @@ def do_branch end if params[:value] DbPackage.find_by_attribute_type_and_value( at, params[:value], params[:package] ) do |pkg| - @packages.push({ :target_project => pkg.db_project, :package => pkg, :target_package => "#{pkg.name}.#{pkg.db_project.name}" }) + @packages.push({ :base_project => pkg.db_project, :link_target_project => pkg.db_project, :package => pkg, :target_package => "#{pkg.name}.#{pkg.db_project.name}" }) end # FIXME: how to handle linked projects here ? shall we do at all or has the tagger (who creates the attribute) to create the package instance ? else # Find all direct instances of a package DbPackage.find_by_attribute_type( at, params[:package] ).each do |pkg| - @packages.push({ :target_project => pkg.db_project, :package => pkg, :target_package => "#{pkg.name}.#{pkg.db_project.name}" }) + @packages.push({ :base_project => pkg.db_project, :link_target_project => pkg.db_project, :package => pkg, :target_package => "#{pkg.name}.#{pkg.db_project.name}" }) end # Find all indirect instance via project links, a new package will get created on submit accept if params[:package] projects = DbProject.find_by_attribute_type( at ) projects.each do |prj| - unless @packages.map {|p| p[:target_project] }.include? prj # avoid double instance from direct found packages + unless @packages.map {|p| p[:link_target_project] }.include? prj # avoid double instance from direct found packages prj.linkedprojects.each do |lprj| if lprj.linked_db_project if pkg = lprj.linked_db_project.db_packages.find_by_name( params[:package] ) - @packages.push({ :target_project => prj, :package => pkg, :target_package => "#{pkg.name}.#{pkg.db_project.name}" }) + @packages.push({ :base_project => prj,:link_target_project => prj, :package => pkg, :target_package => "#{pkg.name}.#{pkg.db_project.name}" }) else # FIXME: add support for branching from remote projects end @@ -1365,55 +1376,57 @@ def do_branch # Just requests should be nearly the same unless params[:request] @packages.each do |p| - prj = nil + next unless p[:link_target_project].class == DbProject # only for local source projects pkg = p[:package] - next unless pkg.class == DbPackage # only for local packages - prj = pkg.db_project + prj = p[:link_target_project] + if pkg.class == DbPackage + prj = pkg.db_project + pkg_name = pkg.name + else + pkg_name = pkg + end # Check for defined update project if prj and a = prj.find_attribute(update_project_at[0], update_project_at[1]) and a.values[0] - if pa = DbPackage.find_by_project_and_name( a.values[0].value, pkg.name ) + if pa = DbPackage.find_by_project_and_name( a.values[0].value, pkg_name ) # We have a package in the update project already, take that - pkg = pa - prj = pkg.db_project + p[:package] = pa + p[:link_target_project] = pa.db_project logger.debug "branch call found package in update project #{prj.name}" else update_prj = DbProject.find_by_name( a.values[0].value ) if update_prj - update_pkg = update_prj.find_package( pkg.name ) + p[:link_target_project] = update_prj + update_pkg = update_prj.find_package( pkg_name ) if update_pkg # We have no package in the update project yet, but sources are reachable via project link if update_prj.develproject and up = update_prj.develproject.find_package(pkg.name) # nevertheless, check if update project has a devel project which contains an instance - pkg = up - prj = pkg.db_project# unless copy_from_devel + p[:package] = up + p[:link_target_project] = up.db_project else - pkg = update_pkg - prj = update_prj + p[:package] = pkg end end + logger.debug "link target will point to update project #{prj.name}" end end end # validate and resolve devel package or devel project definitions if copy_from_devel - p[:copy_from_devel] = pkg.resolve_devel_package - elsif not params[:ignoredevel] and pkg and ( pkg.develproject or pkg.develpackage or pkg.db_project.develproject ) - pkg = pkg.resolve_devel_package - prj = pkg.db_project - p[:target_package] = pkg.name - p[:target_package] += ".#{pkg.db_project.name}" if extend_names - logger.debug "devel project is #{prj.name} #{pkg.name}" + p[:copy_from_devel] = p[:package].resolve_devel_package + elsif not params[:ignoredevel] and p[:package].class == DbPackage and ( p[:package].develproject or p[:package].develpackage or p[:package].db_project.develproject ) + p[:package] = p[:package].resolve_devel_package + p[:link_target_project] = p[:package].db_project + p[:target_package] = p[:package].name + p[:target_package] += ".#{p[:link_target_project].name}" if extend_names + logger.debug "devel project is #{p[:link_target_project].name} #{p[:package].name}" end - # replace new found package - p[:package] = pkg - p[:target_project] = prj if prj - # set default based on first found package location unless target_project - target_project = "home:#{@http_user.login}:branches:#{p[:target_project].name}" + target_project = "home:#{@http_user.login}:branches:#{p[:link_target_project].name}" end # link against srcmd5 instead of plain revision @@ -1437,11 +1450,11 @@ def do_branch # add packages which link them in the same project to support build of source with multiple build descriptions @packages.each do |p| - next unless pkg.class == DbPackage # only for local packages + next unless p[:package].class == DbPackage # only for local packages p[:package].find_project_local_linking_packages.each do |llp| target_package = llp.name target_package += "." + p[:target_package].gsub(/^[^\.]*\./,'') if extend_names - @packages.push({ :target_project => p[:target_project], :package => llp, :target_package => target_package, :local_link => 1 }) + @packages.push({ :base_project => p[:base_project], :link_target_project => p[:link_target_project], :package => llp, :target_package => target_package, :local_link => 1 }) end end end @@ -1503,16 +1516,17 @@ def do_branch pac = p[:package] if pac.class == DbPackage prj = pac.db_project + elsif p[:link_target_project].class == DbProject + # new package for local project + prj = p[:link_target_project] else - # remote package + # package in remote project prj = p[:project] end # find origin package to be branched - branch_target_project = p[:target_project] - branch_target_project = p[:target_project].name if p[:target_project].class == DbProject branch_target_package = p[:target_package] - proj_name = branch_target_project.gsub(':', '_') + proj_name = target_project.gsub(':', '_') pack_name = branch_target_package.gsub(':', '_') # create branch package @@ -1533,40 +1547,42 @@ def do_branch end # create repositories, if missing - if add_repositories - if p[:target_project].class == DbProject - p[:target_project].repositories.each do |repo| - repoName = repo.name - repoName = prj.name.gsub(':', '_')+"_"+repo.name if extend_names + if p[:link_target_project].class == DbProject + p[:link_target_project].repositories.each do |repo| + repoName = repo.name + repoName = p[:base_project].name.gsub(':', '_')+"_"+repo.name if extend_names + if add_repositories unless tprj.repositories.find_by_name(repoName) trepo = tprj.repositories.create :name => repoName trepo.architectures = repo.architectures trepo.path_elements.create(:link => repo, :position => 1) trigger = "manual" trigger = "maintenance" if MaintenanceIncident.find_by_db_project_id( tprj.id ) # is target an incident project ? - trepo.release_targets.create(:target_repository => repo, :trigger => trigger) if p[:target_project].project_type == "maintenance_release" + trepo.release_targets.create(:target_repository => repo, :trigger => trigger) if p[:link_target_project].project_type == "maintenance_release" end - # enable package builds if project default is disabled - tpkg.flags.create( :position => 1, :flag => 'build', :status => "enable", :repo => repoName ) if tprj.flags.find_by_flag_and_status( 'build', 'disable' ) - # take over debuginfo config from origin project - tpkg.flags.create( :position => 1, :flag => 'debuginfo', :status => "enable", :repo => repoName ) if prj.enabled_for?('debuginfo', repo.name, nil) end - unless extend_names - # take over flags, but explicit disable publishing by default and enable building. Ommiting also lock or we can not create packages - p[:target_project].flags.each do |f| - tprj.flags.create(:status => f.status, :flag => f.flag, :architecture => f.architecture, :repo => f.repo) unless [ "build", "publish", "lock" ].include?(f.flag) - end + # enable package builds if project default is disabled + tpkg.flags.create( :position => 1, :flag => 'build', :status => "enable", :repo => repoName ) if tprj.flags.find_by_flag_and_status( 'build', 'disable' ) + # take over debuginfo config from origin project + tpkg.flags.create( :position => 1, :flag => 'debuginfo', :status => "enable", :repo => repoName ) if prj.enabled_for?('debuginfo', repo.name, nil) + end + unless extend_names + # take over flags, but explicit disable publishing by default and enable building. Ommiting also lock or we can not create packages + p[:link_target_project].flags.each do |f| + tprj.flags.create(:status => f.status, :flag => f.flag, :architecture => f.architecture, :repo => f.repo) unless [ "build", "publish", "lock" ].include?(f.flag) + end + if add_repositories tprj.flags.create(:status => "disable", :flag => 'publish') end - else - # FIXME for remote project instances end + else + # FIXME for remote project instances end tpkg.store if p[:local_link] # copy project local linked packages - Suse::Backend.post "/source/#{tpkg.db_project.name}/#{tpkg.name}?cmd=copy&oproject=#{CGI.escape(branch_target_project)}&opackage=#{CGI.escape(p[:package].name)}&user=#{CGI.escape(@http_user.login)}", nil + Suse::Backend.post "/source/#{tpkg.db_project.name}/#{tpkg.name}?cmd=copy&oproject=#{CGI.escape(p[:link_target_project].name)}&opackage=#{CGI.escape(p[:package].name)}&user=#{CGI.escape(@http_user.login)}", nil # and fix the link link = backend_get "/source/#{tpkg.db_project.name}/#{tpkg.name}/_link" ret = ActiveXML::XMLNode.new(link) @@ -1578,8 +1594,9 @@ def do_branch answer = Suse::Backend.put "/source/#{tpkg.db_project.name}/#{tpkg.name}/_link?user=#{CGI.escape(@http_user.login)}", ret.dump_xml else path = "/source/#{URI.escape(tpkg.db_project.name)}/#{URI.escape(tpkg.name)}" + oproject = p[:link_target_project].class == DbProject ? p[:link_target_project].name : p[:link_target_project] myparam = { :cmd => "branch", - :oproject => branch_target_project, + :oproject => oproject, :opackage => p[:package], :user => @http_user.login, } @@ -1594,7 +1611,7 @@ def do_branch response = {:targetproject => tpkg.db_project.name} else # just a single package transfer, detailed answer - response = {:targetproject => tpkg.db_project.name, :targetpackage => tpkg.name, :sourceproject => branch_target_project, :sourcepackage => myparam[:opackage]} + response = {:targetproject => tpkg.db_project.name, :targetpackage => tpkg.name, :sourceproject => oproject, :sourcepackage => myparam[:opackage]} end # fetch newer sources from devel package, if defined diff --git a/src/api/test/fixtures/backend/binary/packageNew.spec b/src/api/test/fixtures/backend/binary/packageNew.spec new file mode 100644 index 00000000000..8798f3e9763 --- /dev/null +++ b/src/api/test/fixtures/backend/binary/packageNew.spec @@ -0,0 +1,30 @@ +# Minimal rpm package for testing the build controller +# +# build the binaries with "rpmbuild -ba package.spec" + +Name: packageNew +License: GPLv2+ +Group: Development/Tools/Building +AutoReqProv: on +Summary: Test Package +Version: 1.0 +Release: 1 +Requires: bash +Conflicts: something +Provides: myself + +%description + +%prep + +%build + +%install +mkdir -p $RPM_BUILD_ROOT +echo "CONTENT" > $RPM_BUILD_ROOT/my_packaged_file + +%files +%defattr(-,root,root) +/my_packaged_file + +%changelog diff --git a/src/api/test/functional/maintenance_test.rb b/src/api/test/functional/maintenance_test.rb index 5b64f901c23..c480e28a0bf 100644 --- a/src/api/test/functional/maintenance_test.rb +++ b/src/api/test/functional/maintenance_test.rb @@ -155,6 +155,12 @@ def test_mbranch_and_maintenance_request get "/source/home:tom:branches:OBS_Maintained:pack2/pack1.BaseDistro" assert_response :success + # add a new package with defined link target + post "/source/BaseDistro:Update/packN", :cmd => "branch", :target_project => "home:tom:branches:OBS_Maintained:pack2", :missingok => 1, :extend_package_names => 1 + assert_response :success + get "/source/home:tom:branches:OBS_Maintained:pack2/packN.BaseDistro_Update" + assert_response :success + # test branching another package set into same project from same project post "/source", :cmd => "branch", :package => "pack3", :target_project => "home:tom:branches:OBS_Maintained:pack2" assert_response :success @@ -173,7 +179,7 @@ def test_mbranch_and_maintenance_request assert_response :success get "/source/home:tom:branches:OBS_Maintained:pack2/kdelibs.kde4/_link" assert_response :success - assert_tag :tag => "link", :attributes => { :project => "kde4", :package => "kdelibs" } + assert_tag :tag => "link", :attributes => { :project => "ServicePack", :package => "kdelibs" } # do some file changes put "/source/home:tom:branches:OBS_Maintained:pack2/kdelibs.kde4/new_file", "new_content_0815" @@ -278,7 +284,7 @@ def test_mbranch_and_maintenance_request get "/source/#{maintenanceProject}" assert_response :success - assert_tag( :tag => "directory", :attributes => { :count => "8" } ) + assert_tag( :tag => "directory", :attributes => { :count => "9" } ) get "/source/#{maintenanceProject}/pack2.BaseDistro2.0/_meta" assert_response :success @@ -473,6 +479,12 @@ def test_create_maintenance_project_and_release_packages assert_response :success assert_match /DUMMY bnc#1042 CVE-2009-0815/, @response.body + # add a new package with defined link target + post "/source/BaseDistro2.0/packNew", :cmd => "branch", :target_project => maintenanceProject, :missingok => 1, :extend_package_names => 1 + assert_response :success + put "/source/#{maintenanceProject}/packNew.BaseDistro2.0/packageNew.spec", File.open("#{RAILS_ROOT}/test/fixtures/backend/binary/packageNew.spec").read() + assert_response :success + # search will find this new and not yet processed incident now. get "/search/project", :match => '[repository/releasetarget/@trigger="maintenance"]' assert_response :success @@ -510,15 +522,44 @@ def test_create_maintenance_project_and_release_packages # run scheduler once to create job file. x86_64 scheduler gets no work run_scheduler("x86_64") run_scheduler("i586") + # check build state + get "/build/#{maintenanceProject}/_result" + assert_response :success + # BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", :arch=>"i586", :state=>"building"} }, + :tag => "status", :attributes => { :package=>"pack2.BaseDistro2.0", :code=>"scheduled" } + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", :arch=>"i586"} }, + :tag => "status", :attributes => { :package=>"pack2.BaseDistro3", :code=>"disabled" } + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", :arch=>"i586"} }, + :tag => "status", :attributes => { :package=>"pack2_linked.BaseDistro2.0", :code=>"scheduled" } + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", :arch=>"i586"} }, + :tag => "status", :attributes => { :package=>"packNew.BaseDistro2.0", :code=>"scheduled" } + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", :arch=>"i586"} }, + :tag => "status", :attributes => { :package=>"patchinfo", :code=>"blocked" } + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", :arch=>"x86_64", :state=>"building"} }, + :tag => "status", :attributes => { :package=>"patchinfo", :code=>"excluded" } + # BaseDistro3_BaseDistro3_repo + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro3_BaseDistro3_repo", :arch=>"i586", :state=>"building"} }, + :tag => "status", :attributes => { :package=>"pack2.BaseDistro2.0", :code=>"disabled" } + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro3_BaseDistro3_repo", :arch=>"i586"} }, + :tag => "status", :attributes => { :package=>"packNew.BaseDistro2.0", :code=>"disabled" } + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro3_BaseDistro3_repo", :arch=>"i586"} }, + :tag => "status", :attributes => { :package=>"pack2.BaseDistro3", :code=>"scheduled" } # upload build result as a worker would do inject_build_job( maintenanceProject, "pack2.BaseDistro2.0", "BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", "x86_64" ) - inject_build_job( maintenanceProject, "pack2_linked.BaseDistro2.0", "BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", "x86_64" ) inject_build_job( maintenanceProject, "pack2.BaseDistro2.0", "BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", "i586" ) + inject_build_job( maintenanceProject, "pack2_linked.BaseDistro2.0", "BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", "x86_64" ) inject_build_job( maintenanceProject, "pack2_linked.BaseDistro2.0", "BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", "i586" ) + inject_build_job( maintenanceProject, "packNew.BaseDistro2.0", "BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", "x86_64" ) + inject_build_job( maintenanceProject, "packNew.BaseDistro2.0", "BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", "i586" ) inject_build_job( maintenanceProject, "pack2.BaseDistro3", "BaseDistro3_BaseDistro3_repo", "i586" ) # collect the job results run_scheduler( "x86_64" ) run_scheduler( "i586" ) + get "/build/#{maintenanceProject}/_result" + assert_response :success + assert_tag :parent => { :tag => "result", :attributes => { :repository=>"BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo", :arch=>"i586", :state=>"publishing"} }, + :tag => "status", :attributes => { :package=>"patchinfo", :code=>"succeeded" } # check updateinfo get "/build/#{maintenanceProject}/BaseDistro2.0_BaseDistro2LinkedUpdateProject_repo/i586/patchinfo/updateinfo.xml" @@ -934,6 +975,7 @@ def test_copy_project_with_history_and_binaries # as admin prepare_request_with_user "king", "sunflower" + sleep 1 # to ensure that the timestamp becomes newer post "/source/CopyOfBaseDistro?cmd=copy&oproject=BaseDistro&withhistory=1&withbinaries=1&nodelay=1" assert_response :success get "/source/CopyOfBaseDistro/_meta" @@ -966,7 +1008,7 @@ def test_copy_project_with_history_and_binaries assert_equal srcmd5, copysrcmd5 assert_equal vrev.to_i + 1, copyvrev.to_i #the copy gets always a higher vrev assert_equal version, copyversion - assert_not_equal time, copytime + assert_not_equal time, copytime # the timestamp got not copied assert_equal copyhistory.each_revision.last.user.text, "king" # compare binaries diff --git a/src/api/test/functional/request_controller_test.rb b/src/api/test/functional/request_controller_test.rb index 1b47d358d06..3ec2853c93e 100644 --- a/src/api/test/functional/request_controller_test.rb +++ b/src/api/test/functional/request_controller_test.rb @@ -238,6 +238,9 @@ def test_create_request_clone_and_superseed_it assert_response :success get "/source/home:tom:branches:REQUEST_#{id}/TestPack.home_Iggy" assert_response :success + get "/source/home:tom:branches:REQUEST_#{id}/TestPack.home_Iggy/_link" + assert_response :success + assert_tag( :tag => "link", :attributes => { :project => "home:Iggy", :package => "TestPack" } ) get "/source/home:tom:branches:REQUEST_#{id}/_attribute/OBS:RequestCloned" assert_response :success assert_tag( :tag => "attribute", :attributes => { :namespace => "OBS", :name => "RequestCloned" },