Skip to content
4 changes: 2 additions & 2 deletions make_release/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ There are two threads you can do in parallel: publishing crates and generating r
:point_right: check that there is the same number of targets compared to [last release](https://github.com/nushell/nushell/releases/latest)

## 3. Publish `nu` to *crates.io*
- [ ] check the order of dependencies with `nushell/nu_scripts/make_release/nu_deps.nu` from the `nushell` repo
- [ ] release the Nushell crates `nushell/nu_scripts/make_release/nu_release.nu` from the `nushell` repo
- [ ] check that any new crates that should not be published have `package.publish = false` set in their `Cargo.toml`
- [ ] release the Nushell crates with `cargo publish --workspace`
- [ ] **Important!** add any new crates to the `github:nushell:publishing` group on crates.io: `cargo owner --add github:nushell:publishing -p <crate>`

> **Note**
Expand Down
4 changes: 2 additions & 2 deletions make_release/notes/create-pr.nu
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export def main [
version: string@"nu-complete version" # the version of the release
date: datetime@"nu-complete date next" # the date of the upcoming release
] {
let repo = ($nu.temp-path | path join (random uuid))
let repo = ($nu.temp-dir | path join (random uuid))
let branch = $"release-notes-($version)"

let blog_path = (
Expand Down Expand Up @@ -71,7 +71,7 @@ by opening PRs against the `release-notes-($version)` branch.
}
}

let temp_file = $nu.temp-path | path join $"(random uuid).md"
let temp_file = $nu.temp-dir | path join $"(random uuid).md"
[
"<!-- WARNING: Changes made to this file are NOT included in the PR -->"
""
Expand Down
44 changes: 34 additions & 10 deletions make_release/notes/generate.nu
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,16 @@ use util.nu *
export def get-release-notes []: record -> record {
mut pr = $in

# Do not throw any warnings for hidden PRs
let has_hide_label = "notes:hide" in $pr.labels.name
let hidden = $SECTIONS | where label == "notes:hide" | only
if $has_hide_label {
$pr = ($pr | add-notice info "appearance only in full changelog")
return ($pr | insert section $hidden)
}

let has_ready_label = "notes:ready" in $pr.labels.name
let has_hall_of_fame_label = "notes:mention" in $pr.labels.name
let sections = $SECTIONS | where label in $pr.labels.name
let hall_of_fame = $SECTIONS | where label == "notes:mention" | only

Expand All @@ -30,7 +39,10 @@ export def get-release-notes []: record -> record {
$pr.body | extract-notes
} else if $has_ready_label {
# If no release notes summary exists but ready label is set, treat as empty
$pr = $pr | add-notice warning "no release notes section but notes:ready label"
if not $has_hall_of_fame_label {
# Hall of fame does not need release notes section necessarily
$pr = $pr | add-notice warning "no release notes section but notes:ready label"
}
""
} else {
return ($pr | add-notice error "no release notes section")
Expand Down Expand Up @@ -144,26 +156,38 @@ export def generate-section []: record<section: string, prs: table> -> string {
let bullet = $prs | where ($it.notes | lines | length) == 1

# Add header
$body ++= [$"## ($section.h2)\n"]
$body ++= [$"## ($section.h2) <JumpToc/>\n"]

# Add multi-line summaries
for note in $multiline.notes {
if ($note | str ends-with "\n") {
$body ++= [$note]
} else {
$body ++= [($note ++ (char nl))]
}
}
$body ++= $multiline | generate-multiline-notes

# Add single-line summaries
if ($multiline | is-not-empty) and ($bullet | is-not-empty) {
$body ++= [$"### ($section.h3)\n"]
$body ++= [$"### ($section.h3) <JumpToc/>\n"]
}
$body ++= $bullet | each {|pr| "* " ++ $pr.notes ++ $" \(($pr | pr-link)\)" }

($body | str join (char nl)) ++ (char nl)
}

def generate-multiline-notes []: table -> list {
$in | each {|pr|
let number = $pr.number
let author = $pr.author.login

let pr_by_tag = $'<PrBy :pr="($number)" user="($author)" />'
let replacer = $"### $1 <JumpToc/> ($pr_by_tag)\n"
let matcher = "^### ([^\n]*)\n"
let updated = ($pr.notes | str replace --all --regex $matcher $replacer)

if ($updated | str ends-with "\n") {
$updated
} else {
$updated ++ (char nl)
}
}
}

# Generate the "Hall of Fame" section of the release notes.
export def generate-hall-of-fame []: table -> string {
where section.label == "notes:mention"
Expand Down
22 changes: 14 additions & 8 deletions make_release/notes/notice.nu
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,21 @@ export def group-notices []: table -> table {
| sort-by {|i| $TYPES | where type == $i.type | only rank } message
}

# Print all of the notices associated with a PR
export def display-notices []: table -> nothing {
group-notices
| each {|e|
# Format all of the notices associated with a PR
export def format-notices []: table -> string {
mut output = ""

mut first = true
for e in ($in | group-notices) {
if $first { $first = false } else { $output += "\n\n" }
let color = $TYPES | where type == $e.type | only color
let number = $e.items | length
print $"($color)($number) PR\(s\) with ($e.message):"
$e.items | each { format-pr | print $"- ($in)" }
print ""
$output += $"($color)($number) PR\(s\) with ($e.message):"
for item in $e.items {
$item | format-pr | $output += $"\n- ($in)"
}
}
print -n (ansi reset)

$output += (ansi reset)
$output
}
12 changes: 6 additions & 6 deletions make_release/notes/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ As part of this release, we also publish a set of optional [plugins](https://www

# Table of contents

<!-- TODO: once all the content below is finished and committed, `use nu_scripts/make_release/release-note/notes *` and run `write-toc $this_file`. -->
<ReleaseToc/>

# Highlights and themes of this release
# Highlights and themes of this release <JumpToc/>

<!-- NOTE: if you wanna write a section about a breaking change, when it's a very important one,
please add the following snippet to have a "warning" banner :)
Expand All @@ -42,18 +42,18 @@ As part of this release, we also publish a set of optional [plugins](https://www
for the list of available *containers*
-->

# Changes
# Changes <JumpToc/>

{changes}

# Notes for plugin developers
# Notes for plugin developers <JumpToc/>

# Hall of fame
# Hall of fame <JumpToc/>

Thanks to all the contributors below for helping us solve issues, improve documentation, refactor code, and more! :pray:

{hall_of_fame}

# Full changelog
# Full changelog <JumpToc/>

{changelog}
111 changes: 3 additions & 108 deletions make_release/notes/tools.nu
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export def release-notes [
| where not author.is_bot
| sort-by mergedAt
| each { get-release-notes }
| tee { display-notices }
| tee { format-notices }
| where {|pr| "error" not-in ($pr.notices?.type? | default []) }
| generate-notes $version
}
Expand All @@ -75,14 +75,14 @@ export def check-prs [
version: string@"nu-complete version" # the version to generate release notes for
--as-table (-t) # output PR checks as a table
]: [
nothing -> nothing,
nothing -> string,
nothing -> table
] {
query-prs --milestone=$version
| where not author.is_bot
| sort-by mergedAt
| each { get-release-notes }
| if $as_table { group-notices } else { display-notices }
| if $as_table { group-notices } else { format-notices }
}

# Format the output of `list-prs` as a markdown table
Expand All @@ -94,108 +94,3 @@ export def pr-table [] {
| to md
| escape-tag
}

const toc = '[[toc](#table-of-contents)]'

# Generate and write the table of contents to a release notes file
export def write-toc [file: path] {
let known_h1s = [
"# Highlights and themes of this release",
"# Changes",
"# Notes for plugin developers",
"# Hall of fame",
"# Full changelog",
]

let lines = open $file | lines | each { str trim -r }

let content_start = 2 + (
$lines
| enumerate
| where item == '# Table of contents'
| first
| get index
)

let data = (
$lines
| slice $content_start..
| wrap line
| insert level {
get line | split chars | take while { $in == '#' } | length
}
| insert nocomment {
# We assume that comments only have one `#`
if ($in.level != 1) {
return true
}
let line = $in.line

# Try to use the whitelist first
if ($known_h1s | any {|| $line =~ $in}) {
return true
}

# We don't know so let's ask
let user = ([Ignore Accept] |
input list $"Is this a code comment or a markdown h1 heading:(char nl)(ansi blue)($line)(ansi reset)(char nl)Choose if we include it in the TOC!")
match $user {
"Accept" => {true}
"Ignore" => {false}
}

}
)

let table_of_contents = (
$data
| where level in 1..=3 and nocomment == true
| each {|header|
let indent = '- ' | fill -w ($header.level * 2) -a right

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 = (
$text
| str downcase
| str kebab-case
)

# remove PR link from header, if applicable
let regex = r#'(?x) # verbose mode
(?<text>.+?) # 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\)"
}
)

let content = $data | each {
if $in.level in 1..=3 and not ($in.line ends-with $toc) and $in.nocomment {
$'($in.line) ($toc)'
} else {
$in.line
}
}

[
...($lines | slice ..<$content_start)
...$table_of_contents
...$content
]
| save -r -f $file
}