Skip to content

Commit c7dcbcf

Browse files
authored
Inline guide release-dropdown task from core (#1185)
Grails Gradle Plugins `7.0.0` stopped publishing these classes, inline them to retain the release dropdown functionality.
1 parent f7cea30 commit c7dcbcf

File tree

6 files changed

+501
-4
lines changed

6 files changed

+501
-4
lines changed

buildSrc/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,4 @@ dependencies {
5757
implementation 'org.apache.grails:grails-gradle-plugins'
5858
implementation "org.nosphere.apache.rat:org.nosphere.apache.rat.gradle.plugin:${versions.get('ratVersion')}"
5959
implementation "org.gradle.crypto.checksum:org.gradle.crypto.checksum.gradle.plugin:${versions.get('gradleCryptoChecksumVersion')}"
60-
implementation 'org.apache.grails:grails-docs-core'
6160
}
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package grails.doc.dropdown
21+
22+
import java.nio.file.FileVisitResult
23+
import java.nio.file.Files
24+
import java.nio.file.Path
25+
import java.nio.file.SimpleFileVisitor
26+
import java.nio.file.StandardCopyOption
27+
import java.nio.file.attribute.BasicFileAttributes
28+
29+
import javax.inject.Inject
30+
31+
import groovy.transform.CompileStatic
32+
33+
import org.gradle.api.DefaultTask
34+
import org.gradle.api.GradleException
35+
import org.gradle.api.Project
36+
import org.gradle.api.file.ConfigurableFileCollection
37+
import org.gradle.api.file.DirectoryProperty
38+
import org.gradle.api.file.RegularFileProperty
39+
import org.gradle.api.model.ObjectFactory
40+
import org.gradle.api.provider.Property
41+
import org.gradle.api.tasks.CacheableTask
42+
import org.gradle.api.tasks.Input
43+
import org.gradle.api.tasks.InputDirectory
44+
import org.gradle.api.tasks.InputFile
45+
import org.gradle.api.tasks.InputFiles
46+
import org.gradle.api.tasks.OutputDirectory
47+
import org.gradle.api.tasks.PathSensitive
48+
import org.gradle.api.tasks.PathSensitivity
49+
import org.gradle.api.tasks.TaskAction
50+
51+
/**
52+
* Duplicates the documentation and modifies source files to add a release dropdown to the documentation
53+
* @since 6.2.1
54+
*/
55+
@CompileStatic
56+
@CacheableTask
57+
abstract class CreateReleaseDropDownTask extends DefaultTask {
58+
59+
@Input
60+
final Property<String> docBaseUrl
61+
62+
@Input
63+
final Property<String> githubSlug
64+
65+
@InputDirectory
66+
@PathSensitive(PathSensitivity.RELATIVE)
67+
final DirectoryProperty sourceDocsDirectory
68+
69+
@InputFile
70+
@PathSensitive(PathSensitivity.RELATIVE)
71+
final RegularFileProperty gitTags
72+
73+
@Input
74+
final Property<String> projectVersion
75+
76+
@Input
77+
final Property<SoftwareVersion> minimumVersion
78+
79+
@InputFiles
80+
@PathSensitive(PathSensitivity.RELATIVE)
81+
final ConfigurableFileCollection filesToAddDropdowns
82+
83+
@OutputDirectory
84+
final DirectoryProperty modifiedPagesDirectory
85+
86+
@Input
87+
final Property<String> versionHtml
88+
89+
@Input
90+
final Property<String> additionalPath
91+
92+
@Inject
93+
CreateReleaseDropDownTask(ObjectFactory objects, Project project) {
94+
group = 'documentation'
95+
githubSlug = objects.property(String).convention(project.provider {
96+
project.findProperty('githubSlug') as String ?: 'apache/grails-core'
97+
})
98+
sourceDocsDirectory = objects.directoryProperty().convention(project.layout.buildDirectory.dir('manual'))
99+
projectVersion = objects.property(String).convention(project.provider { project.version as String })
100+
filesToAddDropdowns = objects.fileCollection()
101+
modifiedPagesDirectory = objects.directoryProperty().convention(project.layout.buildDirectory.dir('modified-pages'))
102+
gitTags = objects.fileProperty().convention(project.layout.buildDirectory.file('git-tags.txt'))
103+
minimumVersion = objects.property(SoftwareVersion).convention(new SoftwareVersion(major: 5))
104+
docBaseUrl = objects.property(String).convention('https://grails.apache.org/docs')
105+
versionHtml = objects.property(String).convention(project.provider { '<p><strong>Version:</strong> ' + projectVersion.get() + '</p>' })
106+
additionalPath = objects.property(String).convention('')
107+
}
108+
109+
/**
110+
* Add the release dropdown to the documentation*/
111+
@TaskAction
112+
void createReleaseDropDown() {
113+
Path targetOutputDirectory = modifiedPagesDirectory.get().asFile.toPath()
114+
if (Files.exists(targetOutputDirectory)) {
115+
targetOutputDirectory.deleteDir()
116+
}
117+
Files.createDirectories(targetOutputDirectory)
118+
119+
String projectVersion = projectVersion.get()
120+
121+
final List<String> result = gitTags.get().asFile.readLines()*.trim()
122+
List<SoftwareVersion> softwareVersions = parseSoftwareVersions(projectVersion, result)
123+
logger.lifecycle("Detected Project Version: ${projectVersion} and Software Versions: ${softwareVersions*.versionText.join(',')}")
124+
125+
Path guideDirectory = sourceDocsDirectory.get().asFile.toPath()
126+
127+
Map<String, Path> filesToAddDropdown = filesToAddDropdowns.collectEntries { [it.absolutePath, it.toPath()] }
128+
Files.walkFileTree(guideDirectory, new SimpleFileVisitor<Path>() {
129+
130+
@Override
131+
FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
132+
Path targetDir = targetOutputDirectory.resolve(guideDirectory.relativize(dir))
133+
if (!Files.exists(targetDir)) {
134+
Files.createDirectories(targetDir)
135+
}
136+
FileVisitResult.CONTINUE
137+
}
138+
139+
@Override
140+
FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
141+
Path targetFile = targetOutputDirectory.resolve(guideDirectory.relativize(file))
142+
String absolutePath = targetFile.toAbsolutePath().toString()
143+
if (filesToAddDropdown.containsKey(absolutePath)) {
144+
String pageRelativePath = guideDirectory.toFile().relativePath(file.toFile())
145+
String selectHtml = select(options(projectVersion, pageRelativePath, softwareVersions))
146+
147+
final String versionWithSelectHtml = "<p><strong>Version:</strong>&nbsp;<span style='display:inline-block;'>${selectHtml}</span></p>"
148+
targetFile.toFile().text = file.text.replace(versionHtml.get(), versionWithSelectHtml)
149+
150+
filesToAddDropdown.remove(absolutePath)
151+
} else {
152+
Files.copy(file, targetFile, StandardCopyOption.REPLACE_EXISTING)
153+
}
154+
FileVisitResult.CONTINUE
155+
}
156+
157+
@Override
158+
FileVisitResult visitFileFailed(Path file, IOException e) throws IOException {
159+
throw new GradleException("Unable to copy file: ${file}", e)
160+
}
161+
})
162+
}
163+
164+
/**
165+
* Generate the options for the select tag.
166+
*
167+
* @param version The current version of the documentation
168+
* @param pageRelativePath The relative path for the page to add the dropdown to
169+
* @param softwareVersions The list of software versions to include in the dropdown
170+
* @return The list of options for the select tag
171+
*/
172+
private List<String> options(String version, String pageRelativePath, List<SoftwareVersion> softwareVersions) {
173+
List<String> options = []
174+
175+
final String snapshotHref = docBaseUrl.get() + '/snapshot/' + additionalPath.get() + pageRelativePath
176+
options << option(snapshotHref, 'SNAPSHOT', version.endsWith('-SNAPSHOT'))
177+
178+
softwareVersions
179+
.forEach { softwareVersion ->
180+
final String versionName = softwareVersion?.versionText
181+
final String href = docBaseUrl.get() + '/' + (versionName?.endsWith('-SNAPSHOT') ? 'snapshot' : versionName) + '/' + additionalPath.get() + pageRelativePath
182+
options << option(href, versionName, version == versionName)
183+
}
184+
185+
options
186+
}
187+
188+
/**
189+
* Generate the select tag
190+
*
191+
* @param options The List of options tags for the select tag
192+
* @return The select tag with the options
193+
*/
194+
private String select(List<String> options) {
195+
String selectHtml = /<select onChange='window.document.location.href=this.options[this.selectedIndex].value;'>/
196+
options.each { option -> selectHtml += option
197+
}
198+
selectHtml += '</select>'
199+
selectHtml
200+
}
201+
202+
/**
203+
* Generate the option tag
204+
*
205+
* @param value The URL to navigate to
206+
* @param text The version to display
207+
* @param selected Whether the option is selected
208+
*
209+
* @return The option tag
210+
*/
211+
private String option(String value, String text, boolean selected = false) {
212+
if (selected) {
213+
return "<option selected='selected' value='${value}'>${text}</option>"
214+
} else {
215+
return "<option value='${value}'>${text}</option>"
216+
}
217+
}
218+
219+
/**
220+
* Parse the software versions from the resultant JSON
221+
*
222+
* @param result List of all tags in the repository.
223+
* @param minimumVersion Minimum SoftwareVersion to include in the list. Default version is 0.0.0
224+
* @return The list of software versions
225+
*/
226+
private List<SoftwareVersion> parseSoftwareVersions(String projectVersion, List<String> tags) {
227+
def minimum = minimumVersion.get()
228+
229+
LinkedHashSet<String> combined = ["v${projectVersion}" as String]
230+
combined.addAll(tags)
231+
232+
combined.findAll { it ==~ /^v\d.*/ }
233+
.collect { it.replace('v', '') }
234+
.collect { SoftwareVersion.build(it) }
235+
.findAll { it >= minimum }
236+
.toSorted()
237+
.unique()
238+
.reverse()
239+
}
240+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package grails.doc.dropdown
21+
22+
class Snapshot implements Comparable<Snapshot>, Serializable {
23+
24+
private static final long serialVersionUID = 1L
25+
26+
private String text
27+
28+
int getMilestoneVersion() {
29+
text.replace('M', '').toInteger()
30+
}
31+
32+
int getReleaseCandidateVersion() {
33+
text.replace('RC', '').toInteger()
34+
}
35+
36+
boolean isBuildSnapshot() {
37+
text.endsWith('BUILD-SNAPSHOT')
38+
}
39+
40+
boolean isReleaseCandidate() {
41+
text.startsWith('RC')
42+
}
43+
44+
boolean isMilestone() {
45+
text.startsWith('M')
46+
}
47+
48+
Snapshot(String text) {
49+
this.text = text
50+
}
51+
52+
@Override
53+
int compareTo(Snapshot o) {
54+
55+
if (this.buildSnapshot && !o.buildSnapshot) {
56+
return 1
57+
} else if (!this.buildSnapshot && o.buildSnapshot) {
58+
return -1
59+
} else if (this.buildSnapshot && o.buildSnapshot) {
60+
return 0
61+
}
62+
63+
if (this.releaseCandidate && !o.releaseCandidate) {
64+
return 1
65+
} else if (!this.releaseCandidate && o.releaseCandidate) {
66+
return -1
67+
} else if (this.releaseCandidate && o.releaseCandidate) {
68+
return this.releaseCandidateVersion <=> o.releaseCandidateVersion
69+
}
70+
71+
if (this.milestone && !o.milestone) {
72+
return 1
73+
} else if (!this.milestone && o.milestone) {
74+
return -1
75+
} else if (this.milestone && o.milestone) {
76+
return this.milestoneVersion <=> o.milestoneVersion
77+
}
78+
79+
return 0
80+
}
81+
}
82+

0 commit comments

Comments
 (0)