refactor: replace hardcoded URLs etc. with dynamic placeholders for improved configurability#49
refactor: replace hardcoded URLs etc. with dynamic placeholders for improved configurability#49
Conversation
…ed configurability - Updated documentation links and project metadata to use placeholders (e.g., `@GITHUB_REPO_URL@`, `@REPO_SLUG@`). - Dynamically resolve repository details via Gradle project properties. - Enhanced documentation build process to replace tokens with computed values.
* Metadata in gradle.properties: index.tmlp now 100% generic, as it uses metadata from gradle.properties * Same data is used in plugin/build.gradle (except from developers)
|
@jdaugherty @matrei I am asking either of you to review this PR because I want to make something similar for grails-server-timing (the current blueprint for Grails 7 plugins) I would like for all the build-logic (and release description) to be in gradle.properties and with the necessary information there, it is possible to get the developers list from GitHub when publishing the plugin. Thoughts, rants and suggestions are welcomed! Next plan coming up is standard publish to the Slack #plugin channel when a new version of a plugin is released |
jdaugherty
left a comment
There was a problem hiding this comment.
I love the effort to standardize some of this, but I think we should consider:
- moving the contributor.yaml population to a github action (i'm willing to help write this if you want) that opens a PR for periodic merging
- making this lazy (avoid flatMap, etc) to adhere to our best practices
- moving the task + versions to their own gradle plugin that we publish (I'm willing to help fix this since I did make it private to not deal with it 😂)
| @@ -0,0 +1,9 @@ | |||
|
|
|||
| def fetchContributors = tasks.register("fetchContributors", contributor.ContributorTask) { | |||
There was a problem hiding this comment.
The original reason I didn't add a fetch in core, and the other areas is b/c it's not accurate without a malimap. I think for plugins this is probably ok though.
| yamlOutput.convention(layout.buildDirectory.file("generated/contributors.yml")) | ||
| } | ||
|
|
||
| extensions.add("contributorsData", fetchContributors.flatMap { it.contributors }) |
There was a problem hiding this comment.
Flatmap is non-lazy so you're invoking the task here. We typically avoid this as it's going to happen as part of the configuration workflow. Some possible workarounds:
- have a task dependency on the output of the fetchContributors as an input to wherever you need it (or a provider even)
- have the fetch contributors write to a file so the task is cacheable and then read from that file, you can then tweak the task for when it fetches
| import org.gradle.api.tasks.OutputFile | ||
| import org.gradle.api.tasks.TaskAction | ||
|
|
||
| abstract class ContributorTask extends DefaultTask { |
There was a problem hiding this comment.
- the task should be cacheable
- this seems like something we should publish instead of having it in every project
| def outputFile = yamlOutput.get().asFile | ||
| outputFile.parentFile.mkdirs() | ||
|
|
||
| if (!token) { |
There was a problem hiding this comment.
You're assuming Github token access to have a reproducible build. We typically don't do this as part of the grails builds.
| .reverse() | ||
| .findAll { it.type == 'dir' } | ||
| .collect { it.name as String } | ||
| .findAll { it ==~ /\d+\.\d+\.(\d+|x)(-.*)?/ } |
There was a problem hiding this comment.
You're parsing semversioning when there are libraries to do this. There are actually multiple classes in grails-core with this, we really should centralize this logic and publish it
| String latestVersion = "" | ||
| try { | ||
| def conn = URI.create('https://api.github.com/repos/gpc/grails-export/contents/?ref=gh-pages').toURL().openConnection() | ||
| def conn = URI.create("https://api.github.com/repos/${githubOrg}/${githubProject}/contents/?ref=gh-pages").toURL().openConnection() |
There was a problem hiding this comment.
It would probably be a better design to have a github action that just generates a contributor.yml and merges it into a branch, then it can be updated either manually or externally via github
There was a problem hiding this comment.
If we should externalize the contributor.yml and make it a part of the project, how about moving all the meta-data to a project.yml and have it contain stuff like
projectTitle
projectDescription
projectOrganization
githubOrg
githubProject
contributors
historicVersions
Then it does not have to be in two separate files (gradle.properties and contributors.yml) and it can be easily read and updated by a github action?
| String optionsHtml = versions | ||
| ? versions.collect { v -> "<option value=\"${v}\">${v}</option>" }.join('\n ') | ||
| : '<option value="" disabled>No previous versions available</option>' | ||
| ? versions.collect { v -> "<option value=\"${v}\">${v}</option>" }.join('\n ') |
There was a problem hiding this comment.
We should just clean up the documentation tasks in grails-core and publish them. The main blocker here is we need to pull our themeing templates out from the project and host them somewhere (we talked about doing it on the grails website itself)
| ? versions.collect { v -> "<option value=\"${v}\">${v}</option>" }.join('\n ') | ||
| : '<option value="" disabled>No previous versions available</option>' | ||
|
|
||
| def tokens = [ |
There was a problem hiding this comment.
Gradle supports template expansion:
- it can do it as part of the processResources for templates being published
- you can do it as part of the copy task itself:
tasks.register('generateConfig', Copy) {
from 'templates/config.tpl'
into "$buildDir/generated"
rename { 'config.conf' }
expand([
version: project.version,
env: 'prod'
])
}
| extensions.configure(org.apache.grails.gradle.publish.GrailsPublishExtension) { | ||
| it.artifactId = project.name | ||
| it.githubSlug = 'gpc/grails-export' | ||
| it.githubSlug = "${githubOrg}/${githubProject}" |
There was a problem hiding this comment.
I don't think you even need to define some of these if you define the properties by default. the publish plugin by default looks for properties
| } | ||
| } | ||
|
|
||
| pluginManager.withPlugin('maven-publish') { |
There was a problem hiding this comment.
This isn't the right way to do this - the publish plugin already supports handling this information (https://github.com/apache/grails-gradle-publish/blob/d6951fd43f742c7887e9726435607d1663b60f3c/plugin/src/main/groovy/org/apache/grails/gradle/publish/GrailsPublishExtension.groovy#L77)
This pull request introduces dynamic project and repository metadata handling, automates contributor fetching, and improves documentation and publishing workflows by centralizing configuration and using templates. The main themes are metadata centralization, automation, and improved maintainability.
Project and Repository Metadata Centralization:
gradle.propertiesfor GitHub org, project, and project metadata, and updated all references in build scripts and documentation templates to use these properties instead of hardcoded values. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]Automated Contributor Fetching and Publishing:
ContributorTask(build-logic/src/main/groovy/contributor/ContributorTask.groovy) andconfig.contributors.gradleto fetch contributors from GitHub, store them as YAML, and expose them for use in publishing. [1] [2]Documentation Improvements:
docs/src/docs/index.tmpl) to use tokens for project/repo metadata and versioning, and improved version sorting and selection in the documentation generation Gradle task. [1] [2] [3] [4] [5] [6] [7]Dependency Updates:
org.apache.groovy:groovy-yamlas a build dependency to support YAML processing for contributors.These changes make the build and release process more maintainable and ensure that documentation and published artifacts always reflect the latest project state and contributor information.