@@ -96,7 +96,7 @@ def _parse_github_url(url: str) -> tuple[str | None, str | None]:
9696
9797
9898def _read_and_parse_description () -> tuple [str , str ]:
99- """Read DESCRIPTION.md and parse title and body.
99+ """Read DESCRIPTION.md and parse title and body (expects plain format) .
100100
101101 Returns:
102102 (title, body) tuple
@@ -105,31 +105,13 @@ def _read_and_parse_description() -> tuple[str, str]:
105105 err ("Error: DESCRIPTION.md not found. Run 'ghpr init' first" )
106106 exit (1 )
107107
108- with open ('DESCRIPTION.md' , 'r' ) as f :
109- content = f .read ()
110-
111- lines = content .split ('\n ' )
112- if not lines :
113- err ("Error: DESCRIPTION.md is empty" )
108+ # Read plain format (pre-creation)
109+ title , body = read_description_file (expect_plain = True )
110+ if not title :
111+ err ("Error: Could not parse DESCRIPTION.md" )
114112 exit (1 )
115113
116- # Parse title from first line
117- first_line = lines [0 ].strip ()
118- if first_line .startswith ('#' ):
119- title = first_line .lstrip ('#' ).strip ()
120- # Remove any [owner/repo#NUM] prefix if present
121- title = re .sub (r'^\[?[^/\]]+/[^#\]]+#\d+]?\s*' , '' , title )
122- title = re .sub (r'^[^/]+/[^#]+#\w+\s+' , '' , title ) # Handle owner/repo#NUMBER format
123- else :
124- title = first_line
125-
126- # Get body (rest of the file)
127- body_lines = lines [1 :]
128- while body_lines and not body_lines [0 ].strip ():
129- body_lines = body_lines [1 :]
130- body = '\n ' .join (body_lines ).strip ()
131-
132- return title , body
114+ return title , body or ''
133115
134116
135117def _finalize_created_item (
@@ -152,13 +134,13 @@ def _finalize_created_item(
152134 new_filename = f'{ repo } #{ number } .md'
153135 new_file = Path (new_filename )
154136
155- # Read title and body from DESCRIPTION.md
156- title , body = read_description_file ()
137+ # Read title and body from DESCRIPTION.md (plain format)
138+ title , body = read_description_file (expect_plain = True )
157139 if not title :
158140 err ("Warning: Could not parse title from DESCRIPTION.md" )
159141 return
160142
161- # Write using helper with proper link reference format
143+ # Write using helper with link- reference format
162144 write_description_with_link_ref (
163145 new_file ,
164146 owner ,
@@ -255,21 +237,57 @@ def init(
255237 proc .run ('git' , 'config' , 'pr.base' , base , log = None )
256238 err (f"Base branch: { base } " )
257239
258- # Create initial DESCRIPTION.md
240+ # Create initial DESCRIPTION.md (plain format - link-reference added after PR creation)
259241 with open ('DESCRIPTION.md' , 'w' ) as f :
260- if repo :
261- f .write (f"# { repo } #NUMBER Title\n \n " )
262- else :
263- f .write ("# owner/repo#NUMBER Title\n \n " )
242+ f .write ("# Title\n \n " )
264243 f .write ("Description of the PR...\n " )
265244
266245 err ("Created DESCRIPTION.md template" )
267246
247+ # Create initial commit
248+ proc .run ('git' , 'add' , 'DESCRIPTION.md' , log = None )
249+ proc .run ('git' , 'commit' , '-m' , 'Initial PR draft' , log = None )
250+ err ("Created initial commit" )
251+
252+ # Create and configure gist mirror
253+ from ..gist import create_gist
254+ try :
255+ # Create gist (public by default, matching typical repo visibility)
256+ description = f'Draft PR for { owner } /{ repo_name } ' if owner and repo_name else 'Draft PR'
257+ gist_id = create_gist (
258+ file_path = 'DESCRIPTION.md' ,
259+ description = description ,
260+ is_public = True ,
261+ store_id = True # Automatically stores in git config pr.gist
262+ )
263+
264+ if gist_id :
265+ # Add gist as remote
266+ gist_url = f'git@gist.github.com:{ gist_id } .git'
267+ proc .run ('git' , 'remote' , 'add' , 'g' , gist_url , log = None )
268+ proc .run ('git' , 'config' , 'pr.gist-remote' , 'g' , log = None )
269+ err (f"Created gist: https://gist.github.com/{ gist_id } " )
270+ err ("Added remote 'g' for gist mirror" )
271+
272+ # Fetch and set up tracking
273+ proc .run ('git' , 'fetch' , 'g' , log = None )
274+ proc .run ('git' , 'branch' , '--set-upstream-to=g/main' , 'main' , log = None )
275+ err ("Configured main branch to track g/main" )
276+
277+ # Push initial commit to gist (with history)
278+ proc .run ('git' , 'push' , '-f' , 'g' , 'main' , log = None )
279+ err ("Pushed initial commit to gist" )
280+ except Exception as e :
281+ err (f"Warning: Could not create gist mirror: { e } " )
282+ err ("You can add it later with 'ghpr push -g'" )
283+
284+ # End of cd(new_dir) context - we're done working in gh/new/
285+
268286 err ("" )
269287 err ("Next steps:" )
270288 err (" cd gh/new" )
271289 err (" vim DESCRIPTION.md # Edit title and description" )
272- err (" git add DESCRIPTION.md && git commit -m 'Draft PR'" )
290+ err (" git commit -am 'Update PR description '" )
273291 err (" ghpr create" )
274292
275293
@@ -279,25 +297,31 @@ def create(
279297 draft : bool ,
280298 issue : bool ,
281299 repo : str | None ,
282- web : bool ,
300+ yes : int ,
283301 dry_run : bool ,
284302) -> None :
285303 """Create a new PR or Issue from the current draft."""
286304 if issue :
287- create_new_issue (repo , web , dry_run )
305+ create_new_issue (repo , yes , dry_run )
288306 else :
289- create_new_pr (head , base , draft , repo , web , dry_run )
307+ create_new_pr (head , base , draft , repo , yes , dry_run )
290308
291309
292310def create_new_pr (
293311 head : str | None ,
294312 base : str | None ,
295313 draft : bool ,
296314 repo_arg : str | None ,
297- web : bool ,
315+ yes : int ,
298316 dry_run : bool ,
299317) -> None :
300- """Create a new PR from DESCRIPTION.md."""
318+ """Create a new PR from DESCRIPTION.md.
319+
320+ Args:
321+ yes: 0 = open web editor during creation (default)
322+ 1 = skip prompt, create then open result
323+ 2+ = skip all, create silently
324+ """
301325 # Read and parse DESCRIPTION.md
302326 title , body = _read_and_parse_description ()
303327
@@ -343,28 +367,41 @@ def create_new_pr(
343367
344368 # Get head branch - try to auto-detect from parent repo
345369 if not head :
370+ # Go up one level (to get out of gh/new/) and find the git repo root
346371 parent_dir = Path ('..' ).resolve ()
347- if exists (join (parent_dir , '.git' )):
348- try :
349- with cd (parent_dir ):
350- # Use branch resolution
372+ try :
373+ with cd (parent_dir ):
374+ # Find the git repo root
375+ repo_root = proc .line ('git' , 'rev-parse' , '--show-toplevel' , err_ok = True , log = None )
376+ if not repo_root :
377+ err ("Error: Could not detect head branch. Specify --head explicitly" )
378+ exit (1 )
379+
380+ with cd (repo_root ):
381+ # Use branch resolution to get remote tracking branch
351382 ref_name , remote_ref = resolve_remote_ref (verbose = False )
352- if ref_name :
383+ if remote_ref :
384+ # Extract branch name from remote_ref (e.g., "m/rw/ws3" -> "rw/ws3")
385+ # GitHub expects just the branch name without the remote prefix
386+ if '/' in remote_ref :
387+ head = '/' .join (remote_ref .split ('/' )[1 :])
388+ else :
389+ head = remote_ref
390+ err (f"Auto-detected head branch from remote: { head } " )
391+ elif ref_name :
392+ # Fallback to local branch name if no remote tracking
353393 head = ref_name
354- err (f"Auto-detected head branch: { head } " )
394+ err (f"Auto-detected head branch (local) : { head } " )
355395
356396 if not head :
357397 # Fallback to current branch
358398 head = proc .line ('git' , 'rev-parse' , '--abbrev-ref' , 'HEAD' , log = None )
359399 if head == 'HEAD' :
360400 err ("Error: Parent repo is in detached HEAD state. Specify --head explicitly" )
361401 exit (1 )
362- except Exception as e :
363- err (f"Error detecting head branch: { e } " )
364- err ("Specify --head explicitly" )
365- exit (1 )
366- else :
367- err ("Error: Could not detect head branch. Specify --head explicitly" )
402+ except Exception as e :
403+ err (f"Error detecting head branch: { e } " )
404+ err ("Specify --head explicitly" )
368405 exit (1 )
369406
370407 # Create the PR
@@ -392,12 +429,60 @@ def create_new_pr(
392429 if draft :
393430 cmd .append ('--draft' )
394431
395- if web :
432+ # Determine opening behavior based on yes count
433+ use_web_editor = (yes == 0 )
434+ open_after = (yes == 1 )
435+
436+ if use_web_editor :
396437 cmd .append ('--web' )
397438
398439 try :
399440 output = proc .text (* cmd , log = None ).strip ()
400- if not web :
441+
442+ if use_web_editor :
443+ # Web editor mode: wait for user to finish editing in browser
444+ err ("Opened PR in web editor" )
445+ err ("Press Enter when you've finished creating the PR in the browser..." )
446+ input ()
447+
448+ # Query GitHub to find the newly created PR
449+ err ("Fetching PR information..." )
450+ try :
451+ # List PRs for the head branch
452+ prs = proc .json ('gh' , 'pr' , 'list' , '-R' , f'{ owner } /{ repo } ' , '--head' , head , '--json' , 'number,url' , log = None )
453+ if prs and len (prs ) > 0 :
454+ pr_number = str (prs [0 ]['number' ])
455+ pr_url = prs [0 ]['url' ]
456+
457+ # Store PR info in git config
458+ proc .run ('git' , 'config' , 'pr.number' , pr_number , log = None )
459+ proc .run ('git' , 'config' , 'pr.url' , pr_url , log = None )
460+ err (f"Found PR #{ pr_number } : { pr_url } " )
461+
462+ # Check for gist remote and store its ID if found
463+ try :
464+ remotes = proc .lines ('git' , 'remote' , '-v' , log = None )
465+ for remote_line in remotes :
466+ if 'gist.github.com' in remote_line :
467+ gist_match = GIST_ID_PATTERN .search (remote_line )
468+ if gist_match :
469+ gist_id = gist_match .group (1 )
470+ proc .run ('git' , 'config' , 'pr.gist' , gist_id , log = None )
471+ err (f"Detected and stored gist ID: { gist_id } " )
472+ break
473+ except Exception :
474+ pass
475+
476+ # Finalize: rename file, commit, rename directory
477+ _finalize_created_item (owner , repo , pr_number , pr_url , 'pr' )
478+ else :
479+ err ("Warning: Could not find newly created PR" )
480+ err ("You may need to run 'ghpr pull' to sync with GitHub" )
481+ except Exception as e :
482+ err (f"Error: Could not fetch PR information: { e } " )
483+ raise
484+ else :
485+ # API mode: PR number returned immediately
401486 # Extract PR number from URL
402487 match = re .search (r'/pull/(\d+)' , output )
403488 if match :
@@ -408,6 +493,10 @@ def create_new_pr(
408493 err (f"Created PR #{ pr_number } : { output } " )
409494 err ("PR info stored in git config" )
410495
496+ # Open PR in browser if requested
497+ if open_after :
498+ proc .run ('gh' , 'pr' , 'view' , pr_number , '--web' , '-R' , f'{ owner } /{ repo } ' , log = None )
499+
411500 # Check for gist remote and store its ID if found
412501 try :
413502 remotes = proc .lines ('git' , 'remote' , '-v' , log = None )
@@ -435,10 +524,16 @@ def create_new_pr(
435524
436525def create_new_issue (
437526 repo_arg : str | None ,
438- web : bool ,
527+ yes : int ,
439528 dry_run : bool ,
440529) -> None :
441- """Create a new Issue from DESCRIPTION.md."""
530+ """Create a new Issue from DESCRIPTION.md.
531+
532+ Args:
533+ yes: 0 = open web editor during creation (default)
534+ 1 = skip prompt, create then open result
535+ 2+ = skip all, create silently
536+ """
442537 # Read and parse DESCRIPTION.md
443538 title , body = _read_and_parse_description ()
444539
@@ -461,12 +556,47 @@ def create_new_issue(
461556 '--title' , title ,
462557 '--body' , body ]
463558
464- if web :
559+ # Determine opening behavior based on yes count
560+ use_web_editor = (yes == 0 )
561+ open_after = (yes == 1 )
562+
563+ if use_web_editor :
465564 cmd .append ('--web' )
466565
467566 try :
468567 output = proc .text (* cmd , log = None ).strip ()
469- if not web :
568+
569+ if use_web_editor :
570+ # Web editor mode: wait for user to finish editing in browser
571+ err ("Opened issue in web editor" )
572+ err ("Press Enter when you've finished creating the issue in the browser..." )
573+ input ()
574+
575+ # Query GitHub to find the newly created issue
576+ err ("Fetching issue information..." )
577+ try :
578+ # List recent issues in the repo and find the newest one
579+ issues = proc .json ('gh' , 'issue' , 'list' , '-R' , f'{ owner } /{ repo } ' , '--json' , 'number,url' , '--limit' , '1' , log = None )
580+ if issues and len (issues ) > 0 :
581+ issue_number = str (issues [0 ]['number' ])
582+ issue_url = issues [0 ]['url' ]
583+
584+ # Store issue info in git config
585+ proc .run ('git' , 'config' , 'pr.number' , issue_number , log = None )
586+ proc .run ('git' , 'config' , 'pr.type' , 'issue' , log = None )
587+ proc .run ('git' , 'config' , 'pr.url' , issue_url , log = None )
588+ err (f"Found issue #{ issue_number } : { issue_url } " )
589+
590+ # Finalize: rename file, commit, rename directory
591+ _finalize_created_item (owner , repo , issue_number , issue_url , 'issue' )
592+ else :
593+ err ("Warning: Could not find newly created issue" )
594+ err ("You may need to run 'ghpr pull' to sync with GitHub" )
595+ except Exception as e :
596+ err (f"Error: Could not fetch issue information: { e } " )
597+ raise
598+ else :
599+ # API mode: issue number returned immediately
470600 # Extract issue number from URL
471601 match = re .search (r'/issues/(\d+)' , output )
472602 if match :
@@ -478,10 +608,14 @@ def create_new_issue(
478608 err (f"Created issue #{ issue_number } : { output } " )
479609 err ("Issue info stored in git config" )
480610
611+ # Open issue in browser if requested
612+ if open_after :
613+ proc .run ('gh' , 'issue' , 'view' , issue_number , '--web' , '-R' , f'{ owner } /{ repo } ' , log = None )
614+
481615 # Finalize: rename file, commit, rename directory
482616 _finalize_created_item (owner , repo , issue_number , output , 'issue' )
483- else :
484- err (f"Created issue: { output } " )
617+ else :
618+ err (f"Created issue: { output } " )
485619 except Exception as e :
486620 err (f"Error creating issue: { e } " )
487621 exit (1 )
@@ -506,7 +640,7 @@ def register(cli):
506640 flag ('-i' , '--issue' , help = 'Create an issue instead of a PR' )(
507641 flag ('-n' , '--dry-run' , help = 'Show what would be done without creating' )(
508642 opt ('-r' , '--repo' , help = 'Repository (owner/repo format, default: auto-detect)' )(
509- flag ('-w ' , '--web ' , help = 'Open in web browser after creating ' )(
643+ opt ('-y ' , '--yes ' , count = True , default = 0 , help = 'Skip prompt: once = create then view, twice = create silently (default: open web editor during creation) ' )(
510644 create
511645 )
512646 )
0 commit comments