diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d8136f2ad04..877bc2b1e62 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,3 @@ - - ## Summary * what changed and how? * why are we changing it? @@ -14,7 +10,8 @@ than 72 characters --> Fixes full_issue_url --- - + ## Notes for Reviewers * leave additional context for reviewers diff --git a/.github/workflows/slash-command-merge.yml b/.github/workflows/slash-command-merge.yml index b6f96911569..b4a425a7669 100644 --- a/.github/workflows/slash-command-merge.yml +++ b/.github/workflows/slash-command-merge.yml @@ -15,6 +15,10 @@ jobs: name: Trim description and merge runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + tools/ci_format_pr_description.js - id: pr-data name: Get PR data and trim PR body uses: actions/github-script@v6 @@ -51,8 +55,10 @@ jobs: return; } + const formatPR = require('../../tools/ci_format_pr_description.js'); + let [ body, body_tail ] = pr_info.body.split(/^---\s*$/m, 2); - body = body.replace(/<\!--.*?-->/s, ""); + body = formatPR.formatPRdescription(body, 72); body = body.trimEnd(); body_tail = body_tail?.trimEnd() || ''; // Only runs when the PR is still open and is not staged for merging. diff --git a/tests/tools/tci_format_pr_description.nim b/tests/tools/tci_format_pr_description.nim new file mode 100644 index 00000000000..67fae18c398 --- /dev/null +++ b/tests/tools/tci_format_pr_description.nim @@ -0,0 +1,170 @@ +discard """ +description: "Test the PR description formatter" +joinable: false +target: js +""" + +import std/jsffi + +let formatPR = require "../../tools/ci_format_pr_description.js" + +proc formatPRdescription(formatPR: JSObject, str: cstring, maxLineLength: int): cstring {.importjs.} + +let testingText = cstring"""Lorem ipsum dolor sit amet, consectetur i adipiscing elit. Nullam blandit mauris id venenatis tincidunt. Vestibulum at gravida sapien. Mauris tellus augue, aliquet sed laoreet blandit, pulvinar sed felis. Phasellus nec est vitae enim blandit facilisis. +Vestibulum fermentum ligula sit amet volutpat fermentum. Sed in faucibus orci. Pellentesque a dui ex. Curabitur sollicitudin, nulla id dignissim lacinia, odio mauris blandit nisi, eget auctor arcu odio nec est. + +========================================= + +## Summary +* The quick brown fox now jumps over the lazy dog + + +## Details +* THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG'S BACK 1234567890 +* Hamburgevons + + + +``` +this is a triple quote delimited codeblock: + it should not be linewrapped as should no other style of codeblock be + there are also some birds sitting on a html comment: + ___ ___ + (o o) (o o) + ( V ) ( V ) + +``` +Here's some text. + And some indented text, that will be linewrapped, + but must not be dedented + + + + and this is an indented codeblock: + with a cat: + !"#%&'()*+,-./012 _._ _,-'""`-._ 3456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefgh + "#%&'()*+,-./0123 (,-.'._,'( |\`-/| 456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghi + #%&'()*+,-./01234 '-.-' \ )-`( , o o) 56789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghij + %&'()*+,-./012345 '- \`_`"'- 6789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijk + + + + +https://www.some.url/that/is/quite/long/abcdefghijklmnopqrstuvw123467890xyz + +(test) ========================================= +(test) ======================================= i + + + ~~~tokipona + + + jan ali li kama lon nasin ni: ona li ken tawa li ken pali. + jan ali li kama lon sama. jan ali li jo e ken pi pilin suli. + jan ali li ken pali e wile pona ona. + jan ali li jo e ken pi sona pona e ken pi pali pona. + jan ali li wile pali nasin ni: ona li jan pona pi jan ante. + +~~~ + +=================================== split this +================================= `keep this` + +there are trailing spaces after this sentence +and they must not leak into this line + +the next line is indented + and it should stay this way +""" + +let testingTextWrapped = cstring"""Lorem ipsum dolor sit amet, consectetur i +adipiscing elit. Nullam blandit mauris id +venenatis tincidunt. Vestibulum at +gravida sapien. Mauris tellus augue, +aliquet sed laoreet blandit, pulvinar sed +felis. Phasellus nec est vitae enim +blandit facilisis. +Vestibulum fermentum ligula sit amet +volutpat fermentum. Sed in faucibus orci. +Pellentesque a dui ex. Curabitur +sollicitudin, nulla id dignissim lacinia, +odio mauris blandit nisi, eget auctor +arcu odio nec est. + +========================================= + +## Summary +* The quick brown fox now jumps over the +lazy dog + + +## Details +* THE QUICK BROWN FOX JUMPED OVER THE +LAZY DOG'S BACK 1234567890 +* Hamburgevons + + + +``` +this is a triple quote delimited codeblock: + it should not be linewrapped as should no other style of codeblock be + there are also some birds sitting on a html comment: + ___ ___ + (o o) (o o) + ( V ) ( V ) + +``` +Here's some text. + And some indented text, that will be +linewrapped, + but must not be dedented + + + + and this is an indented codeblock: + with a cat: + !"#%&'()*+,-./012 _._ _,-'""`-._ 3456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefgh + "#%&'()*+,-./0123 (,-.'._,'( |\`-/| 456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghi + #%&'()*+,-./01234 '-.-' \ )-`( , o o) 56789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghij + %&'()*+,-./012345 '- \`_`"'- 6789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijk + + + + +https://www.some.url/that/is/quite/long/abcdefghijklmnopqrstuvw123467890xyz + +(test) +========================================= +(test) +======================================= i + + + ~~~tokipona + + + jan ali li kama lon nasin ni: ona li ken tawa li ken pali. + jan ali li kama lon sama. jan ali li jo e ken pi pilin suli. + jan ali li ken pali e wile pona ona. + jan ali li jo e ken pi sona pona e ken pi pali pona. + jan ali li wile pali nasin ni: ona li jan pona pi jan ante. + +~~~ + +=================================== split +this +================================= +`keep this` + +there are trailing spaces after this +sentence +and they must not leak into this line + +the next line is indented + and it should stay this way +""" + +echo formatPR.formatPRdescription(testingText, 41) +assert formatPR.formatPRdescription(testingText, 41) == testingTextWrapped + diff --git a/tools/ci_format_pr_description.js b/tools/ci_format_pr_description.js new file mode 100644 index 00000000000..2c826a2be7c --- /dev/null +++ b/tools/ci_format_pr_description.js @@ -0,0 +1,53 @@ +// This file is imported by .github/workflows/slash-command-merge.yml +// and tested by tests/tools/tci_forrmat_pr_description.nim + +function getSegments(regex, str) { + // Returns the segments that `regex` + // divides `str` into, along with the + // info of wether each segment was matching + // the regex or not + let segments = []; + let lastIndex = 0; + let match; + regex.lastIndex = 0; // In case there's a dangling previous search + while (match = regex.exec(str)) { + if (match.index > lastIndex) { + segments.push([false, str.substring(lastIndex, match.index)]); + } + segments.push([true, match[0]]); + lastIndex = match.index + match[0].length; + } + if (lastIndex < str.length) { + segments.push([false, str.substring(lastIndex)]); + } + return segments; +} + +exports.formatPRdescription = (text, maxLineLength) => + // Returns `text` stripped of HTML comments and linewrapped, + // respecting codeblocks and codespans + getSegments(/(?:^ {0,3}(```|~~~)[^]*?^ {0,3}\1 *$)|^(?:\n {4,}.*)+/gm, text) + .map( ([isCodeBlock, segment]) => + isCodeBlock + ? segment // Don't touch code blocks + : segment + // Remove HTML comments first: + .replace(/<\!--.*?-->/s, "") + .split('\n').map(line => + line.length <= maxLineLength + ? line // Line isn't too long, nothing to do + : getSegments(/(`+).*?\1/g, line) + // Treat codespans as single words: + .flatMap( ([isCodeSpan, segment]) => isCodeSpan ? segment : segment.split(' ') ) + .reduce( ([wrappedLine, lineLength, isStart], word) => + // Don't touch indentation nor start with a line break: + isStart + ? [wrappedLine + word, lineLength + word.length, false] + : // Don't touch trailing spaces: + word.length > 0 && lineLength + 1 + word.length > maxLineLength + ? [wrappedLine + '\n' + word, word.length, false] + : [wrappedLine + ' ' + word, lineLength + 1 + word.length, false] + , ['', 0, true] + )[0] + ).join('\n') + ).join('')