From patchwork Wed Dec 17 02:26:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 938 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1765938447; bh=ZQOi+GQYeSY+uskFF9vEWjpSqaEwN+N7RY4B2IFTiJ4=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=MmW28shJcUi/LILm2NXxOXXOc79nj7kyf3a+8/UHXnPZOUSpVryL+ZNlf/JJ91hbY nerP2qcPP+7y5l8aZtTZDpu1afH/IP3Vy6VKkHrGkVOOBlLKn1uqIlChYsvAOfCpPo G1zUbG3BDETDG9R1bnRh94eU0t6eQWzClsBD5Nh19vMdmuCTnScU+LWCF76QcqMHjF pqRdXWeEmfOBM2Gw2pv4YJrBuME47T0qXOvKYmqmFIFoozSCY3yW84Eo7CyyAIKOzs XgwLDNT/mm5/3TS9pWGZYuEpTxjfs+BA4Bvo8NLB3eEXGd1MBgXOdCov3c4yqoXsnh VB6mZXa/vkEfg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 8226268BC5 for ; Tue, 16 Dec 2025 19:27:27 -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 tgudz3VN6Hea for ; Tue, 16 Dec 2025 19:27:27 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1765938446; bh=ZQOi+GQYeSY+uskFF9vEWjpSqaEwN+N7RY4B2IFTiJ4=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=c4fpZBxVjgBr0J8IWvVcF1X2dTlUkAKBroE8bLmu1mUGzAjUPzHeqh+LvivFW0/Ij PhJzNBq9H5Q9VNWLyeiZ03iypE83DDzfeeBWDT3y4WwEQdPGEuJCIErEprQPK+uX+G Bt5cXGTP0m37fSszWK5fqdrmO3yB5kgn9zfAipFRGk2dADKrhiwWqkAXlcKNKi3JP9 vNO8TFWPJvR3dl2NuFDLyGXjGG9A0zQgeFIi69NKOAPiUqnqj+Ub1WU8X1FaM1PS5s aMISDl9XHHRJx09+HM4ElSJlTSUBN/KocymzQ+2cy8Q5N9YoGVzUXb52QUQh7cEnJe LU5MazF6zdpqA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 88D7168BC0 for ; Tue, 16 Dec 2025 19:27:26 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1765938443; bh=kbq0V37pzwz65V88kHZrdY/6RgCf0cNuyUXIxCxiRV8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GoGFor9gQfmrgn/rWXwMc9yp3apBR1C5jNL8CivBxW8+bsEDezcgbDaZmNoh/UXuB VQ976yXUFj9Mkmumki+8dKGtjjSE4f9JBfxYebne6h7ndd4tariCA5m7ZRtrsT2LrH rNbZlNPLCkOVXvgU8EtZ7evwv56jGRUQnUSyBEagNfIQfqVioInkurZDFvg/0xy4Uu 9OPFfrKdyTL6k1oZ42DKrkk6fsEAUkTCxLWoDBysHSrBHoU5zpndvLkk4oTVZl6Zwj cb7WQV4mpQDLiNVIn2O0ObM2KjUYB/kkZzkFM/e8AQS1FgHBMZ84WEmFA3+U7jj+06 fMzFQ2nfdLjaQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 79C8D68BAC; Tue, 16 Dec 2025 19:27:23 -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 10026) with ESMTP id LUbeDk3PlzQF; Tue, 16 Dec 2025 19:27:23 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1765938438; bh=Gm4+Q755tibtS09ozmAuZRhLQYDXw0jNWjcQHhRojTk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oYbmZJtabGZS6XZz5Cm5/3qXK38923Q7LOzY1Ye0a8P/w8fonQN+3gl64r6ooVAB7 3idPlUkNaRabWjp5Y5T+WrF4LSSIL40fOtWcOxhvMXcQjvscmdG+xHrD/LlBXkYPHU 8Vkl4tTPMRsp22xBFHTZ9YDwDglxIRIswgdVh1q5/RFvb73OrQEGlhR3f5K5xB3IiO HbHjhBrACfff2qIW1CwGoNtFWN+ehAvrR1v0qSVX148x8t5XJ2FE1ahy9E0uYrcxx4 d/bc/fjuKkTCf5U3H50mtoQTtLrNxnn5851FyLh9PolRq9pggEb+oWUXjxkJBufDE1 8pg76NQaMBGZQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 687176884F; Tue, 16 Dec 2025 19:27:18 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 16 Dec 2025 19:26:00 -0700 Message-ID: <20251217022611.389379-13-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251217022611.389379-1-sjg@u-boot.org> References: <20251217022611.389379-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: X4EXQQIRVCUGA42WRD7UYECP2LVUFDAD X-Message-ID-Hash: X4EXQQIRVCUGA42WRD7UYECP2LVUFDAD X-MailFrom: sjg@u-boot.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: Heinrich Schuchardt , Simon Glass , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 12/17] pickman: Add commit-source command List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a command to update the database with the last cherry-picked commit. This allows reviewing the cherry-picked branch before committing to the database. Usage: pickman commit-source us/next Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- tools/pickman/README.rst | 7 +++++ tools/pickman/__main__.py | 5 +++ tools/pickman/control.py | 36 ++++++++++++++++++++++ tools/pickman/ftest.py | 65 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) diff --git a/tools/pickman/README.rst b/tools/pickman/README.rst index ab37763a918..d15b15f3331 100644 --- a/tools/pickman/README.rst +++ b/tools/pickman/README.rst @@ -73,6 +73,13 @@ On successful cherry-pick, an entry is appended to ``.pickman-history`` with: This file is committed automatically and included in the MR description when using ``-p``. +After successfully applying commits, update the database to record progress:: + + ./tools/pickman/pickman commit-source us/next + +This updates the last cherry-picked commit for the source branch, so subsequent +``next-set`` and ``apply`` commands will start from the new position. + Requirements ------------ diff --git a/tools/pickman/__main__.py b/tools/pickman/__main__.py index ac029a38382..1693af991ac 100755 --- a/tools/pickman/__main__.py +++ b/tools/pickman/__main__.py @@ -45,6 +45,11 @@ def parse_args(argv): apply_cmd.add_argument('-t', '--target', default='master', help='Target branch for MR (default: master)') + commit_src = subparsers.add_parser('commit-source', + help='Update database with last commit') + commit_src.add_argument('source', help='Source branch name') + commit_src.add_argument('commit', help='Commit hash to record') + subparsers.add_parser('compare', help='Compare branches') subparsers.add_parser('list-sources', help='List tracked source branches') diff --git a/tools/pickman/control.py b/tools/pickman/control.py index a482de85b00..fe840ee2740 100644 --- a/tools/pickman/control.py +++ b/tools/pickman/control.py @@ -401,6 +401,41 @@ def do_apply(args, dbs): # pylint: disable=too-many-locals return 0 if success else 1 +def do_commit_source(args, dbs): + """Update the database with the last cherry-picked commit + + Args: + args (Namespace): Parsed arguments with 'source' and 'commit' attributes + dbs (Database): Database instance + + Returns: + int: 0 on success, 1 on failure + """ + source = args.source + commit = args.commit + + # Resolve the commit to a full hash + try: + full_hash = run_git(['rev-parse', commit]) + except Exception: # pylint: disable=broad-except + tout.error(f"Could not resolve commit '{commit}'") + return 1 + + old_commit = dbs.source_get(source) + if not old_commit: + tout.error(f"Source '{source}' not found in database") + return 1 + + dbs.source_set(source, full_hash) + dbs.commit() + + short_old = old_commit[:12] + short_new = full_hash[:12] + tout.info(f"Updated '{source}': {short_old} -> {short_new}") + + return 0 + + def do_test(args, dbs): # pylint: disable=unused-argument """Run tests for this module. @@ -424,6 +459,7 @@ def do_test(args, dbs): # pylint: disable=unused-argument COMMANDS = { 'add-source': do_add_source, 'apply': do_apply, + 'commit-source': do_commit_source, 'compare': do_compare, 'list-sources': do_list_sources, 'next-set': do_next_set, diff --git a/tools/pickman/ftest.py b/tools/pickman/ftest.py index 4f5c90980c6..9b445173b3b 100644 --- a/tools/pickman/ftest.py +++ b/tools/pickman/ftest.py @@ -127,6 +127,13 @@ class TestParseArgs(unittest.TestCase): self.assertEqual(args.source, 'us/next') self.assertEqual(args.branch, 'my-branch') + def test_parse_commit_source(self): + """Test parsing commit-source command.""" + args = pickman.parse_args(['commit-source', 'us/next', 'abc123']) + self.assertEqual(args.cmd, 'commit-source') + self.assertEqual(args.source, 'us/next') + self.assertEqual(args.commit, 'abc123') + def test_parse_compare(self): """Test parsing compare command.""" args = pickman.parse_args(['compare']) @@ -942,6 +949,64 @@ class TestApply(unittest.TestCase): self.assertIn('No new commits to cherry-pick', stdout.getvalue()) +class TestCommitSource(unittest.TestCase): + """Tests for commit-source command.""" + + def setUp(self): + """Set up test fixtures.""" + fd, self.db_path = tempfile.mkstemp(suffix='.db') + os.close(fd) + os.unlink(self.db_path) + self.old_db_fname = control.DB_FNAME + control.DB_FNAME = self.db_path + database.Database.instances.clear() + + def tearDown(self): + """Clean up test fixtures.""" + control.DB_FNAME = self.old_db_fname + if os.path.exists(self.db_path): + os.unlink(self.db_path) + database.Database.instances.clear() + command.TEST_RESULT = None + + def test_commit_source_not_found(self): + """Test commit-source with unknown source.""" + with terminal.capture(): + dbs = database.Database(self.db_path) + dbs.start() + dbs.close() + + database.Database.instances.clear() + command.TEST_RESULT = command.CommandResult(stdout='fullhash123') + + args = argparse.Namespace(cmd='commit-source', source='unknown', + commit='abc123') + with terminal.capture() as (_, stderr): + ret = control.do_pickman(args) + self.assertEqual(ret, 1) + self.assertIn("Source 'unknown' not found", stderr.getvalue()) + + def test_commit_source_success(self): + """Test commit-source updates database.""" + with terminal.capture(): + dbs = database.Database(self.db_path) + dbs.start() + dbs.source_set('us/next', 'oldcommit12345') + dbs.commit() + dbs.close() + + database.Database.instances.clear() + command.TEST_RESULT = command.CommandResult(stdout='newcommit67890') + + args = argparse.Namespace(cmd='commit-source', source='us/next', + commit='abc123') + with terminal.capture() as (stdout, _): + ret = control.do_pickman(args) + self.assertEqual(ret, 0) + self.assertIn('oldcommit123', stdout.getvalue()) + self.assertIn('newcommit678', stdout.getvalue()) + + class TestParseUrl(unittest.TestCase): """Tests for parse_url function."""