From e12403b34880dd1a4fce1b0f624b6086e853064b Mon Sep 17 00:00:00 2001 From: rhiroe Date: Wed, 9 Sep 2026 03:12:06 +0000 Subject: [PATCH 1/2] improve(github-cli): retry gh extension install before falling back to git clone gh extension install failures fell through silently to the git-clone fallback. Retry it up to 3 times with backoff before falling back, since failures are most often transient (network/API rate limiting) rather than the extension being fundamentally unusable, and log each failed attempt's exit code so provisioning logs show why the fallback was hit. Extensions that require a build step (e.g. github/gh-stack) are not usable after a plain git clone. Improving the fallback itself (e.g. downloading a prebuilt release binary) would add significant logic and ongoing maintenance cost, so that path is not pursued here; instead, after cloning, check for the expected gh- executable and exit 1 if it's missing, so a build-requiring extension fails provisioning loudly instead of leaving a broken extension in place. --- src/github-cli/scripts/install-extensions.sh | 35 ++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/github-cli/scripts/install-extensions.sh b/src/github-cli/scripts/install-extensions.sh index 05285aa7b..be861283a 100644 --- a/src/github-cli/scripts/install-extensions.sh +++ b/src/github-cli/scripts/install-extensions.sh @@ -20,19 +20,42 @@ install_extension() { local extension="$1" local extensions_root local repo_name + local install_status + local attempt + local max_attempts=3 extensions_root="${XDG_DATA_HOME:-"${HOME}/.local/share"}/gh/extensions" repo_name="${extension##*/}" mkdir -p "${extensions_root}" - if [ ! -d "${extensions_root}/${repo_name}" ]; then - if ! gh extension install "${extension}"; then - git \ - -c credential.helper= \ - -c credential.helper='!gh auth git-credential' \ - clone --depth 1 "https://github.com/${extension}.git" "${extensions_root}/${repo_name}" + if [ -d "${extensions_root}/${repo_name}" ]; then + return + fi + + attempt=1 + while [ "${attempt}" -le "${max_attempts}" ]; do + if gh extension install "${extension}"; then + return + fi + install_status=$? + echo "Warning: 'gh extension install ${extension}' failed (exit code ${install_status}, attempt ${attempt}/${max_attempts})." >&2 + attempt=$((attempt + 1)) + if [ "${attempt}" -le "${max_attempts}" ]; then + sleep $((attempt * 2)) fi + done + + git \ + -c credential.helper= \ + -c credential.helper='!gh auth git-credential' \ + clone --depth 1 "https://github.com/${extension}.git" "${extensions_root}/${repo_name}" + + if [ ! -x "${extensions_root}/${repo_name}/gh-${repo_name}" ]; then + echo "Error: '${extension}' requires a build step; 'git clone' fallback won't work." >&2 + rm -rf "${extensions_root}/${repo_name}" + exit 1 fi + echo "Warning: cloned ${extension} instead of installing via 'gh extension install'." >&2 } ensure_gh_extension_list_wrapper() { From 8eb1c8931fc607eb8b096bdc48efec257402fdb0 Mon Sep 17 00:00:00 2001 From: rhiroe Date: Fri, 18 Sep 2026 10:17:14 +0900 Subject: [PATCH 2/2] fix(github-cli): capture real exit code in extension install retry log bash's 'if' returns 0 when the condition is false and there is no else, so 'install_status=$?' right after the if always read 0 instead of the actual gh failure code. --- src/github-cli/scripts/install-extensions.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/github-cli/scripts/install-extensions.sh b/src/github-cli/scripts/install-extensions.sh index be861283a..186d5149a 100644 --- a/src/github-cli/scripts/install-extensions.sh +++ b/src/github-cli/scripts/install-extensions.sh @@ -34,10 +34,11 @@ install_extension() { attempt=1 while [ "${attempt}" -le "${max_attempts}" ]; do - if gh extension install "${extension}"; then + install_status=0 + gh extension install "${extension}" || install_status=$? + if [ "${install_status}" -eq 0 ]; then return fi - install_status=$? echo "Warning: 'gh extension install ${extension}' failed (exit code ${install_status}, attempt ${attempt}/${max_attempts})." >&2 attempt=$((attempt + 1)) if [ "${attempt}" -le "${max_attempts}" ]; then