Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions scripts/test_update_cli_nav.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import json
import os
import subprocess
import tempfile


def _write(path, frontmatter):
with open(path, "w", encoding="utf-8") as f:
f.write("---\n" + frontmatter + "\n---\n\nbody\n")


def test_nav_skips_hidden_and_has_no_deprecated_group():
with tempfile.TemporaryDirectory() as d:
docs_dir = os.path.join(d, "client_reference")
os.makedirs(docs_dir)
_write(os.path.join(docs_dir, "overview.md"), 'title: "Overview"')
_write(os.path.join(docs_dir, "output_and_verbosity.md"), 'title: "Output"')
_write(os.path.join(docs_dir, "kosli_attest_generic.md"), 'title: "kosli attest generic"')
_write(os.path.join(docs_dir, "kosli_report_approval.md"),
'title: "kosli report approval"\ntag: "DEPRECATED"')
_write(os.path.join(docs_dir, "kosli_attest_decision.md"),
'title: "kosli attest decision"\ntag: "BETA"\nhidden: true')

nav_path = os.path.join(d, "navigation.json")
with open(nav_path, "w", encoding="utf-8") as f:
json.dump({"tabs": [{"tab": "Reference", "menu": [
{"item": "CLI Reference", "icon": "terminal", "groups": []}]}]}, f)

subprocess.run(
["python", os.path.join(os.path.dirname(__file__), "update-cli-nav.py"),
"--docs-dir", docs_dir, "--nav-file", nav_path],
check=True,
)

with open(nav_path, encoding="utf-8") as f:
nav = json.load(f)
groups = nav["tabs"][0]["menu"][0]["groups"]
all_pages = [p for g in groups for p in g["pages"]]
group_names = [g["group"] for g in groups]

assert "client_reference/kosli_attest_decision" not in all_pages, "hidden page must be skipped"
assert "client_reference/kosli_attest_generic" in all_pages
assert "client_reference/kosli_report_approval" in all_pages, "deprecated page stays in its family group"
assert "Deprecated" not in group_names, "separate Deprecated group must be removed"


if __name__ == "__main__":
test_nav_skips_hidden_and_has_no_deprecated_group()
print("PASS")
61 changes: 17 additions & 44 deletions scripts/update-cli-nav.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@


def get_command_info(filepath):
"""Extract command name and deprecated status from a CLI reference file."""
"""Extract command title and hidden status from a CLI reference file."""
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()

# Parse front matter
match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not match:
return None
Expand All @@ -32,19 +31,9 @@ def get_command_info(filepath):
if not fm or 'title' not in fm:
return None

title = fm['title']
deprecated = fm.get('deprecated', False)

# Check for deprecated warning in body (for converted files that don't have
# the deprecated field but have a Warning about deprecation)
if not deprecated:
body = content[match.end():]
if re.search(r'is deprecated', body[:500], re.IGNORECASE):
deprecated = True

return {
'title': title,
'deprecated': deprecated,
'title': fm['title'],
'hidden': bool(fm.get('hidden', False)),
}


Expand Down Expand Up @@ -96,46 +85,38 @@ def get_command_group(title):


def build_nav_groups(docs_dir):
"""Scan CLI reference files and build navigation groups."""
"""Scan CLI reference files and build navigation groups.

Hidden pages (hidden: true) are excluded from navigation; they remain
reachable by direct URL. Lifecycle tags (BETA/DEPRECATED) render as sidebar
pills automatically from each page's front matter, so there is no separate
Deprecated group.
"""
commands = []

for filename in sorted(os.listdir(docs_dir)):
if not filename.endswith('.md'):
continue
# Skip manually-maintained intro pages; they are inserted into the
# General group below in a fixed order.
if filename in ('overview.md', 'output_and_verbosity.md'):
continue

filepath = os.path.join(docs_dir, filename)
info = get_command_info(filepath)
if info is None:
continue
if info['hidden']:
continue

page_path = f'client_reference/{filename[:-3]}' # Remove .md
page_path = f'client_reference/{filename[:-3]}'
commands.append({
'page': page_path,
'title': info['title'],
'deprecated': info['deprecated'],
'group': get_command_group(info['title']),
})

# Separate active and deprecated commands
active = [c for c in commands if not c['deprecated']]
deprecated = [c for c in commands if c['deprecated']]

# Group active commands
groups_dict = {}
for cmd in active:
group = cmd['group']
if group not in groups_dict:
groups_dict[group] = []
groups_dict[group].append(cmd['page'])

# Build ordered navigation groups.
# 1. General — manually-maintained intro pages, fixed order.
# 2. Top-level commands — auto-generated single-word kosli commands.
# 3. Remaining command families in alphabetical order, prefixed 'kosli '.
for cmd in commands:
groups_dict.setdefault(cmd['group'], []).append(cmd['page'])

nav_groups = [
{
'group': 'General',
Expand All @@ -153,19 +134,11 @@ def build_nav_groups(docs_dir):
})

for group_name in sorted(groups_dict.keys()):
display_name = f'kosli {group_name}'
nav_groups.append({
'group': display_name,
'group': f'kosli {group_name}',
'pages': groups_dict[group_name],
})

# Add deprecated group if there are deprecated commands
if deprecated:
nav_groups.append({
'group': 'Deprecated',
'pages': [c['page'] for c in deprecated],
})

return nav_groups


Expand Down
6 changes: 6 additions & 0 deletions snippets/cli-beta-notice.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Warning>
This is a beta feature. Beta features provide early access to product
functionality. These features may change between releases without warning, or
can be removed in a future release. Please contact us to enable this feature
for your organization.
</Warning>
4 changes: 4 additions & 0 deletions snippets/cli-deprecated-notice.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Warning>
This command is deprecated. Deprecated commands will be removed in a future
release.
</Warning>