From patchwork Fri Jan 30 03:58:25 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1778 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org Authentication-Results: mail.u-boot.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=Vq491uQk; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7F9D4697CD for ; Thu, 29 Jan 2026 20:59:18 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id TjfMMfTAHjW2 for ; Thu, 29 Jan 2026 20:59:18 -0700 (MST) Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 81924697E0 for ; Thu, 29 Jan 2026 20:59:16 -0700 (MST) Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id F23C3697CB for ; Thu, 29 Jan 2026 20:59:12 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id VRzV2wQEt1wD for ; Thu, 29 Jan 2026 20:59:12 -0700 (MST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.210.43; helo=mail-ot1-f43.google.com; envelope-from=sjg@chromium.org; receiver=u-boot.org Received: from mail-ot1-f43.google.com (mail-ot1-f43.google.com [209.85.210.43]) by mail.u-boot.org (Postfix) with ESMTPS id A5E98697C8 for ; Thu, 29 Jan 2026 20:59:06 -0700 (MST) Received: by mail-ot1-f43.google.com with SMTP id 46e09a7af769-7d18dd2adf7so991330a34.1 for ; Thu, 29 Jan 2026 19:59:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1769745545; x=1770350345; darn=u-boot.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HFod0DCEXCMVnlrA1DV5T4WXtObYF4fj2+3JZiJK8QI=; b=Vq491uQkPUPbmDcqO5u1w+00zE9y5Hzj7esXd6Jhz+uW/1I/li6BR6XrMP4tjtzmWf HEm9HsJAdBHb2dT8KZconhOA1CfsBdJ87kX78mtrzZMOrIFtZCtwNqWb5osJYO74/aYl PVmgf7a/K8VM3IPR0kCm90Knk4h9zonvYoan8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769745545; x=1770350345; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=HFod0DCEXCMVnlrA1DV5T4WXtObYF4fj2+3JZiJK8QI=; b=on8o/0LlQXsdiyaPPW67ExqHP9u8I8Gf5oiERq/v2DYw/+XEzWKD2F2yIuQzj9QIXO CUUmMytccx/KiNxKbWE55zF4BourVjesB0jBK3qcayvvXDHBf2OWcxDZYtSsGTzyXeY8 SA8YEIeLJusq8e9Erp/eRiTc/rwnmxI0yK7crA951vDH7wRr7P6DsR3dghGgD+p/3+iq W1T5z+3ijWttxNW5A22GyR1+09+KMuFOHfdiQG/YqlqSJtbdMk6tkR3dL8fMxYhyGPIa 41fGP22A8GlcOeDnqWsCuVB0cWAsZ8AZdHcNJDpnTVTxFqjmxBaH8uaOZxMg5UyBCneH g06A== X-Gm-Message-State: AOJu0Yz63nOJBs6bASr0+13KudNAUj0LlCred+NOtQE2TgSp3k9W5MBp OYkrFkx+Zj4hItBIOxQAMHkOtEF1o6N1C0sQiRTLQ0MlpZKbAejyUJONLG6NrEw/V8S73n7CTNb BPK2wzQ== X-Gm-Gg: AZuq6aIHGnQwTdu2h3/eQuVbxUOgHkBF1LaKfPV2wht4kDuCtEiFQM/OfGDmDEWTkrK eFljho72qTyF3PCSyewW6bYg19ybWvI8wh14itpgQwk5A4Yk/pjf4jRSv/DnL32w7Xx4+U+mpTo SjxdILV+he4mq4oRE9dfhkxVd1DRtGlzYpcfnCyEU4pUxeELBWw7v6kE/howUGF4lCINdPMQS2t b7zxRgqS9PeCaRk3L9Ke+G8MjgvYCT3bMp27Kx6/9rdlsuPwu3vcRnqT6asqxBqen9FNYf+VbmE qJDRGl3tLQFUrpW+xhY53h4vxN4khfcoukjunq1ARa/RssnbCNxhdf/DbFSkaBEfXaU56iHyl6Z o1vcsII6HUIDj/MZ3ZyabXWhT/eaG7Z8LaSmVjGDfgxdgHXuVraLrlpOl9tX10x3orrf2M5tSVR ylAIj2stKw7wTcBj+e X-Received: by 2002:a05:6820:1787:b0:662:f74d:69f7 with SMTP id 006d021491bc7-6630f3847fcmr808954eaf.54.1769745545061; Thu, 29 Jan 2026 19:59:05 -0800 (PST) Received: from chromium.org ([73.34.74.121]) by smtp.gmail.com with ESMTPSA id 006d021491bc7-662f9a4e491sm4128687eaf.16.2026.01.29.19.59.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Jan 2026 19:59:03 -0800 (PST) From: Simon Glass X-Google-Original-From: Simon Glass To: U-Boot Concept Date: Thu, 29 Jan 2026 20:58:25 -0700 Message-ID: <20260130035849.3580212-3-simon.glass@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260130035849.3580212-1-simon.glass@canonical.com> References: <20260130035849.3580212-1-simon.glass@canonical.com> MIME-Version: 1.0 Message-ID-Hash: A5GTT6TKNYXSVXEEMEIVT452ELNRNADJ X-Message-ID-Hash: A5GTT6TKNYXSVXEEMEIVT452ELNRNADJ X-MailFrom: sjg@chromium.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 02/19] buildman: Add option to build then show summary List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The -s option shows a summary of existing build results, but requires that a build has already been done. Add a -z/--build-summary option which performs the build first, then shows the summary afterwards. The summary is shown regardless of whether the build succeeds, and the return code reflects the build result. Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- tools/buildman/buildman.rst | 5 +- tools/buildman/cmdline.py | 2 + tools/buildman/control.py | 4 ++ tools/buildman/test.py | 110 ++++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) diff --git a/tools/buildman/buildman.rst b/tools/buildman/buildman.rst index 603b019540b..831431670d3 100644 --- a/tools/buildman/buildman.rst +++ b/tools/buildman/buildman.rst @@ -111,7 +111,10 @@ Otherwise buildman will perform random actions. Use -n to check what the random actions might be. Buildman effectively has two modes: without -s it builds, with -s it -summarises the results of previous (or active) builds. +summarises the results of previous (or active) builds. You can combine +both with -z (--build-summary), which builds first and then shows the +summary. This is useful when you want to do a build and immediately see +a summary of the results without running buildman twice. If you just want to build the current source tree, leave off the -b flag. This will display results and errors as they happen. You can still look at diff --git a/tools/buildman/cmdline.py b/tools/buildman/cmdline.py index fae1910307b..f4a1a3d018c 100644 --- a/tools/buildman/cmdline.py +++ b/tools/buildman/cmdline.py @@ -185,6 +185,8 @@ def add_after_m(parser): parser.add_argument('-Y', '--filter-migration-warnings', action='store_true', default=False, help='Filter out migration warnings from output') + parser.add_argument('-z', '--build-summary', action='store_true', + default=False, help='Build first, then show a summary of the results') def parse_args(): diff --git a/tools/buildman/control.py b/tools/buildman/control.py index 728389d9a8b..7fc0d20574a 100644 --- a/tools/buildman/control.py +++ b/tools/buildman/control.py @@ -573,6 +573,10 @@ def run_builder(builder, commits, board_selected, display_options, args): fail, warned, excs = builder.build_boards( commits, board_selected, args.keep_outputs, args.verbose, args.fragments) + if args.build_summary: + builder.commits = commits + builder.result_handler.show_summary( + commits, board_selected, args.step) if excs: return 102 if fail: diff --git a/tools/buildman/test.py b/tools/buildman/test.py index 0f4a5b9e543..37930ad9720 100644 --- a/tools/buildman/test.py +++ b/tools/buildman/test.py @@ -1222,6 +1222,116 @@ class TestBuildMisc(TestBuildBase): 'other_board')) +class TestBuildSummary(TestBuildBase): + """Tests for build summary functionality""" + + def test_build_summary(self): + """Test --build-summary option builds then shows summary""" + opts = DisplayOptions( + show_errors=False, show_sizes=False, show_detail=False, + show_bloat=False, show_config=False, show_environment=False, + show_unknown=False, ide=False, list_error_boards=False) + build = builder.Builder(self.toolchains, self.base_dir, None, 1, + 2, self._col, ResultHandler(self._col, opts), + checkout=False) + build._result_handler.set_builder(build) + + # Track calls to build_boards and show_summary + build_boards_called = [] + show_summary_called = [] + + def mock_build_boards(*args, **kwargs): + build_boards_called.append(True) + return False, False, False + + def mock_show_summary(*args, **kwargs): + show_summary_called.append(True) + + build.build_boards = mock_build_boards + build._result_handler.show_summary = mock_show_summary + + # Create args with build_summary=True + class Args: + summary = False + build_summary = True + step = 1 + keep_outputs = False + verbose = False + fragments = '' + ignore_warnings = False + ide = False + filter_dtb_warnings = False + filter_migration_warnings = False + git = '.' + threads = 1 + jobs = 1 + + args = Args() + board_selected = self.brds.get_selected_dict() + + # Mock gnu_make detection + with patch.object(command, 'output', return_value='make'): + control.run_builder(build, self.commits, board_selected, + opts, args) + + # Verify both build_boards and show_summary were called + self.assertEqual(1, len(build_boards_called), + 'build_boards should be called once') + self.assertEqual(1, len(show_summary_called), + 'show_summary should be called once') + + def test_build_summary_with_failures(self): + """Test --build-summary shows summary even when build fails""" + opts = DisplayOptions( + show_errors=False, show_sizes=False, show_detail=False, + show_bloat=False, show_config=False, show_environment=False, + show_unknown=False, ide=False, list_error_boards=False) + build = builder.Builder(self.toolchains, self.base_dir, None, 1, + 2, self._col, ResultHandler(self._col, opts), + checkout=False) + build._result_handler.set_builder(build) + + show_summary_called = [] + + def mock_build_boards(*args, **kwargs): + # Simulate build failure + return True, False, False + + def mock_show_summary(*args, **kwargs): + show_summary_called.append(True) + + build.build_boards = mock_build_boards + build._result_handler.show_summary = mock_show_summary + + class Args: + summary = False + build_summary = True + step = 1 + keep_outputs = False + verbose = False + fragments = '' + ignore_warnings = False + ide = False + filter_dtb_warnings = False + filter_migration_warnings = False + git = '.' + threads = 1 + jobs = 1 + + args = Args() + board_selected = self.brds.get_selected_dict() + + with patch.object(command, 'output', return_value='make'): + ret = control.run_builder(build, self.commits, board_selected, + opts, args) + + # Summary should still be shown even with failures + self.assertEqual(1, len(show_summary_called), + 'show_summary should be called even on failure') + # Return code should indicate failure + self.assertEqual(100, ret) + + class TestBuilderFuncs(TestBuildBase): """Tests for individual Builder methods"""