Skip to content

Commit b91a7ff

Browse files
Reflective docs for Ops
2 parents dc21310 + 549655a commit b91a7ff

38 files changed

Lines changed: 2339 additions & 5 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+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Schema Validation
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
paths:
9+
- 'skainet-lang/**'
10+
- '.github/workflows/schema-validation.yml'
11+
12+
jobs:
13+
validate-schema:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
20+
- name: Set up JDK 17
21+
uses: actions/setup-java@v4
22+
with:
23+
java-version: '17'
24+
distribution: 'temurin'
25+
26+
- name: Cache Gradle packages
27+
uses: actions/cache@v4
28+
with:
29+
path: |
30+
~/.gradle/caches
31+
~/.gradle/wrapper
32+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
33+
restore-keys: |
34+
${{ runner.os }}-gradle-
35+
36+
- name: Grant execute permission for gradlew
37+
run: chmod +x gradlew
38+
39+
- name: Generate operator documentation (KSP)
40+
run: ./gradlew :skainet-lang:skainet-lang-core:kspCommonMainKotlinMetadata
41+
42+
- name: Validate JSON schema via Gradle plugin
43+
run: ./gradlew validateOperatorSchema
44+
45+
- name: Upload validation artifacts
46+
if: failure()
47+
uses: actions/upload-artifact@v4
48+
with:
49+
name: validation-logs
50+
path: |
51+
**/build/generated/**/*.json
52+
**/build/logs/
53+
retention-days: 7

.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

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,46 @@ This project follows established development practices for maintaining code qual
1111

1212
* **Branching Model**: We use [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) as our branching strategy for managing feature development, releases, and hotfixes.
1313
* **Versioning**: We follow [Semantic Versioning (SemVer)](https://semver.org/) for all releases, ensuring predictable version numbering based on the nature of changes.
14+
15+
## Reflective Documentation (short overview)
16+
17+
SKaiNET includes a reflective documentation system that keeps docs in sync with the code. During the build, a KSP processor extracts operator metadata (signatures, parameters, backend availability, implementation status) into a JSON file. A small DocGen tool then converts this JSON into AsciiDoc fragments and pages.
18+
19+
- Source of truth (generated): skainet-lang/skainet-lang-core/build/generated/ksp/metadata/commonMain/resources/operators.json
20+
- Generated docs output: docs/modules/operators/_generated_/
21+
- Asciidoctor site output: build/docs/asciidoc/ (if you run an Asciidoctor task locally)
22+
23+
### Quick start: generate reflective docs
24+
25+
Use any of the following Gradle tasks from the project root:
26+
27+
1) Full pipeline (recommended)
28+
./gradlew generateDocs
29+
- Runs KSP to produce operators.json (if needed)
30+
- Generates AsciiDoc files under docs/modules/operators/_generated_
31+
- Optionally, you can run an Asciidoctor task to build an HTML site locally (output under build/docs/asciidoc)
32+
33+
2) Operators documentation only
34+
./gradlew generateOperatorDocs
35+
- Depends on KSP; runs the built-in generateDocs task and then Asciidoctor
36+
37+
Open the generated AsciiDoc sources in docs/modules/operators/_generated_ with your preferred AsciiDoc viewer. If you build an HTML site locally with Asciidoctor, open build/docs/asciidoc.
38+
39+
### Documentation tooling
40+
41+
We now use the Gradle plugin (buildSrc) only. The former skainet-lang-export-ops module has been removed. All everyday workflows are covered by:
42+
- generateDocs — converts KSP JSON to AsciiDoc
43+
- validateOperatorSchema — validates generated operators.json against the JSON schema
44+
45+
Run from the project root, for example:
46+
- ./gradlew generateDocs
47+
- ./gradlew validateOperatorSchema
48+
49+
---
50+
51+
## Development Practices
52+
53+
This project follows established development practices for maintaining code quality and release management:
54+
55+
* Branching Model: We use GitFlow as our branching strategy for managing feature development, releases, and hotfixes.
56+
* Versioning: We follow Semantic Versioning (SemVer) for all releases, ensuring predictable version numbering based on the nature of changes.

build.gradle.kts

Lines changed: 38 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,38 @@ 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+
// Configure outputs for incremental builds
39+
outputs.dir("docs/modules/operators/_generated_")
40+
outputs.cacheIf { true }
41+
42+
// Depend on KSP processing
43+
dependsOn(":skainet-lang:skainet-lang-core:kspCommonMainKotlinMetadata")
44+
45+
// Run built-in documentation generation task (provided by sk.ainet.documentation plugin)
46+
dependsOn("generateDocs")
47+
48+
doLast {
49+
println("Operator documentation generation completed")
50+
}
51+
}
52+
53+
// Documentation plugin configuration
54+
documentation {
55+
inputFile.set(file("skainet-lang/skainet-lang-core/build/generated/ksp/metadata/commonMain/resources/operators.json"))
56+
outputDirectory.set(file("docs/modules/operators/_generated_"))
57+
includeBackendStatus.set(true)
58+
generateIndex.set(true)
59+
}
60+
61+
tasks.named("generateDocs") {
62+
dependsOn(":skainet-lang:skainet-lang-core:kspCommonMainKotlinMetadata")
2563
}

buildSrc/build.gradle.kts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
// JSON schema validation dependencies for SchemaValidationTask
17+
implementation("com.networknt:json-schema-validator:1.0.87")
18+
implementation("com.fasterxml.jackson.core:jackson-databind:2.15.2")
19+
implementation(gradleApi())
20+
}
21+
22+
kotlin {
23+
jvmToolchain(17)
24+
}
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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import org.gradle.api.Plugin
2+
import org.gradle.api.Project
3+
import org.gradle.api.Action
4+
import org.gradle.kotlin.dsl.named
5+
import org.gradle.kotlin.dsl.register
6+
import org.gradle.kotlin.dsl.configureEach
7+
8+
class DocumentationPlugin : Plugin<Project> {
9+
override fun apply(project: Project) {
10+
val extension = project.extensions.create("documentation", DocumentationExtension::class.java, project)
11+
12+
project.tasks.register("generateDocs", GenerateDocumentationTask::class.java, object : Action<GenerateDocumentationTask> {
13+
override fun execute(task: GenerateDocumentationTask) {
14+
task.group = "documentation"
15+
task.description = "Generate documentation from KSP metadata"
16+
17+
task.inputFile.set(extension.inputFile)
18+
task.outputDirectory.set(extension.outputDirectory)
19+
task.templateDirectory.set(extension.templateDirectory)
20+
task.format.set(extension.format)
21+
task.includeBackendStatus.set(extension.includeBackendStatus)
22+
task.generateIndex.set(extension.generateIndex)
23+
}
24+
})
25+
26+
// Register schema validation task in plugin (migrated from skainet-lang-export-ops)
27+
val validateTaskProvider = project.tasks.register("validateOperatorSchema", SchemaValidationTask::class.java, object : Action<SchemaValidationTask> {
28+
override fun execute(task: SchemaValidationTask) {
29+
task.group = "verification"
30+
task.description = "Validate generated operators.json files against the JSON schema"
31+
// By default search from the root project dir to find all operators.json
32+
task.searchDirectory.set(project.rootProject.layout.projectDirectory)
33+
}
34+
})
35+
}
36+
}

0 commit comments

Comments
 (0)