POC: Generate the glab CLI navigation block from the cobra command tree
## Summary A proof-of-concept implementation of the glab-specific approach explored in #669: Make the **GitLab CLI (glab)** section of `data/en-us/navigation.yaml` *generated* from the `gitlab-org/cli` cobra command tree instead of hand-maintained. Scope is **V1: generator + drift guard + manual (now monthly) splice**. Event-driven cross-repo MR automation (the original "Option 1") is intentionally deferred; see the Stage 3 design sketch: https://gitlab.com/gitlab-org/technical-writing/docs-gitlab-com/-/work_items/671#note_3410109315. Related to #669. ## Status **V1 is shipped.** The generator (gitlab-org/cli!3359) and splicer (!2287) are merged, and the first real drift was caught and fixed (!2366, merged). Two open MRs make the ongoing sync a single command and a recurring chore: !2367 (HTTPS fetch + `make` targets) and team-tasks!472 (monthly task). ## Goals Today the glab nav entries are maintained by hand, in a separate repo from the commands they describe. That creates four recurring problems; this POC targets each: | Problem today | Improvement | |---------------|-------------| | Nav entries are hand-edited and drift from the actual commands (missing `glab` prefixes, title typos, wrong ordering, stale entries for removed commands). | The nav block is **derived** from the cobra command tree, so it is correct by construction. | | Drift is only noticed when someone happens to spot it. | A **drift guard** in `gitlab-org/cli` (lefthook pre-commit/pre-push, plus the `check_docs_update` CI job) regenerates the block and fails on any diff, so drift is caught before merge — locally and in CI. | | A new/renamed/removed command needs a *separate*, easy-to-forget nav MR in `docs-gitlab-com`. | The nav block lives next to the commands as a checked-in, reviewable artifact, regenerated in the same place the command changes. | | Each fix is bespoke and manual. | A small, repeatable `generate → splice` flow that a later step can automate (see Stage 3). | **Out of scope (deliberately):** A general, cross-project nav solution and full automation of the MR. This POC proves the generation + guard pattern for glab first. The broader effort stays in #669. ## How it works The glab nav block is a deterministic projection of the cobra command tree. Two repos, three stages: ### 1. Generate (in `gitlab-org/cli`) `make gen-docs` walks the cobra command tree (the same walk it uses to generate the docs pages) and also writes the glab submenu to a checked-in artifact, `docs/navigation-glab.yaml`. For each available command it emits: - **title**: The full command path, e.g. `glab ci cancel job` - **url**: The matching docs path, e.g. `cli/ci/cancel/job/` - **nesting**: A `submenu` wherever a command has subcommands - **order**: Alphabetical (cobra's default sort) Help, hidden, and deprecated commands are skipped, so the nav and the generated docs pages always agree on what exists. ### 2. Guard (in `gitlab-org/cli`) Nav generation is part of `make gen-docs`, which is already wired into the lefthook **pre-commit** (`check-docs`) and **pre-push** (`check-generated`) checks. They regenerate the artifact and fail on any diff, so it can never silently fall out of sync with the command definitions — the same way generated docs pages are already guarded. > The same check also runs in CI: the `check_docs_update` job runs `make gen-docs` and fails on any `docs/` diff, so a stale artifact can't merge. ### 3. Splice (in `docs-gitlab-com`) `scripts/sync_glab_nav.cjs` reads the generated artifact, re-indents it to fit the navigation tree, and replaces everything between the `# BEGIN glab-cli` / `# END glab-cli` sentinel comments in `data/en-us/navigation.yaml`. It is idempotent and supports `--check` (report drift without writing). By default it **fetches the artifact from `cli`'s `main` over HTTPS**, so no local `cli` checkout is needed (a local path or custom URL can still be passed with `--source`). Two `make` wrappers drive it: `make sync-glab-nav` (re-splice) and `make check-glab-nav` (drift check). Exit codes: `0` in sync, `1` drift, `2` error. > In V1 this splice is run by hand, as a monthly maintenance task (team-tasks!472). Automating *when* it runs (and opening the docs MR) is Stage 3. ## What the first sync corrected Every diff was a correction derived from the command tree: - `check-update` → `glab check-update` (the missing-prefix drift #669 called out) - removed `glab duo ask` (the command is `Hidden` + `Deprecated`) - `glab issues delete` → `glab issue delete` (title typo; URL was already correct) - restored alphabetical ordering in `label`, `mr`, `runner`, and `work-items` ## Merge requests | MR | Project | Status | What | |----|---------|--------|------| | gitlab-org/cli!3359 | `gitlab-org/cli` | **Merged** | Folds nav generation into `cmd/gen-docs`; `make gen-docs` emits the checked-in artifact `docs/navigation-glab.yaml` and is wired into the pre-commit/pre-push and CI drift checks. | | !2287 | `docs-gitlab-com` | **Merged** | `# BEGIN/END glab-cli` sentinels + `scripts/sync_glab_nav.cjs` splicer; first sync of the generated block. | | !2366 | `docs-gitlab-com` | **Merged** | First real drift fix: re-splices two new `glab packages` commands (`delete`, `download`) and corrects the `# BEGIN glab-cli` sentinel comment. | | !2367 | `docs-gitlab-com` | Open | Defaults `--source` to fetch the artifact from `cli`'s `main` over HTTPS (no local checkout); adds `make sync-glab-nav` / `make check-glab-nav` and async error handling. | | gitlab-org/technical-writing/team-tasks!472 | `team-tasks` | Open | Adds the sync to the monthly Technical Writing tasks, folded into the existing "pages not in the global nav" task. Depends on !2367. | **Merge order:** `gitlab-org/cli!3359` → !2287 → !2366 (all done); then !2367 → team-tasks!472. ## Known follow-up Removing a command drops its nav entry but leaves its generated source page orphaned (e.g. `cli/duo/ask/`), because `gen-docs` doesn't prune pages for unavailable commands. Acceptable for now (`duo ask` is deprecated until 2026-07-26; `pages_not_in_nav` is non-blocking). Tracked in gitlab-org/cli#8341.
issue