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>
This commit is contained in:
2026-10-05 15:54:02 +08:00
co-authored by Claude Sonnet 5.5
parent 736cdb42fc
commit 0030334e5e
19 changed files with 1185 additions and 68 deletions
+38 -1
View File
@@ -4,7 +4,7 @@
#
# Part of create-project.sh: sourced by it, never run on its own.
#
# Provides: is_reused, repo_owner, repo_url
# Provides: is_reused, repo_owner, repo_url, gitea_host, origin_protocol, origin_url, github_remote_url, framework_url
# is_reused HOST: succeed if the existing repository on HOST will be reused.
is_reused() {
@@ -26,3 +26,40 @@ repo_url() {
printf '%s/%s/%s' "${CONFIG[GITHUB_WEB_URL]}" "${PROJECT[github_owner]}" "${PROJECT[name]}"
fi
}
# gitea_host: the host name of the Gitea server, from GITEA_URL.
gitea_host() {
local host="${CONFIG[GITEA_URL]#https://}"
host="${host%%/*}"
printf '%s' "${host%%:*}"
}
# origin_protocol: SSH when the SSH test passed, otherwise HTTPS.
origin_protocol() {
if ((${STATE[is_ssh_ok]:-0})); then
printf 'SSH'
else
printf 'HTTPS'
fi
}
# origin_url: the address of the Gitea repository for the origin remote. It
# never holds a credential: "git@" is the SSH user name, not a secret.
origin_url() {
if [[ $(origin_protocol) == SSH ]]; then
printf 'ssh://git@%s:%s/%s/%s.git' "$(gitea_host)" "${CONFIG[GITEA_SSH_PORT]}" \
"${PROJECT[gitea_owner]}" "${PROJECT[name]}"
else
printf '%s/%s/%s.git' "${CONFIG[GITEA_URL]}" "${PROJECT[gitea_owner]}" "${PROJECT[name]}"
fi
}
github_remote_url() {
printf '%s/%s/%s.git' "${CONFIG[GITHUB_WEB_URL]}" "${PROJECT[github_owner]}" "${PROJECT[name]}"
}
# framework_url: where the framework submodule comes from (always SSH).
framework_url() {
printf 'ssh://git@%s:%s/%s.git' "$(gitea_host)" "${CONFIG[GITEA_SSH_PORT]}" \
"${CONFIG[FRAMEWORK_REPO]}"
}