[PATCH] tools: download series mbox once
David Marchand
david.marchand at redhat.com
Fri Jul 24 16:10:07 CEST 2026
Trying to apply the patch on various branch results in multiple series
download.
patchwork instances are under fire those recent days... let's be good
citizens and download once and for all.
Signed-off-by: David Marchand <david.marchand at redhat.com>
---
tools/create_series_artifact.py | 128 ++++++++++++++++++--------------
1 file changed, 72 insertions(+), 56 deletions(-)
diff --git a/tools/create_series_artifact.py b/tools/create_series_artifact.py
index 8225a4e..63cdd6b 100755
--- a/tools/create_series_artifact.py
+++ b/tools/create_series_artifact.py
@@ -67,6 +67,7 @@ class CreateSeriesParameters(object):
output_properties: pathlib.Path
no_depends: bool
docs_only: bool
+ series_mbox_path: pathlib.Path
class ProjectTree(object):
@@ -227,16 +228,14 @@ class ProjectTree(object):
def apply_patch_series(self) -> bool:
self.set_properties(applied_commit_id=self.commit_id, tree=self.tree)
- # Run git-pw to apply the series.
- # Configure the tree to point at the given patchwork server and project
- self.repo.config["pw.server"] = self.data.pw_server
- self.repo.config["pw.project"] = self.data.pw_project
+ # Configure git user for the commit
self.repo.config["user.email"] = self.data.git_email
self.repo.config["user.name"] = self.data.git_user
+ # Apply the series from the locally downloaded mbox file.
result = subprocess.run(
- ["git", "pw", "series", "apply", str(self.data.series["id"])],
+ ["git", "am", self.data.series_mbox_path],
cwd=self.path,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
@@ -247,6 +246,15 @@ class ProjectTree(object):
self.log(result.stdout.decode())
self.log(result.stderr.decode())
+ # If apply failed, abort to clean up the state for potential retry.
+ if result.returncode != 0:
+ subprocess.run(
+ ["git", "am", "--abort"],
+ cwd=self.path,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+
# Store whether there was an error, and return the flag.
error = result.returncode != 0
self.set_properties(apply_error=error)
@@ -323,30 +331,29 @@ class ProjectTree(object):
return True
-def get_patch_filename(patch_name: str) -> str:
- filename: str = "".join(
- [
- "-" if char.isspace() else char.lower()
- for char in patch_name
- if char.isalnum() or char.isspace()
- ]
- )
- return f"{filename}.patch"
+def download_series_mbox(series: Dict) -> pathlib.Path:
+ """Download the series mbox file and return the path to it.
+
+ The file is saved in the current working directory (outside the dpdk/
+ git repo) so it persists across operations on the working directory.
+ """
+ series_filename = f"series-{series['id']}.mbox"
+ series_path = pathlib.Path(os.getcwd(), series_filename)
+
+ # Pull down the patch series as a single file.
+ pw_api.download(series["mbox"], None, str(series_path))
+
+ return series_path
def get_tags(
patch_parser_script: pathlib.Path,
patch_parser_cfg: pathlib.Path,
- series: Dict,
+ series_mbox_path: pathlib.Path,
) -> List[str]:
- series_filename = get_patch_filename(series.get("name", "unnamed"))
-
- # Pull down the patch series as a single file.
- pw_api.download(series["mbox"], None, series_filename)
-
# Call the patch parser script to obtain the tags
parse_result = subprocess.run(
- [patch_parser_script, patch_parser_cfg, series_filename],
+ [patch_parser_script, patch_parser_cfg, series_mbox_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
@@ -439,8 +446,11 @@ def collect_series_info(args: argparse.Namespace) -> CreateSeriesParameters:
resp.raise_for_status()
series = resp.json()
+ # Download the series mbox once.
+ series_mbox_path = download_series_mbox(series)
+
# Get the labels using the patch parser.
- labels = get_tags(patch_parser_script, patch_parser_cfg, series)
+ labels = get_tags(patch_parser_script, patch_parser_cfg, series_mbox_path)
# See if this is a documentation-only patch.
docs_only = len(labels) == 1 and labels[0] == "documentation"
@@ -469,6 +479,7 @@ def collect_series_info(args: argparse.Namespace) -> CreateSeriesParameters:
output_properties=output_properties,
no_depends=args.no_depends,
docs_only=docs_only,
+ series_mbox_path=series_mbox_path,
)
@@ -485,43 +496,48 @@ def try_to_apply(tree: ProjectTree) -> bool:
def main() -> int:
data = collect_series_info(parse_args())
- # Pull down the DPDK mirror.
- tree = ProjectTree(data)
-
- if data.branch_override:
- guessed_tree: str = (
- BRANCH_NAME_MAP.get(data.branch_override) or data.branch_override
- )
+ try:
+ # Pull down the DPDK mirror.
+ tree = ProjectTree(data)
- # Try to check out to the tree.
- if not tree.checkout(guessed_tree):
- print(
- f'Could not checkout to specified branch "{data.branch_override}" because it did not exist.'
+ if data.branch_override:
+ guessed_tree: str = (
+ BRANCH_NAME_MAP.get(data.branch_override) or data.branch_override
)
+
+ # Try to check out to the tree.
+ if not tree.checkout(guessed_tree):
+ print(
+ f'Could not checkout to specified branch "{data.branch_override}" because it did not exist.'
+ )
+ return 1
+ else:
+ guessed_tree = tree.guess_git_tree()
+
+ if not guessed_tree:
+ print("Failed to guess git tree. Trying main instead...")
+ guessed_tree = "main"
+
+ # Try to apply this patch.
+ if not (
+ try_to_apply(tree) # First, try to apply on the guessed tree.
+ or not data.branch_override # Skip when branch is given
+ and guessed_tree != "main" # 2nd attempt on main if guess not main
+ and tree.checkout("main") # Checkout to main, then
+ and try_to_apply(tree) # Try to apply on main
+ ):
+ tree.write_log()
+ tree.write_properties()
+ tree.move_logs()
+
+ print("FAILURE")
+
return 1
- else:
- guessed_tree = tree.guess_git_tree()
-
- if not guessed_tree:
- print("Failed to guess git tree. Trying main instead...")
- guessed_tree = "main"
-
- # Try to apply this patch.
- if not (
- try_to_apply(tree) # First, try to apply on the guessed tree.
- or not data.branch_override # Skip when branch is given
- and guessed_tree != "main" # 2nd attempt on main if guess not main
- and tree.checkout("main") # Checkout to main, then
- and try_to_apply(tree) # Try to apply on main
- ):
- tree.write_log()
- tree.write_properties()
- tree.move_logs()
-
- print("FAILURE")
-
- return 1
- return 0
+ return 0
+ finally:
+ # Clean up the downloaded mbox file.
+ if data.series_mbox_path.exists():
+ data.series_mbox_path.unlink()
if __name__ == "__main__":
--
2.54.0
More information about the ci
mailing list