From 1a2594756cfd9f1138b7607154bd723d30d82fc9 Mon Sep 17 00:00:00 2001 From: David Smiley Date: Thu, 18 Jun 2026 11:19:56 -0400 Subject: [PATCH 1/2] Gradle task writeChangelogPr For when there will be no JIRA. --- gradle/changelog.gradle | 108 +++++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/gradle/changelog.gradle b/gradle/changelog.gradle index aa9c32a13a39..c4120d7c2578 100644 --- a/gradle/changelog.gradle +++ b/gradle/changelog.gradle @@ -22,39 +22,9 @@ logchange { generateChangesXml = false } -task writeChangelog { - description = 'Generates a change/log description file (YAML)' - doLast { - def gitBranchFull = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim() - - // Prevent running on main or branches prefixed with 'branch_' - if (gitBranchFull == 'main' || gitBranchFull.startsWith('branch_')) { - throw new GradleException("Cannot create changelog on branch '${gitBranchFull}'. This task should only be run on feature branches.") - } - - def gitBranch = gitBranchFull.replaceFirst(/^.*\//, "") - - def gitUserName = 'git config user.name'.execute().text.trim() - def configuredName = providers.gradleProperty("user.name").getOrElse(gitUserName) - def githubId = providers.gradleProperty("user.githubid").getOrElse(null) - def nick = githubId ? "\n nick: ${githubId}" : "" - def asfId = providers.gradleProperty("user.asfid").getOrElse(null) - def asfIdUrl = asfId ? "\n url: https://home.apache.org/phonebook.html?uid=${asfId}" : "" - def jiraMatcher = gitBranch =~ /(?i)SOLR-\d\d\d+/ - def jiraRef = jiraMatcher ? jiraMatcher[0].toUpperCase() : "SOLR-XXXX" - def jiraUrl = "https://issues.apache.org/jira/browse/${jiraRef}" - def jiraLinks = jiraMatcher ? "links:\n - name: ${jiraRef}\n url: ${jiraUrl}" : "" - def title = gitBranch.replaceFirst(/(?i)SOLR-\d\d\d+\b-?/, "").replace("-", " ").capitalize() - // Warn user when generating empty title - if (title.isEmpty()) { - println "WARNING: Title in generated changelog is empty, please edit" - } - // Strip everything before and including '/', then sanitize special characters - def sanitizedBranchName = gitBranch.replaceAll(/^.*\//, "").replaceAll(/[^a-zA-Z0-9._-]/, "-") - def fileName = "changelog/unreleased/${sanitizedBranchName}.yml" - def file = new File(fileName) - file.parentFile.mkdirs() - file.text = """# (DELETE ALL COMMENTS UP HERE AFTER FILLING THIS IN +// Shared comment block placed at the top of generated changelog YAML files +def changelogYamlComments = '''\ +# (DELETE ALL COMMENTS UP HERE AFTER FILLING THIS IN # See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc @@ -76,17 +46,57 @@ task writeChangelog { # `dependency_update` for updates to dependencies # `other` for anything else, like large/significant refactorings, build changes, # test infrastructure, or documentation. -# Most such changes are too small/minor to bother with a changelog entry. +# Most such changes are too small/minor to bother with a changelog entry.''' + +// Returns a map with: gitBranch, sanitizedBranchName, configuredName, nick, asfIdUrl +def changelogSetup = { + def gitBranchFull = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim() + if (gitBranchFull == 'main' || gitBranchFull.startsWith('branch_')) { + throw new GradleException("Cannot create changelog on branch '${gitBranchFull}'. This task should only be run on feature branches.") + } + def gitBranch = gitBranchFull.replaceFirst(/^.*\//, "") + def sanitizedBranchName = gitBranch.replaceAll(/[^a-zA-Z0-9._-]/, "-") + def gitUserName = 'git config user.name'.execute().text.trim() + def configuredName = providers.gradleProperty("user.name").getOrElse(gitUserName) + def githubId = providers.gradleProperty("user.githubid").getOrElse(null) + def nick = githubId ? "\n nick: ${githubId}" : "" + def asfId = providers.gradleProperty("user.asfid").getOrElse(null) + def asfIdUrl = asfId ? "\n url: https://home.apache.org/phonebook.html?uid=${asfId}" : "" + return [gitBranch: gitBranch, sanitizedBranchName: sanitizedBranchName, + configuredName: configuredName, nick: nick, asfIdUrl: asfIdUrl] +} -title: ${title} +// Writes the changelog YAML file; linksYaml is either "" or a "links:\n - ..." block +def writeChangelogFile = {String fileName, String title, Map ctx, String linksYaml -> + if (title.isEmpty()) { + println "WARNING: Title in generated changelog is empty, please edit" + } + def file = new File(fileName) + file.parentFile.mkdirs() + file.text = """${changelogYamlComments} + +title: > + ${title} type: authors: - - name: ${configuredName}${nick}${asfIdUrl} -${jiraLinks} + - name: ${ctx.configuredName}${ctx.nick}${ctx.asfIdUrl} +${linksYaml} """ + println "Generated file: ${fileName} -- open and edit before committing" + println "Read dev-docs/changelog.adoc if you don't contribute here often." +} - println "Generated file: ${fileName} -- open and edit before committing" - println "Read dev-docs/changelog.adoc if you don't contribute here often." +task writeChangelog { + description = 'Generates a change/log description file (YAML)' + doLast { + def ctx = changelogSetup() + def jiraMatcher = ctx.gitBranch =~ /(?i)SOLR-\d\d\d+/ + def jiraRef = jiraMatcher ? jiraMatcher[0].toUpperCase() : "SOLR-XXXX" + def jiraLinks = jiraMatcher ? "links:\n - name: ${jiraRef}\n url: https://issues.apache.org/jira/browse/${jiraRef}" : + "" + def title = ctx.gitBranch.replaceFirst(/(?i)SOLR-\d\d\d+\b-?/, "") + .replace("-", " ").capitalize() + writeChangelogFile("changelog/unreleased/${ctx.sanitizedBranchName}.yml", title, ctx, jiraLinks) } } @@ -99,3 +109,23 @@ task newChangelog { dependsOn writeChangelog description = 'Generates a change/log description file (YAML)' } + +task writeChangelogPr { + description = 'Generates a changelog entry file (YAML) for the current GitHub PR' + doLast { + def ctx = changelogSetup() + def prInfoProc = ['gh', 'pr', 'view', '--json', 'number,title'].execute() + prInfoProc.waitFor() + if (prInfoProc.exitValue() != 0) { + throw new GradleException("Could not find a GitHub PR for branch '${ctx.gitBranch}'. Make sure you've pushed this branch and created a PR.\n${prInfoProc.err.text.trim()}") + } + def prJson = new groovy.json.JsonSlurper().parseText(prInfoProc.text) + def prNumber = prJson.number + def title = prJson.title ?: ctx.gitBranch.replace("-", " ").capitalize() + def prLinks = "links:\n - name: PR#${prNumber}\n url: https://github.com/apache/solr/pull/${prNumber}" + writeChangelogFile("changelog/unreleased/PR#${prNumber}-${ctx.sanitizedBranchName}.yml", + title, + ctx, + prLinks) + } +} From 8dde35e49c0783e79178d4996c4f788de30fe85a Mon Sep 17 00:00:00 2001 From: David Smiley Date: Thu, 2 Jul 2026 15:31:10 -0400 Subject: [PATCH 2/2] documentation --- AGENTS.md | 2 +- dev-docs/changelog.adoc | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e77f8f105095..e7542117d443 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -70,5 +70,5 @@ While README.md and CONTRIBUTING.md are mainly written for humans, this file is ## Changelog - We use the "logchange" tooling to manage our changelog. See `dev-docs/changelog.adoc` for details and conventions -- To scaffold a new changelog entry, run `gradlew writeChangelog`, and then edit the new file located in `changelog/unreleased/`. +- To scaffold a new changelog entry, run `gradlew writeChangelog` (JIRA) or `gradlew writeChangeLogPr` (no JIRA), and then edit the new file located in `changelog/unreleased/`. - Do not add a changelog entry before a JIRA issue or a Github PR is assigned, as one is required. diff --git a/dev-docs/changelog.adoc b/dev-docs/changelog.adoc index bd80fec42929..47df7a0baec8 100644 --- a/dev-docs/changelog.adoc +++ b/dev-docs/changelog.adoc @@ -90,8 +90,9 @@ links: === 3.1 Tool to draft a YAML for your change -We have a gradle task that bootstraps a YAML file in the `changelog/unreleased/` directory. The task will use your current branch name as a file name and also title, and will -try to parse JIRA id from the branch name if it exists to add the `links`. +We have two gradle tasks that bootstraps a YAML file in the `changelog/unreleased/` directory. +`writeChangeLog` will infer the JIRA id from the current branch if possible, otherwise you'll need to add the JIRA link manually. +If the change isn't worth a JIRA yet a changelog would still be nice, use `writeChangelogPr` after you've created the PR. It will incorporate a link to the PR in the entry. Invoke the task with: