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
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
repository: basefoundry/base-bash-libs
ref: 8bcc1d2c1104ffa6c8bb4a95b3f328811401bf27
ref: d62e8c1fec2de9148bc832977c206b9f1827dd19
path: .dependencies/base-bash-libs

- name: Install BATS
Expand Down Expand Up @@ -91,7 +91,7 @@ jobs:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
repository: basefoundry/base-bash-libs
ref: 8bcc1d2c1104ffa6c8bb4a95b3f328811401bf27
ref: d62e8c1fec2de9148bc832977c206b9f1827dd19
path: .dependencies/base-bash-libs

- name: Set up Python
Expand Down Expand Up @@ -167,7 +167,7 @@ jobs:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
repository: basefoundry/base-bash-libs
ref: 8bcc1d2c1104ffa6c8bb4a95b3f328811401bf27
ref: d62e8c1fec2de9148bc832977c206b9f1827dd19
path: .dependencies/base-bash-libs

- name: Set up Python
Expand Down Expand Up @@ -210,7 +210,7 @@ jobs:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
repository: basefoundry/base-bash-libs
ref: 8bcc1d2c1104ffa6c8bb4a95b3f328811401bf27
ref: d62e8c1fec2de9148bc832977c206b9f1827dd19
path: .dependencies/base-bash-libs

- name: Expose reusable Bash library checkout as sibling
Expand Down
100 changes: 14 additions & 86 deletions cli/bash/commands/basectl/subcommands/gh.sh
Original file line number Diff line number Diff line change
Expand Up @@ -249,23 +249,11 @@ base_gh_require_git_repo() {
}

base_gh_default_branch() {
local default_branch
local base_default_branch repo_root

if default_branch="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null)"; then
default_branch="${default_branch#origin/}"
[[ -n "$default_branch" ]] && {
printf '%s\n' "$default_branch"
return 0
}
fi

if git show-ref --verify --quiet refs/heads/main; then
printf '%s\n' main
return 0
fi

if git show-ref --verify --quiet refs/heads/master; then
printf '%s\n' master
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || printf '.')"
if gh_detect_default_branch "$repo_root" base_default_branch; then
printf '%s\n' "$base_default_branch"
return 0
fi

Expand Down Expand Up @@ -373,30 +361,12 @@ base_gh_pr_changed_paths() {
}

base_gh_infer_github_repo() {
local remote_url
local github_repo repo_root

remote_url="$(git remote get-url origin 2>/dev/null || true)"
[[ -n "$remote_url" ]] || return 1

case "$remote_url" in
git@github.com:*.git)
remote_url="${remote_url#git@github.com:}"
remote_url="${remote_url%.git}"
;;
https://github.com/*.git)
remote_url="${remote_url#https://github.com/}"
remote_url="${remote_url%.git}"
;;
https://github.com/*)
remote_url="${remote_url#https://github.com/}"
;;
*)
return 1
;;
esac
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || printf '.')"
gh_infer_repo_from_origin "$repo_root" github_repo || return 1

[[ "$remote_url" == */* ]] || return 1
printf '%s\n' "$remote_url"
printf '%s\n' "$github_repo"
}

base_gh_default_project_title() {
Expand Down Expand Up @@ -977,37 +947,21 @@ base_gh_format_unix_date() {

base_gh_worktree_path_for_branch() {
local branch="$1"
local target_ref="refs/heads/$branch"
local line path="" ref

while IFS= read -r line; do
case "$line" in
"worktree "*)
path="${line#worktree }"
;;
"branch "*)
ref="${line#branch }"
if [[ "$ref" == "$target_ref" ]]; then
printf '%s\n' "$path"
return 0
fi
;;
esac
done < <(git worktree list --porcelain)

return 1
gh_worktree_path_for_branch "$branch"
}

base_gh_branch_upstream() {
local branch="$1"
git for-each-ref --format='%(upstream:short)' "refs/heads/$branch"

gh_branch_upstream . "$branch"
}

base_gh_branch_merged_to_ref() {
local branch="$1"
local ref="$2"

git merge-base --is-ancestor "refs/heads/$branch" "$ref" >/dev/null 2>&1
gh_branch_merged_to_ref . "$branch" "$ref"
}

base_gh_prune_github_ready() {
Expand Down Expand Up @@ -1066,13 +1020,7 @@ base_gh_branch_delete() {
}

base_gh_list_remote_branches() {
local output ref

output="$(git ls-remote --heads origin)" || return 1
while read -r _sha ref; do
[[ "$ref" == refs/heads/* ]] || continue
printf '%s\n' "${ref#refs/heads/}"
done <<< "$output"
gh_list_remote_branches .
}

base_gh_branch_delete_remote() {
Expand Down Expand Up @@ -1291,27 +1239,7 @@ base_gh_resolve_physical_path() {
}

base_gh_list_worktree_branches() {
local line path="" branch=""

while IFS= read -r line; do
if [[ -z "$line" ]]; then
if [[ -n "$path" && -n "$branch" ]]; then
branch="${branch#refs/heads/}"
printf '%s\t%s\n' "$path" "$branch"
fi
path=""
branch=""
continue
fi
case "$line" in
"worktree "*)
path="${line#worktree }"
;;
"branch "*)
branch="${line#branch }"
;;
esac
done < <(git worktree list --porcelain; printf '\n')
gh_list_worktree_branches .
}

base_gh_worktree_dirty() {
Expand Down
59 changes: 10 additions & 49 deletions cli/bash/commands/basectl/subcommands/repo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1174,33 +1174,11 @@ base_repo_write_baseline() {

base_repo_infer_github_repo() {
local path="$1"
local remote_url
local github_repo

remote_url="$(git -C "$path" remote get-url origin 2>/dev/null || true)"
[[ -n "$remote_url" ]] || return 1
gh_infer_repo_from_origin "$path" github_repo || return 1

case "$remote_url" in
git@github.com:*.git)
remote_url="${remote_url#git@github.com:}"
remote_url="${remote_url%.git}"
;;
git@github.com:*)
remote_url="${remote_url#git@github.com:}"
;;
https://github.com/*.git)
remote_url="${remote_url#https://github.com/}"
remote_url="${remote_url%.git}"
;;
https://github.com/*)
remote_url="${remote_url#https://github.com/}"
;;
*)
return 1
;;
esac

[[ "$remote_url" == */* ]] || return 1
printf '%s\n' "$remote_url"
printf '%s\n' "$github_repo"
}

base_repo_require_gh() {
Expand Down Expand Up @@ -1688,41 +1666,24 @@ base_repo_require_pr_worktree() {
}

base_repo_default_branch_for_pr() {
local default_branch
local base_remote_default_branch
local repo="$1"

base_repo_require_gh || return 1
default_branch="$(gh repo view "$repo" --json defaultBranchRef --jq .defaultBranchRef.name 2>/dev/null)" || {
if ! gh_repo_default_branch "$repo" base_remote_default_branch; then
log_error "Unable to determine the default branch for GitHub repository '$repo'."
return 1
}
[[ -n "$default_branch" ]] || {
log_error "GitHub repository '$repo' does not report a default branch."
return 1
}
fi

printf '%s\n' "$default_branch"
printf '%s\n' "$base_remote_default_branch"
}

base_repo_detect_default_branch() {
local default_branch
local base_default_branch
local root="$1"

if default_branch="$(git -C "$root" symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null)"; then
default_branch="${default_branch#origin/}"
if [[ -n "$default_branch" ]]; then
printf '%s\n' "$default_branch"
return 0
fi
fi

if git -C "$root" show-ref --verify --quiet refs/heads/main; then
printf '%s\n' main
return 0
fi

if git -C "$root" show-ref --verify --quiet refs/heads/master; then
printf '%s\n' master
if gh_detect_default_branch "$root" base_default_branch; then
printf '%s\n' "$base_default_branch"
return 0
fi

Expand Down
65 changes: 65 additions & 0 deletions cli/bash/commands/basectl/tests/gh.bats
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,76 @@ run_gh_subcommand() {
[[ "$(type -t gh_require_cli)" == "function" ]]
[[ "$(type -t gh_auth_status_diagnostics)" == "function" ]]
[[ "$(type -t gh_run)" == "function" ]]
[[ "$(type -t gh_detect_default_branch)" == "function" ]]
[[ "$(type -t gh_infer_repo_from_origin)" == "function" ]]
[[ "$(type -t gh_worktree_path_for_branch)" == "function" ]]
[[ "$(type -t gh_branch_merged_to_ref)" == "function" ]]
'

[ "$status" -eq 0 ]
}

@test "basectl gh default branch and repo inference delegate to reusable gh helpers" {
run env \
HOME="$TEST_HOME" \
BASE_HOME="$BASE_REPO_ROOT" \
bash -c '
source "$BASE_HOME/base_init.sh"
source "$BASE_HOME/cli/bash/commands/basectl/subcommands/gh.sh"
gh_detect_default_branch() {
printf -v "$2" "%s" "develop"
}
gh_infer_repo_from_origin() {
printf -v "$2" "%s" "owner/repo"
}
printf "default=%s\n" "$(base_gh_default_branch)"
printf "repo=%s\n" "$(base_gh_infer_github_repo)"
'

[ "$status" -eq 0 ]
[[ "$output" == *"default=develop"* ]]
[[ "$output" == *"repo=owner/repo"* ]]
}

@test "basectl gh branch and worktree primitives delegate to reusable gh helpers" {
run env \
HOME="$TEST_HOME" \
BASE_HOME="$BASE_REPO_ROOT" \
bash -c '
source "$BASE_HOME/base_init.sh"
source "$BASE_HOME/cli/bash/commands/basectl/subcommands/gh.sh"
gh_worktree_path_for_branch() {
printf "%s\n" "/tmp/shared-worktree"
}
gh_branch_upstream() {
printf "%s\n" "origin/feature"
}
gh_branch_merged_to_ref() {
[[ "$2" == "feature" && "$3" == "main" ]]
}
gh_list_remote_branches() {
printf "%s\n" "main" "feature"
}
gh_list_worktree_branches() {
printf "%s\t%s\n" "/tmp/shared-worktree" "feature"
}
remote_branches="$(base_gh_list_remote_branches)"
printf "worktree=%s\n" "$(base_gh_worktree_path_for_branch feature)"
printf "upstream=%s\n" "$(base_gh_branch_upstream feature)"
base_gh_branch_merged_to_ref feature main
printf "merged=$?\n"
printf "remote=%s\n" "${remote_branches//$'\''\n'\''/,}"
printf "worktrees=%s\n" "$(base_gh_list_worktree_branches)"
'

[ "$status" -eq 0 ]
[[ "$output" == *"worktree=/tmp/shared-worktree"* ]]
[[ "$output" == *"upstream=origin/feature"* ]]
[[ "$output" == *"merged=0"* ]]
[[ "$output" == *"remote=main,feature"* ]]
[[ "$output" == *$'worktrees=/tmp/shared-worktree\tfeature'* ]]
}

@test "basectl gh joins CSV output through reusable string helper" {
run env \
HOME="$TEST_HOME" \
Expand Down
33 changes: 33 additions & 0 deletions cli/bash/commands/basectl/tests/repo.bats
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,44 @@ run_repo_command_with_mocks() {
[[ "$(type -t gh_require_cli)" == "function" ]]
[[ "$(type -t gh_auth_status_diagnostics)" == "function" ]]
[[ "$(type -t gh_run)" == "function" ]]
[[ "$(type -t gh_infer_repo_from_origin)" == "function" ]]
[[ "$(type -t gh_detect_default_branch)" == "function" ]]
[[ "$(type -t gh_repo_default_branch)" == "function" ]]
'

[ "$status" -eq 0 ]
}

@test "basectl repo GitHub helpers delegate to reusable gh helpers" {
run env \
HOME="$TEST_HOME" \
BASE_HOME="$BASE_REPO_ROOT" \
bash -c '
source "$BASE_HOME/base_init.sh"
source "$BASE_HOME/cli/bash/commands/basectl/subcommands/repo.sh"
base_repo_require_gh() {
return 0
}
gh_infer_repo_from_origin() {
printf -v "$2" "%s" "owner/repo"
}
gh_detect_default_branch() {
printf -v "$2" "%s" "develop"
}
gh_repo_default_branch() {
printf -v "$2" "%s" "trunk"
}
printf "repo=%s\n" "$(base_repo_infer_github_repo /tmp/repo)"
printf "detected=%s\n" "$(base_repo_detect_default_branch /tmp/repo)"
printf "remote=%s\n" "$(base_repo_default_branch_for_pr owner/repo)"
'

[ "$status" -eq 0 ]
[[ "$output" == *"repo=owner/repo"* ]]
[[ "$output" == *"detected=develop"* ]]
[[ "$output" == *"remote=trunk"* ]]
}

@test "basectl repo prints help" {
run_basectl repo --help

Expand Down
Loading