Repository navigation
refactor(git): centralize linked-worktree validity checks #580
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -556,7 +556,7 @@ release_module_check() { | |
| check_release_tree() { | ||
| local manifest="$1" | ||
| local release_ref="$2" | ||
| local symbol | ||
| local symbol release_manifest="$manifest" historical_manifest="" | ||
| local -a fields=() | ||
| local -A release_module_sources=() | ||
| local -A release_module_docs=() | ||
|
|
@@ -569,18 +569,35 @@ check_release_tree() { | |
| error "release reference is not a local commit: $release_ref" | ||
| return 1 | ||
| } | ||
| if [[ "$manifest" == "$default_manifest" ]]; then | ||
| historical_manifest="$(mktemp "${TMPDIR:-/tmp}/base-api-release-manifest.XXXXXX")" || return 1 | ||
| if ! git -C "$repo_root" show "$release_ref:base_api_manifest.yaml" > "$historical_manifest" 2> /dev/null; then | ||
| rm -f "$historical_manifest" | ||
| error "release reference '$release_ref' does not contain base_api_manifest.yaml" | ||
| return 1 | ||
| fi | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cleanup: duplicated historical-manifest-loading boilerplate The new block here (mktemp +
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deferred as intentionally non-blocking cleanup for this PR. The duplicated historical-manifest loading paths have identical behavior today, while extracting a helper would widen the diff without changing the release contract. The correctness fix and its regression coverage remain the merge prerequisite; helper extraction can be tracked separately if desired. |
||
| # The compatibility check above verifies that every historical stable | ||
| # symbol remains available. The release tree check must inspect the | ||
| # historical manifest so additive stable APIs are allowed in a minor | ||
| # v2 release without pretending they were present in v2.0.0. | ||
| release_manifest="$historical_manifest" | ||
| fi | ||
| while IFS=$'\t' read -r -a fields; do | ||
| [[ -n "${fields[0]-}" ]] || continue | ||
| release_module_sources["${fields[0]}"]="${fields[2]}" | ||
| release_module_docs["${fields[0]}"]="${fields[3]}" | ||
| release_module_tests["${fields[0]}"]="${fields[4]}" | ||
| release_module_symbols["${fields[0]}"]="${fields[8]}" | ||
| release_module_dependencies["${fields[0]}"]="${fields[5]}" | ||
| done < <(manifest_rows "$manifest") | ||
| done < <(manifest_rows "$release_manifest") | ||
| while IFS=$'\t' read -r -a fields; do | ||
| [[ -n "${fields[0]-}" && "${fields[14]}" == stable ]] || continue | ||
| release_module_check "${fields[0]}" "${fields[0]}" || return 1 | ||
| done < <(manifest_rows "$manifest") | ||
| release_module_check "${fields[0]}" "${fields[0]}" || { | ||
| rm -f "$historical_manifest" | ||
| return 1 | ||
| } | ||
| done < <(manifest_rows "$release_manifest") | ||
| rm -f "$historical_manifest" | ||
| printf 'Stable API release reference is valid: %s\n' "$release_ref" | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correctness: submodule checkouts misclassified as valid linked worktrees
A Git submodule's checked-out directory also has
.gitas a regular file (a gitlink, e.g.gitdir: ../.git/modules/<name>), andgit -C <submodule_path> rev-parse --is-inside-work-treealso returns true/exit 0 for it, exactly as for a real linked worktree. Sobase_git_worktree_path_is_valid <submodule_path>returns 0 (success) for a submodule, even though a submodule is not a linked worktree.Verified empirically:
Both guard clauses in the new function pass for
sub, so it validates as a linked worktree.This contradicts the documented contract (README.md / docs/v2-api-contract.md): "Return success only when
pathis a valid linked Git worktree ... ordinary repositories ... return 1" — a submodule is neither an ordinary repository checkout nor a linked worktree, but isn't excluded by either check. Per #579 / basefoundry/base#2621, this predicate is meant to gate "dirty checks and removal" of worktree-like directories in downstream consumers (Base), so a false positive here is a real correctness gap, not just a doc nuance. Consider adding a submodule-exclusion check, e.g. verifying the.gitfile'sgitdir:target resolves under<repo>/.git/worktrees/rather than.git/modules/.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit 857df0d. base_git_worktree_path_is_valid now resolves --git-dir and --git-common-dir and accepts only paths below the repository worktrees/ administrative directory, so submodules under .git/modules/ return status 1. Added a real submodule regression fixture and updated the README, v2 API contract, and changelog. Focused BATS passes 79/79 and the full ./tests/validate.sh gate passes 715/715 plus the repository release and quality contracts.