feat(binder): improve user prompts with clear defaults and options

- Standardize all prompts to show available options with explanations
- Add clear default values in format [default: X]
- Enhance release notes review with preview and multiple options
- Improve branch switching, compression, and publishing prompts
- Add color-coded option descriptions for better UX
- Handle empty input gracefully by using specified defaults

All prompts now provide clear guidance on what each option does
and what the recommended choice is.
This commit is contained in:
Vijay Janapa Reddi
2025-08-05 19:48:06 -04:00
parent f02296ff99
commit 562e632f2e

165
binder
View File

@@ -1092,15 +1092,25 @@ class BookBinder:
console.print(f"[blue] Current branch: {current_branch}[/blue]")
console.print("[blue] Publishing requires being on main branch with latest dev changes[/blue]")
console.print()
console.print("[yellow]Move to main branch and pull in dev changes? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Switch to main and merge dev changes (recommended)")
console.print("[red] n/no[/red] - Cancel publishing (default)")
console.print("[yellow]Move to main branch and pull in dev changes? [y/N] [default: N]: [/yellow]", end="")
choice = input().strip().lower()
if not choice:
choice = 'n'
if choice in ['y', 'yes']:
# Step 1: Handle uncommitted changes
if changes_count > 0:
console.print("[yellow]⚠️ You have uncommitted changes on current branch[/yellow]")
console.print("[yellow]Commit current changes before switching? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Commit changes before switching")
console.print("[red] n/no[/red] - Cancel (cannot switch with uncommitted changes) [default]")
console.print("[yellow]Commit current changes before switching? [y/N] [default: N]: [/yellow]", end="")
commit_choice = input().strip().lower()
if not commit_choice:
commit_choice = 'n'
if commit_choice in ['y', 'yes']:
console.print("[white]Commit message [fix: update before switching to main]: [/white]", end="")
commit_msg = input().strip() or "fix: update before switching to main"
@@ -1143,8 +1153,13 @@ class BookBinder:
return False
elif changes_count > 0:
console.print("[yellow]⚠️ You have uncommitted changes[/yellow]")
console.print("[yellow]Commit changes before continuing? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Commit and push changes before publishing")
console.print("[red] n/no[/red] - Cancel publishing (cannot continue with uncommitted changes) [default]")
console.print("[yellow]Commit changes before continuing? [y/N] [default: N]: [/yellow]", end="")
choice = input().strip().lower()
if not choice:
choice = 'n'
if choice in ['y', 'yes']:
console.print("[white]Commit message [fix: update before publishing]: [/white]", end="")
commit_msg = input().strip() or "fix: update before publishing"
@@ -1183,8 +1198,10 @@ class BookBinder:
console.print()
console.print("[white]What type of changes are you publishing?[/white]")
console.print("[white]Select option [1-4] [2 for minor]: [/white]", end="")
choice = input().strip() or "2"
console.print("[white]Select option [1-4] [default: 2 for minor]: [/white]", end="")
choice = input().strip()
if not choice:
choice = "2"
release_types = ["patch", "minor", "major", "custom"]
try:
@@ -1217,8 +1234,13 @@ class BookBinder:
console.print("[dim] This will delete the existing tag from both local and remote repositories[/dim]")
console.print("[dim] and recreate it with the new release[/dim]")
console.print()
console.print("[yellow]Delete existing tag and recreate? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Delete existing tag and recreate with new release")
console.print("[red] n/no[/red] - Cancel publishing (keep existing tag) [default]")
console.print("[yellow]Delete existing tag and recreate? [y/N] [default: N]: [/yellow]", end="")
choice = input().strip().lower()
if not choice:
choice = 'n'
if choice in ['y', 'yes']:
console.print("[purple]🔄 Deleting existing tag...[/purple]")
self._delete_version(new_version)
@@ -1232,8 +1254,10 @@ class BookBinder:
console.print()
console.print("[bold white]📝 Release Description:[/bold white]")
console.print("[dim] This will appear in the GitHub release and help users understand what changed[/dim]")
console.print("[white]Enter description [Content updates and improvements]: [/white]", end="")
description = input().strip() or "Content updates and improvements"
console.print("[white]Enter description [default: Content updates and improvements]: [/white]", end="")
description = input().strip()
if not description:
description = "Content updates and improvements"
return {
'version': new_version,
@@ -1269,8 +1293,13 @@ class BookBinder:
console.print("[green] • Create GitHub release with PDF (optional)[/green]")
console.print()
console.print("[yellow]Proceed with publishing? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Proceed with publishing to production")
console.print("[red] n/no[/red] - Cancel publishing [default]")
console.print("[yellow]Proceed with publishing? [y/N] [default: N]: [/yellow]", end="")
choice = input().strip().lower()
if not choice:
choice = 'n'
if choice in ['y', 'yes']:
return True
@@ -1300,8 +1329,13 @@ class BookBinder:
console.print()
console.print("[white]Reuse existing builds? This will skip the build phase and save time.[/white]")
console.print("[yellow]Reuse existing builds? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Use existing builds (faster)")
console.print("[blue] n/no[/blue] - Rebuild from scratch (slower, fresher) [default]")
console.print("[yellow]Reuse existing builds? [y/N] [default: N]: [/yellow]", end="")
choice = input().strip().lower()
if not choice:
choice = 'n'
if choice in ['y', 'yes']:
console.print("[blue]✅ Using existing builds[/blue]")
@@ -1315,8 +1349,13 @@ class BookBinder:
console.print("[dim] Uses Ghostscript with /ebook settings to reduce file size[/dim]")
console.print("[dim] Good balance between size and quality for web distribution[/dim]")
console.print(f"[blue] Current PDF size: {size_mb:.1f} MB[/blue]")
console.print("[yellow]Compress PDF? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Compress PDF for smaller file size (recommended)")
console.print("[blue] n/no[/blue] - Keep original PDF without compression [default]")
console.print("[yellow]Compress PDF? [y/N] [default: N]: [/yellow]", end="")
compress_choice = input().strip().lower()
if not compress_choice:
compress_choice = 'n'
if compress_choice in ['y', 'yes']:
console.print("[purple]🔄 Compressing PDF...[/purple]")
if not self._compress_pdf():
@@ -1598,8 +1637,13 @@ class BookBinder:
console.print()
console.print("[bold white]🌐 GitHub Pages Deployment:[/bold white]")
console.print("[dim] Deploy the website to your public GitHub Pages (recommended)[/dim]")
console.print("[yellow]Deploy to GitHub Pages? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Deploy website to GitHub Pages (recommended)")
console.print("[blue] n/no[/blue] - Skip GitHub Pages deployment [default]")
console.print("[yellow]Deploy to GitHub Pages? [y/N] [default: N]: [/yellow]", end="")
choice = input().strip().lower()
if not choice:
choice = 'n'
if choice in ['y', 'yes']:
console.print("[purple]🔄 Deploying to GitHub Pages...[/purple]")
if self._deploy_to_github_pages():
@@ -1613,8 +1657,13 @@ class BookBinder:
console.print()
console.print("[bold white]📦 GitHub Release Creation:[/bold white]")
console.print("[dim] Create a public release with downloadable PDF and AI-generated release notes[/dim]")
console.print("[yellow]Create GitHub release? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Create public release with downloadable PDF (recommended)")
console.print("[blue] n/no[/blue] - Skip GitHub release creation [default]")
console.print("[yellow]Create GitHub release? [y/N] [default: N]: [/yellow]", end="")
choice = input().strip().lower()
if not choice:
choice = 'n'
release_created = False
if choice in ['y', 'yes']:
pdf_path = self.build_dir / "pdf" / "Machine-Learning-Systems.pdf"
@@ -1632,8 +1681,13 @@ class BookBinder:
console.print()
console.print("[bold white]🌐 GitHub Pages PDF Update:[/bold white]")
console.print("[dim] Update the PDF in mlsysbook.ai/assets/ to match the release[/dim]")
console.print("[yellow]Update GitHub Pages PDF? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Update PDF on website (mlsysbook.ai/assets/)")
console.print("[blue] n/no[/blue] - Keep existing PDF on website [default]")
console.print("[yellow]Update GitHub Pages PDF? [y/N] [default: N]: [/yellow]", end="")
choice = input().strip().lower()
if not choice:
choice = 'n'
if choice in ['y', 'yes']:
console.print("[purple]🔄 Updating GitHub Pages PDF...[/purple]")
if self._update_github_pages_pdf(pdf_path):
@@ -1711,12 +1765,30 @@ class BookBinder:
console.print(f"[green]✅ Release notes generated and saved to: {release_notes_file}[/green]")
console.print()
console.print("[bold white]📝 Review and Edit Release Notes:[/bold white]")
console.print(f"[blue] File: {release_notes_file}[/blue]")
console.print("[dim] You can now review and edit the release notes in your favorite editor[/dim]")
# Show a preview of the generated release notes
console.print("[bold white]📝 Generated Release Notes Preview:[/bold white]")
preview_lines = release_notes.split('\n')[:15] # Show first 15 lines
preview_panel = Panel(
'\n'.join(preview_lines) + ('\n...' if len(release_notes.split('\n')) > 15 else ''),
title="Release Notes Preview",
border_style="blue",
padding=(1, 2)
)
console.print(preview_panel)
console.print("[bold white]📝 Review and Edit Options:[/bold white]")
console.print(f"[blue] 📄 File location: {release_notes_file}[/blue]")
console.print("[dim] You can review and edit the release notes before publishing[/dim]")
console.print()
console.print("[yellow]Open file in default editor? [y/N]: [/yellow]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Open file in default editor for review/editing")
console.print("[blue] n/no[/blue] - Use release notes as-is [default]")
console.print("[cyan] s/show[/cyan] - Show full release notes content in terminal")
console.print("[yellow]Open file in default editor? [y/n/s] [default: n]: [/yellow]", end="")
open_choice = input().strip().lower()
if not open_choice:
open_choice = 'n'
if open_choice in ['y', 'yes']:
try:
import subprocess
@@ -1732,10 +1804,54 @@ class BookBinder:
except Exception as e:
console.print(f"[yellow]⚠️ Could not open file automatically: {e}[/yellow]")
console.print(f"[blue]💡 Please open manually: {release_notes_file}[/blue]")
console.print()
console.print("[yellow]Press Enter to continue after reviewing/editing the release notes...[/yellow]", end="")
input()
console.print()
console.print("[yellow]Press Enter to continue after reviewing/editing the release notes...[/yellow]", end="")
input()
elif open_choice in ['s', 'show']:
# Show full release notes in terminal
console.print()
full_notes_panel = Panel(
release_notes,
title="Full Release Notes Content",
border_style="cyan",
padding=(1, 2)
)
console.print(full_notes_panel)
console.print()
console.print("[bold white]Options:[/bold white]")
console.print("[green] e/edit[/green] - Open in editor for modifications")
console.print("[blue] c/continue[/blue] - Use as-is and continue [default]")
console.print("[yellow]What would you like to do? [e/c] [default: c]: [/yellow]", end="")
action = input().strip().lower()
if not action:
action = 'c'
if action in ['e', 'edit']:
try:
import subprocess
import platform
system = platform.system().lower()
if system == "darwin": # macOS
subprocess.run(['open', str(release_notes_file)])
elif system == "linux":
subprocess.run(['xdg-open', str(release_notes_file)])
elif system == "windows":
subprocess.run(['start', str(release_notes_file)], shell=True)
console.print("[green]✅ File opened in default editor[/green]")
console.print()
console.print("[yellow]Press Enter to continue after editing...[/yellow]", end="")
input()
except Exception as e:
console.print(f"[yellow]⚠️ Could not open file automatically: {e}[/yellow]")
console.print(f"[blue]💡 Please open manually: {release_notes_file}[/blue]")
else:
console.print("[blue]✅ Using release notes as-is[/blue]")
else:
console.print("[blue]✅ Using generated release notes as-is[/blue]")
# Read the potentially edited release notes
try:
@@ -2724,7 +2840,10 @@ Please format as:
console.print(f" Email: {current_email}")
console.print("\n[blue]Would you like to update your Git configuration?[/blue]")
console.print("[bold]Update Git config? (y/N) [N]: [/bold]", end="")
console.print("[bold white]Options:[/bold white]")
console.print("[green] y/yes[/green] - Update Git configuration")
console.print("[blue] n/no[/blue] - Keep current configuration [default]")
console.print("[bold]Update Git config? [y/N] [default: N]: [/bold]", end="")
update_choice = input().strip().lower()
if not update_choice:
update_choice = 'n'