def test_regression_590073(self): """bug.blocks is sometimes a str sometimes an int.""" try: # test the int case # TODO: test the string case bts.get_status(568657) except TypeError: self.fail()
def test_regression_799528(): """fields of buglog are sometimes base64 encoded.""" # bug with base64 encoding originator [bug] = bts.get_status(711111) assert 'ł' in bug.originator # bug with base64 encoding subject [bug] = bts.get_status(779005) assert '‘' in bug.subject
def test_regression_799528(self): """fields of buglog are sometimes base64 encoded.""" # bug with base64 encoding originator [bug] = bts.get_status(711111) self.assertTrue('ł' in bug.originator) # bug with base64 encoding subject [bug] = bts.get_status(779005) self.assertTrue('‘' in bug.subject)
def test_regression_590073(): """bug.blocks is sometimes a str sometimes an int.""" try: # test the int case # TODO: test the string case bts.get_status(568657) except TypeError: pytest.fail()
def testStatusBatchesLargeBugCounts(self): """get_status should perform requests in batches to reduce server load.""" with mock.patch.object(bts.server, 'get_status') as MockStatus: MockStatus.return_value = None nr = bts.BATCH_SIZE + 10.0 calls = int(math.ceil(nr / bts.BATCH_SIZE)) bts.get_status([722226] * int(nr)) self.assertEqual(MockStatus.call_count, calls)
def test_done_by_decoding(): """Done by is properly base64 decoded when needed.""" # no base64 encoding bug = bts.get_status(486212)[0] assert bug.done_by == 'Bastian Venthur <*****@*****.**>' # base64 encoding bug = bts.get_status(938128)[0] assert bug.done_by == 'Ondřej Nový <*****@*****.**>'
def test_status_batches_large_bug_counts(mock_build_client): """get_status should perform requests in batches to reduce server load.""" mock_build_client.return_value = mock_client = mock.Mock() mock_client.call.return_value = SimpleXMLElement( '<a><s-gensym3/></a>') nr = bts.BATCH_SIZE + 10.0 calls = int(math.ceil(nr / bts.BATCH_SIZE)) bts.get_status([722226] * int(nr)) assert mock_client.call.call_count == calls
def test_status_batches_large_bug_counts(self): """get_status should perform requests in batches to reduce server load.""" with mock.patch.object(bts, '_build_soap_client') as mock_build_client: mock_build_client.return_value = mock_client = mock.Mock() mock_client.call.return_value = SimpleXMLElement( '<a><s-gensym3/></a>') nr = bts.BATCH_SIZE + 10.0 calls = int(math.ceil(nr / bts.BATCH_SIZE)) bts.get_status([722226] * int(nr)) self.assertEqual(mock_client.call.call_count, calls)
def test_mergedwith(self): """Mergedwith is always a list of int.""" # this one is merged with two other bugs m = bts.get_status(486212)[0].mergedwith self.assertTrue(len(m) == 2) for i in m: self.assertEqual(type(i), type(int())) # this one was merged with one bug m = bts.get_status(433550)[0].mergedwith self.assertTrue(len(m) == 1) self.assertEqual(type(m[0]), type(int())) # this one was not merged m = bts.get_status(474955)[0].mergedwith self.assertEqual(m, list())
def test_mergedwith(): """Mergedwith is always a list of int.""" # this one is merged with two other bugs m = bts.get_status(486212)[0].mergedwith assert len(m) == 2 for i in m: assert isinstance(i, int) # this one was merged with one bug m = bts.get_status(433550)[0].mergedwith assert len(m) == 1 assert isinstance(m[0], int) # this one was not merged m = bts.get_status(474955)[0].mergedwith assert m == list()
def test_status_batches_multiple_arguments(mock_build_client): """get_status should batch multiple arguments into one request.""" mock_build_client.return_value = mock_client = mock.Mock() mock_client.call.return_value = SimpleXMLElement( '<a><s-gensym3/></a>') batch_size = bts.BATCH_SIZE calls = 1 bts.get_status(*list(range(batch_size))) assert mock_client.call.call_count == calls calls += 2 bts.get_status(*list(range(batch_size + 1))) assert mock_client.call.call_count == calls
def test_status_batches_multiple_arguments(self): """get_status should batch multiple arguments into one request.""" with mock.patch.object(bts, '_build_soap_client') as mock_build_client: mock_build_client.return_value = mock_client = mock.Mock() mock_client.call.return_value = SimpleXMLElement( '<a><s-gensym3/></a>') batch_size = bts.BATCH_SIZE calls = 1 bts.get_status(*list(range(batch_size))) self.assertEqual(mock_client.call.call_count, calls) calls += 2 bts.get_status(*list(range(batch_size + 1))) self.assertEqual(mock_client.call.call_count, calls)
def test_generate_blank_report(self): report = utils.generate_blank_report('reportbug', '1.2.3', 'normal', '', '', '', type='debbugs') self.assertIsNotNone(report) self.assertIn('Package: reportbug', report) self.assertIn('Version: 1.2.3', report) self.assertIn('Severity: normal', report) report = utils.generate_blank_report('reportbug', '1.2.3', 'normal', '', '', '', type='debbugs', issource=True) self.assertIn('Source: reportbug', report) # test with exinfo (represents the bug number if this is a followup): # int, string, unconvertible (to int) datatype report = utils.generate_blank_report('reportbug', '1.2.3', 'normal', '', '', '', type='debbugs', exinfo=123456) self.assertIn('Followup-For: Bug #123456', report) bug = debianbts.get_status(123456)[0] report = utils.generate_blank_report('reportbug', '1.2.3', 'normal', '', '', '', type='debbugs', exinfo=bug) self.assertIn('Followup-For: Bug #123456', report) with self.assertRaises(TypeError): report = utils.generate_blank_report('reportbug', '1.2.3', 'normal', '', '', '', type='debbugs', exinfo={'123456': ''})
def test_unicode_convertion_in_str(self): """string representation must deal with unicode correctly.""" [bug] = bts.get_status(773321) try: bug.__str__() except UnicodeEncodeError: self.fail()
def test_unicode_conversion_in_str(): """string representation must deal with unicode correctly.""" [bug] = bts.get_status(773321) try: bug.__str__() except UnicodeEncodeError: pytest.fail()
def test_followup(self): self.body = 'test' self.package = 'reportbug' self.report = bugreport(package=self.package, body=self.body, followup=123456) self.text = self.report.__unicode__() self.assertIn('Followup-For: Bug #123456', self.text) self.assertNotIn('Severity: ', self.text) # test also a bugreport instance, and a datatype unconvertible to int bug = debianbts.get_status(123456)[0] self.report = bugreport(package=self.package, body=self.body, followup=bug) self.text = self.report.__unicode__() self.assertIn('Followup-For: Bug #123456', self.text) self.assertNotIn('Severity: ', self.text) with self.assertRaises(TypeError): self.report = bugreport(package=self.package, body=self.body, followup={'123456': 654321})
def get_report(number, timeout, system='debian', mirrors=None, http_proxy='', archived=False, followups=False): number = int(number) if system == 'debian': status = debianbts.get_status(number)[0] log = debianbts.get_bug_log(number) # add Date/Subject/From headers to the msg bodies bodies = [] for l in log: f = email.parser.FeedParser() f.feed(l['header']) h = f.close() hdrs = [] for i in ['Date', 'Subject', 'From']: if i in h: hdrs.append(i + ': ' + h.get(i)) bodies.append('\n'.join(sorted(hdrs)) + '\n\n' + l['body']) # returns the bug status and a list of mail bodies return (status, bodies) if SYSTEMS[system].get('cgiroot'): result = get_cgi_report(number, timeout, system, http_proxy, archived, followups) if result: return result url = report_url(system, number, mirrors) if not url: return None return parse_html_report(number, url, http_proxy, timeout, followups, cgi=False)
def test_affects(self): """affects is a list of str.""" # this one affects one bug #a = bts.get_status(290501)[0].affects #self.assertTrue(len(a) == 1) #self.assertEqual(type(a[0]), type(str())) # this one affects no other bug a = bts.get_status(437154)[0].affects self.assertEqual(a, [])
def test_get_status_params(caplog): BUG = 223344 BUG2 = 334455 bugs = bts.get_status(BUG) assert isinstance(bugs, list) assert len(bugs) == 1 bugs = bts.get_status([BUG, BUG2]) assert isinstance(bugs, list) assert len(bugs) == 2 bugs = bts.get_status((BUG, BUG2)) assert isinstance(bugs, list) assert len(bugs) == 2 bugs = bts.get_status(BUG, BUG2) assert isinstance(bugs, list) assert len(bugs) == 2 assert "deprecated" in caplog.text
def get_bug_versions(bug): """Gets a list of only the version numbers for which the bug is found. Newest versions are returned first.""" # debianbts returns it in the format package/1.2.3 or 1.2.3 which will become 1.2.3 return list( reversed( sorted( [x.rsplit("/", 1)[-1] for x in debianbts.get_status((bug,))[0].found_versions], cmp=apt_pkg.version_compare, ) ) ) or ["~"]
def unclassified_bugs(self): """ Returns a list of open bugs which have not yet been classified by one of our usertags. """ tagged_bugs = bts.get_usertag('*****@*****.**') tagged_bugs_ftp = [] for tags in tagged_bugs.keys(): tagged_bugs_ftp += tagged_bugs[tags] return [bug for bug in bts.get_status(bts.get_bugs("package", "ftp.debian.org")) if bug.pending == 'pending' and bug.bug_num not in tagged_bugs_ftp]
def fetch_bugs(filepath, email, usertag): """Fetch the bugs from bts and save them in a pickle to don't have to query bts again Return: list of debianbts.Bugreport items """ bugnrlist = bts.get_usertag(email, usertag) bugs = bts.get_status(bugnrlist[usertag]) with open(filepath,'w') as f: pickle.dump(bugs,f) print 'saved bts history to %s ' % filepath return bugs
def get_bug_versions(bug): """Gets a list of only the version numbers for which the bug is found. Newest versions are returned first.""" # debianbts returns it in the format package/1.2.3 or 1.2.3 which will become 1.2.3 versions = [] for found_version in debianbts.get_status((bug,))[0].found_versions: v = found_version.rsplit('/', 1)[-1] if v == "None": # only allow the distro-qualified "$distro/None" version if found_version == distro + "/" + v: versions.append(v) else: versions.append(v) return list(reversed(sorted(versions, cmp=apt_pkg.version_compare))) or ['~']
def lookup_debian_issue(app, tracker_config, issue_id): import debianbts try: # get the bug bug = debianbts.get_status(issue_id)[0] except IndexError: return None # check if issue matches project if tracker_config.project not in (bug.package, bug.source): return None return Issue(id=issue_id, title=bug.subject, closed=bug.done, url=DEBIAN_URL.format(issue_id))
def search(self, sources, bug_numbers=None): if bug_numbers is None: bug_numbers = set() else: bug_numbers = set(bug_numbers) bug_numbers.update(debianbts.get_bugs('src', sources)) # process in batches. stolen from python-debianbts. BATCH_SIZE = 500 result = [] for i in range(0, len(bug_numbers), BATCH_SIZE): slice = list(bug_numbers)[i:i + BATCH_SIZE] result += debianbts.get_status(slice) return [ _DebianBugReport(b, self.binary_source_map, self.ignore_unknown_binaries) for b in result ]
def get_bug_versions(bug): """Gets a list of only the version numbers for which the bug is found. Newest versions are returned first.""" # debianbts returns it in the format package/1.2.3 or 1.2.3 which will become 1.2.3 versions = [] for found_version in debianbts.get_status((bug, ))[0].found_versions: v = found_version.rsplit('/', 1)[-1] if v == "None": # only allow the distro-qualified "$distro/None" version if found_version == distro + "/" + v: versions.append(v) else: versions.append(v) return list(reversed(sorted(versions, cmp=apt_pkg.version_compare))) or ['~']
def test_bug_class(self): bug = debianbts.get_status(415801)[0] gtk_bug = ui.Bug(bug) self.assertIsNotNone(gtk_bug) self.assertEqual(bug.bug_num, gtk_bug.id) self.assertEqual(bug.severity, gtk_bug.severity) self.assertEqual(bug.package, gtk_bug.package) self.assertEqual(bug.originator, gtk_bug.reporter) self.assertEqual(bug.date, gtk_bug.date) for tag in bug.tags: self.assertIn(tag, gtk_bug.tag) for item in gtk_bug: self.assertIsNotNone(item)
def test_followup(self): self.body = "test" self.package = "reportbug" self.report = bugreport(package=self.package, body=self.body, followup=123456) self.text = self.report.__unicode__() self.assertIn("Followup-For: Bug #123456", self.text) self.assertNotIn("Severity: ", self.text) # test also a bugreport instance, and a datatype unconvertible to int bug = debianbts.get_status(123456)[0] self.report = bugreport(package=self.package, body=self.body, followup=bug) self.text = self.report.__unicode__() self.assertIn("Followup-For: Bug #123456", self.text) self.assertNotIn("Severity: ", self.text) with self.assertRaises(TypeError): self.report = bugreport(package=self.package, body=self.body, followup={"123456": 654321})
def bug_versions(self, bug): """Gets a list of only the version numbers for which the bug is found. Newest versions are returned first.""" # debianbts returns it in the format package/1.2.3 or 1.2.3 which will become 1.2.3 if not bug in self._bug_versions: self._misses += 1 signal(SIGALRM, alarm_handler) alarm(60) found_versions = debianbts.get_status(bug)[0].found_versions alarm(0) versions = [] for found_version in found_versions: v = found_version.rsplit('/', 1)[-1] if v == "None": # ignore $DISTRO/None versions pass else: versions.append(v) self._bug_versions[bug] = list(reversed(sorted(versions, cmp=apt_pkg.version_compare))) or ['~'] self._queries += 1 return self._bug_versions[bug]
def test_sample_get_status(): """test retrieving of a "known" bug status""" bugs = bts.get_status(486212) assert len(bugs) == 1 bug = bugs[0] assert bug.bug_num == 486212 assert bug.date == datetime.datetime(2008, 6, 14, 10, 30, 2) assert bug.subject.startswith('[reportbug-ng] segm') assert bug.package == 'reportbug-ng' assert bug.severity == 'normal' assert bug.tags == ['help'] assert bug.blockedby == [] assert bug.blocks == [] assert bug.summary == '' assert bug.location == 'archive' assert bug.source == 'reportbug-ng' assert bug.log_modified == datetime.datetime(2008, 8, 17, 7, 26, 22) assert bug.pending == 'done' assert bug.done assert bug.archived assert bug.found_versions == ['reportbug-ng/0.2008.06.04'] assert bug.fixed_versions == ['reportbug-ng/1.0'] assert bug.affects == []
def test_sample_get_status(): """test retrieving of a "known" bug status""" bugs = bts.get_status(486212) assert len(bugs) == 1 bug = bugs[0] assert bug.bug_num == 486212 assert bug.date == datetime.datetime(2008, 6, 14, 10, 30, 2) assert bug.subject.startswith('[reportbug-ng] segm') assert bug.package == 'reportbug-ng' assert bug.severity == 'normal' assert bug.tags == ['help'] assert bug.blockedby == [] assert bug.blocks == [] assert bug.summary == '' assert bug.location == 'archive' assert bug.source == 'reportbug-ng' assert bug.log_modified == datetime.datetime(2008, 8, 17, 7, 26, 22) assert bug.pending == 'done' assert bug.done assert bug.done_by == 'Bastian Venthur <*****@*****.**>' assert bug.archived assert bug.found_versions == ['reportbug-ng/0.2008.06.04'] assert bug.fixed_versions == ['reportbug-ng/1.0'] assert bug.affects == []
def test_sample_get_status(self): """test retrieving of a "known" bug status""" bugs = bts.get_status(486212) self.assertEqual(len(bugs), 1) bug = bugs[0] self.assertEqual(bug.bug_num, 486212) self.assertEqual(bug.date, datetime.datetime(2008, 6, 14, 10, 30, 2)) self.assertTrue(bug.subject.startswith('[reportbug-ng] segm')) self.assertEqual(bug.package, 'reportbug-ng') self.assertEqual(bug.severity, 'normal') self.assertEqual(bug.tags, ['help']) self.assertEqual(bug.blockedby, []) self.assertEqual(bug.blocks, []) self.assertEqual(bug.summary, '') self.assertEqual(bug.location, 'archive') self.assertEqual(bug.source, 'reportbug-ng') self.assertEqual(bug.log_modified, datetime.datetime(2008, 8, 17, 7, 26, 22)) self.assertEqual(bug.pending, 'done') self.assertEqual(bug.done, True) self.assertEqual(bug.archived, True) self.assertEqual(bug.found_versions, ['reportbug-ng/0.2008.06.04']) self.assertEqual(bug.fixed_versions, ['reportbug-ng/1.0']) self.assertEqual(bug.affects, [])
def fetch_bug_summary(bug_num): bug = debianbts.get_status(bug_num) if not bug: raise RuntimeError("No BTS data for #%s" % bug_num) return bug[0]
def remove(session, reason, suites, removals, whoami=None, partial=False, components=None, done_bugs=None, date=None, carbon_copy=None, close_related_bugs=False): """Batch remove a number of packages Verify that the files listed in the Files field of the .dsc are those expected given the announced Format. @type session: SQLA Session @param session: The database session in use @type reason: string @param reason: The reason for the removal (e.g. "[auto-cruft] NBS (no longer built by <source>)") @type suites: list @param suites: A list of the suite names in which the removal should occur @type removals: list @param removals: A list of the removals. Each element should be a tuple (or list) of at least the following for 4 items from the database (in order): package, version, architecture, (database) id. For source packages, the "architecture" should be set to "source". @type partial: bool @param partial: Whether the removal is "partial" (e.g. architecture specific). @type components: list @param components: List of components involved in a partial removal. Can be an empty list to not restrict the removal to any components. @type whoami: string @param whoami: The person (or entity) doing the removal. Defaults to utils.whoami() @type date: string @param date: The date of the removal. Defaults to commands.getoutput("date -R") @type done_bugs: list @param done_bugs: A list of bugs to be closed when doing this removal. @type close_related_bugs: bool @param done_bugs: Whether bugs related to the package being removed should be closed as well. NB: Not implemented for more than one suite. @type carbon_copy: list @param carbon_copy: A list of mail addresses to CC when doing removals. NB: all items are taken "as-is" unlike "dak rm". @rtype: None @return: Nothing """ # Generate the summary of what's to be removed d = {} summary = "" sources = [] binaries = [] whitelists = [] versions = [] suite_ids_list = [] suites_list = utils.join_with_commas_and(suites) cnf = utils.get_conf() con_components = '' ####################################################################################################### if not reason: raise ValueError("Empty removal reason not permitted") if not removals: raise ValueError("Nothing to remove!?") if not suites: raise ValueError("Removals without a suite!?") if whoami is None: whoami = utils.whoami() if date is None: date = commands.getoutput("date -R") if partial and components: component_ids_list = [] for componentname in components: component = get_component(componentname, session=session) if component is None: raise ValueError("component '%s' not recognised." % componentname) else: component_ids_list.append(component.component_id) if component_ids_list: con_components = "AND component IN (%s)" % ", ".join( [str(i) for i in component_ids_list]) for i in removals: package = i[0] version = i[1] architecture = i[2] if package not in d: d[package] = {} if version not in d[package]: d[package][version] = [] if architecture not in d[package][version]: d[package][version].append(architecture) for package in sorted(d): versions = sorted(d[package], cmp=apt_pkg.version_compare) for version in versions: d[package][version].sort(utils.arch_compare_sw) summary += "%10s | %10s | %s\n" % (package, version, ", ".join( d[package][version])) for package in summary.split("\n"): for row in package.split("\n"): element = row.split("|") if len(element) == 3: if element[2].find("source") > 0: sources.append( "%s_%s" % tuple(elem.strip(" ") for elem in element[:2])) element[2] = sub("source\s?,?", "", element[2]).strip(" ") if element[2]: binaries.append("%s_%s [%s]" % tuple(elem.strip(" ") for elem in element)) dsc_type_id = get_override_type('dsc', session).overridetype_id deb_type_id = get_override_type('deb', session).overridetype_id for suite in suites: s = get_suite(suite, session=session) if s is not None: suite_ids_list.append(s.suite_id) whitelists.append(s.mail_whitelist) ####################################################################################################### log_filename = cnf["Rm::LogFile"] log822_filename = cnf["Rm::LogFile822"] with utils.open_file(log_filename, "a") as logfile, utils.open_file( log822_filename, "a") as logfile822: fcntl.lockf(logfile, fcntl.LOCK_EX) fcntl.lockf(logfile822, fcntl.LOCK_EX) logfile.write( "=========================================================================\n" ) logfile.write("[Date: %s] [ftpmaster: %s]\n" % (date, whoami)) logfile.write("Removed the following packages from %s:\n\n%s" % (suites_list, summary)) if done_bugs: logfile.write("Closed bugs: %s\n" % (", ".join(done_bugs))) logfile.write( "\n------------------- Reason -------------------\n%s\n" % reason) logfile.write("----------------------------------------------\n") logfile822.write("Date: %s\n" % date) logfile822.write("Ftpmaster: %s\n" % whoami) logfile822.write("Suite: %s\n" % suites_list) if sources: logfile822.write("Sources:\n") for source in sources: logfile822.write(" %s\n" % source) if binaries: logfile822.write("Binaries:\n") for binary in binaries: logfile822.write(" %s\n" % binary) logfile822.write("Reason: %s\n" % reason.replace('\n', '\n ')) if done_bugs: logfile822.write("Bug: %s\n" % (", ".join(done_bugs))) for i in removals: package = i[0] architecture = i[2] package_id = i[3] for suite_id in suite_ids_list: if architecture == "source": session.execute( "DELETE FROM src_associations WHERE source = :packageid AND suite = :suiteid", { 'packageid': package_id, 'suiteid': suite_id }) else: session.execute( "DELETE FROM bin_associations WHERE bin = :packageid AND suite = :suiteid", { 'packageid': package_id, 'suiteid': suite_id }) # Delete from the override file if not partial: if architecture == "source": type_id = dsc_type_id else: type_id = deb_type_id # TODO: Fix this properly to remove the remaining non-bind argument session.execute( "DELETE FROM override WHERE package = :package AND type = :typeid AND suite = :suiteid %s" % (con_components), { 'package': package, 'typeid': type_id, 'suiteid': suite_id }) session.commit() # ### REMOVAL COMPLETE - send mail time ### # # If we don't have a Bug server configured, we're done if "Dinstall::BugServer" not in cnf: if done_bugs or close_related_bugs: utils.warn( "Cannot send mail to BugServer as Dinstall::BugServer is not configured" ) logfile.write( "=========================================================================\n" ) logfile822.write("\n") return # read common subst variables for all bug closure mails Subst_common = {} Subst_common["__RM_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"] Subst_common["__BUG_SERVER__"] = cnf["Dinstall::BugServer"] Subst_common["__CC__"] = "X-DAK: dak rm" if carbon_copy: Subst_common["__CC__"] += "\nCc: " + ", ".join(carbon_copy) Subst_common["__SUITE_LIST__"] = suites_list Subst_common["__SUBJECT__"] = "Removed package(s) from %s" % ( suites_list) Subst_common["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"] Subst_common["__DISTRO__"] = cnf["Dinstall::MyDistribution"] Subst_common["__WHOAMI__"] = whoami # Send the bug closing messages if done_bugs: Subst_close_rm = Subst_common bcc = [] if cnf.find("Dinstall::Bcc") != "": bcc.append(cnf["Dinstall::Bcc"]) if cnf.find("Rm::Bcc") != "": bcc.append(cnf["Rm::Bcc"]) if bcc: Subst_close_rm["__BCC__"] = "Bcc: " + ", ".join(bcc) else: Subst_close_rm["__BCC__"] = "X-Filler: 42" summarymail = "%s\n------------------- Reason -------------------\n%s\n" % ( summary, reason) summarymail += "----------------------------------------------\n" Subst_close_rm["__SUMMARY__"] = summarymail for bug in done_bugs: Subst_close_rm["__BUG_NUMBER__"] = bug if close_related_bugs: mail_message = utils.TemplateSubst( Subst_close_rm, cnf["Dir::Templates"] + "/rm.bug-close-with-related") else: mail_message = utils.TemplateSubst( Subst_close_rm, cnf["Dir::Templates"] + "/rm.bug-close") utils.send_mail(mail_message, whitelists=whitelists) # close associated bug reports if close_related_bugs: Subst_close_other = Subst_common bcc = [] wnpp = utils.parse_wnpp_bug_file() versions = list(set([re_bin_only_nmu.sub('', v) for v in versions])) if len(versions) == 1: Subst_close_other["__VERSION__"] = versions[0] else: logfile.write( "=========================================================================\n" ) logfile822.write("\n") raise ValueError( "Closing bugs with multiple package versions is not supported. Do it yourself." ) if bcc: Subst_close_other["__BCC__"] = "Bcc: " + ", ".join(bcc) else: Subst_close_other["__BCC__"] = "X-Filler: 42" # at this point, I just assume, that the first closed bug gives # some useful information on why the package got removed Subst_close_other["__BUG_NUMBER__"] = done_bugs[0] if len(sources) == 1: source_pkg = source.split("_", 1)[0] else: logfile.write( "=========================================================================\n" ) logfile822.write("\n") raise ValueError( "Closing bugs for multiple source packages is not supported. Please do it yourself." ) Subst_close_other["__BUG_NUMBER_ALSO__"] = "" Subst_close_other["__SOURCE__"] = source_pkg merged_bugs = set() other_bugs = bts.get_bugs('src', source_pkg, 'status', 'open', 'status', 'forwarded') if other_bugs: for bugno in other_bugs: if bugno not in merged_bugs: for bug in bts.get_status(bugno): for merged in bug.mergedwith: other_bugs.remove(merged) merged_bugs.add(merged) logfile.write("Also closing bug(s):") logfile822.write("Also-Bugs:") for bug in other_bugs: Subst_close_other["__BUG_NUMBER_ALSO__"] += str( bug) + "-done@" + cnf["Dinstall::BugServer"] + "," logfile.write(" " + str(bug)) logfile822.write(" " + str(bug)) logfile.write("\n") logfile822.write("\n") if source_pkg in wnpp: logfile.write("Also closing WNPP bug(s):") logfile822.write("Also-WNPP:") for bug in wnpp[source_pkg]: # the wnpp-rm file we parse also contains our removal # bugs, filtering that out if bug != Subst_close_other["__BUG_NUMBER__"]: Subst_close_other["__BUG_NUMBER_ALSO__"] += str( bug) + "-done@" + cnf["Dinstall::BugServer"] + "," logfile.write(" " + str(bug)) logfile822.write(" " + str(bug)) logfile.write("\n") logfile822.write("\n") mail_message = utils.TemplateSubst( Subst_close_other, cnf["Dir::Templates"] + "/rm.bug-close-related") if Subst_close_other["__BUG_NUMBER_ALSO__"]: utils.send_mail(mail_message) logfile.write( "=========================================================================\n" ) logfile822.write("\n")
def issues(self): # Initialise empty list of bug numbers collected_bugs = [] # Search BTS for bugs owned by email address if self.email: owned_bugs = debianbts.get_bugs("owner", self.email, "status", "open") collected_bugs.extend(owned_bugs) # Search BTS for bugs related to specified packages if self.packages: packages = self.packages.split(",") for pkg in packages: pkg_bugs = debianbts.get_bugs("package", pkg, "status", "open") for bug in pkg_bugs: if bug not in collected_bugs: collected_bugs.append(bug) # Search UDD bugs search for bugs belonging to packages that # are maintained by the email address if self.udd: udd_bugs = self._get_udd_bugs() for bug in udd_bugs: if bug not in collected_bugs: collected_bugs.append(bug['id']) issues = [self._record_for_bug(bug) for bug in debianbts.get_status(collected_bugs)] log.debug(" Found %i total.", len(issues)) if self.ignore_pkg: ignore_pkg = self.ignore_pkg.split(",") for pkg in ignore_pkg: issues = [issue for issue in issues if not issue['package'] == pkg] if self.ignore_src: ignore_src = self.ignore_src.split(",") for src in ignore_src: issues = [issue for issue in issues if not issue['source'] == src] if self.ignore_pending: issues = [issue for issue in issues if not issue['status'] == 'pending-fixed'] issues = [issue for issue in issues if not (issue['status'] == 'done' or issue['status'] == 'fixed')] log.debug(" Pruned down to %i.", len(issues)) for issue in issues: issue_obj = self.get_issue_for_record(issue) extra = { 'annotations': self.annotations(issue, issue_obj) } issue_obj.update_extra(extra) yield issue_obj
def test_string_status_originator(self): """test reading of bug status originator that is not base64-encoded""" bug = bts.get_status(711112)[0] self._assert_unicode(bug.originator) self.assertTrue(bug.originator.endswith('debian.org>'))
def test_base64_status_fields(): """fields in bug status are sometimes base64-encoded""" bug = bts.get_status(711111)[0] assert is_unicode(bug.originator) assert bug.originator.endswith('gmail.com>') assert 'ł' in bug.originator
def lineedit_return_pressed(self): # # just in case ;) # text = unicode(self.lineEdit.text()) if text.startswith("http://"): self._show_url(text) return if len(text) == 0: return self.logger.info("Return pressed.") self.lineEdit.clear() # TODO: self.lineEdit.clear() does not always work, why? #QtCore.QTimer.singleShot(0,self.lineEdit,QtCore.SLOT("clear()")) query = rng.translate_query(text) self.logger.debug("Query: %s" % str(query)) # test if there is a submit-as field available and rename the packages # if nececesairy for i in range(0, len(query), 2): if query[i] == 'package': realname = bug.submit_as(query[i + 1]) if query[i + 1] != realname: self.logger.debug( "Using %s as package name as requested by developer." % str(realname)) query[i + 1] = realname # Single bug or list of bugs? if query[0]: buglist = bts.get_bugs(query) else: buglist = [query[1]] # ok, we know the package, so enable some buttons which don't depend # on the existence of the acutal packe (wnpp) or bugreports for that # package. if query[0] in ("src", "package"): self._stateChanged(query[1], None) # if we got a bugnumber we'd like to select it and enable some more # buttons. unfortunately we don't know if the bugnumber actually exists # for now, so we have to wait a bit until the bug is fetched. else: self._stateChanged(None, None) self.logger.debug("Buglist matching the query: %s" % str(buglist)) chunksize = 50 if len(buglist) > chunksize: self.load_started() self.logger.debug("Buglist longer than %i, splitting in chunks." % chunksize) self.bugs = [] i = 0 for chunk in chunks(buglist, chunksize): i += 1 progress = int(100. * i * chunksize / len(buglist)) if progress > 100: progress = 100 self.load_progress(progress) bl = bts.get_status(chunk) if len(bl) == 0: self.logger.error( "One of the following bugs caused the BTS to hickup: %s" % str(bl)) self.bugs.extend(bl) self.load_finished(True) else: self.bugs = bts.get_status(buglist) # ok, we fetched the bugs. see if the list isn't empty if query[0] in (None, ) and len(self.bugs) > 0: self.currentBug = self.bugs[0] self.currentPackage = self.currentBug.package self._stateChanged(self.currentPackage, self.currentBug) self.model.set_elements(self.bugs) self.tableView.resizeRowsToContents()
def get_reports(package, timeout, system='debian', mirrors=None, version=None, http_proxy='', archived=False, source=False): if system == 'debian': if isinstance(package, str): if source: pkg_filter = 'src' else: pkg_filter = 'package' bugs = debianbts.get_bugs(pkg_filter, package) else: bugs = list(map(int, package)) try: # retrieve bugs and generate the hierarchy stats = debianbts.get_status(bugs) except: raise QuertBTSError d = defaultdict(list) for s in stats: # We now return debianbts.Bugreport objects, containing all the info # for a bug, so UIs can extract them as needed d[s.severity].append(s) # keep the bugs ordered per severity # XXX: shouldn't it be something UI-related? # # The hierarchy is a list of tuples: # (description of the severity, list of bugs for that severity) hier = [] for sev in SEVLIST: if sev in d: hier.append(('Bugs with severity %s' % sev, d[sev])) return (len(bugs), 'Bug reports for %s' % package, hier) # XXX: is the code below used at all now? can we remove it? if isinstance(package, str): if SYSTEMS[system].get('cgiroot'): try: result = get_cgi_reports(package, timeout, system, http_proxy, archived, source, version=version) except: raise NoNetwork if result: return result url = package_url(system, package, mirrors, source) try: page = open_url(url, http_proxy, timeout) except: raise NoNetwork if not page: return (0, None, None) # content = page.read() # if 'Maintainer' not in content: # return (0, None, None) parser = BTSParser() for line in page.splitlines(): parser.feed(line) parser.close() return parser.bugcount, parser.title, parser.hierarchy # A list of bug numbers this_hierarchy = [] package = [int(x) for x in package] package.sort() for bug in package: result = get_report(bug, timeout, system, mirrors, http_proxy, archived) if result: title, body = result this_hierarchy.append(title) # print title title = "Multiple bug reports" bugcount = len(this_hierarchy) hierarchy = [('Reports', this_hierarchy)] return bugcount, title, hierarchy
print "Command execution failed! Bailing out ..." sys.exit(1) # Pull bug reports, and remind user to check for closures try: bugs_fixed_upstream = debianbts.get_bugs('package', pkg_name, 'tag', 'fixed-upstream') bugs_upstream = debianbts.get_bugs('package', pkg_name, 'tag', 'upstream') bugs_all = debianbts.get_bugs('package', pkg_name) print "\n" + "**********" * 8 if len(bugs_fixed_upstream) > 0: print "\nBugs tagged 'fixed-upstream':" for b in bugs_fixed_upstream: if b in bugs_all: bugs_all.remove(b) # avoid repeats below s = debianbts.get_status(b) if not s[0].done: print "\tBug %s: %s" % (s[0].bug_num, s[0].subject) if len(bugs_upstream) > 0: print "\nBugs tagged 'upstream':" for b in bugs_upstream: if b in bugs_all: bugs_all.remove(b) # avoid repeats below s = debianbts.get_status(b) if not s[0].done: print "\tBug %s: %s" % (s[0].bug_num, s[0].subject) if len(bugs_all) > 0: print "\nAll other bugs:" for b in bugs_all: s = debianbts.get_status(b) if not s[0].done: print "\tBug %s: %s" % (s[0].bug_num, s[0].subject) print "\nPlease remember to check for and make note of closed bugs\n" except SOAPpy.Errors.HTTPError, HTTPError:
def test_empty_get_status(): """get_status should return empty list if bug doesn't exits""" bugs = bts.get_status(0) assert isinstance(bugs, list) assert len(bugs) == 0
def test_regression_670446(): """affects should be split by ','""" bug = bts.get_status(657408)[0] assert bug.affects == ['epiphany-browser-dev', 'libwebkit-dev']
def test_get_status_affects(): """test a bug with "affects" field""" bugs = bts.get_status(290501, 770490) assert len(bugs) == 2 assert bugs[0].affects == [] assert bugs[1].affects == ['conkeror']
def test_regression_670446(self): """affects should be split by ','""" bug = bts.get_status(657408)[0] self.assertEqual(bug.affects, ['epiphany-browser-dev', 'libwebkit-dev'])
action="store_true", help='dont look for modules on PyPI (for DEBUG)') args = parser.parse_args() if not os.path.isdir(args.destdir): os.makedirs(args.destdir) log('Retrieving WNPP bugs information...') if args.bugs: wnpp_bugs_ids = args.bugs else: wnpp_bugs_ids = debianbts.get_bugs('package', 'wnpp') if args.limit: wnpp_bugs_ids = wnpp_bugs_ids[:args.limit] log(f"Found {len(wnpp_bugs_ids)} WNPP bugs, getting status...") wnpp_bugs = debianbts.get_status(wnpp_bugs_ids) wnpp = {} for wnpp_bug in wnpp_bugs: if wnpp_bug.done: continue m = WNPPRE.match(wnpp_bug.subject) if m: tag, src = m.groups() wnpp[src] = (tag, wnpp_bug.bug_num) else: log(f"Badly formatted WNPP bug: retitle {wnpp_bug.bug_num} \"{wnpp_bug.subject}\"" ) log('Retrieving ftp.debian.org bugs information...') if args.bugs: ftpdo_bugs_ids = args.bugs
def test_string_status_originator(): """test reading of bug status originator that is not base64-encoded""" bug = bts.get_status(711112)[0] assert is_unicode(bug.originator) assert bug.originator.endswith('debian.org>')