feat(dev-env): backport matured dev-env implementation from /etc/nixos
Replace the stub dev-env with the real, working implementation that grew
in the reference machine config — de-identified for the public scaffold.
Nix layer:
- options.nix: full project schema (url/upstream/fork/category/
worktreeRoot/worktrees{branch,path,remote}/isClone/deployFlakeInput),
deploy.targets, github.forkUser, writeDirenvHints. Drops the
forgejo-URL block + deploy-flake auto-derivation (incoherent in a
scaffold that uses explicit per-project urls).
- lib.nix: mkProject + worktreePath/bareRepoPath/projectRemotes,
generalized to the explicit-url model (origin falls back to upstream).
- config.nix: renders /etc/dev-env/{config.sh,projects.json,
tmux-sessions.json}, installs helpers via writeShellScriptBin, loads
shell functions into interactive shells, wires the git pre-commit hook.
Scripts (config-driven, read /etc/dev-env at runtime):
- bootstrap.sh, nav.sh, worktree.sh, pr-helpers.sh, rebase.sh,
status.sh, deploy.sh, regtest.sh, tmux-launch.sh.
- Stripped aiolabs/forgejo/bitspire/lamassu/webapp hardcoding; the
github-fork remote is renamed 'fork' to match git.remotes vocabulary.
- Removes the dev.sh stub (the matured impl uses discrete commands +
shell functions, not a unified 'dev' CLI).
presets/example.nix: a worked, generic project list replacing the
identity-specific aiolabs preset. tests/smoke.nix + flake checks
exercise the schema; 'nix flake check' is green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
773632562e
commit
e38d313db2
17 changed files with 2925 additions and 147 deletions
144
modules/dev-env/scripts/pr-helpers.sh
Normal file
144
modules/dev-env/scripts/pr-helpers.sh
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#!/usr/bin/env bash
|
||||
# dev-env: upstream PR worktree helpers
|
||||
#
|
||||
# Sourced into interactive shells. Provides prb / prc / prl. Each PR gets
|
||||
# a throwaway worktree at ${UPSTREAM_PRS_DIR}/<repo>-<branch> based on
|
||||
# upstream/main (or master), ready to push to the `fork` remote and open
|
||||
# a PR. Reads paths from /etc/dev-env/config.sh.
|
||||
|
||||
_devenv_load_config() {
|
||||
if [[ -r /etc/dev-env/config.sh ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/dev-env/config.sh
|
||||
fi
|
||||
}
|
||||
|
||||
# Create a PR worktree at ${UPSTREAM_PRS_DIR}/<repo>-<branch>.
|
||||
#
|
||||
# Usage: git-pr-branch <repo-name> <branch-name>
|
||||
git-pr-branch() {
|
||||
_devenv_load_config
|
||||
local repo_name="${1:-}"
|
||||
local branch_name="${2:-}"
|
||||
local repos_dir="${REPOS_DIR:-$DEV_ROOT/repos}"
|
||||
local prs_dir="${UPSTREAM_PRS_DIR:-$DEV_ROOT/upstream-prs}"
|
||||
|
||||
if [[ -z "$repo_name" || -z "$branch_name" ]]; then
|
||||
echo "Usage: git-pr-branch <repo-name> <branch-name>"
|
||||
echo "Example: git-pr-branch lnbits fix-invoice-bug"
|
||||
echo ""
|
||||
echo "Creates a worktree at $prs_dir/<repo>-<branch>"
|
||||
echo "based on upstream/main, ready for an upstream PR."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local bare_repo="$repos_dir/${repo_name}.git"
|
||||
local pr_path="$prs_dir/${repo_name}-${branch_name}"
|
||||
|
||||
if [[ ! -d "$bare_repo" ]]; then
|
||||
echo "Repo not found: $bare_repo"
|
||||
echo "Available repos:"
|
||||
ls -1 "$repos_dir"/*.git 2>/dev/null | xargs -n1 basename | sed 's/\.git$//'
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -d "$pr_path" ]]; then
|
||||
echo "PR worktree already exists: $pr_path"
|
||||
echo "To remove it: git-pr-cleanup $repo_name $branch_name"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Fetch upstream
|
||||
echo "Fetching upstream..."
|
||||
git -C "$bare_repo" fetch upstream 2>/dev/null || {
|
||||
echo "No 'upstream' remote on $repo_name — cannot create PR branch"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Determine base branch (main or master)
|
||||
local base_branch="main"
|
||||
git -C "$bare_repo" show-ref --verify --quiet "refs/remotes/upstream/main" \
|
||||
|| base_branch="master"
|
||||
|
||||
echo "Creating branch '$branch_name' from upstream/$base_branch..."
|
||||
git -C "$bare_repo" branch "$branch_name" "upstream/$base_branch" 2>/dev/null \
|
||||
|| git -C "$bare_repo" branch -f "$branch_name" "upstream/$base_branch"
|
||||
|
||||
mkdir -p "$prs_dir"
|
||||
git -C "$bare_repo" worktree add "$pr_path" "$branch_name"
|
||||
|
||||
if ! git -C "$bare_repo" remote get-url fork &>/dev/null; then
|
||||
echo ""
|
||||
echo "Note: 'fork' remote not configured for $repo_name."
|
||||
echo "Add it with:"
|
||||
echo " git -C $bare_repo remote add fork git@github.com:${GITHUB_FORK_USER:-<user>}/${repo_name}.git"
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Ready! Your PR worktree is at:
|
||||
cd $pr_path
|
||||
|
||||
Workflow:
|
||||
1. cd $pr_path
|
||||
2. Edit, test, commit
|
||||
3. git push fork $branch_name
|
||||
4. Open the PR on GitHub (against upstream/$base_branch)
|
||||
5. After merge: git-pr-cleanup $repo_name $branch_name
|
||||
EOF
|
||||
}
|
||||
|
||||
# Remove a PR worktree after the PR is merged (or abandoned).
|
||||
git-pr-cleanup() {
|
||||
_devenv_load_config
|
||||
local repo_name="${1:-}"
|
||||
local branch_name="${2:-}"
|
||||
local repos_dir="${REPOS_DIR:-$DEV_ROOT/repos}"
|
||||
local prs_dir="${UPSTREAM_PRS_DIR:-$DEV_ROOT/upstream-prs}"
|
||||
|
||||
if [[ -z "$repo_name" || -z "$branch_name" ]]; then
|
||||
echo "Usage: git-pr-cleanup <repo-name> <branch-name>"
|
||||
echo ""
|
||||
echo "Active PR worktrees:"
|
||||
ls -1 "$prs_dir" 2>/dev/null || echo " (none)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local bare_repo="$repos_dir/${repo_name}.git"
|
||||
local pr_path="$prs_dir/${repo_name}-${branch_name}"
|
||||
|
||||
[[ -d "$pr_path" ]] || { echo "PR worktree not found: $pr_path"; return 1; }
|
||||
|
||||
echo "Removing worktree: $pr_path"
|
||||
git -C "$bare_repo" worktree remove "$pr_path"
|
||||
|
||||
echo "Deleting branch: $branch_name"
|
||||
git -C "$bare_repo" branch -d "$branch_name" 2>/dev/null \
|
||||
|| git -C "$bare_repo" branch -D "$branch_name"
|
||||
|
||||
echo "Done."
|
||||
}
|
||||
|
||||
# List all active PR worktrees.
|
||||
git-pr-list() {
|
||||
_devenv_load_config
|
||||
local prs_dir="${UPSTREAM_PRS_DIR:-$DEV_ROOT/upstream-prs}"
|
||||
|
||||
echo "=== Active PR Worktrees ==="
|
||||
if [[ -d "$prs_dir" && -n "$(ls -A "$prs_dir" 2>/dev/null)" ]]; then
|
||||
for pr_dir in "$prs_dir"/*; do
|
||||
[[ -d "$pr_dir" ]] || continue
|
||||
local name branch status
|
||||
name="$(basename "$pr_dir")"
|
||||
branch="$(git -C "$pr_dir" branch --show-current 2>/dev/null || echo '?')"
|
||||
status="$(git -C "$pr_dir" status -sb 2>/dev/null | head -1 || echo '?')"
|
||||
printf " %-40s %s %s\n" "$name" "$branch" "$status"
|
||||
done
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
}
|
||||
|
||||
alias prb='git-pr-branch'
|
||||
alias prc='git-pr-cleanup'
|
||||
alias prl='git-pr-list'
|
||||
Reference in a new issue