Files
RepoFoundry/src/lib/localproject.sh
T
TirsvadandClaude Sonnet 5.5 0030334e5e Add the local project, framework submodule, hooks and templates
After the repositories and the mirror, the script now creates the local
project: the directory, git on main, credential-free origin (and github)
remotes, and the license history from Gitea. Then it adds the framework as
a submodule over SSH, installs its skills and git hooks once (plan gate
optional), and copies the AGENTS.md and artifact registry templates.

Nothing is overwritten without a yes: an existing directory, core.hooksPath,
AGENTS.md or docs/artifact-registry.md each ask first (default no). Without
SSH the framework steps can only be skipped, after a yes. No commit is made
in the new project. New optional config key FRAMEWORK_REPO.

New library files git.sh, localproject.sh and framework.sh. Tests run real
git against local bare repositories that stand in for Gitea and the
framework, with a private git configuration (769 checks). The README is now
the full guide.

Task: MIL-003#1
Task: MIL-003#2
Task: MIL-003#3
Task: MIL-003#4
Task: MIL-003#5
Refs #15
Refs #16
Refs #17
Refs #18
Refs #19

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-05 15:54:02 +08:00

91 lines
3.6 KiB
Bash

# shellcheck shell=bash
# shellcheck disable=SC2004,SC2034,SC2154 # shared state and arrays are declared in constants.sh
# localproject.sh - The local project: its directory, its git repository and its remotes.
#
# Part of create-project.sh: sourced by it, never run on its own.
#
# Provides: inspect_local_directory, confirm_local_directory, ensure_remote, checkout_gitea_history, create_local_project
# inspect_local_directory: record in STATE[local_dir] whether the project
# directory is missing, empty or not_empty. It creates nothing.
inspect_local_directory() {
local dir="${PROJECT[directory]}"
if [[ ! -e $dir ]]; then
STATE[local_dir]="missing"
elif [[ ! -d $dir ]]; then
die "$dir already exists and is not a directory"
elif [[ -z "$(find "$dir" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then
STATE[local_dir]="empty"
else
STATE[local_dir]="not_empty"
fi
}
# confirm_local_directory: an existing directory is only used after a yes.
confirm_local_directory() {
local dir="${PROJECT[directory]}" what="is empty"
if [[ ${STATE[local_dir]} == missing ]]; then
return 0
fi
if [[ ${STATE[local_dir]} == not_empty ]]; then
what="already has files"
fi
prompt_yes_no "The directory $dir already exists and $what. Use it" n
if ! ((REPLY)); then
die "stopped: choose another directory or remove this one"
fi
}
# ensure_remote DIR NAME URL: add the remote, or accept one that already has
# exactly this address. A different address is never overwritten.
ensure_remote() {
local dir="$1" name="$2" url="$3" existing
# git config exits 1 when the remote is not set; that is the normal case.
existing="$(git_project "$dir" config --get "remote.$name.url" || true)"
if [[ -z $existing ]]; then
git_project "$dir" remote add "$name" "$url"
elif [[ $existing != "$url" ]]; then
die "the remote '$name' in $dir already points to $existing; remove it or choose another directory"
fi
}
# checkout_gitea_history DIR: when the Gitea repository holds the license
# commit, fetch it and start the local branch from it, so the local history
# begins with that commit. Existing files are never overwritten: git refuses.
checkout_gitea_history() {
local dir="$1" err
if ! fetch_origin "$dir" 2>/dev/null; then
die "could not fetch the Gitea repository from $(origin_url); check your SSH key (or, over HTTPS, the token) and run the same command again"
fi
if ! git_project "$dir" rev-parse --verify -q refs/remotes/origin/main >/dev/null; then
return 0
fi
if git_project "$dir" rev-parse --verify -q HEAD >/dev/null 2>&1; then
warn "$dir already has history: the Gitea content was fetched but not checked out"
return 0
fi
make_temp_file
err="$REPLY"
if ! git_project "$dir" checkout -q -b main --track origin/main 2>"$err"; then
die "git would overwrite files in $dir with the Gitea content; move them away and run again. Git said: $(head -n 2 "$err" | tr '\n' ' ')"
fi
}
# create_local_project: the directory, the git repository on main, the
# remotes and, when GitHub is chosen, the license history. No commit is made.
create_local_project() {
local label="Local project" dir="${PROJECT[directory]}"
begin_step "$label"
mkdir -p -- "$dir"
if [[ ! -e $dir/.git ]]; then
git_project "$dir" init -q
git_project "$dir" symbolic-ref HEAD "refs/heads/$DEFAULT_BRANCH"
fi
ensure_remote "$dir" origin "$(origin_url)"
if ((PROJECT[has_github])); then
ensure_remote "$dir" github "$(github_remote_url)"
checkout_gitea_history "$dir"
fi
finish_step "$label" "created" "$dir (origin over $(origin_protocol))"
}