def test_select_multibuild_package(self): self.wf.setup_rings() staging = self.wf.create_staging('A', freeze=True) project = self.wf.create_project('devel:gcc') package = OBSLocal.Package(name='gcc9', project=project) package.create_commit(filename='gcc9.spec', text='Name: gcc9') package.create_commit(filename='gcc9-tests.spec') package.create_commit( '<multibuild><flavor>gcc9-tests.spec</flavor></multibuild>', filename='_multibuild') self.wf.submit_package(package) ret = SelectCommand(self.wf.api, staging.name).perform(['gcc9']) self.assertEqual(True, ret) self.assertEqual(package_list(self.wf.apiurl, staging.name), ['gcc9']) file = source_file_load(self.wf.apiurl, staging.name, 'gcc9', 'gcc9.spec') self.assertEqual(file, 'Name: gcc9') uc = UnselectCommand(self.wf.api) self.assertIsNone(uc.perform(['gcc9'], False, None)) # no stale links self.assertEqual([], package_list(self.wf.apiurl, staging.name))
def test_accept_switch_to_multibuild_package(self): wf = self.setup_wf() staging = wf.create_staging('A', freeze=True) tpackage = wf.create_package('target', 'gcc9') tpackage.create_commit(filename='gcc9.spec') tpackage.create_commit(filename='gcc9-tests.spec') lpackage = wf.create_package('target', 'gcc9-tests') lpackage.create_commit('<link package="gcc9" cicount="copy" />', filename='_link') project = wf.create_project('devel:gcc') package = OBSLocal.Package(name='gcc9', project=project) package.create_commit(filename='gcc9.spec') package.create_commit(filename='gcc9-tests.spec') package.create_commit('<multibuild><flavor>gcc9-tests.spec</flavor></multibuild>', filename='_multibuild') wf.submit_package(package) ret = SelectCommand(wf.api, staging.name).perform(['gcc9']) ac = AcceptCommand(wf.api) self.assertEqual(True, ac.accept_all(['A'], True)) # no stale links self.assertEqual([], package_list(wf.apiurl, staging.name)) self.assertEqual(['gcc9', 'wine'], package_list(wf.apiurl, wf.project))
def test_select_multiple_spec(self): self.wf.setup_rings() staging = self.wf.create_staging('A', freeze=True) project = self.wf.create_project('devel:gcc') package = OBSLocal.Package(name='gcc8', project=project) package.create_commit(filename='gcc8.spec', text='Name: gcc8') package.create_commit(filename='gcc8-tests.spec') self.wf.submit_package(package) ret = SelectCommand(self.wf.api, staging.name).perform(['gcc8']) self.assertEqual(True, ret) self.assertEqual(package_list(self.wf.apiurl, staging.name), ['gcc8', 'gcc8-tests']) file = source_file_load(self.wf.apiurl, staging.name, 'gcc8', 'gcc8.spec') self.assertEqual(file, 'Name: gcc8') # we should see the spec file also in the 2nd package file = source_file_load(self.wf.apiurl, staging.name, 'gcc8-tests', 'gcc8.spec') self.assertEqual(file, 'Name: gcc8') uc = UnselectCommand(self.wf.api) self.assertIsNone(uc.perform(['gcc8'], False, None)) # no stale links self.assertEqual([], package_list(self.wf.apiurl, staging.name))
def test_accept_new_multispec_package(self): wf = self.setup_wf() staging = wf.create_staging('A', freeze=True) project = wf.create_project('devel:gcc') package = OBSLocal.Package(name='gcc9', project=project) package.create_commit(filename='gcc9.spec') package.create_commit(filename='gcc9-tests.spec') wf.submit_package(package) ret = SelectCommand(wf.api, staging.name).perform(['gcc9']) ac = AcceptCommand(wf.api) self.assertEqual(True, ac.accept_all(['A'], True)) # no stale links self.assertEqual([], package_list(wf.apiurl, staging.name)) self.assertEqual(['gcc9', 'gcc9-tests', 'wine'], package_list(wf.apiurl, wf.project))
def test_select_multiple_spec(self): self.wf.setup_rings() staging = self.wf.create_staging('A', freeze=True) project = self.wf.create_project('devel:gcc') package = OBSLocal.Package(name='gcc8', project=project) package.create_commit(filename='gcc8.spec') package.create_commit(filename='gcc8-tests.spec') self.wf.submit_package(package) ret = SelectCommand(self.wf.api, staging.name).perform(['gcc8']) self.assertEqual(True, ret) self.assertEqual(package_list(self.wf.apiurl, staging.name), ['gcc8', 'gcc8-tests']) uc = UnselectCommand(self.wf.api) self.assertIsNone(uc.perform(['gcc8'])) # no stale links self.assertEqual([], package_list(self.wf.apiurl, staging.name))
def osrt_origin_update_packages(apiurl, project): packages = set(package_list_kind_filtered(apiurl, project)) # Include packages from origins with initial update enabled to allow for # potential new package submissions. for origin in origin_updatable_initial(apiurl, project): for package in package_list(apiurl, origin): # Only add missing package if it does not exist in target # project. If it exists in target then it is not a source # package (since origin list is filtered to source) and should # not be updated. This also properly avoids submitting a package # that is a subpackage in target, but is a source package in an # origin project. if package in packages or entity_exists(apiurl, project, package): continue # No sense submitting a non-source package (most expensive). if package_kind(apiurl, origin, package) == 'source': packages.add(package) return packages
def main(args): # Store the default apiurl in addition to the overriden url if the # option was set and thus overrides the default config value. # Using the OBS link does not work for ?view=issues. if args.apiurl is not None: osc.conf.get_config() apiurl_default = osc.conf.config['apiurl'] else: apiurl_default = None osc.conf.get_config(override_apiurl=args.apiurl) osc.conf.config['debug'] = args.debug apiurl = osc.conf.config['apiurl'] Cache.init() git_repo_url = '[email protected]:jberry-suse/openSUSE-release-tools-issue-db.git' git_message = 'Sync issue-diff.py changes.' db_dir = sync(args.cache_dir, git_repo_url, git_message) db_file = os.path.join(db_dir, '{}.yml'.format(args.project)) if os.path.exists(db_file): db = yaml.safe_load(open(db_file).read()) if db is None: db = {} else: print('Loaded db file: {}'.format(db_file)) else: db = {} if args.print_stats: print_stats(db) return print('Comparing {} against {}'.format(args.project, args.factory)) bugzilla_api = bugzilla_init(args.bugzilla_apiurl) bugzilla_defaults = (args.bugzilla_product, args.bugzilla_component, args.bugzilla_version) trackers = issue_trackers(apiurl) packages_project = package_list(apiurl, args.project) packages_factory = package_list(apiurl_default, args.factory) packages = set(packages_project).intersection(set(packages_factory)) new = 0 shuffle(list(packages)) for index, package in enumerate(packages, start=1): if index % 50 == 0: print('Checked {} of {}'.format(index, len(packages))) if package in db and db[package] == 'whitelist': print('Skipping package {}'.format(package)) continue issues_project = issues_get(apiurl, args.project, package, trackers, db) issues_factory = issues_get(apiurl_default, args.factory, package, trackers, db) missing_from_factory = set(issues_project.keys()) - set(issues_factory.keys()) # Filtering by age must be done after set diff in order to allow for # matches with issues newer than --newest. for label in set(missing_from_factory): if issues_project[label]['age'] < args.newest: missing_from_factory.remove(label) if len(missing_from_factory) == 0: continue print('{}: {} missing'.format(package, len(missing_from_factory))) # Generate summaries for issues missing from factory. changes = {} for issue in missing_from_factory: info = issues_project[issue] summary = ISSUE_SUMMARY if info['owner'] else ISSUE_SUMMARY_PLAIN changes[issue] = summary.format( label=issue, url=info['url'], owner=info['owner'], summary=info['summary']) # Prompt user to decide which issues to whitelist. changes_after = prompt_interactive(changes, args.project, package) # Determine if any real changes (vs typos) and create text issue list. issues = [] cc = [] if len(changes_after) > 0: for issue, summary in changes.items(): if issue in changes_after: info = issues_project[issue] if issue.startswith('bsc'): # Reformat for bugzilla markdown. summary = ISSUE_SUMMARY_BUGZILLA if info['owner'] else ISSUE_SUMMARY_PLAIN_BUGZILLA issue = issue.replace('bsc', 'bug') summary = summary.format( label=issue, url=info['url'], owner=info['owner'], summary=info['summary']) issues.append('- ' + summary) if info['owner'] is not None: cc.append(info['owner']) # Prompt user about how to continue. response = prompt_continue(len(issues)) if response == 'n': break if response == 's': continue # File a bug if not all issues whitelisted. if len(issues) > 0: summary = BUG_SUMMARY.format(project=args.project, factory=args.factory, package=package) message = BUG_TEMPLATE.format( message_start=MESSAGE_START.format( project=args.project, factory=args.factory, package=package, newest=args.newest), issues='\n'.join(issues)) if len(message) > 65535: # Truncate messages longer than bugzilla limit. message = message[:65535 - 3] + '...' # Determine bugzilla meta information to use when creating bug. meta = bug_meta(bugzilla_api, bugzilla_defaults, trackers, changes.keys()) owner = bug_owner(apiurl, package) if args.bugzilla_cc: cc.append(args.bugzilla_cc) # Try to create bug, but allow for handling faults. tries = 0 while tries < 10: try: bug_id = bug_create(bugzilla_api, meta, owner, cc, summary, message) break except Fault as e: if 'There is no component named' in e.faultString: print('Invalid component {}, fallback to default'.format(meta[1])) meta = (meta[0], bugzilla_defaults[1], meta[2]) elif 'is not a valid username' in e.faultString: username = e.faultString.split(' ', 3)[2] cc.remove(username) print('Removed invalid username {}'.format(username)) else: raise e tries += 1 # Mark changes in db. notified, whitelisted = 0, 0 for issue in changes: if package not in db: db[package] = {} if issue in changes_after: db[package][issue] = str(bug_id) notified += 1 else: db[package][issue] = 'whitelist' whitelisted += 1 # Write out changes after each package to avoid loss. with open(db_file, 'w') as outfile: yaml.safe_dump(db, outfile, default_flow_style=False, default_style="'") if notified > 0: print('{}: {} notified in bug {}, {} whitelisted'.format(package, notified, bug_id, whitelisted)) else: print('{}: {} whitelisted'.format(package, whitelisted)) if response == 'b': break new += 1 if new == args.limit: print('stopped at limit') break sync(args.cache_dir, git_repo_url, git_message)
def main(args): # Store the default apiurl in addition to the overriden url if the # option was set and thus overrides the default config value. # Using the OBS link does not work for ?view=issues. if args.apiurl is not None: osc.conf.get_config() apiurl_default = osc.conf.config['apiurl'] else: apiurl_default = None osc.conf.get_config(override_apiurl=args.apiurl) osc.conf.config['debug'] = args.debug apiurl = osc.conf.config['apiurl'] Cache.init() git_repo_url = '[email protected]:jberry-suse/openSUSE-release-tools-issue-db.git' git_message = 'Sync issue-diff.py changes.' db_dir = sync(args.cache_dir, git_repo_url, git_message) db_file = os.path.join(db_dir, '{}.yml'.format(args.project)) if os.path.exists(db_file): db = yaml.safe_load(open(db_file).read()) if db is None: db = {} else: print('Loaded db file: {}'.format(db_file)) else: db = {} if args.print_stats: print_stats(db) return print('Comparing {} against {}'.format(args.project, args.factory)) bugzilla_api = bugzilla_init(args.bugzilla_apiurl) bugzilla_defaults = (args.bugzilla_product, args.bugzilla_component, args.bugzilla_version) trackers = issue_trackers(apiurl) packages_project = package_list(apiurl, args.project) packages_factory = package_list(apiurl_default, args.factory) packages = set(packages_project).intersection(set(packages_factory)) new = 0 shuffle(list(packages)) for index, package in enumerate(packages, start=1): if index % 50 == 0: print('Checked {} of {}'.format(index, len(packages))) if package in db and db[package] == 'whitelist': print('Skipping package {}'.format(package)) continue issues_project = issues_get(apiurl, args.project, package, trackers, db) issues_factory = issues_get(apiurl_default, args.factory, package, trackers, db) missing_from_factory = set(issues_project.keys()) - set( issues_factory.keys()) # Filtering by age must be done after set diff in order to allow for # matches with issues newer than --newest. for label in set(missing_from_factory): if issues_project[label]['age'] < args.newest: missing_from_factory.remove(label) if len(missing_from_factory) == 0: continue print('{}: {} missing'.format(package, len(missing_from_factory))) # Generate summaries for issues missing from factory. changes = {} for issue in missing_from_factory: info = issues_project[issue] summary = ISSUE_SUMMARY if info['owner'] else ISSUE_SUMMARY_PLAIN changes[issue] = summary.format(label=issue, url=info['url'], owner=info['owner'], summary=info['summary']) # Prompt user to decide which issues to whitelist. changes_after = prompt_interactive(changes, args.project, package) # Determine if any real changes (vs typos) and create text issue list. issues = [] cc = [] if len(changes_after) > 0: for issue, summary in changes.items(): if issue in changes_after: info = issues_project[issue] if issue.startswith('bsc'): # Reformat for bugzilla markdown. summary = ISSUE_SUMMARY_BUGZILLA if info[ 'owner'] else ISSUE_SUMMARY_PLAIN_BUGZILLA issue = issue.replace('bsc', 'bug') summary = summary.format(label=issue, url=info['url'], owner=info['owner'], summary=info['summary']) issues.append('- ' + summary) if info['owner'] is not None: cc.append(info['owner']) # Prompt user about how to continue. response = prompt_continue(len(issues)) if response == 'n': break if response == 's': continue # File a bug if not all issues whitelisted. if len(issues) > 0: summary = BUG_SUMMARY.format(project=args.project, factory=args.factory, package=package) message = BUG_TEMPLATE.format(message_start=MESSAGE_START.format( project=args.project, factory=args.factory, package=package, newest=args.newest), issues='\n'.join(issues)) if len(message) > 65535: # Truncate messages longer than bugzilla limit. message = message[:65535 - 3] + '...' # Determine bugzilla meta information to use when creating bug. meta = bug_meta(bugzilla_api, bugzilla_defaults, trackers, changes.keys()) owner = bug_owner(apiurl, package) if args.bugzilla_cc: cc.append(args.bugzilla_cc) # Try to create bug, but allow for handling faults. tries = 0 while tries < 10: try: bug_id = bug_create(bugzilla_api, meta, owner, cc, summary, message) break except Fault as e: if 'There is no component named' in e.faultString: print( 'Invalid component {}, fallback to default'.format( meta[1])) meta = (meta[0], bugzilla_defaults[1], meta[2]) elif 'is not a valid username' in e.faultString: username = e.faultString.split(' ', 3)[2] cc.remove(username) print('Removed invalid username {}'.format(username)) else: raise e tries += 1 # Mark changes in db. notified, whitelisted = 0, 0 for issue in changes: if package not in db: db[package] = {} if issue in changes_after: db[package][issue] = str(bug_id) notified += 1 else: db[package][issue] = 'whitelist' whitelisted += 1 # Write out changes after each package to avoid loss. with open(db_file, 'w') as outfile: yaml.safe_dump(db, outfile, default_flow_style=False, default_style="'") if notified > 0: print('{}: {} notified in bug {}, {} whitelisted'.format( package, notified, bug_id, whitelisted)) else: print('{}: {} whitelisted'.format(package, whitelisted)) if response == 'b': break new += 1 if new == args.limit: print('stopped at limit') break sync(args.cache_dir, git_repo_url, git_message)