temporary scripts for branch maintenance#15488
Conversation
There was a problem hiding this comment.
Pull request overview
Adds Gradle-invokable maintenance automation for GitHub branch hygiene in apache/grails-core (protect release branches, delete stale branches) via two Groovy scripts executed from the root build.gradle.
Changes:
- Registers two new Gradle maintenance tasks:
deleteBranchesandprotectBranches. - Introduces
ProtectBranches.groovyto apply GitHub branch protection to a curated list of release branches. - Introduces
DeleteBranches.groovyto delete a curated list of merged/closed branches via the GitHub API.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| build.gradle | Adds Gradle tasks that execute the maintenance Groovy scripts via GroovyShell. |
| ProtectBranches.groovy | New script that calls GitHub’s branch protection API for listed branches. |
| DeleteBranches.groovy | New script that calls GitHub’s refs API to delete listed branches. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def githubToken = System.getenv('GITHUB_TOKEN') ?: System.getProperty('github.token') | ||
| def repoOwner = "apache" | ||
| def repoName = "grails-core" | ||
| def baseApiUrl = "https://api.github.com/repos/${repoOwner}/${repoName}" |
There was a problem hiding this comment.
The target repository is hardcoded to apache/grails-core. That makes it easy to accidentally run this from a fork/clone and still delete branches on the upstream repo if the token has access. Make repoOwner/repoName configurable (env/Gradle properties) and/or require an explicit confirmation that prints the resolved target before proceeding.
|
It's my understanding that the protection logic can't be updated by us. We have to use .asf.yaml to set the protection. The issue is the asf.yaml process hasn't historically supported regex based protection rules - only specific branches. The reason for this is because the rest api does not support setting up this type of protections. Only the graphql library supports this. Have you researched this? Does asf.yaml still have this limitation? Maybe we could contribute to the ASF implementation to get this support so we can then define these in .asf.yaml. |
…l not fail the script
|
The TestLens GitHub App is installed in this repository but TestLens is currently in private beta. Please contact us to finish onboarding this repository. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ProtectBranches.groovy
Outdated
| if (body) { | ||
| conn.doOutput = true | ||
| conn.setRequestProperty("Content-Type", "application/json") | ||
| conn.outputStream.withWriter { it << body } | ||
| } | ||
|
|
||
| if (conn.responseCode in [200, 201, 204]) { | ||
| println "SUCCESS: ${conn.responseCode}" | ||
| } else { | ||
| def errorText = conn.errorStream?.text ?: "No error stream available" | ||
| throw new RuntimeException("HTTP ${conn.responseCode} - ${errorText}") | ||
| } | ||
| } finally { | ||
| conn?.disconnect() | ||
| } |
There was a problem hiding this comment.
The response/error streams are never explicitly closed. With HttpURLConnection, leaving streams unclosed can leak resources and (in some JVMs) prevent clean connection teardown. Ensure input/error streams are read/closed (e.g., withCloseable) on both success and failure paths.
| if (body) { | ||
| conn.doOutput = true | ||
| conn.setRequestProperty("Content-Type", "application/json") | ||
| conn.outputStream.withWriter { it << body } | ||
| } | ||
|
|
||
| if (conn.responseCode in [200, 201, 204]) { | ||
| println "SUCCESS: ${conn.responseCode}" | ||
| } else { | ||
| def errorText = conn.errorStream?.text ?: "No error stream available" | ||
| throw new RuntimeException("HTTP ${conn.responseCode} - ${errorText}") | ||
| } | ||
| } finally { | ||
| conn?.disconnect() | ||
| } |
There was a problem hiding this comment.
Same as ProtectBranches.groovy: response/error streams aren’t explicitly closed. Close streams deterministically to avoid resource leaks and make failure modes more reliable.
ProtectBranches.groovy
Outdated
| if (!githubToken || githubToken == "YOUR_PERSONAL_ACCESS_TOKEN") { | ||
| throw new IllegalStateException( | ||
| "GitHub token is required. Set the GITHUB_TOKEN environment variable or the -Dgithub.token system property." | ||
| ) | ||
| } |
There was a problem hiding this comment.
The sentinel check against \"YOUR_PERSONAL_ACCESS_TOKEN\" looks like leftover scaffolding and is inconsistent with DeleteBranches.groovy (which only checks for presence). Either document the expected placeholder usage or remove this special-case to keep behavior consistent and predictable.
Two tasks one to protect the release branches and another to delete stale branches