mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-05 15:00:29 +00:00
Use a Gradle plugin to download illuaminate
Previously illumainate required manual users to manually download it and place it in ./bin/. This is both inconvenient for the user, and makes it hard to ensure people are running the "right" version. We now provide a small Gradle plugin which registers illuaminate as a ependency, downloading the appropriate (now versioned!) file. This also theoretically supports Macs, though I don't have access to one to test this. This enables the following changes: - The Lua lint script has been converted to a Gradle task (./gradle lintLua). - illuaminateDocs now uses a task definition with an explicit output directory. We can now consume this output as an input to another task, and get a task dependency implicitly. - Move the pre-commit config into the root of the tree. We can now use the default GitHub action to run our hooks. - Simplify CONTRIBUTING.md a little bit. Hopefully it's less intimidating now.
This commit is contained in:
parent
db8c979a06
commit
ba64e06ca7
27
.github/workflows/main-ci.yml
vendored
27
.github/workflows/main-ci.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
with:
|
||||
java-version: 8
|
||||
|
||||
- name: Cache gradle dependencies
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
@ -32,7 +32,7 @@ jobs:
|
||||
run: |
|
||||
./gradlew assemble || ./gradlew assemble
|
||||
./gradlew downloadAssets || ./gradlew downloadAssets
|
||||
xvfb-run ./gradlew build
|
||||
./gradlew build
|
||||
|
||||
- name: Upload Jar
|
||||
uses: actions/upload-artifact@v2
|
||||
@ -40,31 +40,12 @@ jobs:
|
||||
name: CC-Tweaked
|
||||
path: build/libs
|
||||
|
||||
- name: Upload Screnshots
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Screenshots
|
||||
path: test-files/client/screenshots
|
||||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
if: failure()
|
||||
|
||||
- name: Upload Coverage
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v2
|
||||
|
||||
- name: Parse test reports
|
||||
run: ./tools/parse-reports.py
|
||||
if: ${{ failure() }}
|
||||
|
||||
- name: Cache pre-commit
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: ${{ runner.os }}-pre-commit-${{ hashFiles('config/pre-commit/config.yml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pre-commit-
|
||||
|
||||
- name: Run linters
|
||||
run: |
|
||||
pip install pre-commit
|
||||
pre-commit run --config config/pre-commit/config.yml --show-diff-on-failure --all --color=always
|
||||
uses: pre-commit/action@v3.0.0
|
||||
|
6
.github/workflows/make-doc.yml
vendored
6
.github/workflows/make-doc.yml
vendored
@ -26,12 +26,6 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
|
||||
- name: Setup illuaminate
|
||||
run: |
|
||||
test -d bin || mkdir bin
|
||||
test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
|
||||
chmod +x bin/illuaminate
|
||||
|
||||
- name: Setup node
|
||||
run: npm ci
|
||||
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
/classes
|
||||
/logs
|
||||
/build
|
||||
/buildSrc/build
|
||||
/out
|
||||
/doc/out/
|
||||
/node_modules
|
||||
|
@ -17,6 +17,6 @@ vscode:
|
||||
|
||||
tasks:
|
||||
- name: Setup pre-commit hool
|
||||
init: pre-commit install --config config/pre-commit/config.yml --allow-missing-config
|
||||
init: pre-commit install --allow-missing-config
|
||||
- name: Install npm packages
|
||||
init: npm ci
|
||||
|
@ -41,8 +41,8 @@ repos:
|
||||
- id: illuaminate
|
||||
name: Check Lua code
|
||||
files: ".*\\.(lua|java|md)"
|
||||
language: script
|
||||
entry: config/pre-commit/illuaminate-lint.sh
|
||||
language: system
|
||||
entry: ./gradlew lintLua -i
|
||||
pass_filenames: false
|
||||
require_serial: true
|
||||
|
@ -39,40 +39,30 @@ are run whenever you submit a PR, it's often useful to run this before committin
|
||||
|
||||
- **[Checkstyle]:** Checks Java code to ensure it is consistently formatted. This can be run with `./gradlew build` or
|
||||
`./gradle check`.
|
||||
- **[illuaminate]:** Checks Lua code for semantic and styleistic issues. See [the usage section][illuaminate-usage] for
|
||||
how to download and run it. You may need to generate the Java documentation stubs (see "Documentation" below) for all
|
||||
lints to pass.
|
||||
- **[illuaminate]:** Checks Lua code for semantic and styleistic issues. This can be run with `./gradlew lintLua`.
|
||||
|
||||
### Documentation
|
||||
When writing documentation for [CC: Tweaked's documentation website][docs], it may be useful to build the documentation
|
||||
and preview it yourself before submitting a PR.
|
||||
|
||||
Building all documentation is, sadly, a multi-stage process (though this is largely hidden by Gradle). First we need to
|
||||
convert Java doc-comments into Lua ones, we also generate some Javascript to embed. All of this is then finally fed into
|
||||
illuaminate, which spits out our HTML.
|
||||
Our documentation generation pipeline is rather complex, and involves invoking several external tools. Most of this
|
||||
complexity is hidden by Gradle, but you will need to perform some initial setup:
|
||||
|
||||
#### Setting up the tooling
|
||||
For various reasons, getting the environment set up to build documentation can be pretty complex. I'd quite like to
|
||||
automate this via Docker and/or nix in the future, but this needs to be done manually for now.
|
||||
- Install [Node/npm][node].
|
||||
- Run `npm ci` to install our Node dependencies.
|
||||
|
||||
This tooling is only needed if you need to build the whole website. If you just want to generate the Lua stubs, you can
|
||||
skp this section.
|
||||
- Install Node/npm and install our Node packages with `npm ci`.
|
||||
- Install [illuaminate][illuaminate-usage] as described above.
|
||||
|
||||
#### Building documentation
|
||||
Gradle should be your entrypoint to building most documentation. There's two tasks which are of interest:
|
||||
|
||||
- `./gradlew luaJavadoc` - Generate documentation stubs for Java methods.
|
||||
- `./gradlew docWebsite` - Generate the whole website (including Javascript pages). The resulting HTML is stored at
|
||||
`./build/docs/site/`.
|
||||
You can now run `./gradlew docWebsite`. This generates documentation from our Lua and Java code, writing the resulting
|
||||
HTML into `./build/docs/site`.
|
||||
|
||||
#### Writing documentation
|
||||
illuaminate's documentation system is not currently documented (somewhat ironic), but is _largely_ the same as
|
||||
[ldoc][ldoc]. Documentation comments are written in Markdown,
|
||||
|
||||
Our markdown engine does _not_ support GitHub flavoured markdown, and so does not support all the features one might
|
||||
expect (such as tables). It is very much recommended that you build and preview the docs locally first.
|
||||
expect. It is recommended that you build and preview the docs locally first.
|
||||
|
||||
When iterating on documentation, you can get Gradle to rebuild the website every time a file changes by running
|
||||
`./gradlew docWebsite -t`. This will take a couple of seconds to run, but definitely beats running it manually!
|
||||
|
||||
### Testing
|
||||
Thankfully running tests is much simpler than running the documentation generator! `./gradlew check` will run the
|
||||
@ -90,11 +80,10 @@ Before we get into writing tests, it's worth mentioning the various test suites
|
||||
|
||||
These tests are run by the '"Core" Java' test suite, and so are also run with `./gradlew test`.
|
||||
|
||||
- In-game (`./src/testMod/java/dan200/computercraft/ingame/`): These tests are run on an actual Minecraft server and client,
|
||||
using [the same system Mojang do][mc-test]. The aim of these is to test in-game behaviour of blocks and peripherals.
|
||||
- In-game (`./src/testMod/java/dan200/computercraft/ingame/`): These tests are run on an actual Minecraft server, using
|
||||
the same system Mojang do][mc-test]. The aim of these is to test in-game behaviour of blocks and peripherals.
|
||||
|
||||
These are run by `./gradlew testClient` and `./gradlew testServer`. You may want to run the client under `xvfb-run`
|
||||
or similar when running in a headless environment.
|
||||
These tests are run with `./gradlew testServer`.
|
||||
|
||||
## CraftOS tests
|
||||
CraftOS's tests are written using a test system called "mcfly", heavily inspired by [busted] (and thus RSpec). Groups of
|
||||
@ -107,9 +96,9 @@ asserts that your variable `foo` is equal to the expected value `"bar"`.
|
||||
[community]: README.md#Community "Get in touch with the community."
|
||||
[checkstyle]: https://checkstyle.org/
|
||||
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
|
||||
[illuaminate-usage]: https://github.com/SquidDev/illuaminate/blob/master/README.md#usage "Installing Illuaminate"
|
||||
[weblate]: https://i18n.tweaked.cc/projects/cc-tweaked/minecraft/ "CC: Tweaked weblate instance"
|
||||
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
|
||||
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
|
||||
[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
|
||||
[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing."
|
||||
[node]: https://nodejs.org/en/ "Node.js"
|
||||
|
47
build.gradle
47
build.gradle
@ -11,9 +11,12 @@ plugins {
|
||||
id "org.spongepowered.mixin" version "0.7.+"
|
||||
id "org.parchmentmc.librarian.forgegradle" version "1.+"
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
id "cc-tweaked.illuaminate"
|
||||
}
|
||||
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
import cc.tweaked.gradle.IlluaminateExec
|
||||
import cc.tweaked.gradle.IlluaminateExecToDir
|
||||
|
||||
version = mod_version
|
||||
|
||||
@ -152,6 +155,10 @@ dependencies {
|
||||
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.7'
|
||||
}
|
||||
|
||||
illuaminate {
|
||||
version.set("0.1.0-3-g0f40379")
|
||||
}
|
||||
|
||||
// Compile tasks
|
||||
|
||||
javadoc {
|
||||
@ -302,32 +309,36 @@ def rollup = tasks.register("rollup", Exec.class) {
|
||||
commandLine mkCommand('"node_modules/.bin/rollup" --config rollup.config.js')
|
||||
}
|
||||
|
||||
def illuaminateDocs = tasks.register("illuaminateDocs", Exec.class) {
|
||||
def illuaminateDocs = tasks.register("illuaminateDocs", IlluaminateExecToDir.class) {
|
||||
group = "documentation"
|
||||
description = "Generates docs using Illuaminate"
|
||||
dependsOn(rollup, luaJavadoc)
|
||||
dependsOn(rollup)
|
||||
|
||||
inputs.files(fileTree("doc")).withPropertyName("docs")
|
||||
inputs.files(fileTree("src/main/resources/data/computercraft/lua/rom")).withPropertyName("lua rom")
|
||||
// Config files
|
||||
inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp")
|
||||
inputs.dir("$buildDir/docs/luaJavadoc")
|
||||
// Sources
|
||||
inputs.files(fileTree("doc")).withPropertyName("docs")
|
||||
inputs.files(fileTree("src/main/resources/data/computercraft/lua")).withPropertyName("lua rom")
|
||||
inputs.files(luaJavadoc)
|
||||
// Additional assets
|
||||
inputs.file("$buildDir/rollup/index.js").withPropertyName("scripts")
|
||||
inputs.file("src/web/styles.css").withPropertyName("styles")
|
||||
outputs.dir("$buildDir/docs/lua")
|
||||
|
||||
commandLine mkCommand('"bin/illuaminate" doc-gen')
|
||||
// Output directory. Also defined in illuaminate.sexp and transform.tsx
|
||||
output.set(new File(buildDir, "docs/lua"))
|
||||
|
||||
args = ["doc-gen"]
|
||||
}
|
||||
|
||||
def jsxDocs = tasks.register("jsxDocs", Exec) {
|
||||
group = "documentation"
|
||||
description = "Post-processes documentation to statically render some dynamic content."
|
||||
dependsOn(illuaminateDocs)
|
||||
|
||||
inputs.files(fileTree("src/web")).withPropertyName("sources")
|
||||
inputs.file("src/generated/export/index.json").withPropertyName("export")
|
||||
inputs.file("package-lock.json").withPropertyName("package-lock.json")
|
||||
inputs.file("tsconfig.json").withPropertyName("Typescript config")
|
||||
inputs.files(fileTree("$buildDir/docs/lua"))
|
||||
inputs.files(illuaminateDocs)
|
||||
outputs.dir("$buildDir/docs/site")
|
||||
|
||||
commandLine mkCommand('"node_modules/.bin/ts-node" -T --esm src/web/transform.tsx')
|
||||
@ -391,6 +402,24 @@ license {
|
||||
|
||||
check.dependsOn("licenseCheck")
|
||||
|
||||
def lintLua = tasks.register("lintLua", IlluaminateExec.class) {
|
||||
group = JavaBasePlugin.VERIFICATION_GROUP
|
||||
description = "Lint Lua (and Lua docs) with illuaminate"
|
||||
|
||||
// Config files
|
||||
inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp")
|
||||
// Sources
|
||||
inputs.files(fileTree("doc")).withPropertyName("docs")
|
||||
inputs.files(fileTree("src/main/resources/data/computercraft/lua")).withPropertyName("lua rom")
|
||||
inputs.files(luaJavadoc)
|
||||
|
||||
args = ["lint"]
|
||||
|
||||
doFirst { if (System.getenv("GITHUB_ACTIONS") != null) println("::add-matcher::.github/matchers/illuaminate.json") }
|
||||
doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
|
||||
}
|
||||
|
||||
|
||||
def setupServer = tasks.register("setupServer", Copy.class) {
|
||||
group "test server"
|
||||
description "Sets up the environment for the test server."
|
||||
|
18
buildSrc/build.gradle.kts
Normal file
18
buildSrc/build.gradle.kts
Normal file
@ -0,0 +1,18 @@
|
||||
plugins {
|
||||
`java-gradle-plugin`
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
register("cc-tweaked.illuaminate") {
|
||||
id = "cc-tweaked.illuaminate"
|
||||
implementationClass = "cc.tweaked.gradle.IlluaminatePlugin"
|
||||
}
|
||||
}
|
||||
}
|
11
buildSrc/src/main/kotlin/cc/tweaked/gradle/ExecTasks.kt
Normal file
11
buildSrc/src/main/kotlin/cc/tweaked/gradle/ExecTasks.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.AbstractExecTask
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import java.io.File
|
||||
|
||||
abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
|
||||
@get:OutputDirectory
|
||||
abstract val output: Property<File>
|
||||
}
|
121
buildSrc/src/main/kotlin/cc/tweaked/gradle/Illuaminate.kt
Normal file
121
buildSrc/src/main/kotlin/cc/tweaked/gradle/Illuaminate.kt
Normal file
@ -0,0 +1,121 @@
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.AbstractExecTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import java.io.File
|
||||
|
||||
abstract class IlluaminateExtension {
|
||||
/** The version of illuaminate to use. */
|
||||
abstract val version: Property<String>
|
||||
|
||||
/** The path to illuaminate. If not given, illuaminate will be downloaded automatically. */
|
||||
abstract val file: Property<File>
|
||||
}
|
||||
|
||||
class IlluaminatePlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
val extension = project.extensions.create("illuaminate", IlluaminateExtension::class.java)
|
||||
extension.file.convention(setupDependency(project, extension.version))
|
||||
|
||||
project.tasks.register(SetupIlluaminate.NAME, SetupIlluaminate::class.java) {
|
||||
file.set(extension.file.map { it.absolutePath })
|
||||
}
|
||||
}
|
||||
|
||||
/** Set up a repository for illuaminate and download our binary from it. */
|
||||
private fun setupDependency(project: Project, version: Provider<String>): Provider<File> {
|
||||
project.repositories.ivy {
|
||||
name = "Illuaminate"
|
||||
setUrl("https://squiddev.cc/illuaminate/bin/")
|
||||
patternLayout {
|
||||
artifact("[revision]/[artifact]-[ext]")
|
||||
}
|
||||
metadataSources {
|
||||
artifact()
|
||||
}
|
||||
content {
|
||||
includeModule("cc.squiddev", "illuaminate")
|
||||
}
|
||||
}
|
||||
|
||||
return version.map {
|
||||
val dep = illuaminateArtifact(project, it)
|
||||
val configuration = project.configurations.detachedConfiguration(dep)
|
||||
configuration.isTransitive = false
|
||||
configuration.resolve().single()
|
||||
}
|
||||
}
|
||||
|
||||
/** Define a dependency for illuaminate from a version number and the current operating system. */
|
||||
private fun illuaminateArtifact(project: Project, version: String): Dependency {
|
||||
val osName = System.getProperty("os.name").toLowerCase()
|
||||
val (os, suffix) = when {
|
||||
osName.contains("windows") -> Pair("windows", ".exe")
|
||||
osName.contains("mac os") || osName.contains("darwin") -> Pair("macos", "")
|
||||
osName.contains("linux") -> Pair("linux", "")
|
||||
else -> error("Unsupported OS $osName for illuaminate")
|
||||
}
|
||||
|
||||
val osArch = System.getProperty("os.arch").toLowerCase()
|
||||
val arch = when {
|
||||
osArch == "arm" || osArch.startsWith("aarch") -> error("Unsupported architecture '$osArch' for illuaminate")
|
||||
osArch.contains("64") -> "x86_64"
|
||||
else -> error("Unsupported architecture $osArch for illuaminate")
|
||||
}
|
||||
|
||||
return project.dependencies.create(
|
||||
mapOf(
|
||||
"group" to "cc.squiddev",
|
||||
"name" to "illuaminate",
|
||||
"version" to version,
|
||||
"ext" to "$os-$arch$suffix",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val Task.illuaminatePath: String? // "?" needed to avoid overload ambiguity in setExecutable below.
|
||||
get() = project.extensions.getByType(IlluaminateExtension::class.java).file.get().absolutePath
|
||||
|
||||
/** Prepares illuaminate for being run. This simply requests the dependency and then marks it as executable. */
|
||||
abstract class SetupIlluaminate : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val file: Property<String>
|
||||
|
||||
@TaskAction
|
||||
fun setExecutable() {
|
||||
val file = File(this.file.get())
|
||||
if (file.canExecute()) {
|
||||
didWork = false
|
||||
return
|
||||
}
|
||||
|
||||
file.setExecutable(true)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME: String = "setupIlluaminate"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class IlluaminateExec : AbstractExecTask<IlluaminateExec>(IlluaminateExec::class.java) {
|
||||
init {
|
||||
dependsOn(SetupIlluaminate.NAME)
|
||||
executable = illuaminatePath
|
||||
}
|
||||
}
|
||||
|
||||
abstract class IlluaminateExecToDir : ExecToDir() {
|
||||
init {
|
||||
dependsOn(SetupIlluaminate.NAME)
|
||||
executable = illuaminatePath
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
set -e
|
||||
|
||||
test -d bin || mkdir bin
|
||||
test -f bin/illuaminate || curl -s -obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
|
||||
chmod +x bin/illuaminate
|
||||
|
||||
if [ -n ${GITHUB_ACTIONS+x} ]; then
|
||||
# Register a problem matcher (see https://github.com/actions/toolkit/blob/master/docs/problem-matchers.md)
|
||||
# for illuaminate.
|
||||
echo "::add-matcher::.github/matchers/illuaminate.json"
|
||||
trap 'echo "::remove-matcher owner=illuaminate::"' EXIT
|
||||
fi
|
||||
|
||||
./gradlew luaJavadoc
|
||||
bin/illuaminate lint
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
Loading…
Reference in New Issue
Block a user