Skip to content

Commit

Permalink
Merge branch 'refs/heads/feat-java-doc' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
fulminazzo committed Aug 6, 2024
2 parents ee13d46 + e1b1f9b commit ecad662
Show file tree
Hide file tree
Showing 11 changed files with 1,078 additions and 1 deletion.
14 changes: 14 additions & 0 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ jobs:
- name: Test and Build with Gradle Wrapper
run: ./gradlew build

update-pages:
needs: test
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: write
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
uses: ./.github/workflows/pages.yml

jacoco:
needs: test
runs-on: ubuntu-latest
Expand Down
49 changes: 49 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages

on:
workflow_call:

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Pages
uses: actions/configure-pages@v5

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '8'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5

- name: Generate Javadoc
run: ./gradlew aggregateJavaDoc

- name: Generate Coverage
run: |-
./gradlew testCodeCoverageReport
mv build/reports/jacoco/testCodeCoverageReport/html html/coverage
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload from html
path: './html/'

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
9 changes: 8 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ allprojects {
legacy_version = minecraftVersion
obsolete_version = minecraftVersion

subprojects.findAll { it.path.contains("bukkit") }.each {dependsOn "${it.path}:test" }
subprojects.findAll { it.path.contains("bukkit") }.each { dependsOn "${it.path}:test" }
}

tasks.register('sourcesJar', Jar) {
Expand Down Expand Up @@ -184,6 +184,13 @@ allprojects {
}
}

tasks.register("aggregateJavaDoc") {
allprojects.forEach { dependsOn "${it.path}:javadoc" }
doLast {
JavaDocUtils.aggregateJavaDoc("html/docs", rootProject.name, rootProject.version, TEST_MODULE)
}
}

testCodeCoverageReport {
dependsOn test
reports {
Expand Down
23 changes: 23 additions & 0 deletions buildSrc/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
id 'java'
}

repositories {
mavenCentral()
maven {
name = "Fulminazzo repository"
url = "https://repo.fulminazzo.it/releases"
}
}

dependencies {
testImplementation platform(libs.junit.platform)
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.junit.jupiter:junit-jupiter-params'

testImplementation libs.yamlparser
}

test {
useJUnitPlatform()
}
7 changes: 7 additions & 0 deletions buildSrc/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files("../gradle/libs.versions.toml"))
}
}
}
158 changes: 158 additions & 0 deletions buildSrc/src/main/groovy/JavaDocUtils.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import groovy.transform.CompileDynamic

import java.nio.file.Files
import java.nio.file.StandardCopyOption

/**
* A collection of utilities to aggregate Javadocs
*/
@CompileDynamic
class JavaDocUtils {
private static final String DOCS_DIR = 'javadoc'
private static final String[] IGNORE_DIRS = [ 'main', 'java', 'groovy', 'html', 'src', 'buildSrc', 'resources' ]
private static final String[] RESOURCES = [ 'index.html', 'javadoc-stylesheet.css' ]
private static final String MODULE_PLACEHOLDER = '%modules%'
private static final String MODULE_FORMAT_FILE = 'module-format.html'

/**
* Aggregates the javadoc of all the root and subprojects into a single directory
*
* @param output the output directory
* @param ignoreDirs the directories (modules) to be ignore
*/
static aggregateJavaDoc(String output, String name, String version, String... ignoreDirs) {
def current = new File(System.getProperty('user.dir'))
if (current.name == 'buildSrc') current = current.parentFile
def outputDir = new File(current, output)

if (outputDir.exists() && !outputDir.deleteDir())
throw new IllegalStateException("Could not delete previous directory ${output}")
if (!outputDir.mkdirs()) throw new IllegalStateException("Could not create directory ${output}")

aggregateJavaDocRec(current, outputDir, ignoreDirs)
createModulesPage(name, version, outputDir)
}

/**
* Copies the given file.
*
* @param src the source (copied) file
* @param dst the destination (copy) file
*/
static copyDirectory(File src, File dst) {
if (src.directory) {
def files = src.listFiles()
dst.mkdirs()
if (files != null)
files*.name.each { copyDirectory(new File(src, it), new File(dst, it)) }
} else Files.copy(src.toPath(), dst.toPath(), StandardCopyOption.REPLACE_EXISTING)
}

/**
* Finds the most common path between the two given files
*
* @param file1 the first file
* @param file2 the second file
* @return the common path
*/
static commonPath(File file1, File file2) {
def path1 = file1.absolutePath
def path2 = file2.absolutePath
def result = ''

for (i in 0..Math.min(path1.length(), path2.length())) {
def c1 = path1[i]
def c2 = path2[i]
if (c1 != c2) break
else result += c1
}

return result
}

/**
* Gets the given resource.
*
* @param name the name
* @return the resource
*/
static getResource(String name) {
while (name.startsWith('/')) name = name.substring(1)
def resource = JavaDocUtils.getResourceAsStream(name)
if (resource == null) resource = JavaDocUtils.getResourceAsStream("/${name}")
if (resource == null) throw new IllegalArgumentException("Could not find resource '${name}'")
return resource
}

private static aggregateJavaDocRec(File current, File output, String... ignoreDirs) {
if (!current.directory) return

def files = current.listFiles()
if (files == null)
throw new IllegalArgumentException("Could not list files of ${current.path}")

files.findAll { f -> f.directory }
.findAll { f -> !IGNORE_DIRS.any { d -> d == f.name } }
.findAll { f -> !ignoreDirs.any { d -> d == f.name } }
.each { f ->
if (f.name == DOCS_DIR) {
def dest = getDestinationFromModule(output, f)
def out = new File(output, dest)
copyDirectory(f, out)
} else aggregateJavaDocRec(f, output)
}
}

private static createModulesPage(String name, String version, File file) {
if (!file.directory) return
def files = file.listFiles()
if (files == null) return
if (files.any { it.name.contains('.html') }) return

RESOURCES.each { parseResource(file, it, name, version, files) }

files.each { createModulesPage(it.name, version, it) }
}

private static parseResource(File parentFile, String resource, String name, String version, File[] files) {
getResource("${resource}").withReader { reader ->
new File(parentFile, resource).withWriter { writer ->
String line
while ((line = reader.readLine()) != null) {
line = line.replace('%module_name%', name)
.replace('%module_version%', version)
if (line.contains(MODULE_PLACEHOLDER))
line = parseModulesPlaceholder(line, files)
writer.write(line)
writer.write('\n')
}
}
}
}

private static parseModulesPlaceholder(String line, File[] files) {
String output = ''
files*.name.each { n ->
getResource("/${MODULE_FORMAT_FILE}").withReader { r ->
String l
while ((l = r.readLine()) != null)
output += l.replace('%submodule_name%', n)
.replace('%submodule_path%', "${n}${File.separator}index.html")
}
}
line.replace(MODULE_PLACEHOLDER, output)
}

private static getDestinationFromModule(File output, File file) {
def parent = new File(commonPath(output, file))
def module = new File(file, '')
while (module.parentFile.parentFile != parent)
module = module.parentFile
def moduleName = module.name

def dst = "${module.parentFile.name}"
if (moduleName != 'build') dst += "${File.separator}${module.name}"
return dst
}

}
79 changes: 79 additions & 0 deletions buildSrc/src/main/resources/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Overview (%module_name% %module_version% API)</title>
<link rel="stylesheet" type="text/css" href="javadoc-stylesheet.css" title="Style">
</head>
<body>
<!-- ======== START OF TOP NAVBAR ======= -->
<div class="top-nav">
<ul class="nav-list" title="Navigation">
<li class="nav-bar-cell-1-rev">Overview</li>
<li>Package</li>
<li>Class</li>
<li>Tree</li>
<li>Deprecated</li>
<li>Index</li>
<li>Help</li>
</ul>
</div>
<div class="sub-nav">
<ul class="nav-list">
<li>Prev</li>
<li>Next</li>
</ul>
<ul class="nav-list">
<li><a href="#">Frames</a></li>
<li><a href="#">No&nbsp;Frames</a></li>
</ul>
<ul class="nav-list" id="all-classes-navbar-top">
<li><a href="#">All&nbsp;Classes</a></li>
</ul>
</div>
<!-- ======== END OF TOP NAVBAR ======= -->

<div class="header">
<h1 class="title">%module_name% %module_version% API</h1>
</div>

<div class="content-container">
<table class="overview-summary" border="0" cellpadding="3" cellspacing="0">
<caption><span>Submodules</span><span class="tab-end">&nbsp;</span></caption>
<tr>
<th class="col-first" scope="col">Submodule</th>
<th class="col-last" scope="col">Description</th>
</tr>
<tbody>
%modules%
</tbody>
</table>
</div>

<!-- ======= START OF BOTTOM NAVBAR ====== -->
<div class="bottom-nav">
<ul class="nav-list" title="Navigation">
<li class="nav-bar-cell-1-rev">Overview</li>
<li>Package</li>
<li>Class</li>
<li>Tree</li>
<li>Deprecated</li>
<li>Index</li>
<li>Help</li>
</ul>
</div>
<div class="sub-nav">
<ul class="nav-list">
<li>Prev</li>
<li>Next</li>
</ul>
<ul class="nav-list">
<li><a href="#">Frames</a></li>
<li><a href="#">No&nbsp;Frames</a></li>
</ul>
<ul class="nav-list" id="all-classes-navbar-bottom">
<li><a href="#">All&nbsp;Classes</a></li>
</ul>
</div>
<!-- ======== END OF BOTTOM NAVBAR ======= -->
</body>
</html>
Loading

0 comments on commit ecad662

Please sign in to comment.