diff --git a/make_release/notes/generate.nu b/make_release/notes/generate.nu index ae1e35e1..a77a7b97 100644 --- a/make_release/notes/generate.nu +++ b/make_release/notes/generate.nu @@ -96,10 +96,9 @@ export def extract-notes []: string -> string { # this should already have been checked | if ($in | is-empty) { assert false } else {} | skip 1 # remove header - # extract until next heading - | take until { - $in starts-with "# " or $in starts-with "## " or $in starts-with "---" - } + # extract until end of summary + | reduce -f {code: false, done: false, out: []} (extract_until_end) + | get out | str join (char nl) # remove HTML comments | str replace -amr '' '' @@ -151,12 +150,12 @@ export def generate-section []: record -> string { $body ++= $multiline.notes # Add single-line summaries - if ($multiline | is-not-empty) { + if ($multiline | is-not-empty) and ($bullet | is-not-empty) { $body ++= [$"### ($section.h3)"] } $body ++= $bullet | each {|pr| "* " ++ $pr.notes ++ $" \(($pr | pr-link)\)" } - $body | str join (char nl) + $body | str join $"(char nl)(char nl)" } # Generate the "Hall of Fame" section of the release notes. @@ -178,6 +177,31 @@ export def generate-full-changelog [version: string]: nothing -> string { | pr-table } +# Create closure for `reduce` to extract the whole release notes summary. +def extract_until_end []: nothing -> closure { + let terminators = ["# " "## " "---"] + {|line: string, state: record| + mut state = $state + + if $state.done { return $state } + + # check if we're entering/exiting a code block + # this might be kind of brittle + if $line has "```" { + $state.code = not $state.code + } + + let found_terminator = $terminators | any { $line starts-with $in } + if $found_terminator and not $state.code { + $state.done = true + return $state + } + + $state.out ++= [$line] + $state + } +} + # Get section labels which don't have a corresponding heading (i.e., don't appear in Changes section) def labels-without-heading [] { $SECTIONS | where h2 == null | get label diff --git a/make_release/notes/tools.nu b/make_release/notes/tools.nu index 65848aa8..cf8e613e 100644 --- a/make_release/notes/tools.nu +++ b/make_release/notes/tools.nu @@ -45,11 +45,16 @@ def query-prs [ let query = $query_parts | str join ' ' - (gh --repo $repo pr list --state merged - --limit (inf | into int) - --json author,title,number,mergedAt,url,body,labels - --search $query) - | from json + let results = ( + gh --repo $repo pr list --state merged + --limit (inf | into int) + --json author,title,number,mergedAt,url,body,labels + --search $query + | from json + ) + + assert ($results | is-not-empty) "Query returned no results" + $results } # Generate the release notes for the specified version. @@ -148,11 +153,9 @@ export def write-toc [file: path] { | each {|header| let indent = '- ' | fill -w ($header.level * 2) -a right - let text = $header.line | str trim -l -c '#' | str trim -l - let text = if $text ends-with $toc { - $text | str substring ..<(-1 * ($toc | str length)) | str trim -r - } else { - $text + mut text = $header.line | str trim -l -c '#' | str trim -l + if $text ends-with $toc { + $text = $text | str substring ..<(-1 * ($toc | str length)) | str trim -r } let link = ( @@ -161,6 +164,22 @@ export def write-toc [file: path] { | str kebab-case ) + # remove PR link from header, if applicable + let regex = r#'(?x) # verbose mode + (?.+?) # the actual header text + \s+ + \( # start PR link + \[\#\d+\] # PR number component + (?: # optional non-capturing group + \(.+?\) # link to PR + )? # end group + \) + '# + let prlink = $text | parse -r $regex + if ($prlink | is-not-empty) { + $text = $prlink.0.text + } + $"($indent)[_($text)_]\(#($link)-toc\)" } )