Skip to content

Commit 0d8e711

Browse files
committed
Implement docs generation as plugin instead of a separate app
Related-To #139
1 parent c23e79a commit 0d8e711

32 files changed

Lines changed: 1347 additions & 748 deletions

File tree

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: Documentation Build and Preview
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
paths:
7+
- 'skainet-lang/**'
8+
- 'tools/docgen/**'
9+
- 'docs/**'
10+
- '.github/workflows/documentation.yml'
11+
pull_request:
12+
branches: [ main, develop ]
13+
paths:
14+
- 'skainet-lang/**'
15+
- 'tools/docgen/**'
16+
- 'docs/**'
17+
- '.github/workflows/documentation.yml'
18+
19+
jobs:
20+
build-documentation:
21+
runs-on: ubuntu-latest
22+
timeout-minutes: 30
23+
24+
steps:
25+
- name: Checkout code
26+
uses: actions/checkout@v4
27+
28+
- name: Set up JDK 17
29+
uses: actions/setup-java@v4
30+
with:
31+
java-version: '17'
32+
distribution: 'temurin'
33+
34+
- name: Cache Gradle packages
35+
uses: actions/cache@v4
36+
with:
37+
path: |
38+
~/.gradle/caches
39+
~/.gradle/wrapper
40+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
41+
restore-keys: |
42+
${{ runner.os }}-gradle-
43+
44+
- name: Grant execute permission for gradlew
45+
run: chmod +x gradlew
46+
47+
- name: Copy CI gradle.properties
48+
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
49+
50+
- name: Generate operator documentation
51+
run: ./gradlew generateDocs --stacktrace
52+
53+
- name: Upload generated documentation
54+
uses: actions/upload-artifact@v4
55+
with:
56+
name: operator-documentation
57+
path: |
58+
docs/modules/operators/_generated_/**
59+
skainet-lang/skainet-lang-core/build/generated/ksp/metadata/commonMain/resources/operators.json
60+
retention-days: 30
61+
62+
- name: Upload documentation preview (PR only)
63+
if: github.event_name == 'pull_request'
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: documentation-preview-${{ github.event.number }}
67+
path: |
68+
docs/**
69+
tools/docgen/build/docs/asciidoc/**
70+
retention-days: 7
71+
72+
# Job for documentation preview generation on PRs
73+
preview-documentation:
74+
if: github.event_name == 'pull_request'
75+
needs: build-documentation
76+
runs-on: ubuntu-latest
77+
78+
steps:
79+
- name: Download documentation artifacts
80+
uses: actions/download-artifact@v4
81+
with:
82+
name: documentation-preview-${{ github.event.number }}
83+
path: ./docs-preview
84+
85+
- name: Setup Node.js for preview server
86+
uses: actions/setup-node@v4
87+
with:
88+
node-version: '18'
89+
90+
- name: Install serve package
91+
run: npm install -g serve
92+
93+
- name: Start preview server
94+
run: |
95+
cd docs-preview
96+
serve -s . -l 3000 &
97+
sleep 5
98+
echo "Preview server started at http://localhost:3000"
99+
100+
- name: Create PR comment with preview link
101+
uses: actions/github-script@v7
102+
with:
103+
script: |
104+
const { data: comments } = await github.rest.issues.listComments({
105+
owner: context.repo.owner,
106+
repo: context.repo.repo,
107+
issue_number: context.issue.number,
108+
});
109+
110+
const botComment = comments.find(comment =>
111+
comment.user.type === 'Bot' &&
112+
comment.body.includes('📖 Documentation Preview')
113+
);
114+
115+
const commentBody = `📖 **Documentation Preview**
116+
117+
The documentation has been built successfully for this PR.
118+
119+
**Generated Files:**
120+
- Operator documentation: \`docs/modules/operators/_generated_/\`
121+
- JSON schema output: \`operators.json\`
122+
123+
**Artifacts:**
124+
- Download the \`documentation-preview-${{ github.event.number }}\` artifact to view the complete documentation locally.
125+
126+
_This comment will be updated automatically when the PR is updated._`;
127+
128+
if (botComment) {
129+
await github.rest.issues.updateComment({
130+
owner: context.repo.owner,
131+
repo: context.repo.repo,
132+
comment_id: botComment.id,
133+
body: commentBody
134+
});
135+
} else {
136+
await github.rest.issues.createComment({
137+
owner: context.repo.owner,
138+
repo: context.repo.repo,
139+
issue_number: context.issue.number,
140+
body: commentBody
141+
});
142+
}

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,15 @@ out/
2121

2222
### Mac OS ###
2323
.DS_Store
24+
25+
.java-version
26+
27+
### BROKK'S CONFIGURATION ###
28+
.brokk/**
29+
/.brokk/workspace.properties
30+
/.brokk/sessions/
31+
/.brokk/dependencies/
32+
/.brokk/history.zip
33+
!.brokk/style.md
34+
!.brokk/review.md
35+
!.brokk/project.properties

build.gradle.kts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ plugins {
55
alias(libs.plugins.vanniktech.mavenPublish) apply false
66
alias(libs.plugins.kover)
77
alias(libs.plugins.binary.compatibility.validator) apply false
8+
alias(libs.plugins.ksp) apply false
9+
alias(libs.plugins.asciidoctorJvm) apply false
10+
alias(libs.plugins.dokka) apply false
11+
id("sk.ainet.documentation")
812
}
913

1014
allprojects {
@@ -22,4 +26,43 @@ kover {
2226
}
2327
}
2428
}
29+
}
30+
31+
// Custom task to generate operator documentation
32+
tasks.register("generateOperatorDocs") {
33+
group = "documentation"
34+
description = "Generate operator documentation from KSP-generated JSON files"
35+
36+
// Configure inputs for incremental builds
37+
inputs.files("skainet-lang/skainet-lang-core/build/generated/ksp/metadata/commonMain/resources/operators.json")
38+
inputs.files("tools/docgen/src/main/kotlin")
39+
40+
// Configure outputs for incremental builds
41+
outputs.dir("docs/modules/operators/_generated_")
42+
outputs.cacheIf { true }
43+
44+
// Depend on KSP processing
45+
dependsOn(":skainet-lang:skainet-lang-core:kspCommonMainKotlinMetadata")
46+
47+
// Depend on DocGen application
48+
dependsOn(":tools:docgen:run")
49+
50+
// Final step: process with AsciiDoctor
51+
finalizedBy(":tools:docgen:asciidoctor")
52+
53+
doLast {
54+
println("Operator documentation generation completed")
55+
}
56+
}
57+
58+
// Documentation plugin configuration
59+
documentation {
60+
inputFile.set(file("skainet-lang/skainet-lang-core/build/generated/ksp/metadata/commonMain/resources/operators.json"))
61+
outputDirectory.set(file("docs/modules/operators/_generated_"))
62+
includeBackendStatus.set(true)
63+
generateIndex.set(true)
64+
}
65+
66+
tasks.named("generateDocs") {
67+
dependsOn(":skainet-lang:skainet-lang-core:kspCommonMainKotlinMetadata")
2568
}

buildSrc/build.gradle.kts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
plugins {
2+
`kotlin-dsl`
3+
kotlin("jvm") version "2.2.20"
4+
kotlin("plugin.serialization") version "2.2.20"
5+
}
6+
7+
repositories {
8+
gradlePluginPortal()
9+
mavenCentral()
10+
}
11+
12+
dependencies {
13+
implementation(kotlin("stdlib"))
14+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
15+
implementation("org.asciidoctor:asciidoctorj:3.0.0")
16+
implementation(gradleApi())
17+
}
18+
19+
kotlin {
20+
jvmToolchain(17)
21+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import models.DocumentationFormat
2+
import org.gradle.api.Project
3+
import org.gradle.api.file.DirectoryProperty
4+
import org.gradle.api.file.RegularFileProperty
5+
import org.gradle.api.provider.Property
6+
7+
open class DocumentationExtension(project: Project) {
8+
val inputFile: RegularFileProperty = project.objects.fileProperty()
9+
val outputDirectory: DirectoryProperty = project.objects.directoryProperty()
10+
val templateDirectory: DirectoryProperty = project.objects.directoryProperty()
11+
val format: Property<DocumentationFormat> = project.objects.property(DocumentationFormat::class.java)
12+
.convention(DocumentationFormat.ASCIIDOC)
13+
val includeBackendStatus: Property<Boolean> = project.objects.property(Boolean::class.java)
14+
.convention(true)
15+
val generateIndex: Property<Boolean> = project.objects.property(Boolean::class.java)
16+
.convention(true)
17+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import org.gradle.api.Plugin
2+
import org.gradle.api.Project
3+
import org.gradle.api.Action
4+
5+
class DocumentationPlugin : Plugin<Project> {
6+
override fun apply(project: Project) {
7+
val extension = project.extensions.create("documentation", DocumentationExtension::class.java, project)
8+
9+
project.tasks.register("generateDocs", GenerateDocumentationTask::class.java, object : Action<GenerateDocumentationTask> {
10+
override fun execute(task: GenerateDocumentationTask) {
11+
task.group = "documentation"
12+
task.description = "Generate documentation from KSP metadata"
13+
14+
task.inputFile.set(extension.inputFile)
15+
task.outputDirectory.set(extension.outputDirectory)
16+
task.templateDirectory.set(extension.templateDirectory)
17+
task.format.set(extension.format)
18+
task.includeBackendStatus.set(extension.includeBackendStatus)
19+
task.generateIndex.set(extension.generateIndex)
20+
}
21+
})
22+
}
23+
}

0 commit comments

Comments
 (0)