Maintainer workflows discussions
 help / color / mirror / Atom feed
* Re: [PATCH v1 05/30] docs: reporting-issues: outline why reporting is complicated
From: Thorsten Leemhuis @ 2026-01-14  5:02 UTC (permalink / raw)
  To: Jonathan Corbet; +Cc: workflows, linux-doc, regressions, linux-kernel
In-Reply-To: <ae9a3fec-4872-4cb7-9e9f-dbeafb4daab7@leemhuis.info>

On 1/13/26 17:07, Thorsten Leemhuis wrote:

> I thought about this for a while, but in the end I this section and the
> one from 4/30 are worth it.

And having slept about this once more, I after my reply yesterday now
think it might be wise to merge the important parts from 4/30 into this
patch -- that should get things shorter and still get across chat I care
about. Sorry, took me a moment to realize that.

Ciao, Thorsten

^ permalink raw reply

* Re: [PATCH] docs: netdev: refine 15-patch limit
From: Simon Horman @ 2026-01-14  8:04 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: David S. Miller, Eric Dumazet, Paolo Abeni, Jonathan Corbet,
	netdev, workflows, linux-doc
In-Reply-To: <20260113173454.55a995cc@kernel.org>

On Tue, Jan 13, 2026 at 05:34:54PM -0800, Jakub Kicinski wrote:
> On Tue, 13 Jan 2026 17:47:15 +0000 Simon Horman wrote:
> > +Limit patches outstanding on mailing list
> > +-----------------------------------------
> > +
> > +Avoid having more than 15 patches, across all series, outstanding for
> > +review on the mailing list. This limit is intended to focus developer
> > +effort on testing patches before upstream review. Aiding the quality of
> > +upstream submissions, and easing the load on reviewers.
> 
> Thanks for adding this.
> 
> In practice I think the limit is also per tree (net vs net-next)
> to avoid head of line blocking fixes.

Thanks Jakub,

In v2 I'll update the wording to state that the limit is per-tree.

^ permalink raw reply

* Re: [LTP] [PATCH RESEND v2] checkpatch: Suppress warnings when Reported-by: is followed by Link:
From: Petr Vorel @ 2026-01-15  7:22 UTC (permalink / raw)
  To: cryolitia
  Cc: Andy Whitcroft, Joe Perches, Dwaipayan Ray, Lukas Bulwahn,
	Cryolitia PukNgae via B4 Relay, linux-doc, linux-kernel, linux-mm,
	workflows, niecheng1, ltp, zhanjun
In-Reply-To: <20260113-checkpatch-v2-1-5dfe8b9f4d90@uniontech.com>

Hi Cryolitia,

> From: Cryolitia PukNgae <cryolitia@uniontech.com>

> > The tag should be followed by a Closes: tag pointing to the report,
> > unless the report is not available on the web. The Link: tag can be
> > used instead of Closes: if the patch fixes a part of the issue(s)
> > being reported.

Indeed, this is true, although there is a prerequisite:

	The Link: tag can be used instead of Closes: if the patch fixes a part of
	the issue(s) being reported.

Reviewed-by: Petr Vorel <pvorel@suse.cz>

I also see you Cc LTP ML. FYI we vendored scripts/checkpatch.pl (with occasional
updates).

Kind regards,
Petr

> Accroding to Documentation/process/submitting-patches.rst , Link: is
> also acceptable to followed a Reported-by:

> Signed-off-by: Cryolitia PukNgae <cryolitia@uniontech.com>
> ---
> Link to previous: https://lore.kernel.org/r/20251023-checkpatch-v1-1-ff73ed1027d6@uniontech.com
> ---
>  scripts/checkpatch.pl | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)

> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> index c0250244cf7a..dac9d98133c6 100755
> --- a/scripts/checkpatch.pl
> +++ b/scripts/checkpatch.pl
> @@ -3209,10 +3209,10 @@ sub process {
>  			if ($sign_off =~ /^reported(?:|-and-tested)-by:$/i) {
>  				if (!defined $lines[$linenr]) {
>  					WARN("BAD_REPORTED_BY_LINK",
> -					     "Reported-by: should be immediately followed by Closes: with a URL to the report\n" . $herecurr . "\n");
> -				} elsif ($rawlines[$linenr] !~ /^closes:\s*/i) {
> +					     "Reported-by: should be immediately followed by Closes: or Link: with a URL to the report\n" . $herecurr . "\n");
> +				} elsif ($rawlines[$linenr] !~ /^(closes|link):\s*/i) {
>  					WARN("BAD_REPORTED_BY_LINK",
> -					     "Reported-by: should be immediately followed by Closes: with a URL to the report\n" . $herecurr . $rawlines[$linenr] . "\n");
> +					     "Reported-by: should be immediately followed by Closes: or Link: with a URL to the report\n" . $herecurr . $rawlines[$linenr] . "\n");
>  				}
>  			}
>  		}

^ permalink raw reply

* [PATCH v2] docs: netdev: refine 15-patch limit
From: Simon Horman @ 2026-01-15 13:54 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Jonathan Corbet
  Cc: netdev, workflows, linux-doc

The 15 patch limit is intended by the maintainers to cover
all outstanding patches on the mailing list on a per-tree basis.
Not just those in a single patchset. Document this practice accordingly.

Signed-off-by: Simon Horman <horms@kernel.org>
---
Changes in v2:
- Clarify that the limit is per-tree. (Jakub)
- Link to v1: https://lore.kernel.org/r/20260113-15-minutes-of-fame-v1-1-0806b418c6fd@kernel.org
---
 Documentation/process/maintainer-netdev.rst | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst
index 989192421cc9db6c93c816f2dfb7afbe48dd25fc..6bce4507d5d3136270bbf552880451e08b137b61 100644
--- a/Documentation/process/maintainer-netdev.rst
+++ b/Documentation/process/maintainer-netdev.rst
@@ -363,6 +363,18 @@ just do it. As a result, a sequence of smaller series gets merged quicker and
 with better review coverage. Re-posting large series also increases the mailing
 list traffic.
 
+Limit patches outstanding on mailing list
+-----------------------------------------
+
+Avoid having more than 15 patches, across all series, outstanding for
+review on the mailing list for a single tree. In other words, a maximum of
+15 patches under review on net, and a maximum of 15 patches under review on
+net-next.
+
+This limit is intended to focus developer effort on testing patches before
+upstream review. Aiding the quality of upstream submissions, and easing the
+load on reviewers.
+
 .. _rcs:
 
 Local variable ordering ("reverse xmas tree", "RCS")




^ permalink raw reply related

* [PATCH] kunit: add bash completion
From: Ryota Sakamoto @ 2026-01-15 14:53 UTC (permalink / raw)
  To: Brendan Higgins, David Gow, Rae Moar, Jonathan Corbet
  Cc: linux-kernel, linux-kselftest, kunit-dev, workflows, linux-doc,
	Ryota Sakamoto

Currently, kunit.py has many subcommands and options, making it difficult
to remember them without checking the help message.

Add --list-cmds and --list-opts to kunit.py to get available commands and
options, use those outputs in kunit-completion.sh to show completion.

This implementation is similar to perf and tools/perf/perf-completion.sh.

Example output:
  $ source tools/testing/kunit/kunit-completion.sh
  $ ./tools/testing/kunit/kunit.py [TAB][TAB]
  build   config  exec    parse   run
  $ ./tools/testing/kunit/kunit.py run --k[TAB][TAB]
  --kconfig_add  --kernel_args  --kunitconfig

Signed-off-by: Ryota Sakamoto <sakamo.ryota@gmail.com>
---
 Documentation/dev-tools/kunit/run_wrapper.rst |  9 ++++++++
 tools/testing/kunit/kunit-completion.sh       | 33 +++++++++++++++++++++++++++
 tools/testing/kunit/kunit.py                  | 30 ++++++++++++++++++++++++
 tools/testing/kunit/kunit_tool_test.py        | 21 +++++++++++++++++
 4 files changed, 93 insertions(+)

diff --git a/Documentation/dev-tools/kunit/run_wrapper.rst b/Documentation/dev-tools/kunit/run_wrapper.rst
index 6697c71ee8ca020b8ac7e91b46e29ab082d9dea0..3c0b585dcfffbd3929d0eef1ab9376fa4f380872 100644
--- a/Documentation/dev-tools/kunit/run_wrapper.rst
+++ b/Documentation/dev-tools/kunit/run_wrapper.rst
@@ -335,3 +335,12 @@ command line arguments:
 
 - ``--list_tests_attr``: If set, lists all tests that will be run and all of their
   attributes.
+
+Command-line completion
+==============================
+
+The kunit_tool comes with a bash completion script:
+
+.. code-block:: bash
+
+	source tools/testing/kunit/kunit-completion.sh
diff --git a/tools/testing/kunit/kunit-completion.sh b/tools/testing/kunit/kunit-completion.sh
new file mode 100644
index 0000000000000000000000000000000000000000..3b9b68e3bc384c026f10f74b8a1df2129cb2cd50
--- /dev/null
+++ b/tools/testing/kunit/kunit-completion.sh
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: GPL-2.0
+# bash completion support for KUnit
+
+_kunit_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+
+_kunit()
+{
+	local cur prev words cword
+	_init_completion || return
+
+	local script="${_kunit_dir}/kunit.py"
+
+	if [[ $cword -eq 1 && "$cur" != -* ]]; then
+		local cmds=$(${script} --list-cmds 2>/dev/null)
+		COMPREPLY=($(compgen -W "${cmds}" -- "$cur"))
+		return 0
+	fi
+
+	if [[ "$cur" == -* ]]; then
+		if [[ -n "${words[1]}" && "${words[1]}" != -* ]]; then
+			local opts=$(${script} ${words[1]} --list-opts 2>/dev/null)
+			COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
+			return 0
+		else
+			local opts=$(${script} --list-opts 2>/dev/null)
+			COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
+			return 0
+		fi
+	fi
+}
+
+complete -o default -F _kunit kunit.py
+complete -o default -F _kunit kunit
diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index cd99c1956331dbbfb06cf4ddf130db3dcf2a7c31..a5aee1eb88e65fa2387b2623642d2ee9a66db600 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -323,6 +323,17 @@ def get_default_jobs() -> int:
 		return ncpu
 	raise RuntimeError("os.cpu_count() returned None")
 
+def add_completion_opts(parser: argparse.ArgumentParser) -> None:
+	parser.add_argument('--list-opts',
+			    help=argparse.SUPPRESS,
+			    action='store_true')
+
+def add_root_opts(parser: argparse.ArgumentParser) -> None:
+	parser.add_argument('--list-cmds',
+			    help=argparse.SUPPRESS,
+			    action='store_true')
+	add_completion_opts(parser)
+
 def add_common_opts(parser: argparse.ArgumentParser) -> None:
 	parser.add_argument('--build_dir',
 			    help='As in the make command, it specifies the build '
@@ -374,6 +385,8 @@ def add_common_opts(parser: argparse.ArgumentParser) -> None:
 			    help='Additional QEMU arguments, e.g. "-smp 8"',
 			    action='append', metavar='')
 
+	add_completion_opts(parser)
+
 def add_build_opts(parser: argparse.ArgumentParser) -> None:
 	parser.add_argument('--jobs',
 			    help='As in the make command, "Specifies  the number of '
@@ -569,6 +582,7 @@ subcommand_handlers_map = {
 def main(argv: Sequence[str]) -> None:
 	parser = argparse.ArgumentParser(
 			description='Helps writing and running KUnit tests.')
+	add_root_opts(parser)
 	subparser = parser.add_subparsers(dest='subcommand')
 
 	# The 'run' command will config, build, exec, and parse in one go.
@@ -603,12 +617,28 @@ def main(argv: Sequence[str]) -> None:
 	parse_parser.add_argument('file',
 				  help='Specifies the file to read results from.',
 				  type=str, nargs='?', metavar='input_file')
+	add_completion_opts(parse_parser)
 
 	cli_args = parser.parse_args(massage_argv(argv))
 
 	if get_kernel_root_path():
 		os.chdir(get_kernel_root_path())
 
+	if cli_args.list_cmds:
+		print(" ".join(subparser.choices.keys()))
+		return
+
+	if cli_args.list_opts:
+		target_parser = subparser.choices.get(cli_args.subcommand)
+		if not target_parser:
+			target_parser = parser
+
+		# Accessing private attribute _option_string_actions to get
+		# the list of options. This is not a public API, but argparse
+		# does not provide a way to inspect options programmatically.
+		print(' '.join(target_parser._option_string_actions.keys()))
+		return
+
 	subcomand_handler = subcommand_handlers_map.get(cli_args.subcommand, None)
 
 	if subcomand_handler is None:
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index bbba921e0eacb18663abfcabb2bccf330d8666f5..a7f09a6c97a473ff85e087d17c2f5faf7755b994 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -11,11 +11,13 @@ from unittest import mock
 
 import tempfile, shutil # Handling test_tmpdir
 
+import io
 import itertools
 import json
 import os
 import signal
 import subprocess
+import sys
 from typing import Iterable
 
 import kunit_config
@@ -855,5 +857,24 @@ class KUnitMainTest(unittest.TestCase):
 			mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', filter='', filter_action=None, timeout=300),
 		])
 
+	@mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
+	def test_list_cmds(self, mock_stdout):
+		kunit.main(['--list-cmds'])
+		output = mock_stdout.getvalue()
+		output_cmds = sorted(output.split())
+		expected_cmds = sorted(['build', 'config', 'exec', 'parse', 'run'])
+		self.assertEqual(output_cmds, expected_cmds)
+
+	@mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
+	def test_run_list_opts(self, mock_stdout):
+		kunit.main(['run', '--list-opts'])
+		output = mock_stdout.getvalue()
+		output_cmds = set(output.split())
+		self.assertIn('--help', output_cmds)
+		self.assertIn('--kunitconfig', output_cmds)
+		self.assertIn('--jobs', output_cmds)
+		self.assertIn('--kernel_args', output_cmds)
+		self.assertIn('--raw_output', output_cmds)
+
 if __name__ == '__main__':
 	unittest.main()

---
base-commit: b71e635feefc852405b14620a7fc58c4c80c0f73
change-id: 20260114-kunit-completion-265889f59c52

Best regards,
-- 
Ryota Sakamoto <sakamo.ryota@gmail.com>


^ permalink raw reply related

* Re: [PATCH] [v5] Documentation: Provide guidelines for tool-generated content
From: Lee Jones @ 2026-01-15 15:04 UTC (permalink / raw)
  To: Dave Hansen
  Cc: Dave Hansen, linux-kernel, Shuah Khan, Kees Cook,
	Greg Kroah-Hartman, Miguel Ojeda, Luis Chamberlain, SeongJae Park,
	Dan Williams, Steven Rostedt, Paul E . McKenney, Simon Glass,
	NeilBrown, Lorenzo Stoakes, Theodore Ts'o, Sasha Levin,
	Jonathan Corbet, Vlastimil Babka, workflows, ksummit
In-Reply-To: <921e154d-7e54-40ff-ae85-97b6cee7f8b2@intel.com>

On Tue, 13 Jan 2026, Dave Hansen wrote:

> On 1/13/26 02:36, Lee Jones wrote:
> ...
> >> +Even if your tool use is out of scope, you should still always consider
> >> +if it would help reviewing your contribution if the reviewer knows
> >> +about the tool that you used.
> > 
> > Parsing ... okay, that took a few goes.  How about:
> > 
> >   Even if disclosure of your tool isn't mandated, providing this context
> >   often helps reviewers evaluate your contribution more effectively.
> >   Clear documentation of your workflow ensures a faster review with less
> >   contention.
> I agree that the sentence is hard to parse. But, I want to explicitly
> say "out of scope" to tie this in to the rest of the section. How about
> this?
> 
> 	Even if your tool use is out of scope, consider disclosing how
> 	you used the tool. Clear documentation of your workflow often
> 	helps reviewers do their jobs more efficiently.
> 
> BTW, I do think we're well into diminishing returns territory. I'll roll
> this into a v6 if there's a v6. But, if it's pulled in as-is, I think
> the original can stay without causing too much harm.

Agree.  Thanks for considering.

> ...>> +Some examples:
> >> + - Any tool-suggested fix such as ``checkpatch.pl --fix``
> >> + - Coccinelle scripts
> >> + - A chatbot generated a new function in your patch to sort list entries.
> >> + - A .c file in the patch was originally generated by a coding
> >> +   assistant but cleaned up by hand.
> >> + - The changelog was generated by handing the patch to a generative AI
> >> +   tool and asking it to write the changelog.
> >> + - The changelog was translated from another language.
> > 
> > Nit: Suggest removing the sporadic use of full-stops (periods) across all lists.
> > 
> > Or add them everywhere - so long as it's consistent.
> 
> The rule that I read is that when the bullets are full, complete
> sentences, you should use periods. When they are just nouns or shards of
> sentences, leave off the periods.
> 
> I _think_ that's the consensus for how to punctuate bulleted list items.
> 
> But I don't remember where I read that, if it was in Documentation/
> somewhere or it was some random rule on the Internet I decided to apply.

The non-consistency of it makes me twitch, but perhaps just my issue.

-- 
Lee Jones [李琼斯]

^ permalink raw reply

* [PATCH RESEND] docs: kselftest: remove link to obsolete wiki
From: Brett A C Sheffield @ 2026-01-15 17:24 UTC (permalink / raw)
  To: Shuah Khan, Jonathan Corbet, linux-kselftest, workflows,
	linux-doc, linux-kernel
  Cc: Brett A C Sheffield

Remove the reference to the obsolete kselftest wiki.

The kselftest wiki is marked obsolete and is no longer updated. The last
edit was in 2019, and the information is outdated, referring readers for
support to IRC networks that have not been used for years, and to kernel
versions that are no longer supported.

If there is any relevant information left in the wiki it needs to be
cleaned up and moved into the canonical kselftest documentation here.

Signed-off-by: Brett A C Sheffield <bacs@librecast.net>
---
Original: https://lore.kernel.org/linux-doc/20250824075007.13901-2-bacs@librecast.net/
---
 Documentation/dev-tools/kselftest.rst | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst
index 18c2da67fae4..e13aff7a80b5 100644
--- a/Documentation/dev-tools/kselftest.rst
+++ b/Documentation/dev-tools/kselftest.rst
@@ -15,11 +15,6 @@ able to run that test on an older kernel. Hence, it is important to keep
 code that can still test an older kernel and make sure it skips the test
 gracefully on newer releases.
 
-You can find additional information on Kselftest framework, how to
-write new tests using the framework on Kselftest wiki:
-
-https://kselftest.wiki.kernel.org/
-
 On some systems, hot-plug tests could hang forever waiting for cpu and
 memory to be ready to be offlined. A special hot-plug target is created
 to run the full range of hot-plug tests. In default mode, hot-plug tests run
-- 
2.52.0


^ permalink raw reply related

* Re: [PATCH RESEND] docs: kselftest: remove link to obsolete wiki
From: Bagas Sanjaya @ 2026-01-15 23:45 UTC (permalink / raw)
  To: Brett A C Sheffield, Shuah Khan, Jonathan Corbet, linux-kselftest,
	workflows, linux-doc, linux-kernel
In-Reply-To: <20260115172817.7120-1-bacs@librecast.net>

[-- Attachment #1: Type: text/plain, Size: 1035 bytes --]

On Thu, Jan 15, 2026 at 05:24:44PM +0000, Brett A C Sheffield wrote:
> diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst
> index 18c2da67fae4..e13aff7a80b5 100644
> --- a/Documentation/dev-tools/kselftest.rst
> +++ b/Documentation/dev-tools/kselftest.rst
> @@ -15,11 +15,6 @@ able to run that test on an older kernel. Hence, it is important to keep
>  code that can still test an older kernel and make sure it skips the test
>  gracefully on newer releases.
>  
> -You can find additional information on Kselftest framework, how to
> -write new tests using the framework on Kselftest wiki:
> -
> -https://kselftest.wiki.kernel.org/
> -
>  On some systems, hot-plug tests could hang forever waiting for cpu and
>  memory to be ready to be offlined. A special hot-plug target is created
>  to run the full range of hot-plug tests. In default mode, hot-plug tests run

Acked-by: Bagas Sanjaya <bagasdotme@gmail.com>

-- 
An old man doll... just what I always wanted! - Clara

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH RESEND] docs: kselftest: remove link to obsolete wiki
From: SeongJae Park @ 2026-01-16  2:23 UTC (permalink / raw)
  To: Brett A C Sheffield
  Cc: SeongJae Park, Shuah Khan, Jonathan Corbet, linux-kselftest,
	workflows, linux-doc, linux-kernel
In-Reply-To: <20260115172817.7120-1-bacs@librecast.net>

On Thu, 15 Jan 2026 17:24:44 +0000 Brett A C Sheffield <bacs@librecast.net> wrote:

> Remove the reference to the obsolete kselftest wiki.
> 
> The kselftest wiki is marked obsolete and is no longer updated. The last
> edit was in 2019, and the information is outdated, referring readers for
> support to IRC networks that have not been used for years, and to kernel
> versions that are no longer supported.
> 
> If there is any relevant information left in the wiki it needs to be
> cleaned up and moved into the canonical kselftest documentation here.
> 
> Signed-off-by: Brett A C Sheffield <bacs@librecast.net>

Acked-by: SeongJae Park <sj@kernel.org>


Thanks,
SJ

[...]

^ permalink raw reply

* [PATCH] doc: kgdb: Add description about rodata=off kernel parameter
From: junan @ 2026-01-16  5:03 UTC (permalink / raw)
  To: jason.wessel, danielt, dianders, corbet
  Cc: workflows, linux-doc, linux-kernel, junan, Will Deacon

STRICT_KERNEL_RWX can not be turned off throught menuconfig on some
architectures, pass "rodata=off" to the kernel in this case.

Tested with qemu on arm64.

Signed-off-by: junan <junan76@163.com>
Suggested-by: Will Deacon <will@kernel.org>
---
 Documentation/process/debugging/kgdb.rst | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/process/debugging/kgdb.rst b/Documentation/process/debugging/kgdb.rst
index b29b0aac2717..f2c57de7992f 100644
--- a/Documentation/process/debugging/kgdb.rst
+++ b/Documentation/process/debugging/kgdb.rst
@@ -380,6 +380,13 @@ virtual address where the kernel image is mapped and confuses
 gdb which resolves addresses of kernel symbols from the symbol table
 of vmlinux.
 
+Kernel parameter: ``rodata``
+----------------------------
+
+``CONFIG_STRICT_KERNEL_RWX`` is turned on by default and is not
+visible to menuconfig on some architectures (arm64 for example),
+you can pass ``rodata=off`` to the kernel in this case.
+
 Using kdb
 =========
 
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] kunit: add bash completion
From: David Gow @ 2026-01-16  9:30 UTC (permalink / raw)
  To: Ryota Sakamoto
  Cc: Brendan Higgins, Rae Moar, Jonathan Corbet, linux-kernel,
	linux-kselftest, kunit-dev, workflows, linux-doc
In-Reply-To: <20260115-kunit-completion-v1-1-4de6564962c4@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 8894 bytes --]

On Thu, 15 Jan 2026 at 22:54, Ryota Sakamoto <sakamo.ryota@gmail.com> wrote:
>
> Currently, kunit.py has many subcommands and options, making it difficult
> to remember them without checking the help message.
>
> Add --list-cmds and --list-opts to kunit.py to get available commands and
> options, use those outputs in kunit-completion.sh to show completion.
>
> This implementation is similar to perf and tools/perf/perf-completion.sh.
>
> Example output:
>   $ source tools/testing/kunit/kunit-completion.sh
>   $ ./tools/testing/kunit/kunit.py [TAB][TAB]
>   build   config  exec    parse   run
>   $ ./tools/testing/kunit/kunit.py run --k[TAB][TAB]
>   --kconfig_add  --kernel_args  --kunitconfig
>
> Signed-off-by: Ryota Sakamoto <sakamo.ryota@gmail.com>
> ---

This is awesome!

Two small suggestions:
- Could we add './tools/testing/kunit/kunit.py' to the list of
commands? That's what's recommended in lots of documentation, emails,
etc.
- It'd be great to rebase this on top of kselftest/kunit -- there's a
conflict with your previous patch.

Otherwise, this is great!

Reviewed-by: David Gow <davidgow@google.com>

Cheers,
-- David

>  Documentation/dev-tools/kunit/run_wrapper.rst |  9 ++++++++
>  tools/testing/kunit/kunit-completion.sh       | 33 +++++++++++++++++++++++++++
>  tools/testing/kunit/kunit.py                  | 30 ++++++++++++++++++++++++
>  tools/testing/kunit/kunit_tool_test.py        | 21 +++++++++++++++++
>  4 files changed, 93 insertions(+)
>
> diff --git a/Documentation/dev-tools/kunit/run_wrapper.rst b/Documentation/dev-tools/kunit/run_wrapper.rst
> index 6697c71ee8ca020b8ac7e91b46e29ab082d9dea0..3c0b585dcfffbd3929d0eef1ab9376fa4f380872 100644
> --- a/Documentation/dev-tools/kunit/run_wrapper.rst
> +++ b/Documentation/dev-tools/kunit/run_wrapper.rst
> @@ -335,3 +335,12 @@ command line arguments:
>
>  - ``--list_tests_attr``: If set, lists all tests that will be run and all of their
>    attributes.
> +
> +Command-line completion
> +==============================
> +
> +The kunit_tool comes with a bash completion script:
> +
> +.. code-block:: bash
> +
> +       source tools/testing/kunit/kunit-completion.sh
> diff --git a/tools/testing/kunit/kunit-completion.sh b/tools/testing/kunit/kunit-completion.sh
> new file mode 100644
> index 0000000000000000000000000000000000000000..3b9b68e3bc384c026f10f74b8a1df2129cb2cd50
> --- /dev/null
> +++ b/tools/testing/kunit/kunit-completion.sh
> @@ -0,0 +1,33 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# bash completion support for KUnit
> +
> +_kunit_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
> +
> +_kunit()
> +{
> +       local cur prev words cword
> +       _init_completion || return
> +
> +       local script="${_kunit_dir}/kunit.py"
> +
> +       if [[ $cword -eq 1 && "$cur" != -* ]]; then
> +               local cmds=$(${script} --list-cmds 2>/dev/null)
> +               COMPREPLY=($(compgen -W "${cmds}" -- "$cur"))
> +               return 0
> +       fi
> +
> +       if [[ "$cur" == -* ]]; then
> +               if [[ -n "${words[1]}" && "${words[1]}" != -* ]]; then
> +                       local opts=$(${script} ${words[1]} --list-opts 2>/dev/null)
> +                       COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
> +                       return 0
> +               else
> +                       local opts=$(${script} --list-opts 2>/dev/null)
> +                       COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
> +                       return 0
> +               fi
> +       fi
> +}
> +
> +complete -o default -F _kunit kunit.py
> +complete -o default -F _kunit kunit

Can we add:
complete -o default -F _kunit  ./tools/testing/kunit/kunit.py

as well?

> diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
> index cd99c1956331dbbfb06cf4ddf130db3dcf2a7c31..a5aee1eb88e65fa2387b2623642d2ee9a66db600 100755
> --- a/tools/testing/kunit/kunit.py
> +++ b/tools/testing/kunit/kunit.py
> @@ -323,6 +323,17 @@ def get_default_jobs() -> int:
>                 return ncpu
>         raise RuntimeError("os.cpu_count() returned None")
>
> +def add_completion_opts(parser: argparse.ArgumentParser) -> None:
> +       parser.add_argument('--list-opts',
> +                           help=argparse.SUPPRESS,
> +                           action='store_true')
> +
> +def add_root_opts(parser: argparse.ArgumentParser) -> None:
> +       parser.add_argument('--list-cmds',
> +                           help=argparse.SUPPRESS,
> +                           action='store_true')
> +       add_completion_opts(parser)
> +
>  def add_common_opts(parser: argparse.ArgumentParser) -> None:
>         parser.add_argument('--build_dir',
>                             help='As in the make command, it specifies the build '
> @@ -374,6 +385,8 @@ def add_common_opts(parser: argparse.ArgumentParser) -> None:
>                             help='Additional QEMU arguments, e.g. "-smp 8"',
>                             action='append', metavar='')
>
> +       add_completion_opts(parser)
> +
>  def add_build_opts(parser: argparse.ArgumentParser) -> None:
>         parser.add_argument('--jobs',
>                             help='As in the make command, "Specifies  the number of '
> @@ -569,6 +582,7 @@ subcommand_handlers_map = {
>  def main(argv: Sequence[str]) -> None:
>         parser = argparse.ArgumentParser(
>                         description='Helps writing and running KUnit tests.')
> +       add_root_opts(parser)
>         subparser = parser.add_subparsers(dest='subcommand')
>
>         # The 'run' command will config, build, exec, and parse in one go.
> @@ -603,12 +617,28 @@ def main(argv: Sequence[str]) -> None:
>         parse_parser.add_argument('file',
>                                   help='Specifies the file to read results from.',
>                                   type=str, nargs='?', metavar='input_file')
> +       add_completion_opts(parse_parser)
>
>         cli_args = parser.parse_args(massage_argv(argv))
>
>         if get_kernel_root_path():
>                 os.chdir(get_kernel_root_path())
>
> +       if cli_args.list_cmds:
> +               print(" ".join(subparser.choices.keys()))
> +               return
> +
> +       if cli_args.list_opts:
> +               target_parser = subparser.choices.get(cli_args.subcommand)
> +               if not target_parser:
> +                       target_parser = parser
> +
> +               # Accessing private attribute _option_string_actions to get
> +               # the list of options. This is not a public API, but argparse
> +               # does not provide a way to inspect options programmatically.
> +               print(' '.join(target_parser._option_string_actions.keys()))
> +               return
> +
>         subcomand_handler = subcommand_handlers_map.get(cli_args.subcommand, None)
>
>         if subcomand_handler is None:
> diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
> index bbba921e0eacb18663abfcabb2bccf330d8666f5..a7f09a6c97a473ff85e087d17c2f5faf7755b994 100755
> --- a/tools/testing/kunit/kunit_tool_test.py
> +++ b/tools/testing/kunit/kunit_tool_test.py
> @@ -11,11 +11,13 @@ from unittest import mock
>
>  import tempfile, shutil # Handling test_tmpdir
>
> +import io
>  import itertools
>  import json
>  import os
>  import signal
>  import subprocess
> +import sys
>  from typing import Iterable
>
>  import kunit_config
> @@ -855,5 +857,24 @@ class KUnitMainTest(unittest.TestCase):
>                         mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', filter='', filter_action=None, timeout=300),
>                 ])
>
> +       @mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
> +       def test_list_cmds(self, mock_stdout):
> +               kunit.main(['--list-cmds'])
> +               output = mock_stdout.getvalue()
> +               output_cmds = sorted(output.split())
> +               expected_cmds = sorted(['build', 'config', 'exec', 'parse', 'run'])
> +               self.assertEqual(output_cmds, expected_cmds)
> +
> +       @mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
> +       def test_run_list_opts(self, mock_stdout):
> +               kunit.main(['run', '--list-opts'])
> +               output = mock_stdout.getvalue()
> +               output_cmds = set(output.split())
> +               self.assertIn('--help', output_cmds)
> +               self.assertIn('--kunitconfig', output_cmds)
> +               self.assertIn('--jobs', output_cmds)
> +               self.assertIn('--kernel_args', output_cmds)
> +               self.assertIn('--raw_output', output_cmds)
> +
>  if __name__ == '__main__':
>         unittest.main()
>
> ---
> base-commit: b71e635feefc852405b14620a7fc58c4c80c0f73
> change-id: 20260114-kunit-completion-265889f59c52
>
> Best regards,
> --
> Ryota Sakamoto <sakamo.ryota@gmail.com>
>

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5281 bytes --]

^ permalink raw reply

* Re: [PATCH v1 05/30] docs: reporting-issues: outline why reporting is complicated
From: Thorsten Leemhuis @ 2026-01-16  9:42 UTC (permalink / raw)
  To: Jonathan Corbet; +Cc: workflows, linux-doc, regressions, linux-kernel
In-Reply-To: <80102174-2d5f-4f52-8836-806b61eabd7c@leemhuis.info>



On 1/14/26 06:02, Thorsten Leemhuis wrote:
> On 1/13/26 17:07, Thorsten Leemhuis wrote:
> 
>> I thought about this for a while, but in the end I this section and the
>> one from 4/30 are worth it.
> 
> And having slept about this once more, I after my reply yesterday now
> think it might be wise to merge the important parts from 4/30 into this
> patch -- that should get things shorter and still get across chat I care
> about. Sorry, took me a moment to realize that.

FYI, wrote something new (see below) which is even a few lines shorter
than what is in the document right now, yeah. :-D

Ciao, Thorsten

---

Appendix: Why it's harder to report kernel bugs
===============================================

The developers are well aware that reporting Linux kernel bugs is harder
than in other Free/Libre Open Source Projects. Many reasons for that lie
in the nature of the kernel, its development model, and how the world
uses it:

* *Most kernels of Linux distributions are totally unsuitable for
reporting bugs upstream.* The reference section above already explained
this in detail: outdated codebases as well as modifications and add-ons
lead to kernel bugs that were fixed upstream a long time ago or never
happened there in the first place. Developers of other Open Source
software face these problems as well, but the situation is a lot worse
when it comes to the Linux kernel, as the changes and their impact are
much more severe -- which is why many developers expect reports with
kernels built from fresh and nearly unmodified sources.

* *Bugs often only occur in a special environment.* That is because
Linux is mostly drivers and can be used in a multitude of ways.
Developers often do not have a matching setup at hand -- and therefore
frequently have to rely on bug reporters for isolating a bug's cause and
testing proposed fixes.

* *The kernel has hundreds of maintainers, and all-rounders are
extremely rare.* This is also due to the multitude of drivers and
features, which is why many know little about areas related to their
code and even less about unrelated.

* *It is hard finding where to report issues to, among others, due to
the lack of a central bug tracker.* This is something even some kernel
developers dislike, but that's the situation everyone has to deal with
currently.

* *Stable and longterm kernels are primarily maintained by a dedicated
'stable team', which usually is forbidden to fix bugs just there that
happen in mainline, too.* The team thus will almost always want to know
if mainline is also affected when someone reports a bug, say, using
Linux 6.1.2: if it already happened in 6.1 and still occurs with
6.2-rc1, it is best left to the regular developers, as they know the
area best.

* *Kernel developers are free to solely focus on the latest mainline
kernel.* Some developers, therefore, ignore or react coldly to reports
about bugs in, say, Linux 6.1 when 6.2-rc1 is already out; a similar
reaction might occur when it comes to reports with 6.1.1 or 6.1.2, as
the stable team might have caused the breakage.

* *There might be nobody to help.* That can happen due to the lack of
hardware documentation -- for example, when a driver was built using
reverse engineering or taken over by spare-time developers when the
hardware manufacturer left it behind. Other times there is nobody to
even report bugs to: when maintainers move on without a replacement,
their code often remains as long as it's useful.

Some of these aspects could be improved to facilitate bug reporting --
many Linux kernel developers are well aware of this and would be glad if
a few individuals or an entity would make this their mission.


^ permalink raw reply

* Re: [PATCH] kunit: add bash completion
From: Jani Nikula @ 2026-01-16 10:10 UTC (permalink / raw)
  To: Ryota Sakamoto, Brendan Higgins, David Gow, Rae Moar,
	Jonathan Corbet
  Cc: linux-kernel, linux-kselftest, kunit-dev, workflows, linux-doc,
	Ryota Sakamoto
In-Reply-To: <20260115-kunit-completion-v1-1-4de6564962c4@gmail.com>

On Thu, 15 Jan 2026, Ryota Sakamoto <sakamo.ryota@gmail.com> wrote:
> Currently, kunit.py has many subcommands and options, making it difficult
> to remember them without checking the help message.
>
> Add --list-cmds and --list-opts to kunit.py to get available commands and
> options, use those outputs in kunit-completion.sh to show completion.
>
> This implementation is similar to perf and tools/perf/perf-completion.sh.
>
> Example output:
>   $ source tools/testing/kunit/kunit-completion.sh
>   $ ./tools/testing/kunit/kunit.py [TAB][TAB]
>   build   config  exec    parse   run
>   $ ./tools/testing/kunit/kunit.py run --k[TAB][TAB]
>   --kconfig_add  --kernel_args  --kunitconfig
>

The alternative would be to make the tool more friendly to existing
completion tools such as shtab [1]. Since the kernel as a project is
really averse to adding external dependencies, you could take shtab's
CLI approach, and commit the completion script in the repo. Only
whoever's updating the completions would have to install and run shtab.

And the whole thing could be taken a step further, adding, say,
tools/completions/{bash,zsh,tcsh,...} directories for all the kernel
tool completions instead of spreading them around.

Anyway, just a thought to consider before doing another kernel homebrew
NIH approach.


BR,
Jani.



[1] https://github.com/iterative/shtab


> Signed-off-by: Ryota Sakamoto <sakamo.ryota@gmail.com>
> ---
>  Documentation/dev-tools/kunit/run_wrapper.rst |  9 ++++++++
>  tools/testing/kunit/kunit-completion.sh       | 33 +++++++++++++++++++++++++++
>  tools/testing/kunit/kunit.py                  | 30 ++++++++++++++++++++++++
>  tools/testing/kunit/kunit_tool_test.py        | 21 +++++++++++++++++
>  4 files changed, 93 insertions(+)
>
> diff --git a/Documentation/dev-tools/kunit/run_wrapper.rst b/Documentation/dev-tools/kunit/run_wrapper.rst
> index 6697c71ee8ca020b8ac7e91b46e29ab082d9dea0..3c0b585dcfffbd3929d0eef1ab9376fa4f380872 100644
> --- a/Documentation/dev-tools/kunit/run_wrapper.rst
> +++ b/Documentation/dev-tools/kunit/run_wrapper.rst
> @@ -335,3 +335,12 @@ command line arguments:
>  
>  - ``--list_tests_attr``: If set, lists all tests that will be run and all of their
>    attributes.
> +
> +Command-line completion
> +==============================
> +
> +The kunit_tool comes with a bash completion script:
> +
> +.. code-block:: bash
> +
> +	source tools/testing/kunit/kunit-completion.sh
> diff --git a/tools/testing/kunit/kunit-completion.sh b/tools/testing/kunit/kunit-completion.sh
> new file mode 100644
> index 0000000000000000000000000000000000000000..3b9b68e3bc384c026f10f74b8a1df2129cb2cd50
> --- /dev/null
> +++ b/tools/testing/kunit/kunit-completion.sh
> @@ -0,0 +1,33 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# bash completion support for KUnit
> +
> +_kunit_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
> +
> +_kunit()
> +{
> +	local cur prev words cword
> +	_init_completion || return
> +
> +	local script="${_kunit_dir}/kunit.py"
> +
> +	if [[ $cword -eq 1 && "$cur" != -* ]]; then
> +		local cmds=$(${script} --list-cmds 2>/dev/null)
> +		COMPREPLY=($(compgen -W "${cmds}" -- "$cur"))
> +		return 0
> +	fi
> +
> +	if [[ "$cur" == -* ]]; then
> +		if [[ -n "${words[1]}" && "${words[1]}" != -* ]]; then
> +			local opts=$(${script} ${words[1]} --list-opts 2>/dev/null)
> +			COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
> +			return 0
> +		else
> +			local opts=$(${script} --list-opts 2>/dev/null)
> +			COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
> +			return 0
> +		fi
> +	fi
> +}
> +
> +complete -o default -F _kunit kunit.py
> +complete -o default -F _kunit kunit
> diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
> index cd99c1956331dbbfb06cf4ddf130db3dcf2a7c31..a5aee1eb88e65fa2387b2623642d2ee9a66db600 100755
> --- a/tools/testing/kunit/kunit.py
> +++ b/tools/testing/kunit/kunit.py
> @@ -323,6 +323,17 @@ def get_default_jobs() -> int:
>  		return ncpu
>  	raise RuntimeError("os.cpu_count() returned None")
>  
> +def add_completion_opts(parser: argparse.ArgumentParser) -> None:
> +	parser.add_argument('--list-opts',
> +			    help=argparse.SUPPRESS,
> +			    action='store_true')
> +
> +def add_root_opts(parser: argparse.ArgumentParser) -> None:
> +	parser.add_argument('--list-cmds',
> +			    help=argparse.SUPPRESS,
> +			    action='store_true')
> +	add_completion_opts(parser)
> +
>  def add_common_opts(parser: argparse.ArgumentParser) -> None:
>  	parser.add_argument('--build_dir',
>  			    help='As in the make command, it specifies the build '
> @@ -374,6 +385,8 @@ def add_common_opts(parser: argparse.ArgumentParser) -> None:
>  			    help='Additional QEMU arguments, e.g. "-smp 8"',
>  			    action='append', metavar='')
>  
> +	add_completion_opts(parser)
> +
>  def add_build_opts(parser: argparse.ArgumentParser) -> None:
>  	parser.add_argument('--jobs',
>  			    help='As in the make command, "Specifies  the number of '
> @@ -569,6 +582,7 @@ subcommand_handlers_map = {
>  def main(argv: Sequence[str]) -> None:
>  	parser = argparse.ArgumentParser(
>  			description='Helps writing and running KUnit tests.')
> +	add_root_opts(parser)
>  	subparser = parser.add_subparsers(dest='subcommand')
>  
>  	# The 'run' command will config, build, exec, and parse in one go.
> @@ -603,12 +617,28 @@ def main(argv: Sequence[str]) -> None:
>  	parse_parser.add_argument('file',
>  				  help='Specifies the file to read results from.',
>  				  type=str, nargs='?', metavar='input_file')
> +	add_completion_opts(parse_parser)
>  
>  	cli_args = parser.parse_args(massage_argv(argv))
>  
>  	if get_kernel_root_path():
>  		os.chdir(get_kernel_root_path())
>  
> +	if cli_args.list_cmds:
> +		print(" ".join(subparser.choices.keys()))
> +		return
> +
> +	if cli_args.list_opts:
> +		target_parser = subparser.choices.get(cli_args.subcommand)
> +		if not target_parser:
> +			target_parser = parser
> +
> +		# Accessing private attribute _option_string_actions to get
> +		# the list of options. This is not a public API, but argparse
> +		# does not provide a way to inspect options programmatically.
> +		print(' '.join(target_parser._option_string_actions.keys()))
> +		return
> +
>  	subcomand_handler = subcommand_handlers_map.get(cli_args.subcommand, None)
>  
>  	if subcomand_handler is None:
> diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
> index bbba921e0eacb18663abfcabb2bccf330d8666f5..a7f09a6c97a473ff85e087d17c2f5faf7755b994 100755
> --- a/tools/testing/kunit/kunit_tool_test.py
> +++ b/tools/testing/kunit/kunit_tool_test.py
> @@ -11,11 +11,13 @@ from unittest import mock
>  
>  import tempfile, shutil # Handling test_tmpdir
>  
> +import io
>  import itertools
>  import json
>  import os
>  import signal
>  import subprocess
> +import sys
>  from typing import Iterable
>  
>  import kunit_config
> @@ -855,5 +857,24 @@ class KUnitMainTest(unittest.TestCase):
>  			mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', filter='', filter_action=None, timeout=300),
>  		])
>  
> +	@mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
> +	def test_list_cmds(self, mock_stdout):
> +		kunit.main(['--list-cmds'])
> +		output = mock_stdout.getvalue()
> +		output_cmds = sorted(output.split())
> +		expected_cmds = sorted(['build', 'config', 'exec', 'parse', 'run'])
> +		self.assertEqual(output_cmds, expected_cmds)
> +
> +	@mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
> +	def test_run_list_opts(self, mock_stdout):
> +		kunit.main(['run', '--list-opts'])
> +		output = mock_stdout.getvalue()
> +		output_cmds = set(output.split())
> +		self.assertIn('--help', output_cmds)
> +		self.assertIn('--kunitconfig', output_cmds)
> +		self.assertIn('--jobs', output_cmds)
> +		self.assertIn('--kernel_args', output_cmds)
> +		self.assertIn('--raw_output', output_cmds)
> +
>  if __name__ == '__main__':
>  	unittest.main()
>
> ---
> base-commit: b71e635feefc852405b14620a7fc58c4c80c0f73
> change-id: 20260114-kunit-completion-265889f59c52
>
> Best regards,

-- 
Jani Nikula, Intel

^ permalink raw reply

* Re: [PATCH v3 0/2] scripts: introduce containerized builds
From: Guillaume Tucker @ 2026-01-16 10:28 UTC (permalink / raw)
  To: Nathan Chancellor, Miguel Ojeda, David Gow, Onur Özkan
  Cc: Arnd Bergmann, linux-kernel, rust-for-linux, linux-kbuild,
	automated-testing, workflows, llvm
In-Reply-To: <cover.1767199119.git.gtucker@gtucker.io>

Hello,

On 31/12/2025 17:51, Guillaume Tucker wrote:
> Changes in v3:
> - Refactor common code for Docker and Podman
> - Add docs.kernel.org URL in help message
> - Use pathlib Python package
> - Handle signals in parent process by default
> - Add --shell option to use an interactive shell
> - Tweak debug messages in verbose mode
> - Specify Python 3.10 as minimum version in the docs
> - Provide an example env file in the docs
> - Update docs regarding interactive shell usage

I'm sure you're all busy landing commits ahead of the next merge
window.  Could you please take a look at this v3 when you have a
moment?  I believe I've addressed everything from previous reviews.

Thanks,
Guillaume


^ permalink raw reply

* Re: [PATCH] kunit: add bash completion
From: Ryota Sakamoto @ 2026-01-16 16:58 UTC (permalink / raw)
  To: David Gow
  Cc: Brendan Higgins, Rae Moar, Jonathan Corbet, linux-kernel,
	linux-kselftest, kunit-dev, workflows, linux-doc
In-Reply-To: <CABVgOS=Yn3K+Xzq_3tb0LCrX2eJjU5AG38uMwHaa21nXfxsjEQ@mail.gmail.com>

Hi David,
Thank you for the review.

On Fri, Jan 16, 2026 at 05:30:22PM +0800, David Gow wrote:
> Two small suggestions:
> - Could we add './tools/testing/kunit/kunit.py' to the list of
> commands? That's what's recommended in lots of documentation, emails,
> etc.

Sure, I will add the relative path of the script explicitly.

> - It'd be great to rebase this on top of kselftest/kunit -- there's a
> conflict with your previous patch.

I will rebase the patch on top of kselftest/kunit to resolve the conflict.

Regards,
Ryota Sakamoto

^ permalink raw reply

* Re: [PATCH] kunit: add bash completion
From: Ryota Sakamoto @ 2026-01-16 17:16 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Brendan Higgins, David Gow, Rae Moar, Jonathan Corbet,
	linux-kernel, linux-kselftest, kunit-dev, workflows, linux-doc
In-Reply-To: <44b770121202e9f41648da5abaf9a87d5b8811c6@intel.com>

Hi Jani,
Thank you for the suggestion regarding shtab.

On Fri, Jan 16, 2026 at 12:10:27PM +0200, Jani Nikula wrote:
> The alternative would be to make the tool more friendly to existing
> completion tools such as shtab [1]. Since the kernel as a project is
> really averse to adding external dependencies, you could take shtab's
> CLI approach, and commit the completion script in the repo. Only
> whoever's updating the completions would have to install and run shtab.

I understand your point about avoiding homebrew solutions, however, a main
benefit of this approach is that the completion script does not need to be
regenerated or updated manually.

Using shtab would introduce a new dependency and maintenance where the
static completion script could easily get out of sync.

So I would like to proceed with the current approach.

> And the whole thing could be taken a step further, adding, say,
> tools/completions/{bash,zsh,tcsh,...} directories for all the kernel
> tool completions instead of spreading them around.

I agree that centralizing completions is a good idea. So it would be better
handled as a separate future effort because it is a tree-wide
reorganization.

Regards,
Ryota Sakamoto

^ permalink raw reply

* [PATCH v2] kunit: add bash completion
From: Ryota Sakamoto @ 2026-01-16 17:46 UTC (permalink / raw)
  To: Brendan Higgins, David Gow, Rae Moar, Jonathan Corbet
  Cc: Jani Nikula, linux-kernel, linux-kselftest, kunit-dev, workflows,
	linux-doc, Ryota Sakamoto

Currently, kunit.py has many subcommands and options, making it difficult
to remember them without checking the help message.

Add --list-cmds and --list-opts to kunit.py to get available commands and
options, use those outputs in kunit-completion.sh to show completion.

This implementation is similar to perf and tools/perf/perf-completion.sh.

Example output:
  $ source tools/testing/kunit/kunit-completion.sh
  $ ./tools/testing/kunit/kunit.py [TAB][TAB]
  build   config  exec    parse   run
  $ ./tools/testing/kunit/kunit.py run --k[TAB][TAB]
  --kconfig_add  --kernel_args  --kunitconfig

Reviewed-by: David Gow <davidgow@google.com>
Signed-off-by: Ryota Sakamoto <sakamo.ryota@gmail.com>
---
Changes in v2:
- Add relative path './tools/testing/kunit/kunit.py' to completion list
- Rebase on kselftest/kunit branch
- Link to v1: https://lore.kernel.org/r/20260115-kunit-completion-v1-1-4de6564962c4@gmail.com
---
 Documentation/dev-tools/kunit/run_wrapper.rst |  9 +++++++
 tools/testing/kunit/kunit-completion.sh       | 34 +++++++++++++++++++++++++++
 tools/testing/kunit/kunit.py                  | 30 +++++++++++++++++++++++
 tools/testing/kunit/kunit_tool_test.py        | 21 +++++++++++++++++
 4 files changed, 94 insertions(+)

diff --git a/Documentation/dev-tools/kunit/run_wrapper.rst b/Documentation/dev-tools/kunit/run_wrapper.rst
index 6697c71ee8ca020b8ac7e91b46e29ab082d9dea0..3c0b585dcfffbd3929d0eef1ab9376fa4f380872 100644
--- a/Documentation/dev-tools/kunit/run_wrapper.rst
+++ b/Documentation/dev-tools/kunit/run_wrapper.rst
@@ -335,3 +335,12 @@ command line arguments:
 
 - ``--list_tests_attr``: If set, lists all tests that will be run and all of their
   attributes.
+
+Command-line completion
+==============================
+
+The kunit_tool comes with a bash completion script:
+
+.. code-block:: bash
+
+	source tools/testing/kunit/kunit-completion.sh
diff --git a/tools/testing/kunit/kunit-completion.sh b/tools/testing/kunit/kunit-completion.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f053e7b5d265aec8317b6eb11c8920063607073f
--- /dev/null
+++ b/tools/testing/kunit/kunit-completion.sh
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+# bash completion support for KUnit
+
+_kunit_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+
+_kunit()
+{
+	local cur prev words cword
+	_init_completion || return
+
+	local script="${_kunit_dir}/kunit.py"
+
+	if [[ $cword -eq 1 && "$cur" != -* ]]; then
+		local cmds=$(${script} --list-cmds 2>/dev/null)
+		COMPREPLY=($(compgen -W "${cmds}" -- "$cur"))
+		return 0
+	fi
+
+	if [[ "$cur" == -* ]]; then
+		if [[ -n "${words[1]}" && "${words[1]}" != -* ]]; then
+			local opts=$(${script} ${words[1]} --list-opts 2>/dev/null)
+			COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
+			return 0
+		else
+			local opts=$(${script} --list-opts 2>/dev/null)
+			COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
+			return 0
+		fi
+	fi
+}
+
+complete -o default -F _kunit kunit.py
+complete -o default -F _kunit kunit
+complete -o default -F _kunit ./tools/testing/kunit/kunit.py
diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index e3d82a038f93df0e86952da92461bc2e02f69ed1..4ec5ecba6d49b1ba3360515a2b66a2a98813bd18 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -328,6 +328,17 @@ def get_default_build_dir() -> str:
 		return os.path.join(os.environ['KBUILD_OUTPUT'], '.kunit')
 	return '.kunit'
 
+def add_completion_opts(parser: argparse.ArgumentParser) -> None:
+	parser.add_argument('--list-opts',
+			    help=argparse.SUPPRESS,
+			    action='store_true')
+
+def add_root_opts(parser: argparse.ArgumentParser) -> None:
+	parser.add_argument('--list-cmds',
+			    help=argparse.SUPPRESS,
+			    action='store_true')
+	add_completion_opts(parser)
+
 def add_common_opts(parser: argparse.ArgumentParser) -> None:
 	parser.add_argument('--build_dir',
 			    help='As in the make command, it specifies the build '
@@ -379,6 +390,8 @@ def add_common_opts(parser: argparse.ArgumentParser) -> None:
 			    help='Additional QEMU arguments, e.g. "-smp 8"',
 			    action='append', metavar='')
 
+	add_completion_opts(parser)
+
 def add_build_opts(parser: argparse.ArgumentParser) -> None:
 	parser.add_argument('--jobs',
 			    help='As in the make command, "Specifies  the number of '
@@ -574,6 +587,7 @@ subcommand_handlers_map = {
 def main(argv: Sequence[str]) -> None:
 	parser = argparse.ArgumentParser(
 			description='Helps writing and running KUnit tests.')
+	add_root_opts(parser)
 	subparser = parser.add_subparsers(dest='subcommand')
 
 	# The 'run' command will config, build, exec, and parse in one go.
@@ -608,12 +622,28 @@ def main(argv: Sequence[str]) -> None:
 	parse_parser.add_argument('file',
 				  help='Specifies the file to read results from.',
 				  type=str, nargs='?', metavar='input_file')
+	add_completion_opts(parse_parser)
 
 	cli_args = parser.parse_args(massage_argv(argv))
 
 	if get_kernel_root_path():
 		os.chdir(get_kernel_root_path())
 
+	if cli_args.list_cmds:
+		print(" ".join(subparser.choices.keys()))
+		return
+
+	if cli_args.list_opts:
+		target_parser = subparser.choices.get(cli_args.subcommand)
+		if not target_parser:
+			target_parser = parser
+
+		# Accessing private attribute _option_string_actions to get
+		# the list of options. This is not a public API, but argparse
+		# does not provide a way to inspect options programmatically.
+		print(' '.join(target_parser._option_string_actions.keys()))
+		return
+
 	subcomand_handler = subcommand_handlers_map.get(cli_args.subcommand, None)
 
 	if subcomand_handler is None:
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index 238a31a5cc291854bb8738f22e04c65bcbaeb11c..b67408147c1faaab12b168aabe3bfba8bf1b00aa 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -11,11 +11,13 @@ from unittest import mock
 
 import tempfile, shutil # Handling test_tmpdir
 
+import io
 import itertools
 import json
 import os
 import signal
 import subprocess
+import sys
 from typing import Iterable
 
 import kunit_config
@@ -886,5 +888,24 @@ class KUnitMainTest(unittest.TestCase):
 			mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', filter='', filter_action=None, timeout=300),
 		])
 
+	@mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
+	def test_list_cmds(self, mock_stdout):
+		kunit.main(['--list-cmds'])
+		output = mock_stdout.getvalue()
+		output_cmds = sorted(output.split())
+		expected_cmds = sorted(['build', 'config', 'exec', 'parse', 'run'])
+		self.assertEqual(output_cmds, expected_cmds)
+
+	@mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
+	def test_run_list_opts(self, mock_stdout):
+		kunit.main(['run', '--list-opts'])
+		output = mock_stdout.getvalue()
+		output_cmds = set(output.split())
+		self.assertIn('--help', output_cmds)
+		self.assertIn('--kunitconfig', output_cmds)
+		self.assertIn('--jobs', output_cmds)
+		self.assertIn('--kernel_args', output_cmds)
+		self.assertIn('--raw_output', output_cmds)
+
 if __name__ == '__main__':
 	unittest.main()

---
base-commit: f126d688193b4dd6d0044c19771469724c03f8f8
change-id: 20260114-kunit-completion-265889f59c52

Best regards,
-- 
Ryota Sakamoto <sakamo.ryota@gmail.com>


^ permalink raw reply related

* Re: [PATCH v3 0/2] scripts: introduce containerized builds
From: Nathan Chancellor @ 2026-01-16 21:12 UTC (permalink / raw)
  To: Guillaume Tucker
  Cc: Miguel Ojeda, David Gow, Onur Özkan, Arnd Bergmann,
	linux-kernel, rust-for-linux, linux-kbuild, automated-testing,
	workflows, llvm
In-Reply-To: <6af4b4cb-cf0a-4647-bdb8-0b2b1cb03b76@gtucker.io>

Hi Guillaume,

On Fri, Jan 16, 2026 at 11:28:24AM +0100, Guillaume Tucker wrote:
> Hello,
> 
> On 31/12/2025 17:51, Guillaume Tucker wrote:
> > Changes in v3:
> > - Refactor common code for Docker and Podman
> > - Add docs.kernel.org URL in help message
> > - Use pathlib Python package
> > - Handle signals in parent process by default
> > - Add --shell option to use an interactive shell
> > - Tweak debug messages in verbose mode
> > - Specify Python 3.10 as minimum version in the docs
> > - Provide an example env file in the docs
> > - Update docs regarding interactive shell usage
> 
> I'm sure you're all busy landing commits ahead of the next merge
> window.  Could you please take a look at this v3 when you have a
> moment?  I believe I've addressed everything from previous reviews.

So sorry for the radio silence. I was going to try and look at this
today to give feedback before the weekend but I will not be able to look
at it until Monday. Given that this is self-contained (no pun intended)
with no regression risks, I would have no qualms with applying this late
in the development cycle.

Cheers,
Nathan

^ permalink raw reply

* [PATCH] kunit: tool: Add (primitive) support for outputting JUnit XML
From: David Gow @ 2026-01-19  7:34 UTC (permalink / raw)
  To: Brendan Higgins, Rae Moar, Shuah Khan
  Cc: David Gow, linux-kselftest, workflows, linux-kernel, kunit-dev

This is used by things like Jenkins and other CI systems, which can
pretty-print the test output and potentially provide test-level comparisons
between runs.

The implementation here is pretty basic: it only provides the raw results,
split into tests and test suites, and doesn't provide any overall metadata.
However, CI systems like Jenkins can injest it and it is already useful.

Signed-off-by: David Gow <davidgow@google.com>
---
 Documentation/dev-tools/kunit/run_wrapper.rst |  3 ++
 tools/testing/kunit/kunit.py                  | 25 +++++++++++-
 tools/testing/kunit/kunit_junit.py            | 36 +++++++++++++++++
 tools/testing/kunit/kunit_tool_test.py        | 40 +++++++++++++++++--
 4 files changed, 100 insertions(+), 4 deletions(-)
 create mode 100644 tools/testing/kunit/kunit_junit.py

diff --git a/Documentation/dev-tools/kunit/run_wrapper.rst b/Documentation/dev-tools/kunit/run_wrapper.rst
index 6697c71ee8ca..e5c318162581 100644
--- a/Documentation/dev-tools/kunit/run_wrapper.rst
+++ b/Documentation/dev-tools/kunit/run_wrapper.rst
@@ -324,6 +324,9 @@ command line arguments:
 - ``--json``: If set, stores the test results in a JSON format and prints to `stdout` or
   saves to a file if a filename is specified.
 
+- ``--junit``: If set, stores the test results in JUnit XML format and prints to `stdout` or
+  saves to a file if a filename is specified.
+
 - ``--filter``: Specifies filters on test attributes, for example, ``speed!=slow``.
   Multiple filters can be used by wrapping input in quotes and separating filters
   by commas. Example: ``--filter "speed>slow, module=example"``.
diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index e3d82a038f93..0698d27c3629 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -21,6 +21,7 @@ from enum import Enum, auto
 from typing import Iterable, List, Optional, Sequence, Tuple
 
 import kunit_json
+import kunit_junit
 import kunit_kernel
 import kunit_parser
 from kunit_printer import stdout, null_printer
@@ -49,6 +50,7 @@ class KunitBuildRequest(KunitConfigRequest):
 class KunitParseRequest:
 	raw_output: Optional[str]
 	json: Optional[str]
+	junit: Optional[str]
 	summary: bool
 	failed: bool
 
@@ -261,6 +263,17 @@ def parse_tests(request: KunitParseRequest, metadata: kunit_json.Metadata, input
 			stdout.print_with_timestamp("Test results stored in %s" %
 				os.path.abspath(request.json))
 
+	if request.junit:
+		junit_str = kunit_junit.get_junit_result(
+					test=test)
+		if request.junit == 'stdout':
+			print(junit_str)
+		else:
+			with open(request.junit, 'w') as f:
+				f.write(junit_str)
+			stdout.print_with_timestamp("Test results stored in %s" %
+				os.path.abspath(request.junit))
+
 	if test.status != kunit_parser.TestStatus.SUCCESS:
 		return KunitResult(KunitStatus.TEST_FAILURE, parse_time), test
 
@@ -302,6 +315,7 @@ def run_tests(linux: kunit_kernel.LinuxSourceTree,
 # So we hackily automatically rewrite --json => --json=stdout
 pseudo_bool_flag_defaults = {
 		'--json': 'stdout',
+		'--junit': 'stdout',
 		'--raw_output': 'kunit',
 }
 def massage_argv(argv: Sequence[str]) -> Sequence[str]:
@@ -436,6 +450,11 @@ def add_parse_opts(parser: argparse.ArgumentParser) -> None:
 			    help='Prints parsed test results as JSON to stdout or a file if '
 			    'a filename is specified. Does nothing if --raw_output is set.',
 			    type=str, const='stdout', default=None, metavar='FILE')
+	parser.add_argument('--junit',
+			    nargs='?',
+			    help='Prints parsed test results as JUnit XML to stdout or a file if '
+			    'a filename is specified. Does nothing if --raw_output is set.',
+			    type=str, const='stdout', default=None, metavar='FILE')
 	parser.add_argument('--summary',
 			    help='Prints only the summary line for parsed test results.'
 				'Does nothing if --raw_output is set.',
@@ -479,6 +498,7 @@ def run_handler(cli_args: argparse.Namespace) -> None:
 					jobs=cli_args.jobs,
 					raw_output=cli_args.raw_output,
 					json=cli_args.json,
+					junit=cli_args.junit,
 					summary=cli_args.summary,
 					failed=cli_args.failed,
 					timeout=cli_args.timeout,
@@ -528,6 +548,7 @@ def exec_handler(cli_args: argparse.Namespace) -> None:
 	exec_request = KunitExecRequest(raw_output=cli_args.raw_output,
 					build_dir=cli_args.build_dir,
 					json=cli_args.json,
+					junit=cli_args.junit,
 					summary=cli_args.summary,
 					failed=cli_args.failed,
 					timeout=cli_args.timeout,
@@ -555,7 +576,9 @@ def parse_handler(cli_args: argparse.Namespace) -> None:
 	# We know nothing about how the result was created!
 	metadata = kunit_json.Metadata()
 	request = KunitParseRequest(raw_output=cli_args.raw_output,
-					json=cli_args.json, summary=cli_args.summary,
+					json=cli_args.json,
+					junit=cli_args.junit,
+					summary=cli_args.summary,
 					failed=cli_args.failed)
 	result, _ = parse_tests(request, metadata, kunit_output)
 	if result.status != KunitStatus.SUCCESS:
diff --git a/tools/testing/kunit/kunit_junit.py b/tools/testing/kunit/kunit_junit.py
new file mode 100644
index 000000000000..58d482e0c793
--- /dev/null
+++ b/tools/testing/kunit/kunit_junit.py
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Generates JSON from KUnit results according to
+# KernelCI spec: https://github.com/kernelci/kernelci-doc/wiki/Test-API
+#
+# Copyright (C) 2025, Google LLC.
+# Author: David Gow <davidgow@google.com>
+
+
+from kunit_parser import Test, TestStatus
+
+def escape_xml_string(string : str) -> str:
+	return string.replace("&", "&amp;").replace("\"", "&quot;").replace("'", "&apos;").replace("<", "&lt;").replace(">", "&gt;")
+
+def get_test_suite(test: Test) -> str:
+	xml_output = '<testsuite name="' + escape_xml_string(test.name) + '" tests="' + str(test.counts.total()) + '" failures="' + str(test.counts.failed) + '" skipped="' +str(test.counts.skipped) + '">\n'
+
+	for subtest in test.subtests:
+		if subtest.subtests:
+			xml_output += get_test_suite(subtest)
+			continue
+		xml_output += '<testcase name="' + escape_xml_string(subtest.name) + '" >\n'
+		if subtest.status == TestStatus.FAILURE:
+			xml_output += '<failure>Test Failed</failure>\n'
+		xml_output += '<system-out><![CDATA[' + "\n".join(subtest.log) + ']]></system-out>\n'
+		xml_output += '</testcase>\n'
+
+	xml_output += '</testsuite>\n\n'
+
+	return xml_output
+
+def get_junit_result(test: Test) -> str:
+	xml_output = '<?xml version="1.0" encoding="UTF-8" ?>\n\n'
+
+	xml_output += get_test_suite(test)
+	return xml_output
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index 238a31a5cc29..e29ef4162f9e 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -22,6 +22,7 @@ import kunit_config
 import kunit_parser
 import kunit_kernel
 import kunit_json
+import kunit_junit
 import kunit
 from kunit_printer import stdout
 
@@ -606,6 +607,39 @@ class StrContains(str):
 	def __eq__(self, other):
 		return self in other
 
+class KUnitJUnitTest(unittest.TestCase):
+	def setUp(self):
+		self.print_mock = mock.patch('kunit_printer.Printer.print').start()
+		self.addCleanup(mock.patch.stopall)
+
+	def _junit_string(self, log_file):
+		with open(_test_data_path(log_file)) as file:
+			test_result = kunit_parser.parse_run_tests(file, stdout)
+			junit_string = kunit_junit.get_junit_result(
+					test=test_result)
+		return junit_string
+
+	def test_xml_escape(self):
+		self.assertEqual(kunit_junit.escape_xml_string("qwertyuiop"), "qwertyuiop")
+		self.assertEqual(kunit_junit.escape_xml_string("\"quoted\""), "&quot;quoted&quot;")
+		self.assertEqual(kunit_junit.escape_xml_string("'quoted'"), "&apos;quoted&apos;")
+		self.assertEqual(kunit_junit.escape_xml_string("<tag>"), "&lt;tag&gt;")
+		self.assertEqual(kunit_junit.escape_xml_string("&amp;"), "&amp;amp;")
+
+	def test_failed_test_junit(self):
+		result = self._junit_string('test_is_test_passed-failure.log')
+		self.assertTrue("<failure>" in result)
+
+	def test_skipped_test_junit(self):
+		result = self._junit_string('test_skip_tests.log')
+		self.assertTrue("skipped=\"1\"" in result)
+
+	def test_no_tests_junit(self):
+		result = self._junit_string('test_is_test_passed-no_tests_run_with_header.log')
+		self.assertTrue("tests=\"0\"" in result)
+		self.assertFalse("testcase" in result)
+
+
 class KUnitMainTest(unittest.TestCase):
 	def setUp(self):
 		path = _test_data_path('test_is_test_passed-all_passed.log')
@@ -853,7 +887,7 @@ class KUnitMainTest(unittest.TestCase):
 		self.linux_source_mock.run_kernel.return_value = ['TAP version 14', 'init: random output'] + want
 
 		got = kunit._list_tests(self.linux_source_mock,
-				     kunit.KunitExecRequest(None, None, False, False, '.kunit', 300, 'suite*', '', None, None, 'suite', False, False))
+				     kunit.KunitExecRequest(None, None, None, False, False, '.kunit', 300, 'suite*', '', None, None, 'suite', False, False))
 		self.assertEqual(got, want)
 		# Should respect the user's filter glob when listing tests.
 		self.linux_source_mock.run_kernel.assert_called_once_with(
@@ -866,7 +900,7 @@ class KUnitMainTest(unittest.TestCase):
 
 		# Should respect the user's filter glob when listing tests.
 		mock_tests.assert_called_once_with(mock.ANY,
-				     kunit.KunitExecRequest(None, None, False, False, '.kunit', 300, 'suite*.test*', '', None, None, 'suite', False, False))
+				     kunit.KunitExecRequest(None, None, None, False, False, '.kunit', 300, 'suite*.test*', '', None, None, 'suite', False, False))
 		self.linux_source_mock.run_kernel.assert_has_calls([
 			mock.call(args=None, build_dir='.kunit', filter_glob='suite.test*', filter='', filter_action=None, timeout=300),
 			mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test*', filter='', filter_action=None, timeout=300),
@@ -879,7 +913,7 @@ class KUnitMainTest(unittest.TestCase):
 
 		# Should respect the user's filter glob when listing tests.
 		mock_tests.assert_called_once_with(mock.ANY,
-				     kunit.KunitExecRequest(None, None, False, False, '.kunit', 300, 'suite*', '', None, None, 'test', False, False))
+				     kunit.KunitExecRequest(None, None, None, False, False, '.kunit', 300, 'suite*', '', None, None, 'test', False, False))
 		self.linux_source_mock.run_kernel.assert_has_calls([
 			mock.call(args=None, build_dir='.kunit', filter_glob='suite.test1', filter='', filter_action=None, timeout=300),
 			mock.call(args=None, build_dir='.kunit', filter_glob='suite.test2', filter='', filter_action=None, timeout=300),
-- 
2.52.0.457.g6b5491de43-goog


^ permalink raw reply related

* Re: [PATCH] kunit: tool: Add (primitive) support for outputting JUnit XML
From: Thomas Weißschuh @ 2026-01-19  7:57 UTC (permalink / raw)
  To: David Gow
  Cc: Brendan Higgins, Rae Moar, Shuah Khan, linux-kselftest, workflows,
	linux-kernel, kunit-dev
In-Reply-To: <20260119073426.1952867-1-davidgow@google.com>

On Mon, Jan 19, 2026 at 03:34:24PM +0800, David Gow wrote:
> This is used by things like Jenkins and other CI systems, which can
> pretty-print the test output and potentially provide test-level comparisons
> between runs.
> 
> The implementation here is pretty basic: it only provides the raw results,
> split into tests and test suites, and doesn't provide any overall metadata.
> However, CI systems like Jenkins can injest it and it is already useful.
> 
> Signed-off-by: David Gow <davidgow@google.com>
> ---
>  Documentation/dev-tools/kunit/run_wrapper.rst |  3 ++
>  tools/testing/kunit/kunit.py                  | 25 +++++++++++-
>  tools/testing/kunit/kunit_junit.py            | 36 +++++++++++++++++
>  tools/testing/kunit/kunit_tool_test.py        | 40 +++++++++++++++++--
>  4 files changed, 100 insertions(+), 4 deletions(-)
>  create mode 100644 tools/testing/kunit/kunit_junit.py

(...)

> diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
> index e3d82a038f93..0698d27c3629 100755
> --- a/tools/testing/kunit/kunit.py
> +++ b/tools/testing/kunit/kunit.py
> @@ -21,6 +21,7 @@ from enum import Enum, auto
>  from typing import Iterable, List, Optional, Sequence, Tuple
>  
>  import kunit_json
> +import kunit_junit
>  import kunit_kernel
>  import kunit_parser
>  from kunit_printer import stdout, null_printer
> @@ -49,6 +50,7 @@ class KunitBuildRequest(KunitConfigRequest):
>  class KunitParseRequest:
>  	raw_output: Optional[str]
>  	json: Optional[str]
> +	junit: Optional[str]
>  	summary: bool
>  	failed: bool
>  
> @@ -261,6 +263,17 @@ def parse_tests(request: KunitParseRequest, metadata: kunit_json.Metadata, input
>  			stdout.print_with_timestamp("Test results stored in %s" %
>  				os.path.abspath(request.json))
>  
> +	if request.junit:
> +		junit_str = kunit_junit.get_junit_result(
> +					test=test)

Unnecessary linebreak?

> +		if request.junit == 'stdout':
> +			print(junit_str)
> +		else:
> +			with open(request.junit, 'w') as f:
> +				f.write(junit_str)
> +			stdout.print_with_timestamp("Test results stored in %s" %
> +				os.path.abspath(request.junit))
> +
>  	if test.status != kunit_parser.TestStatus.SUCCESS:
>  		return KunitResult(KunitStatus.TEST_FAILURE, parse_time), test
>  

(...)

> diff --git a/tools/testing/kunit/kunit_junit.py b/tools/testing/kunit/kunit_junit.py
> new file mode 100644
> index 000000000000..58d482e0c793
> --- /dev/null
> +++ b/tools/testing/kunit/kunit_junit.py
> @@ -0,0 +1,36 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Generates JSON from KUnit results according to
> +# KernelCI spec: https://github.com/kernelci/kernelci-doc/wiki/Test-API
> +#
> +# Copyright (C) 2025, Google LLC.
> +# Author: David Gow <davidgow@google.com>
> +
> +
> +from kunit_parser import Test, TestStatus
> +
> +def escape_xml_string(string : str) -> str:
> +	return string.replace("&", "&amp;").replace("\"", "&quot;").replace("'", "&apos;").replace("<", "&lt;").replace(">", "&gt;")
> +
> +def get_test_suite(test: Test) -> str:
> +	xml_output = '<testsuite name="' + escape_xml_string(test.name) + '" tests="' + str(test.counts.total()) + '" failures="' + str(test.counts.failed) + '" skipped="' +str(test.counts.skipped) + '">\n'
> +
> +	for subtest in test.subtests:
> +		if subtest.subtests:
> +			xml_output += get_test_suite(subtest)
> +			continue
> +		xml_output += '<testcase name="' + escape_xml_string(subtest.name) + '" >\n'
> +		if subtest.status == TestStatus.FAILURE:
> +			xml_output += '<failure>Test Failed</failure>\n'
> +		xml_output += '<system-out><![CDATA[' + "\n".join(subtest.log) + ']]></system-out>\n'
> +		xml_output += '</testcase>\n'
> +
> +	xml_output += '</testsuite>\n\n'
> +
> +	return xml_output
> +
> +def get_junit_result(test: Test) -> str:
> +	xml_output = '<?xml version="1.0" encoding="UTF-8" ?>\n\n'
> +
> +	xml_output += get_test_suite(test)
> +	return xml_output

Did you look into the Python stdlib XML serializer?
https://docs.python.org/3/library/xml.sax.utils.html#xml.sax.saxutils.XMLGenerator
https://docs.python.org/3/library/xml.sax.handler.html#contenthandler-objects

With that there should be no need to mess around with low-level XML syntax.

(...)


Thomas

^ permalink raw reply

* [PATCH 3/9] docs: kdoc: ensure that comments are using our coding style
From: Mauro Carvalho Chehab @ 2026-01-19 12:04 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List
  Cc: Mauro Carvalho Chehab, dri-devel, intel-gfx, linux-kbuild,
	linux-kernel, workflows, Mauro Carvalho Chehab
In-Reply-To: <cover.1768823489.git.mchehab+huawei@kernel.org>

Along kernel-doc libs, we opted to have all comments starting/ending
with a blank comment line. Use the same style here.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 scripts/kernel-doc.py | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index 1ebb16b9bb08..f1f3f56edeb5 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -3,7 +3,7 @@
 # Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
 #
 # pylint: disable=C0103,R0912,R0914,R0915
-
+#
 # NOTE: While kernel-doc requires at least version 3.6 to run, the
 #       command line should work with Python 3.2+ (tested with 3.4).
 #       The rationale is that it shall fail gracefully during Kernel
@@ -12,7 +12,7 @@
 #       - no f-strings can be used on this file.
 #       - the libraries that require newer versions can only be included
 #         after Python version is checked.
-
+#
 # Converted from the kernel-doc script originally written in Perl
 # under GPLv2, copyrighted since 1998 by the following authors:
 #
@@ -197,8 +197,9 @@ def main():
     parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
                                      description=DESC)
 
+    #
     # Normal arguments
-
+    #
     parser.add_argument("-v", "-verbose", "--verbose", action="store_true",
                         help="Verbose output, more warnings and other information.")
 
@@ -213,8 +214,9 @@ def main():
                         action="store_true",
                         help="Enable line number output (only in ReST mode)")
 
+    #
     # Arguments to control the warning behavior
-
+    #
     parser.add_argument("-Wreturn", "--wreturn", action="store_true",
                         help="Warns about the lack of a return markup on functions.")
 
@@ -235,8 +237,9 @@ def main():
     parser.add_argument("-export-file", "--export-file", action='append',
                         help=EXPORT_FILE_DESC)
 
+    #
     # Output format mutually-exclusive group
-
+    #
     out_group = parser.add_argument_group("Output format selection (mutually exclusive)")
 
     out_fmt = out_group.add_mutually_exclusive_group()
@@ -248,8 +251,9 @@ def main():
     out_fmt.add_argument("-N", "-none", "--none", action="store_true",
                          help="Do not output documentation, only warnings.")
 
+    #
     # Output selection mutually-exclusive group
-
+    #
     sel_group = parser.add_argument_group("Output selection (mutually exclusive)")
     sel_mut = sel_group.add_mutually_exclusive_group()
 
@@ -262,7 +266,9 @@ def main():
     sel_mut.add_argument("-s", "-function", "--symbol", action='append',
                          help=FUNCTION_DESC)
 
+    #
     # Those are valid for all 3 types of filter
+    #
     parser.add_argument("-n", "-nosymbol", "--nosymbol", action='append',
                         help=NOSYMBOL_DESC)
 
@@ -295,9 +301,11 @@ def main():
 
     python_ver = sys.version_info[:2]
     if python_ver < (3,6):
+        #
         # Depending on Kernel configuration, kernel-doc --none is called at
         # build time. As we don't want to break compilation due to the
         # usage of an old Python version, return 0 here.
+        #
         if args.none:
             logger.error("Python 3.6 or later is required by kernel-doc. skipping checks")
             sys.exit(0)
@@ -307,7 +315,9 @@ def main():
     if python_ver < (3,7):
         logger.warning("Python 3.7 or later is required for correct results")
 
+    #
     # Import kernel-doc libraries only after checking Python version
+    #
     from kdoc.kdoc_files import KernelFiles             # pylint: disable=C0415
     from kdoc.kdoc_output import RestFormat, ManFormat  # pylint: disable=C0415
 
@@ -346,6 +356,8 @@ def main():
 
     sys.exit(0)
 
+#
 # Call main method
+#
 if __name__ == "__main__":
     main()
-- 
2.52.0


^ permalink raw reply related

* [PATCH 0/9] docs: Fix kernel-doc -Werror and moves it to tools/docs
From: Mauro Carvalho Chehab @ 2026-01-19 12:04 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Mauro Carvalho Chehab, Alex Shi, Carlos Bilbao, David Airlie,
	Federico Vaga, Hu Haowen, Jani Nikula, Joonas Lahtinen,
	Mauro Carvalho Chehab, Nathan Chancellor, Nicolas Schier,
	Rodrigo Vivi, Simona Vetter, Tvrtko Ursulin, Yanteng Si,
	dri-devel, intel-gfx, linux-doc, linux-kbuild, linux-kernel,
	workflows, Thomas Weißschuh, Andy Shevchenko, Avadhut Naik,
	Chenguang Zhao, David Disseldorp, Dongliang Mu, Gang Yan,
	Kees Cook, Masahiro Yamada, Miguel Ojeda, Randy Dunlap,
	Shuah Khan, Steven Rostedt, Tamir Duberstein, Vincent Mailhol,
	WangYuli

Hi Jon,

After a restful weekend and revisiting both yours and my series,
I'm opting to send a patch series merging both into one:

- The first 4 patches are from my series (no changes since v5):
    https://lore.kernel.org/linux-doc/cover.1768642102.git.mchehab+huawei@kernel.org/T/#m81211c0ff38bbaa82b8b0b6606f242ccc0c2a9ac

- It follows by the 2 patches from your renaming series:
    https://lore.kernel.org/linux-doc/20260119111745.4694546b@foz.lan/T/#m51099c31a99dccccdb4d17cbaadc818e9e4df8c4

  with the fix I proposed for kernel-doc to find its libraries

I added 3 patches afterwards:

  - patch 5: move possible return values from docstring to helper message;
  - patch 6: improve MsgFormatter description;
  - patch 7: moves kerneldoc_bin from conf.py to the sphinx/kerneldoc.py
    (this is now just a debugging message - no need to pick it from env)

IMO, this series is ready to be merged.

NOTE:
    I didn't rename kernel-doc to kernel_doc.py nor added any symlinks.
    If we want some day to use sphinx autoparse extension, we can do it
    later. I guess we can also revisit it during -rc period, if needed.

Regards,
Mauro

Jonathan Corbet (2):
  docs: kdoc: remove support for an external kernel-doc from sphinx
  docs: kdoc: move kernel-doc to tools/docs

Mauro Carvalho Chehab (7):
  docs: kdoc: fix logic to handle unissued warnings
  docs: kdoc: avoid error_count overflows
  docs: kdoc: ensure that comments are using our coding style
  docs: kdoc: some fixes to kernel-doc comments
  docs: kdoc: move the return values to the helper message
  docs: kdoc: improve description of MsgFormatter
  docs: conf.py: get rid of the now unused kerneldoc_bin env var

 Documentation/conf.py                         |  4 -
 Documentation/doc-guide/kernel-doc.rst        |  8 +-
 Documentation/kbuild/kbuild.rst               |  2 +-
 Documentation/process/coding-style.rst        |  2 +-
 Documentation/sphinx/kerneldoc.py             | 60 +++----------
 .../it_IT/doc-guide/kernel-doc.rst            |  8 +-
 .../sp_SP/process/coding-style.rst            |  2 +-
 .../zh_CN/doc-guide/kernel-doc.rst            | 10 +--
 .../translations/zh_CN/kbuild/kbuild.rst      |  2 +-
 .../zh_CN/process/coding-style.rst            |  2 +-
 .../zh_TW/process/coding-style.rst            |  2 +-
 MAINTAINERS                                   |  2 -
 Makefile                                      |  2 +-
 drivers/gpu/drm/i915/Makefile                 |  2 +-
 scripts/kernel-doc                            |  1 -
 tools/docs/find-unused-docs.sh                |  2 +-
 .../kernel-doc.py => tools/docs/kernel-doc    | 89 ++++++++++++-------
 tools/docs/sphinx-build-wrapper               |  2 +-
 tools/lib/python/kdoc/kdoc_parser.py          | 35 ++++++--
 19 files changed, 120 insertions(+), 117 deletions(-)
 delete mode 120000 scripts/kernel-doc
 rename scripts/kernel-doc.py => tools/docs/kernel-doc (88%)

-- 
2.52.0


^ permalink raw reply

* [PATCH 5/9] docs: kdoc: remove support for an external kernel-doc from sphinx
From: Mauro Carvalho Chehab @ 2026-01-19 12:05 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List
  Cc: Mauro Carvalho Chehab, dri-devel, intel-gfx, linux-kbuild,
	linux-kernel, workflows, Shuah Khan, Mauro Carvalho Chehab
In-Reply-To: <cover.1768823489.git.mchehab+huawei@kernel.org>

From: Jonathan Corbet <corbet@lwn.net>

The ability to build the docs with an external kernel-doc program involves
some truly confusing logic and complicates the task of moving kernel-doc
out of scripts/.  But this feature is not useful for normal documentation
builds, and the external kernel-doc can always be run by hand when it needs
debugging.  So just remove that feature and make life easier.

There is still a bunch of logic to build a command line that we never use;
the idea is to be able to output it, but I'm not sure if that is worth
keeping.

Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Reviewed-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 Documentation/sphinx/kerneldoc.py | 53 ++++---------------------------
 1 file changed, 6 insertions(+), 47 deletions(-)

diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py
index d8cdf068ef35..afbab458550a 100644
--- a/Documentation/sphinx/kerneldoc.py
+++ b/Documentation/sphinx/kerneldoc.py
@@ -190,35 +190,7 @@ class KernelDocDirective(Directive):
 
         return cmd
 
-    def run_cmd(self, cmd):
-        """
-        Execute an external kernel-doc command.
-        """
-
-        env = self.state.document.settings.env
-        node = nodes.section()
-
-        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        out, err = p.communicate()
-
-        out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
-
-        if p.returncode != 0:
-            sys.stderr.write(err)
-
-            logger.warning("kernel-doc '%s' failed with return code %d"
-                                % (" ".join(cmd), p.returncode))
-            return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
-        elif env.config.kerneldoc_verbosity > 0:
-            sys.stderr.write(err)
-
-        filenames = self.parse_args["file_list"]
-        for filename in filenames:
-            self.parse_msg(filename, node, out, cmd)
-
-        return node.children
-
-    def parse_msg(self, filename, node, out, cmd):
+    def parse_msg(self, filename, node, out):
         """
         Handles a kernel-doc output for a given file
         """
@@ -244,7 +216,7 @@ class KernelDocDirective(Directive):
 
         self.do_parse(result, node)
 
-    def run_kdoc(self, cmd, kfiles):
+    def run_kdoc(self, kfiles):
         """
         Execute kernel-doc classes directly instead of running as a separate
         command.
@@ -258,23 +230,17 @@ class KernelDocDirective(Directive):
         filenames = self.parse_args["file_list"]
 
         for filename, out in kfiles.msg(**self.msg_args, filenames=filenames):
-            self.parse_msg(filename, node, out, cmd)
+            self.parse_msg(filename, node, out)
 
         return node.children
 
     def run(self):
-        global kfiles
-
         cmd = self.handle_args()
         if self.verbose >= 1:
             logger.info(cmd_str(cmd))
 
         try:
-            if kfiles:
-                return self.run_kdoc(cmd, kfiles)
-            else:
-                return self.run_cmd(cmd)
-
+            return self.run_kdoc(kfiles)
         except Exception as e:  # pylint: disable=W0703
             logger.warning("kernel-doc '%s' processing failed with: %s" %
                            (cmd_str(cmd), pformat(e)))
@@ -286,15 +252,8 @@ class KernelDocDirective(Directive):
 
 def setup_kfiles(app):
     global kfiles
-
-    kerneldoc_bin = app.env.config.kerneldoc_bin
-
-    if kerneldoc_bin and kerneldoc_bin.endswith("kernel-doc.py"):
-        print("Using Python kernel-doc")
-        out_style = RestFormat()
-        kfiles = KernelFiles(out_style=out_style, logger=logger)
-    else:
-        print(f"Using {kerneldoc_bin}")
+    out_style = RestFormat()
+    kfiles = KernelFiles(out_style=out_style, logger=logger)
 
 
 def setup(app):
-- 
2.52.0


^ permalink raw reply related

* [PATCH 1/9] docs: kdoc: fix logic to handle unissued warnings
From: Mauro Carvalho Chehab @ 2026-01-19 12:04 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List
  Cc: Mauro Carvalho Chehab, dri-devel, intel-gfx, linux-kbuild,
	linux-kernel, workflows, Andy Shevchenko, Mauro Carvalho Chehab,
	Randy Dunlap, stable
In-Reply-To: <cover.1768823489.git.mchehab+huawei@kernel.org>

Changeset 469c1c9eb6c9 ("kernel-doc: Issue warnings that were silently discarded")
didn't properly addressed the missing messages behavior, as
it was calling directly python logger low-level function,
instead of using the expected method to emit warnings.

Basically, there are two methods to log messages:

- self.config.log.warning() - This is the raw level to emit a
  warning. It just writes the a message at stderr, via python
  logging, as it is initialized as:

    self.config.log = logging.getLogger("kernel-doc")

- self.config.warning() - This is where we actually consider a
  message as a warning, properly incrementing error count.

Due to that, several parsing error messages are internally considered
as success, causing -Werror to not work on such messages.

While here, ensure that the last ignored entry will also be handled
by adding an extra check at the end of the parse handler.

Fixes: 469c1c9eb6c9 ("kernel-doc: Issue warnings that were silently discarded")
Closes: https://lore.kernel.org/linux-doc/20260112091053.00cee29a@foz.lan/
Cc: stable@vger.kernel.org
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 tools/lib/python/kdoc/kdoc_parser.py | 35 ++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 7 deletions(-)

diff --git a/tools/lib/python/kdoc/kdoc_parser.py b/tools/lib/python/kdoc/kdoc_parser.py
index a9a37519145d..c03505889dc2 100644
--- a/tools/lib/python/kdoc/kdoc_parser.py
+++ b/tools/lib/python/kdoc/kdoc_parser.py
@@ -295,7 +295,7 @@ class KernelEntry:
 
     # TODO: rename to emit_message after removal of kernel-doc.pl
     def emit_msg(self, ln, msg, *, warning=True):
-        """Emit a message"""
+        """Emit a message."""
 
         log_msg = f"{self.fname}:{ln} {msg}"
 
@@ -448,18 +448,37 @@ class KernelDoc:
 
         self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args))
 
+    def emit_unused_warnings(self):
+        """
+        When the parser fails to produce a valid entry, it places some
+        warnings under `entry.warnings` that will be discarded when resetting
+        the state.
+
+        Ensure that those warnings are not lost.
+
+        .. note::
+
+              Because we are calling `config.warning()` here, those
+              warnings are not filtered by the `-W` parameters: they will all
+              be produced even when `-Wreturn`, `-Wshort-desc`, and/or
+              `-Wcontents-before-sections` are used.
+
+              Allowing those warnings to be filtered is complex, because it
+              would require storing them in a buffer and then filtering them
+              during the output step of the code, depending on the
+              selected symbols.
+        """
+        if self.entry and self.entry not in self.entries:
+            for log_msg in self.entry.warnings:
+                self.config.warning(log_msg)
+
     def reset_state(self, ln):
         """
         Ancillary routine to create a new entry. It initializes all
         variables used by the state machine.
         """
 
-        #
-        # Flush the warnings out before we proceed further
-        #
-        if self.entry and self.entry not in self.entries:
-            for log_msg in self.entry.warnings:
-                self.config.log.warning(log_msg)
+        self.emit_unused_warnings()
 
         self.entry = KernelEntry(self.config, self.fname, ln)
 
@@ -1741,6 +1760,8 @@ class KernelDoc:
                         # Hand this line to the appropriate state handler
                         self.state_actions[self.state](self, ln, line)
 
+            self.emit_unused_warnings()
+
         except OSError:
             self.config.log.error(f"Error: Cannot open file {self.fname}")
 
-- 
2.52.0


^ permalink raw reply related

* [PATCH 4/9] docs: kdoc: some fixes to kernel-doc comments
From: Mauro Carvalho Chehab @ 2026-01-19 12:04 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List
  Cc: Mauro Carvalho Chehab, dri-devel, intel-gfx, linux-kbuild,
	linux-kernel, workflows, Mauro Carvalho Chehab
In-Reply-To: <cover.1768823489.git.mchehab+huawei@kernel.org>

There are some typos and English errors in the comments of kernel‑doc.py.

Locate them with the help of an LLM (gpt‑oss 14B), executed locally
with this prompt:

        review English grammar and syntax at the comments on the code below:
        <cat scripts/kernel-doc.py>

While LLM worked fine for the task of doing an English grammar review
for strings, being able to distinguish them from the actual code, it
was not is perfect: some things required manual work to fix.

-

While here, replace:

    "/**" with: ``/**``

As, if we ever rename this script to kernel_doc.py and add it to
Sphinx ext autodoc, we want to avoid this warning:

    scripts/kernel_doc.py:docstring of kernel_doc:10: WARNING: Inline strong start-string without end-string. [docutils]

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 scripts/kernel-doc.py | 29 +++++++++++++----------------
 1 file changed, 13 insertions(+), 16 deletions(-)

diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index f1f3f56edeb5..4e3b9cfe3fd7 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -9,9 +9,9 @@
 #       The rationale is that it shall fail gracefully during Kernel
 #       compilation with older Kernel versions. Due to that:
 #       - encoding line is needed here;
-#       - no f-strings can be used on this file.
-#       - the libraries that require newer versions can only be included
-#         after Python version is checked.
+#       - f-strings cannot be used in this file.
+#       - libraries that require newer versions can only be included
+#         after the Python version has been checked.
 #
 # Converted from the kernel-doc script originally written in Perl
 # under GPLv2, copyrighted since 1998 by the following authors:
@@ -88,16 +88,13 @@
 #    Yujie Liu <yujie.liu@intel.com>
 
 """
-kernel_doc
-==========
-
-Print formatted kernel documentation to stdout
+Print formatted kernel documentation to stdout.
 
 Read C language source or header FILEs, extract embedded
 documentation comments, and print formatted documentation
 to standard output.
 
-The documentation comments are identified by the "/**"
+The documentation comments are identified by the ``/**``
 opening comment mark.
 
 See Documentation/doc-guide/kernel-doc.rst for the
@@ -134,13 +131,13 @@ May be used multiple times.
 """
 
 EXPORT_DESC = """
-Only output documentation for the symbols that have been
+Only output documentation for symbols that have been
 exported using EXPORT_SYMBOL() and related macros in any input
 FILE or -export-file FILE.
 """
 
 INTERNAL_DESC = """
-Only output documentation for the symbols that have NOT been
+Only output documentation for symbols that have NOT been
 exported using EXPORT_SYMBOL() and related macros in any input
 FILE or -export-file FILE.
 """
@@ -163,7 +160,7 @@ Header and C source files to be parsed.
 """
 
 WARN_CONTENTS_BEFORE_SECTIONS_DESC = """
-Warns if there are contents before sections (deprecated).
+Warn if there are contents before sections (deprecated).
 
 This option is kept just for backward-compatibility, but it does nothing,
 neither here nor at the original Perl script.
@@ -171,7 +168,7 @@ neither here nor at the original Perl script.
 
 
 class MsgFormatter(logging.Formatter):
-    """Helper class to format warnings on a similar way to kernel-doc.pl"""
+    """Helper class to format warnings in a similar way to kernel-doc.pl."""
 
     def format(self, record):
         record.levelname = record.levelname.capitalize()
@@ -273,7 +270,7 @@ def main():
                         help=NOSYMBOL_DESC)
 
     parser.add_argument("-D", "-no-doc-sections", "--no-doc-sections",
-                        action='store_true', help="Don't outputt DOC sections")
+                        action='store_true', help="Don't output DOC sections")
 
     parser.add_argument("files", metavar="FILE",
                         nargs="+", help=FILES_DESC)
@@ -302,12 +299,12 @@ def main():
     python_ver = sys.version_info[:2]
     if python_ver < (3,6):
         #
-        # Depending on Kernel configuration, kernel-doc --none is called at
+        # Depending on the Kernel configuration, kernel-doc --none is called at
         # build time. As we don't want to break compilation due to the
         # usage of an old Python version, return 0 here.
         #
         if args.none:
-            logger.error("Python 3.6 or later is required by kernel-doc. skipping checks")
+            logger.error("Python 3.6 or later is required by kernel-doc. Skipping checks")
             sys.exit(0)
 
         sys.exit("Python 3.6 or later is required by kernel-doc. Aborting.")
@@ -316,7 +313,7 @@ def main():
         logger.warning("Python 3.7 or later is required for correct results")
 
     #
-    # Import kernel-doc libraries only after checking Python version
+    # Import kernel-doc libraries only after checking the Python version
     #
     from kdoc.kdoc_files import KernelFiles             # pylint: disable=C0415
     from kdoc.kdoc_output import RestFormat, ManFormat  # pylint: disable=C0415
-- 
2.52.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox