1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
# gitctl TODO
Planned features. Each note captures the non-obvious bits so the work does not
re-discover them. Keep the hard rules from CLAUDE.md (stdlib only, single-file
scripts, single-writer repo.desc, idempotent, no em dashes, work on master).
## 1. delete repo -- DONE
`gitctl repo delete <name>` is implemented. It removes a repo from all three
places it lives, the inverse of `repo create`:
- gitolite stanza -> client `remove_stanza` (inverse of `add_stanza`), commit +
push (needs the SSH key / card, like create). PUSHED FIRST so gitolite stops
serving the repo before its bytes move.
- cgit block -> helper verb `delete-repo`, `remove_repo_block` (inverse of
`insert_repo_block`); deletes the repo.url/path/owner block + its spacer
blanks, leaves the section header. Backed up by write_cgitrc_lines, sync after.
- bare repo -> `trash_repo` MOVES it to `TRASH_DIR` (`/var/lib/gitolite3/trash`,
outside REPO_BASE, timestamped name) instead of rm, with a `.trashinfo`
breadcrumb. shutil.move, with a realpath check that the source is one level
under REPO_BASE (defense in depth on top of validate_url).
The helper exposes ONE verb (`delete-repo`) doing cgit-block removal + move +
.trashinfo. Always confirms (the global `-y` is deliberately NOT read by
cmd_delete). Idempotent: a piece already gone is skipped, not an error. Partial
failure (push ok, helper fails, or commit ok but push fails) is resumable by
re-running, same as create. Self-tests: remove_repo_block and remove_stanza both
pinned by an insert/add-then-remove round-trip plus middle/last/missing cases;
trash_repo and do_delete_repo exercised on temp dirs.
FUTURE (not built, YAGNI): a `gc-trash --older-than <days>` prune verb for cron.
The timestamped TRASH_DIR layout already supports it.
## 2. list repos -- DONE
`gitctl repo list` is implemented. It lists EVERY bare repo on disk (the full
set, public and private), not just the cgit-exposed ones, because cgit
auto-discovery is off and private repos are not in cgitrc. Source of truth is
`REPO_BASE/*.git`, not cgitrc; cgitrc membership only tags a repo PUB vs PRIV
and supplies its section. Description comes from each repo's `description` file
(truncated 60). Client renders a table, green public / dim private on a TTY.
Helper verb `list-repos`; primitive `list_repos()` + `repo_sections_from()`
(the latter dedupes the old `find_repo_section`). Self-tests cover both the
cgitrc parse and a temp-FS scan.
Still open from the original plan: extend bash completion to complete repo
NAMES (for `desc` / `delete` / `add-remote`) now that a list verb exists. The
`repo list` action itself is already in completion.
## 3. `-y` / `--yes` flag -- DONE
`-y` / `--yes` is implemented as a GLOBAL flag (on the top-level parser), so it
goes before the subcommand: `gitctl -y repo create ...`. Today the only y/N it
skips is the phase-1 push confirmation in `repo create`; the diff is still
printed and an "auto-confirmed" note shown. It does NOT bypass SSH key auth
(password / smartcard touch), so creation is never fully unattended. Section
auto-create was already silent, so behavior stays consistent.
Hard wall for delete (item 1): `-y` must NEVER be honored by a destructive
delete. The flag help says so, this note records it, and the global -y comment
in the client points at item 1. When delete is built, it reads its own
confirmation and ignores `a.yes`.
Bash completion offers `-y`/`--yes` at the top level and transparently skips a
leading `-y` when resolving group/action.
## Cross-cutting
- Bash completion: once `repo list` exists, complete repo names for `desc`,
`delete`, `add-remote` (like `--section` is completed today). One ssh call,
only when completing a repo-name argument.
- Skill: update both SKILL.md files (repo skills/gitctl + ~/.claude) to mention
delete (and its destructive, confirm-always nature) and `-y`'s real limit.
- Tests: each new helper verb gets self-test coverage (cgit block removal is the
risky one - mirror the insert tests: first/middle/last/missing).
|