Skip to content

Commit cf30855

Browse files
committed
fixes
1 parent b65c539 commit cf30855

File tree

4 files changed

+285
-63
lines changed

4 files changed

+285
-63
lines changed

scripts/create_proposed_change.py

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Create an Infrahub Proposed Change.
4+
5+
This script creates a proposed change from a branch, which allows for
6+
reviewing and validating changes before merging them to the main branch.
7+
8+
Usage:
9+
python scripts/create_proposed_change.py # Use add-dc3 branch
10+
python scripts/create_proposed_change.py --branch my-branch # Use specific branch
11+
"""
12+
13+
import argparse
14+
import asyncio
15+
import sys
16+
17+
from infrahub_sdk import InfrahubClient
18+
from rich.console import Console
19+
from rich.panel import Panel
20+
from rich.progress import Progress, SpinnerColumn, TextColumn
21+
from rich.table import Table
22+
from rich import box
23+
24+
console = Console()
25+
26+
27+
async def create_proposed_change(branch: str) -> int:
28+
"""
29+
Create a proposed change for the specified branch.
30+
31+
Args:
32+
branch: The branch name to create a proposed change for
33+
34+
Returns:
35+
0 on success, 1 on failure
36+
"""
37+
console.print()
38+
console.print(Panel(
39+
f"[bold bright_magenta]🚀 Creating Infrahub Proposed Change[/bold bright_magenta]\n\n"
40+
f"[bright_cyan]Source Branch:[/bright_cyan] [bold yellow]{branch}[/bold yellow]\n"
41+
f"[bright_cyan]Target Branch:[/bright_cyan] [bold green]main[/bold green]",
42+
border_style="bright_magenta",
43+
box=box.DOUBLE,
44+
title="[bold bright_white]Proposed Change[/bold bright_white]",
45+
title_align="left"
46+
))
47+
48+
# Connect to Infrahub
49+
console.print("\n[cyan]→[/cyan] Connecting to Infrahub...")
50+
51+
try:
52+
client = InfrahubClient()
53+
console.print(f"[green]✓[/green] Connected to Infrahub at [bold]{client.address}[/bold]")
54+
except Exception as e:
55+
console.print(f"[red]✗ Failed to connect to Infrahub:[/red] {e}")
56+
return 1
57+
58+
# Check if branch exists
59+
console.print(f"\n[cyan]→[/cyan] Checking if branch [bold]{branch}[/bold] exists...")
60+
61+
try:
62+
branches = await client.branch.all()
63+
branch_names = [b.name for b in branches]
64+
65+
if branch not in branch_names:
66+
console.print(f"[red]✗ Branch '[bold]{branch}[/bold]' does not exist[/red]")
67+
console.print("\n[yellow]Available branches:[/yellow]")
68+
for b in branch_names[:10]: # Show first 10
69+
console.print(f" • {b}")
70+
return 1
71+
72+
console.print(f"[green]✓[/green] Branch [bold]{branch}[/bold] exists")
73+
except Exception as e:
74+
console.print(f"[red]✗ Error checking branches:[/red] {e}")
75+
return 1
76+
77+
# Create proposed change
78+
console.print("\n[yellow]→[/yellow] Creating proposed change...")
79+
80+
try:
81+
with Progress(
82+
SpinnerColumn(spinner_name="dots12", style="bold bright_yellow"),
83+
TextColumn("[progress.description]{task.description}", style="bold white"),
84+
console=console,
85+
) as progress:
86+
progress.add_task(f"Creating proposed change for '{branch}'", total=None)
87+
88+
# Create the proposed change
89+
proposed_change = await client.create(
90+
kind="CoreProposedChange",
91+
data={
92+
"name": {"value": f"Proposed change for {branch}"},
93+
"description": {"value": f"Automated proposed change created for branch {branch}"},
94+
"source_branch": {"value": branch},
95+
"destination_branch": {"value": "main"},
96+
}
97+
)
98+
99+
await proposed_change.save()
100+
progress.stop()
101+
102+
console.print("[green]✓[/green] Proposed change created successfully!")
103+
104+
# Display proposed change details
105+
console.print()
106+
details_table = Table(
107+
title="✨ Proposed Change Details",
108+
box=box.ROUNDED,
109+
show_header=True,
110+
header_style="bold bright_cyan",
111+
border_style="bright_green"
112+
)
113+
details_table.add_column("Property", style="bright_cyan", no_wrap=True)
114+
details_table.add_column("Value", style="bright_white")
115+
116+
details_table.add_row("ID", f"[bold yellow]{proposed_change.id}[/bold yellow]")
117+
details_table.add_row("Name", f"[bold]{proposed_change.name.value}[/bold]")
118+
details_table.add_row("Source Branch", f"[bold yellow]{branch}[/bold yellow]")
119+
details_table.add_row("Destination Branch", "[bold green]main[/bold green]")
120+
details_table.add_row("State", f"[bold bright_magenta]{proposed_change.state.value if hasattr(proposed_change, 'state') else 'open'}[/bold bright_magenta]")
121+
122+
console.print(details_table)
123+
console.print()
124+
125+
# Show URL
126+
pc_url = f"{client.address}/proposed-changes/{proposed_change.id}"
127+
console.print(Panel(
128+
f"[bold bright_white]View Proposed Change:[/bold bright_white]\n\n"
129+
f"[bright_blue]{pc_url}[/bright_blue]",
130+
border_style="bright_green",
131+
box=box.ROUNDED
132+
))
133+
134+
console.print()
135+
console.print("[bold bright_green]🎉 Success![/bold bright_green] Proposed change is ready for review.\n")
136+
137+
return 0
138+
139+
except Exception as e:
140+
console.print(f"[red]✗ Failed to create proposed change:[/red] {e}")
141+
142+
# Show helpful error information
143+
if "already exists" in str(e).lower():
144+
console.print("\n[yellow]💡 Tip:[/yellow] A proposed change for this branch may already exist.")
145+
console.print(" Check the Infrahub UI or delete the existing proposed change first.")
146+
147+
return 1
148+
149+
150+
async def main(branch: str | None = None) -> int:
151+
"""Main function to create proposed change."""
152+
branch_name = branch if branch else "add-dc3"
153+
return await create_proposed_change(branch_name)
154+
155+
156+
if __name__ == "__main__":
157+
parser = argparse.ArgumentParser(
158+
description="Create an Infrahub Proposed Change from a branch",
159+
formatter_class=argparse.RawDescriptionHelpFormatter,
160+
epilog="""
161+
Examples:
162+
# Create proposed change for add-dc3 branch (default)
163+
python scripts/create_proposed_change.py
164+
165+
# Create proposed change for a specific branch
166+
python scripts/create_proposed_change.py --branch my-feature-branch
167+
168+
# Using invoke
169+
uv run invoke create-pc
170+
uv run invoke create-pc --branch my-feature-branch
171+
"""
172+
)
173+
parser.add_argument(
174+
"--branch",
175+
"-b",
176+
type=str,
177+
help="Branch to create proposed change for (default: add-dc3)",
178+
default=None,
179+
)
180+
args = parser.parse_args()
181+
182+
exit_code = asyncio.run(main(branch=args.branch))
183+
sys.exit(exit_code)

tasks.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import os
44
import sys
5+
import time
56
from pathlib import Path
67
from invoke import task, Context # type: ignore
78
from rich.console import Console
89
from rich.panel import Panel
910
from rich.table import Table
11+
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn
1012
from rich import box
1113

1214
console = Console()
@@ -184,9 +186,46 @@ def demo_dc_arista(context: Context, branch: str = "add-dc3") -> None:
184186
context.run(f"uv run infrahubctl object load objects/dc-arista-s.yml --branch {branch}")
185187

186188
console.print(f"\n[green]✓[/green] DC Arista topology loaded to branch '[bold green]{branch}[/bold green]'")
189+
190+
# Wait for generator to finish creating the data
191+
console.print(f"\n[yellow]→[/yellow] Waiting for generator to complete data creation...")
192+
wait_seconds = 60 # Wait 60 seconds for generator to process
193+
194+
with Progress(
195+
SpinnerColumn(spinner_name="dots12", style="bold bright_yellow"),
196+
TextColumn("[progress.description]{task.description}", style="bold white"),
197+
BarColumn(
198+
bar_width=40,
199+
style="yellow",
200+
complete_style="bright_green",
201+
finished_style="bold bright_green",
202+
pulse_style="bright_yellow"
203+
),
204+
TextColumn("[bold bright_cyan]{task.percentage:>3.0f}%"),
205+
TextColumn("•", style="dim"),
206+
TimeElapsedColumn(),
207+
console=console,
208+
) as progress:
209+
task = progress.add_task("⏳ Generator processing", total=wait_seconds)
210+
for _ in range(wait_seconds):
211+
time.sleep(1)
212+
progress.update(task, advance=1)
213+
214+
console.print(f"[green]✓[/green] Generator processing complete")
215+
216+
# Create proposed change
217+
console.print(f"\n[bright_magenta]→[/bright_magenta] Creating proposed change for branch '[bold]{branch}[/bold]'...")
218+
context.run(f"uv run python scripts/create_proposed_change.py --branch {branch}")
219+
187220
console.print()
188221

189222

223+
@task(optional=["branch"], name="create-pc")
224+
def create_proposed_change(context: Context, branch: str = "add-dc3") -> None:
225+
"""Create an Infrahub Proposed Change for a branch."""
226+
context.run(f"uv run python scripts/create_proposed_change.py --branch {branch}")
227+
228+
190229
@task(optional=["branch", "topology"])
191230
def containerlab(context: Context, branch: str = "add-dc3", topology: str = "DC-3") -> None:
192231
"""Generate configs and deploy containerlab topology."""

0 commit comments

Comments
 (0)