diff mbox series

[b4] Add `flow` subcommand

Message ID 20250302-flow-v1-1-3247c022bbac@gmail.com (mailing list archive)
State New
Headers show
Series [b4] Add `flow` subcommand | expand

Commit Message

Rudraksha Gupta March 3, 2025, 12:34 a.m. UTC
`b4 flow` is an interactive session designed to handhold the user into
submitting patches upsteam. As b4 grows in complexity, there will be
multiple commands to remember. `b4 flow` covers the majority of cases and
shows the proper way to use the program.

Signed-off-by: Rudraksha Gupta <guptarud@gmail.com>
---
`b4 flow` is an interactive session designed to handhold the user into
submitting patches upsteam. As b4 grows in complexity, there will be
multiple commands to remember. `b4 flow` covers the majority of cases and
shows the proper way to use the program.
---
 src/b4/command.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)


---
base-commit: 42535902a457332560d860608b770fca9eea1382
change-id: 20250302-flow-954294542408

Best regards,
diff mbox series

Patch

diff --git a/src/b4/command.py b/src/b4/command.py
index 617a2d7..c0ac71a 100644
--- a/src/b4/command.py
+++ b/src/b4/command.py
@@ -9,6 +9,9 @@  import argparse
 import logging
 import b4
 import sys
+import subprocess
+import os
+import tempfile
 
 logger = b4.logger
 
@@ -93,6 +96,74 @@  def cmd_send(cmdargs):
     b4.ez.cmd_send(cmdargs)
 
 
+def cmd_flow(cmdargs):
+    import b4.ez
+    def run_b4_recursively(command_args: str):
+        current_path = os.path.dirname(os.path.abspath(__file__))
+        command_args_run = [os.path.join(current_path, 'b4.sh')] + command_args.split(" ")
+        command_args_bak = [os.path.join(current_path, '..', '..', 'b4.sh')] + command_args.split(" ")
+        # TODO: can we deterministically see where the shell script executed from?
+        try:
+            out = subprocess.run(command_args_run, check=True)
+        except:
+            try:
+                out = subprocess.run(command_args_bak, check=True)
+            except:
+                return False
+        return True
+
+    def question_user(prompt: str, command: str) -> bool:
+        # We want to default this as a Y so that users can use the `yes` command
+        user_input = input(prompt + ' [Y/n]: ')
+        if user_input.strip().lower() not in ['y', '']:
+            return False
+        run_b4_recursively(command)
+        return True
+
+    # Colors
+    WARNING = '\033[93m'
+    ENDC = '\033[0m'
+
+    print("Starting up an interactive session to submit kernel patches upstream. Make your changes prior to running this. Press Ctrl+C to exit at any point.")
+    print(WARNING)
+    print("If you changed a commit message, trailers will NOT be applied for that patch. Please manually apply them.")
+    print(ENDC)
+
+    question_user("Retrieve trailers?", "trailers -u")
+    question_user("Edit cover letter?", "prep --edit-cover")
+    with tempfile.TemporaryDirectory() as tmpdir:
+        if question_user("View patches?", f'send -o {tmpdir}'):
+            for file in os.listdir(tmpdir):
+                print(f"viewing: {file}")
+                file_path = os.path.join(tmpdir, file)
+                with open(file_path, 'r') as f:
+                    content = f.read().encode()
+                    b4.edit_in_editor(content, filehint='Review Patches')
+        # needs to run `b4 send -o {tmpdir}` just in case user says no in the previous question
+        if question_user("Run checkpatch.pl?", f'send -o {tmpdir}'):
+            for file in os.listdir(tmpdir):
+                if file.startswith('0000-'):
+                    continue
+
+                print(file)
+                file_path = os.path.join(tmpdir, file)
+                subprocess.run(["./scripts/checkpatch.pl", file_path], check=True)
+
+    cover, tracking = b4.ez.load_cover(strip_comments=True)
+    revision = tracking['series'].get('revision')
+    if revision > 1:
+        question_user("Compare with previous version?", f"prep --compare-to v{revision - 1}")
+
+    question_user("Auto add emails?", "prep --auto-to-cc")
+    question_user("Check with b4?", "prep --check")
+    question_user("Reflect patches?", "send --reflect")
+
+    print(WARNING)
+    print("You are about to send your patches upstream.")
+    print(ENDC)
+    question_user("Send?", "send")
+
+
 def cmd_am(cmdargs):
     import b4.mbox
     b4.mbox.main(cmdargs)
@@ -389,6 +460,10 @@  def setup_parser() -> argparse.ArgumentParser:
                           help='Submit the token received via verification email')
     sp_send.set_defaults(func=cmd_send)
 
+    # b4 flow
+    sp_flow = subparsers.add_parser('flow', help='Interactive session to submit patches upstream')
+    sp_flow.set_defaults(func=cmd_flow)
+
     return parser