Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
5 changes: 3 additions & 2 deletions dev-docs/changelog.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
108 changes: 69 additions & 39 deletions gradle/changelog.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
}
}

Expand All @@ -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)
}
}
Loading