**Motivations:** - split script failed after subtree split when optional root files (e.g. .dockerignore) were missing on branch test **Root causes:** - git add with a missing path in the list fails entirely and stages nothing; git commit then fails under set -e **Correctifs:** - add each copied file only if it exists in the deploy repo; skip commit if index empty **Evolutions:** - none **Pages affectées:** - setup/split-lecoffre-ng-to-five-repos.sh
209 lines
5.5 KiB
Bash
Executable File
209 lines
5.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Split lecoffre_ng (branch test) into five Git repos with history (git subtree split).
|
|
# Does NOT read or write /home/ncantu/code/lecoffre_ng: work is done in a disposable clone
|
|
# from Gitea (or SPLIT_CLONE_URL). See docs/split-lecoffre-repos.md
|
|
#
|
|
# Env:
|
|
# SPLIT_CLONE_URL clone source (default: git@git.4nkweb.com:4nk/lecoffre_ng.git)
|
|
# SOURCE_BRANCH branch to split (default: test)
|
|
# OUTPUT_BASE parent directory for output repos (default: /home/ncantu/code)
|
|
# REPLACE_OUTPUT=1 remove existing lecoffre-io-*_ng dirs before rebuilding
|
|
# PUSH=1 git push -u origin main for each sub-repo after commits
|
|
# MAIN_BRANCH default: main
|
|
#
|
|
# Usage:
|
|
# REPLACE_OUTPUT=1 ./split-lecoffre-ng-to-five-repos.sh
|
|
# REPLACE_OUTPUT=1 PUSH=1 ./split-lecoffre-ng-to-five-repos.sh
|
|
|
|
set -euo pipefail
|
|
|
|
CLONE_URL="${SPLIT_CLONE_URL:-git@git.4nkweb.com:4nk/lecoffre_ng.git}"
|
|
SOURCE_BRANCH="${SOURCE_BRANCH:-test}"
|
|
OUT="${OUTPUT_BASE:-/home/ncantu/code}"
|
|
MAIN="${MAIN_BRANCH:-main}"
|
|
PUSH="${PUSH:-0}"
|
|
REPLACE_OUTPUT="${REPLACE_OUTPUT:-0}"
|
|
|
|
die() {
|
|
echo "ERROR: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
declare -A REMOTES=(
|
|
[docs]="git@git.4nkweb.com:4nk/lecoffre-io-docs_ng.git"
|
|
[deploy]="git@git.4nkweb.com:4nk/lecoffre-io-deploy_ng.git"
|
|
[shared]="git@git.4nkweb.com:4nk/lecoffre-io-shared_ng.git"
|
|
[frontend]="git@git.4nkweb.com:4nk/lecoffre-io-frontend_ng.git"
|
|
[backend]="git@git.4nkweb.com:4nk/lecoffre-io-backend_ng.git"
|
|
)
|
|
|
|
declare -A DIRS=(
|
|
[docs]="lecoffre-io-docs_ng"
|
|
[deploy]="lecoffre-io-deploy_ng"
|
|
[shared]="lecoffre-io-shared_ng"
|
|
[frontend]="lecoffre-io-frontend_ng"
|
|
[backend]="lecoffre-io-backend_ng"
|
|
)
|
|
|
|
declare -A PREFIX=(
|
|
[docs]="docs"
|
|
[deploy]="deploy"
|
|
[shared]="lecoffre-ressources-dev"
|
|
[frontend]="lecoffre-front-main"
|
|
[backend]="lecoffre-back-main"
|
|
)
|
|
|
|
WORK="$(mktemp -d)"
|
|
MONO="${WORK}/mono"
|
|
cleanup() {
|
|
rm -rf "${WORK}"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
echo "Clone: ${CLONE_URL} (branch ${SOURCE_BRANCH})"
|
|
echo "Output: ${OUT}"
|
|
echo "Replace existing: ${REPLACE_OUTPUT}"
|
|
echo "Push: ${PUSH}"
|
|
echo ""
|
|
|
|
git clone --branch "${SOURCE_BRANCH}" --single-branch "${CLONE_URL}" "${MONO}"
|
|
cd "${MONO}"
|
|
git rev-parse --verify "${SOURCE_BRANCH}" >/dev/null || die "Branch ${SOURCE_BRANCH} missing after clone"
|
|
|
|
split_branch() {
|
|
local key="$1"
|
|
local br="split-lecoffre-${key}"
|
|
cd "${MONO}"
|
|
git branch -D "${br}" 2>/dev/null || true
|
|
git subtree split -P "${PREFIX[${key}]}" -b "${br}" "${SOURCE_BRANCH}" >/dev/null
|
|
}
|
|
|
|
# On branch test, docs/ may be absent: ship top-level *.md into the docs repo instead.
|
|
init_docs_repo() {
|
|
local dest="${OUT}/${DIRS[docs]}"
|
|
if [ "${REPLACE_OUTPUT}" = "1" ] && [ -d "${dest}" ]; then
|
|
rm -rf "${dest}"
|
|
fi
|
|
if [ -d "${dest}" ]; then
|
|
die "Destination exists: ${dest} (set REPLACE_OUTPUT=1 to overwrite)"
|
|
fi
|
|
mkdir -p "${dest}"
|
|
cd "${dest}"
|
|
git init -b "${MAIN}"
|
|
shopt -s nullglob
|
|
local f
|
|
for f in "${MONO}"/*.md; do
|
|
cp -a "${f}" "${dest}/$(basename "${f}")"
|
|
done
|
|
shopt -u nullglob
|
|
if [ -z "$(git status --porcelain)" ]; then
|
|
die "No *.md at monorepo root; cannot build docs repo without docs/"
|
|
fi
|
|
git add .
|
|
git commit -m "Import root markdown from lecoffre_ng (branch ${SOURCE_BRANCH})"
|
|
git remote add origin "${REMOTES[docs]}"
|
|
}
|
|
|
|
init_from_split() {
|
|
local key="$1"
|
|
local dest="${OUT}/${DIRS[${key}]}"
|
|
split_branch "${key}"
|
|
local br="split-lecoffre-${key}"
|
|
if [ "${REPLACE_OUTPUT}" = "1" ] && [ -d "${dest}" ]; then
|
|
rm -rf "${dest}"
|
|
fi
|
|
if [ -d "${dest}" ]; then
|
|
die "Destination exists: ${dest} (set REPLACE_OUTPUT=1 to overwrite)"
|
|
fi
|
|
mkdir -p "${dest}"
|
|
cd "${dest}"
|
|
git init -b "${MAIN}"
|
|
git pull "${MONO}" "${br}"
|
|
git remote add origin "${REMOTES[${key}]}"
|
|
cd "${MONO}"
|
|
git branch -D "split-lecoffre-${key}" 2>/dev/null || true
|
|
}
|
|
|
|
add_root_docs() {
|
|
local dest="${OUT}/${DIRS[docs]}"
|
|
local f
|
|
for f in CHANGELOG.md; do
|
|
if [ -f "${MONO}/${f}" ]; then
|
|
cp -a "${MONO}/${f}" "${dest}/${f}"
|
|
fi
|
|
done
|
|
cd "${dest}"
|
|
if git status --porcelain | grep -q .; then
|
|
git add CHANGELOG.md 2>/dev/null || true
|
|
git commit -m "Add CHANGELOG from monorepo root (branch ${SOURCE_BRANCH})"
|
|
fi
|
|
}
|
|
|
|
add_root_deploy() {
|
|
local dest="${OUT}/${DIRS[deploy]}"
|
|
local files=(
|
|
VERSION
|
|
package.json
|
|
package-lock.json
|
|
.dockerignore
|
|
.editorconfig
|
|
.gitattributes
|
|
.gitmessage
|
|
.prettierignore
|
|
README.md
|
|
)
|
|
local f
|
|
for f in "${files[@]}"; do
|
|
if [ -e "${MONO}/${f}" ]; then
|
|
cp -a "${MONO}/${f}" "${dest}/${f}"
|
|
fi
|
|
done
|
|
cd "${dest}"
|
|
if ! git status --porcelain | grep -q .; then
|
|
return 0
|
|
fi
|
|
# git add with a missing path fails the whole command and stages nothing; add only present files.
|
|
for f in "${files[@]}"; do
|
|
if [ -e "${f}" ]; then
|
|
git add "${f}"
|
|
fi
|
|
done
|
|
if git diff --cached --quiet; then
|
|
return 0
|
|
fi
|
|
git commit -m "Add monorepo root metadata for deploy repo (branch ${SOURCE_BRANCH})"
|
|
}
|
|
|
|
do_push() {
|
|
local key="$1"
|
|
local dest="${OUT}/${DIRS[${key}]}"
|
|
cd "${dest}"
|
|
git push -u origin "${MAIN}"
|
|
}
|
|
|
|
echo "=== docs -> ${DIRS[docs]} ==="
|
|
if [ -d "${MONO}/docs" ]; then
|
|
init_from_split "docs"
|
|
add_root_docs
|
|
else
|
|
echo "(no docs/ on ${SOURCE_BRANCH}: using root *.md)"
|
|
init_docs_repo
|
|
fi
|
|
|
|
for key in deploy shared frontend backend; do
|
|
echo "=== ${key} -> ${DIRS[${key}]} (${PREFIX[${key}]}) ==="
|
|
init_from_split "${key}"
|
|
done
|
|
|
|
add_root_deploy
|
|
|
|
if [ "${PUSH}" = "1" ]; then
|
|
for key in docs deploy shared frontend backend; do
|
|
echo "=== push ${key} ==="
|
|
do_push "${key}"
|
|
done
|
|
fi
|
|
|
|
echo ""
|
|
echo "Done. Repos under ${OUT}/lecoffre-io-*_ng (from ${SOURCE_BRANCH}, lecoffre_ng local untouched)."
|