Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions release-tools/test.bash
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,6 @@ shopt -s inherit_errexit
if [[ "$*" == "diff --cached --quiet" || "$*" == *"diff --quiet --"* ]]; then
exit 1
fi
if [[ "$*" == *"push --set-upstream origin release/homebrew-"* ]]; then
credential_helper="credential.helper=!${X52_GH} auth git-credential"
[[ "$*" == *"-c credential.helper= -c $credential_helper"* ]]
fi
printf 'git' >>"$COMMAND_LOG"
printf ' <%s>' "$@" >>"$COMMAND_LOG"
printf '\n' >>"$COMMAND_LOG"
Expand Down Expand Up @@ -293,7 +289,11 @@ grep -Fq 'assert_match "custom test", shell_output("#{bin}/demo-formula verify")
grep -Fq '# x52-release-tools: begin macos artifacts' "$tap_root/Formula/demo-formula.rb"
grep -Fq 'gh <pr> <create> <--repo> <example/tap> <--base> <release> <--head> <release/homebrew-demo-formula-1.1.0>' "$command_log"
grep -Fq 'git <-C> <'"$tap_root"'> <commit> <-m> <chore: update demo-formula to 1.1.0>' "$command_log"
grep -Fq 'git <-c> <credential.helper=> <-c> <credential.helper=!'"$fake_bin"'/gh auth git-credential> <-C> <'"$tap_root"'> <push> <--set-upstream> <origin> <release/homebrew-demo-formula-1.1.0>' "$command_log"
grep -Fq 'git <-C> <'"$tap_root"'> <push> <--set-upstream> <origin> <release/homebrew-demo-formula-1.1.0>' "$command_log"
if grep -Fq 'gh <auth> <setup-git>' "$command_log"; then
echo "Expected the updater to use the tap checkout's Git credentials" >&2
exit 1
fi

x52-update-homebrew-tap \
--tag demo-v1.2.0 \
Expand All @@ -312,6 +312,17 @@ grep -Fq 'assert_match "manual test", shell_output("#{bin}/manual-demo verify")'
grep -Fq '# x52-release-tools: begin macos artifacts' "$tap_root/Formula/manual-demo.rb"
grep -Fq '# x52-release-tools: begin linux artifacts' "$tap_root/Formula/manual-demo.rb"

unset X52_HOMEBREW_TAP_DIRECTORY
if x52-update-homebrew-tap \
--tag demo-v1.2.0 \
--version 1.2.0 \
--package manual-release \
--source-repository example/manual >"$test_root/missing-tap-directory.log" 2>&1; then
echo "Expected a missing Homebrew tap checkout to fail" >&2
exit 1
fi
grep -Fq -- '--tap-directory or X52_HOMEBREW_TAP_DIRECTORY is required' "$test_root/missing-tap-directory.log"

cat >"$fixture_root/CHANGELOG.md" <<'EOF'
# Changelog

Expand Down
32 changes: 12 additions & 20 deletions release-tools/update-homebrew-tap.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,6 @@ def run(*command: str, cwd: Path | None = None, check: bool = True) -> subproces
return result


def run_authenticated_git(git: str, gh: str, *command: str, check: bool = True) -> subprocess.CompletedProcess[str]:
credential_helper = f"!{shlex.quote(gh)} auth git-credential"
return run(git, "-c", "credential.helper=", "-c", f"credential.helper={credential_helper}", *command, check=check)


def ruby_string(value: str) -> str:
return json.dumps(value, ensure_ascii=False)

Expand Down Expand Up @@ -263,28 +258,25 @@ def main() -> int:
parser.add_argument("--source-repository", default=os.environ.get("GITHUB_REPOSITORY"), help="release repository")
parser.add_argument("--tap", default=os.environ.get("X52_HOMEBREW_TAP_REPOSITORY", "x52dev/homebrew-tap"), help="Homebrew tap repository")
parser.add_argument("--base", default="main", help="tap pull request base branch")
parser.add_argument("--tap-directory", default=os.environ.get("X52_HOMEBREW_TAP_DIRECTORY"), help=argparse.SUPPRESS)
parser.add_argument(
"--tap-directory",
default=os.environ.get("X52_HOMEBREW_TAP_DIRECTORY"),
help="existing Homebrew tap checkout with Git credentials; defaults to X52_HOMEBREW_TAP_DIRECTORY",
)
args = parser.parse_args()

try:
release = release_from_arguments(args)
if not args.source_repository:
raise UpdateError("--source-repository or GITHUB_REPOSITORY is required")
if not args.tap_directory:
raise UpdateError("--tap-directory or X52_HOMEBREW_TAP_DIRECTORY is required")

formula_name = args.formula or args.package
asset_prefix = args.asset_prefix or args.package
log(f"Updating {formula_name} to {release.version} from {args.source_repository} release {release.tag}")
temporary_tap_directory = None
if args.tap_directory:
tap_directory = Path(args.tap_directory)
log(f"Using Homebrew tap checkout {tap_directory}")
else:
temporary_tap_directory = tempfile.TemporaryDirectory()
tap_directory = Path(temporary_tap_directory.name) / "homebrew-tap"
gh = os.environ.get("X52_GH", "gh")
git = os.environ.get("X52_GIT", "git")
log(f"Cloning Homebrew tap {args.tap}")
run_authenticated_git(git, gh, "clone", f"https://github.com/{args.tap}.git", str(tap_directory))
tap_directory = Path(args.tap_directory)
log(f"Using Homebrew tap checkout {tap_directory}")

formula = tap_directory / "Formula" / f"{formula_name}.rb"
if not formula.is_file():
Expand All @@ -293,9 +285,9 @@ def main() -> int:
git = os.environ.get("X52_GIT", "git")
gh = os.environ.get("X52_GH", "gh")
branch = f"release/homebrew-{formula_name}-{release.version}"
if run_authenticated_git(git, gh, "-C", str(tap_directory), "ls-remote", "--exit-code", "--heads", "origin", branch, check=False).returncode == 0:
if run(git, "-C", str(tap_directory), "ls-remote", "--exit-code", "--heads", "origin", branch, check=False).returncode == 0:
log(f"Reusing tap branch {branch}")
run_authenticated_git(git, gh, "-C", str(tap_directory), "fetch", "origin", branch)
run(git, "-C", str(tap_directory), "fetch", "origin", branch)
Comment on lines +288 to +290

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

root="$(mktemp -d)"
trap 'rm -rf "$root"' EXIT

git init --bare "$root/origin.git"
git init -b main "$root/source"
git -C "$root/source" config user.name test
git -C "$root/source" config user.email test@example.invalid
git -C "$root/source" commit --allow-empty -m initial
git -C "$root/source" branch release/test
git -C "$root/source" remote add origin "$root/origin.git"
git -C "$root/source" push origin main release/test

git clone --single-branch --branch main "$root/origin.git" "$root/checkout"
git -C "$root/checkout" fetch origin release/test

if git -C "$root/checkout" show-ref --verify --quiet refs/remotes/origin/release/test; then
  echo "Unexpected remote-tracking ref" >&2
  exit 1
fi

if git -C "$root/checkout" switch --track origin/release/test; then
  echo "Expected switch to fail without origin/release/test" >&2
  exit 1
fi

Repository: x52dev/nix

Length of output: 1187


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant code and fake Git command behavior enough to determine
# whether `git fetch origin <branch>` currently creates `refs/remotes/origin/<branch>`.
printf '--- release-tools/update-homebrew-tap.py relevant lines ---\n'
sed -n '250,315p' release-tools/update-homebrew-tap.py

printf '\n--- release-tools/test.bash relevant lines ---\n'
sed -n '260,310p' release-tools/test.bash

printf '\n--- fake-git command wrapper (if any) ---\n'
rg -n "real_git|git|update-homebrew-tap|switch --track|fetch origin|refs/remotes/origin" release-tools -S

printf '\n--- git version ---\n'
git --version

Repository: x52dev/nix

Length of output: 239


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- release-tools/update-homebrew-tap.py relevant lines ---'
sed -n '250,315p' release-tools/update-homebrew-tap.py

printf '%s\n' ''
printf '%s\n' '--- release-tools/test.bash relevant lines ---'
sed -n '260,310p' release-tools/test.bash

printf '%s\n' ''
printf '%s\n' '--- relevant searches ---'
rg -n "real_git|git|update-homebrew-tap|switch --track|fetch origin|refs/remotes/origin|ls-remote|push" release-tools -S || true

printf '%s\n' ''
printf '%s\n' '--- git version ---'
git --version

Repository: x52dev/nix

Length of output: 16187


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- release-tools/test.bash fake git wrapper ---'
sed -n '140,185p' release-tools/test.bash

printf '%s\n' ''
printf '%s\n' '--- behavioral probe for git fetch explicit source-only refspec ---'
root="$(mktemp -d)"
trap 'rm -rf "$root"' EXIT

git init --bare "$root/origin.git"
git init -b main "$root/source"
git -C "$root/source" config user.name test
git -C "$root/source" config user.email test@example.invalid
git -C "$root/source" commit --allow-empty -m initial
git -C "$root/source" branch release/test
git -C "$root/source" remote add origin "$root/origin.git"
git -C "$root/source" push origin main release/test

git clone --single-branch --branch main "$root/origin.git" "$root/checkout"
git -C "$root/checkout" fetch origin release/test

printf '%s\n' 'remote-tracking ref exists:'
git -C "$root/checkout" show-ref --verify --quiet refs/remotes/origin/release/test && printf 'yes\n' || printf 'no\n'

printf '%s\n' 'FETCH_HEAD:'
git -C "$root/checkout" show-ref --verify --quiet FETCH_HEAD && printf 'yes\n' || printf 'no\n'

set +e
git -C "$root/checkout" switch --track origin/release/test
rc=$?
printf '%s\n' "switch --track origin/release/test exit code: $rc"
set -e

Repository: x52dev/nix

Length of output: 2810


Create the remote-tracking ref before tracking it.

git fetch origin <branch> stores the result in FETCH_HEAD when no remote tracking refspec exists, so git switch --track origin/<branch> fails with invalid reference: origin/<branch>.

Proposed fix
-            run(git, "-C", str(tap_directory), "fetch", "origin", branch)
+            run(
+                git,
+                "-C",
+                str(tap_directory),
+                "fetch",
+                "origin",
+                f"refs/heads/{branch}:refs/remotes/origin/{branch}",
+            )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if run(git, "-C", str(tap_directory), "ls-remote", "--exit-code", "--heads", "origin", branch, check=False).returncode == 0:
log(f"Reusing tap branch {branch}")
run_authenticated_git(git, gh, "-C", str(tap_directory), "fetch", "origin", branch)
run(git, "-C", str(tap_directory), "fetch", "origin", branch)
if run(git, "-C", str(tap_directory), "ls-remote", "--exit-code", "--heads", "origin", branch, check=False).returncode == 0:
log(f"Reusing tap branch {branch}")
run(
git,
"-C",
str(tap_directory),
"fetch",
"origin",
f"refs/heads/{branch}:refs/remotes/origin/{branch}",
)
📍 Affects 2 files
  • release-tools/update-homebrew-tap.py#L288-L290 (this comment)
  • release-tools/test.bash#L292-L296
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@release-tools/update-homebrew-tap.py` around lines 288 - 290, Update the
existing-branch fetch logic in release-tools/update-homebrew-tap.py lines
288-290 to explicitly create or update the origin/<branch> remote-tracking ref
before the later git switch --track operation, rather than relying on
FETCH_HEAD. Apply the same remote-tracking-ref fix in release-tools/test.bash
lines 292-296; both sites must ensure origin/<branch> is available after
fetching.

run(git, "-C", str(tap_directory), "switch", "--track", f"origin/{branch}")
else:
log(f"Creating tap branch {branch}")
Expand All @@ -318,7 +310,7 @@ def main() -> int:
run(git, "-C", str(tap_directory), "add", f"Formula/{formula_name}.rb")
run(git, "-C", str(tap_directory), "commit", "-m", f"chore: update {formula_name} to {release.version}")
log(f"Pushing tap branch {branch}")
run_authenticated_git(git, gh, "-C", str(tap_directory), "push", "--set-upstream", "origin", branch)
run(git, "-C", str(tap_directory), "push", "--set-upstream", "origin", branch)
log(f"Creating pull request in {args.tap}")
run(gh, "pr", "create", "--repo", args.tap, "--base", args.base, "--head", branch, "--title", f"chore: update {formula_name} to {release.version}", "--body", f"Automated update from {args.source_repository} release {release.tag}.")
return 0
Expand Down
Loading