From e2f164336dfe2ea663ba0bb20be1bdc586e04904 Mon Sep 17 00:00:00 2001 From: Marcos Bjoerkelund Date: Fri, 14 Jun 2024 13:56:00 +0200 Subject: [PATCH 1/9] osc results: Add support for --format for default text mode --- osc/commandline.py | 3 ++- osc/core.py | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/osc/commandline.py b/osc/commandline.py index 0bc7dc63..c91628ce 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -6055,7 +6055,7 @@ Please submit there instead, or use --nodevelproject to force direct submission. @cmdln.option('', '--csv', action='store_true', default=False, help='generate output in CSV format') @cmdln.option('', '--format', default='%(repository)s|%(arch)s|%(state)s|%(dirty)s|%(code)s|%(details)s', - help='format string for csv output') + help='format string for default or csv output (not supported for xml)') @cmdln.option('--show-excluded', action='store_true', help='show repos that are excluded for this package') def do_results(self, subcmd, opts, *args): @@ -6129,6 +6129,7 @@ Please submit there instead, or use --nodevelproject to force direct submission. kwargs['verbose'] = opts.verbose kwargs['wait'] = opts.watch kwargs['printJoin'] = '\n' + kwargs['format'] = opts.format get_results(**kwargs) # WARNING: this function is also called by do_results. You need to set a default there diff --git a/osc/core.py b/osc/core.py index 5dd96de5..bc4e5318 100644 --- a/osc/core.py +++ b/osc/core.py @@ -4101,8 +4101,13 @@ def get_results(apiurl: str, project: str, package: str, verbose=False, printJoi # hmm the function name is a bit too generic - something like # get_package_results_human would be better, but this would break the existing # api (unless we keep get_results around as well)... - result_line_templ = '%(rep)-20s %(arch)-10s %(status)s' - result_line_mb_templ = '%(rep)-20s %(arch)-10s %(pkg)-30s %(status)s' + format = kwargs.pop('format') + if format is None: + result_line_templ = '%(rep)-20s %(arch)-10s %(status)s' + result_line_mb_templ = '%(rep)-20s %(arch)-10s %(pkg)-30s %(status)s' + else: + result_line_templ = format + result_line_mb_templ = format r = [] printed = False multibuild_packages = kwargs.pop('multibuild_packages', []) From 60094ba69295d0b7b5883aff581140ea68079f33 Mon Sep 17 00:00:00 2001 From: Marcos Bjoerkelund Date: Fri, 14 Jun 2024 17:03:35 +0200 Subject: [PATCH 2/9] Set a default value for --format only for --csv --- osc/commandline.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osc/commandline.py b/osc/commandline.py index c91628ce..acf26c04 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -6054,7 +6054,7 @@ Please submit there instead, or use --nodevelproject to force direct submission. help='generate output in XML (former results_meta)') @cmdln.option('', '--csv', action='store_true', default=False, help='generate output in CSV format') - @cmdln.option('', '--format', default='%(repository)s|%(arch)s|%(state)s|%(dirty)s|%(code)s|%(details)s', + @cmdln.option('', '--format', default=None, help='format string for default or csv output (not supported for xml)') @cmdln.option('--show-excluded', action='store_true', help='show repos that are excluded for this package') @@ -6123,6 +6123,8 @@ Please submit there instead, or use --nodevelproject to force direct submission. print(decode_it(xml), end='') else: # csv formatting + if opts.format is None: + opts.format='%(repository)s|%(arch)s|%(state)s|%(dirty)s|%(code)s|%(details)s' results = [r for r, _ in result_xml_to_dicts(xml)] print('\n'.join(format_results(results, opts.format))) else: From 5b0fbc43b0bced03f2a653b05ec01180543e9aaa Mon Sep 17 00:00:00 2001 From: Marcos Bjoerkelund Date: Fri, 14 Jun 2024 18:07:11 +0200 Subject: [PATCH 3/9] Fix PEP validation error --- osc/commandline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osc/commandline.py b/osc/commandline.py index acf26c04..980eccb5 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -6124,7 +6124,7 @@ Please submit there instead, or use --nodevelproject to force direct submission. else: # csv formatting if opts.format is None: - opts.format='%(repository)s|%(arch)s|%(state)s|%(dirty)s|%(code)s|%(details)s' + opts.format = '%(repository)s|%(arch)s|%(state)s|%(dirty)s|%(code)s|%(details)s' results = [r for r, _ in result_xml_to_dicts(xml)] print('\n'.join(format_results(results, opts.format))) else: From 673907ea9fa5e9eb2398a1a6051084b0fa7964b9 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Mon, 17 Jun 2024 17:56:24 +0200 Subject: [PATCH 4/9] Fix core.get_package_results() to obey 'multibuild_packages' argument --- osc/core.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/osc/core.py b/osc/core.py index bc4e5318..67fc44ab 100644 --- a/osc/core.py +++ b/osc/core.py @@ -4164,9 +4164,9 @@ def get_results(apiurl: str, project: str, package: str, verbose=False, printJoi return r -def get_package_results(apiurl: str, project: str, package: Optional[str] = None, wait=False, *args, **kwargs): +def get_package_results(apiurl: str, project: str, package: Optional[str] = None, wait=False, multibuild_packages: Optional[List[str]] = None, *args, **kwargs): """generator that returns a the package results as an xml structure""" - xml = '' + xml = b'' waiting_states = ('blocked', 'scheduled', 'dispatching', 'building', 'signing', 'finished') while True: @@ -4199,6 +4199,33 @@ def get_package_results(apiurl: str, project: str, package: Optional[str] = None waiting = True break + # filter the result according to the specified multibuild_packages (flavors) + if multibuild_packages: + for result in list(root): + for status in list(result): + package = status.attrib["package"] + package_flavor = package.rsplit(":", 1) + + # package has flavor, check if the flavor is in multibuild_packages + flavor_match = len(package_flavor) == 2 and package_flavor[1] in multibuild_packages + + # package nas no flavor, check if "" is in multibuild_packages + no_flavor_match = len(package_flavor) == 1 and "" in multibuild_packages + + if not flavor_match and not no_flavor_match: + # package doesn't match multibuild_packages, remove the corresponding from + result.remove(status) + + # remove empty from + if len(result) == 0: + root.remove(result) + + if len(root) == 0: + break + + xmlindent(root) + xml = ET.tostring(root) + if not wait or not waiting: break else: From bf99bf257e3d9584428509bee3c457620a0d50bb Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Mon, 17 Jun 2024 20:08:35 +0200 Subject: [PATCH 5/9] Add couple mutually exclusive options errors to 'results' command --- osc/commandline.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osc/commandline.py b/osc/commandline.py index 980eccb5..c56aa385 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -6090,6 +6090,12 @@ Please submit there instead, or use --nodevelproject to force direct submission. if opts.failed and opts.status_filter: raise oscerr.WrongArgs('-s and -f cannot be used together') + if opts.multibuild_package and opts.no_multibuild: + self.argparser.error("-M/--multibuild-package and --no-multibuild are mutually exclusive") + + if opts.xml and opts.format: + self.argparser.error("--xml and --format are mutually exclusive") + if opts.failed: opts.status_filter = 'failed' opts.brief = True From 46895095fa066103b28e1f6a7d0b77cd5aea5440 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Mon, 17 Jun 2024 20:11:37 +0200 Subject: [PATCH 6/9] Change 'results' command to use csv writer instead of formatting csv as string --- osc/commandline.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/osc/commandline.py b/osc/commandline.py index c56aa385..4652eea6 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -6130,9 +6130,27 @@ Please submit there instead, or use --nodevelproject to force direct submission. else: # csv formatting if opts.format is None: - opts.format = '%(repository)s|%(arch)s|%(state)s|%(dirty)s|%(code)s|%(details)s' - results = [r for r, _ in result_xml_to_dicts(xml)] - print('\n'.join(format_results(results, opts.format))) + columns = ["repository", "arch", "package", "state", "dirty", "code", "details"] + else: + # split columns by colon, semicolon or pipe + columns = opts.format.split(",") + + supported_columns = ["project", "package", "repository", "arch", "state", "dirty", "code", "details"] + unknown_columns = sorted(set(columns) - set(supported_columns)) + + if unknown_columns: + self.argparser.error(f"Unknown format fields: {''.join(unknown_columns)}") + + f = io.StringIO() + writer = csv.writer(f, dialect="unix") + + rows = [r for r, _ in result_xml_to_dicts(xml)] + for row in rows: + writer.writerow([row[i] for i in columns]) + + f.seek(0) + print(f.read(), end="") + else: kwargs['verbose'] = opts.verbose kwargs['wait'] = opts.watch From e1b866d5a7c3b586f8bcb1c80ab3bf2786d90832 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Mon, 17 Jun 2024 21:35:23 +0200 Subject: [PATCH 7/9] Change 'results' command so the normal and multibuild packages have the same output --- osc/core.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/osc/core.py b/osc/core.py index 67fc44ab..041a80b5 100644 --- a/osc/core.py +++ b/osc/core.py @@ -4103,11 +4103,7 @@ def get_results(apiurl: str, project: str, package: str, verbose=False, printJoi # api (unless we keep get_results around as well)... format = kwargs.pop('format') if format is None: - result_line_templ = '%(rep)-20s %(arch)-10s %(status)s' - result_line_mb_templ = '%(rep)-20s %(arch)-10s %(pkg)-30s %(status)s' - else: - result_line_templ = format - result_line_mb_templ = format + format = '%(rep)-20s %(arch)-10s %(pkg)-30s %(status)s' r = [] printed = False multibuild_packages = kwargs.pop('multibuild_packages', []) @@ -4150,10 +4146,7 @@ def get_results(apiurl: str, project: str, package: str, verbose=False, printJoi # of the repository if the result is already prefiltered by the backend. So we need # to filter out the repository states. if code_filter is None or code_filter == res['code']: - if is_multi: - r.append(result_line_mb_templ % res) - else: - r.append(result_line_templ % res) + r.append(format % res) if printJoin: if printed: From 4d4ef09319d7fe48e9632956de7dedcbfd8412ef Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Tue, 18 Jun 2024 09:22:48 +0200 Subject: [PATCH 8/9] Update help text for '--format' option in 'results' command --- osc/commandline.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osc/commandline.py b/osc/commandline.py index 4652eea6..3d7c2b7f 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -6055,7 +6055,10 @@ Please submit there instead, or use --nodevelproject to force direct submission. @cmdln.option('', '--csv', action='store_true', default=False, help='generate output in CSV format') @cmdln.option('', '--format', default=None, - help='format string for default or csv output (not supported for xml)') + help="Change the format of the text (default) or csv output. Not supported for xml output.\n" + "Supported fields: project, package, repository, arch, state, dirty, code, details.\n" + "Text output format requires using the field names in form of named fields for string interpolation: ``%%(field)s``.\n" + "CSV output format requires field names separated with commas.") @cmdln.option('--show-excluded', action='store_true', help='show repos that are excluded for this package') def do_results(self, subcmd, opts, *args): From a501ed31579270583599e58cab6de8e01f686771 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Tue, 18 Jun 2024 09:30:27 +0200 Subject: [PATCH 9/9] Add behave tests for 'results' command --- behave/features/results.feature | 141 ++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 behave/features/results.feature diff --git a/behave/features/results.feature b/behave/features/results.feature new file mode 100644 index 00000000..1ed2aa25 --- /dev/null +++ b/behave/features/results.feature @@ -0,0 +1,141 @@ +Feature: `osc results` command + + +Scenario: Run `osc results` with no arguments + When I execute osc with args "results" + Then the exit code is 2 + And stderr is + """ + No project given + """ + + +Scenario: Run `osc results /` + When I execute osc with args "results test:factory/multibuild-pkg" + Then stdout is + """ + standard x86_64 multibuild-pkg disabled + standard x86_64 multibuild-pkg:flavor1 disabled + standard x86_64 multibuild-pkg:flavor2 disabled + standard i586 multibuild-pkg disabled + standard i586 multibuild-pkg:flavor1 disabled + standard i586 multibuild-pkg:flavor2 disabled + """ + + +Scenario: Run `osc results` from a package checkout + Given I set working directory to "{context.osc.temp}" + And I execute osc with args "checkout test:factory/multibuild-pkg" + And I set working directory to "{context.osc.temp}/test:factory/multibuild-pkg" + When I execute osc with args "results" + Then stdout is + """ + standard x86_64 multibuild-pkg disabled + standard x86_64 multibuild-pkg:flavor1 disabled + standard x86_64 multibuild-pkg:flavor2 disabled + standard i586 multibuild-pkg disabled + standard i586 multibuild-pkg:flavor1 disabled + standard i586 multibuild-pkg:flavor2 disabled + """ + + +Scenario: Run `osc results /`, no multibuild flavors + When I execute osc with args "results test:factory/multibuild-pkg --no-multibuild" + Then stdout is + """ + standard x86_64 multibuild-pkg disabled + standard i586 multibuild-pkg disabled + """ + + +Scenario: Run `osc results` from a package checkout, multibuild flavor specified + Given I set working directory to "{context.osc.temp}" + And I execute osc with args "checkout test:factory/multibuild-pkg" + And I set working directory to "{context.osc.temp}/test:factory/multibuild-pkg" + When I execute osc with args "results -M flavor1" + Then stdout is + """ + standard x86_64 multibuild-pkg:flavor1 disabled + standard i586 multibuild-pkg:flavor1 disabled + """ + +Scenario: Run `osc results /`, specified output format + When I execute osc with args "results test:factory/multibuild-pkg --format='%(repository)s|%(arch)s|%(package)s|%(code)s'" + Then stdout is + """ + standard|x86_64|multibuild-pkg|disabled + standard|x86_64|multibuild-pkg:flavor1|disabled + standard|x86_64|multibuild-pkg:flavor2|disabled + standard|i586|multibuild-pkg|disabled + standard|i586|multibuild-pkg:flavor1|disabled + standard|i586|multibuild-pkg:flavor2|disabled + """ + + +Scenario: Run `osc results /`, csv output + When I execute osc with args "results test:factory/multibuild-pkg --csv" + Then stdout matches + """ + "standard","x86_64","multibuild-pkg","publish.*","False","disabled","" + "standard","x86_64","multibuild-pkg:flavor1","publish.*","False","disabled","" + "standard","x86_64","multibuild-pkg:flavor2","publish.*","False","disabled","" + "standard","i586","multibuild-pkg","publish.*","False","disabled","" + "standard","i586","multibuild-pkg:flavor1","publish.*","False","disabled","" + "standard","i586","multibuild-pkg:flavor2","publish.*","False","disabled","" + """ + + +Scenario: Run `osc results /`, csv output, multibuild flavor specified + When I execute osc with args "results test:factory/multibuild-pkg --csv -M flavor1" + Then stdout matches + """ + "standard","x86_64","multibuild-pkg:flavor1","publish.*","False","disabled","" + "standard","i586","multibuild-pkg:flavor1","publish.*","False","disabled","" + """ + + +Scenario: Run `osc results /`, csv output, specified output format (columns) + When I execute osc with args "results test:factory/multibuild-pkg --csv --format='repository,arch,package,code'" + Then stdout is + """ + "standard","x86_64","multibuild-pkg","disabled" + "standard","x86_64","multibuild-pkg:flavor1","disabled" + "standard","x86_64","multibuild-pkg:flavor2","disabled" + "standard","i586","multibuild-pkg","disabled" + "standard","i586","multibuild-pkg:flavor1","disabled" + "standard","i586","multibuild-pkg:flavor2","disabled" + """ + + +Scenario: Run `osc results /`, xml output + When I execute osc with args "results test:factory/multibuild-pkg --xml" + Then stdout matches + """ + + + + + + + + + + + + + """ + + +Scenario: Run `osc results /`, xml output, multibuild flavor specified + When I execute osc with args "results test:factory/multibuild-pkg --xml -M flavor1" + Then stdout matches + """ + + + + + + + + + """