From f4faadf3f550dc479a00941587f88e7a93ce9f3d Mon Sep 17 00:00:00 2001 From: Oliver Smith Date: Wed, 22 Feb 2023 10:59:25 +0100 Subject: [PATCH] src/grd: replace fetch-gerrit-patch.sh As discussed with Neels, replace the previous version of the script that didn't work anymore (probably due to api change from gerrit) with a new one that works with the current api and also doesn't require unlocking the ssh key. Change-Id: Ie5d061323dce6843cafe49434250cc4780c8c832 --- .gitignore | 2 +- src/README | 29 +++++------ src/fetch-gerrit-patch.sh | 41 ---------------- src/grd | 100 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 56 deletions(-) delete mode 100755 src/fetch-gerrit-patch.sh create mode 100755 src/grd diff --git a/.gitignore b/.gitignore index 3b70a48..6aa1dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,8 @@ tags make-* make/* src/* -!src/fetch-gerrit-patch.sh !src/gits +!src/grd !src/osmo-add-gerrit-hooks.sh !src/README net/* diff --git a/src/README b/src/README index f066561..09b8054 100644 --- a/src/README +++ b/src/README @@ -7,7 +7,7 @@ There are some handy scripts I use for my daily Osmocom development: gerrit commit-msg hook in each one. This requires an ~/.ssh/config entry, see top comment in the script. - fetch-gerrit-patch.sh + grd Pass a patch number seen on gerrit to fetch the latest patch set into your git clone. See top comment in the script. @@ -34,22 +34,23 @@ commit-msg 100% 4688 ----------------------------------------------------------------------------- -cd osmo-msc -../fetch-gerrit-patch.sh 3787 -+ git fetch origin refs/changes/87/3787/2 -From ssh://go/osmo-msc - * branch refs/changes/87/3787/2 -> FETCH_HEAD -+ git checkout -b 3787_2 FETCH_HEAD -Switched to a new branch '3787_2' +$ cd osmo-msc +$ ../grd 3787 +Download https://gerrit.osmocom.org/changes/osmo-msc~3787/detail ++ git fetch https://gerrit.osmocom.org/osmo-msc refs/changes/87/3787/5 +From https://gerrit.osmocom.org/osmo-msc + * branch refs/changes/87/3787/5 -> FETCH_HEAD ++ git checkout -B gerrit/3787_5 FETCH_HEAD +Switched to a new branch 'gerrit/3787_5' # or if you want an earlier patch set -../fetch-gerrit-patch.sh 3787/1 -From ssh://go/osmo-msc - * branch refs/changes/87/3787/1 -> FETCH_HEAD -+ git checkout -b 3787_1 FETCH_HEAD -Switched to a new branch '3787_1' - +$ ../grd 3787 -r1 ++ git fetch https://gerrit.osmocom.org/osmo-msc refs/changes/87/3787/1 +From https://gerrit.osmocom.org/osmo-msc + * branch refs/changes/87/3787/1 -> FETCH_HEAD ++ git checkout -B gerrit/3787_1 FETCH_HEAD +Switched to a new branch 'gerrit/3787_1' ----------------------------------------------------------------------------- diff --git a/src/fetch-gerrit-patch.sh b/src/fetch-gerrit-patch.sh deleted file mode 100755 index 0353461..0000000 --- a/src/fetch-gerrit-patch.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# fetch gerrit patch into new branch named like the patch number. -# -# Usage: go to a git clone and pass a patch number: -# -# cd osmo-msc -# P 973 -# or -# P 973/2 -# -# Will create new local branches '973_4' (if 4 is the latest patch set) -# or '973_2', respectively. - -patch="$1" - -if [ -z "$patch" ]; then - echo "Usage: $0 1234[/5]" - exit 1 -fi - -if [ -z "$(echo "$patch" | grep '/')" ]; then - patch="/$patch/" -fi - -if [ -z "$(echo "$patch" | grep '^/')" ]; then - patch="/$patch" -fi - -last_set="$(git ls-remote origin "changes/*" | grep "$patch" | sed 's#.*/\([^/]*\)$#\1 &#' | sort -n | tail -n 1)" -if [ -z "$last_set" ]; then - echo "Not found: $patch" - exit 1 -fi - -change_name="$(echo "$last_set" | sed 's/.*\(refs.*\)/\1/')" -branch_name="$(echo "$change_name" | sed 's#refs/changes/../\([0-9]*\)/\([0-9]*\)#\1_\2#')" - -set -x -git fetch origin "$change_name" -git checkout -b "$branch_name" FETCH_HEAD - diff --git a/src/grd b/src/grd new file mode 100755 index 0000000..b1623ec --- /dev/null +++ b/src/grd @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-or-later +# "git review download", like git review -d, but without need for ssh key. Run +# this script inside a git repository with the gerrit review ID as argument to +# fetch and checkout the patch. +import argparse +import configparser +import json +import os +import subprocess +import urllib.request + + +def get_topdir(): + try: + return subprocess.run(["git", "rev-parse", "--show-toplevel"], + check=True, capture_output=True, + encoding="UTF-8").stdout.rstrip() + except subprocess.CalledProcessError: + print("ERROR: not running inside a git repository") + exit(1) + + +def get_config_path(): + ret = f"{get_topdir()}/.gitreview" + if not os.path.exists(ret): + print(f"ERROR: config not found: {ret}") + exit(1) + return ret + + +def get_config(): + config_path = get_config_path() + config = configparser.ConfigParser() + config.read(config_path) + return config["gerrit"]["host"], config["gerrit"]["project"] + + +def get_gerrit_details(host, project, patch_id, verbose): + url = f"https://{host}/changes/{project}~{args.patch_id}/detail" + print(f"Download {url}") + with urllib.request.urlopen(url) as response: + content = response.read().decode() + content = "{" + content.split("{", 1)[1] + ret = json.loads(content) + if args.verbose: + print(json.dumps(ret, indent=4)) + return ret + + +def get_highest_revision(details): + ret = 1 + for message in details["messages"]: + rev = message["_revision_number"] + if rev > ret: + ret = rev + return ret + + +def git_fetch(host, project, patch_id, rev): + last_digits = str(patch_id)[-2:] + url = f"https://{host}/{project}" + ref = f"refs/changes/{last_digits}/{patch_id}/{rev}" + cmd = ["git", "fetch", url, ref] + print(f"+ {' '.join(cmd)}") + + try: + return subprocess.run(cmd, check=True) + except subprocess.CalledProcessError: + exit(1) + + +def git_checkout_fetch_head(patch_id, rev): + cmd = ["git", "checkout", "-B", f"gerrit/{patch_id}_{rev}", "FETCH_HEAD"] + print(f"+ {' '.join(cmd)}") + + try: + return subprocess.run(cmd, check=True) + except subprocess.CalledProcessError: + exit(1) + + +desc = "git review download: fetch and checkout a patch from gerrit" +parser = argparse.ArgumentParser(description=desc) +parser.add_argument("patch_id", type=int, + help="gerrit review ID") +parser.add_argument("-r", "--revision", type=int, + help="patchset revision, default is latest") +parser.add_argument("-v", "--verbose", action="store_true") +args = parser.parse_args() + +host, project = get_config() +rev = args.revision + +if not rev: + details = get_gerrit_details(host, project, args.patch_id, args.verbose) + rev = get_highest_revision(details) + +git_fetch(host, project, args.patch_id, rev) +git_checkout_fetch_head(args.patch_id, rev)