Skip to content

Publishing

TheMeinerLP edited this page Aug 1, 2026 · 2 revisions

How Falco's four published artefacts (falco-anvil, falco-light, falco-instance, falco-bom) reach a Maven repository, and why falco-bom is configured differently from the three library modules despite sharing most of the setup.

Which modules publish

val publishedModules = listOf(
    project(":falco-anvil"), project(":falco-light"), project(":falco-instance"), project(":falco-bom")
)

falco-benchmarks and falco-demo deliberately never apply maven-publish, so a ./gradlew publish at the root passes over them without needing an explicit task exclusion — they are simply absent from this list. See Benchmarks and Demo for what those two modules are for instead.

One shared repository configuration

configure(publishedModules) {
    apply(plugin = "maven-publish")

    extensions.configure<PublishingExtension> {
        repositories {
            maven {
                authentication {
                    credentials(PasswordCredentials::class) {
                        username = System.getenv("ONELITEFEATHER_MAVEN_USERNAME")
                        password = System.getenv("ONELITEFEATHER_MAVEN_PASSWORD")
                    }
                }
                name = "OneLiteFeatherRepository"
                url = if (project.version.toString().contains("SNAPSHOT")) {
                    uri("https://repo.onelitefeather.dev/snapshots")
                } else {
                    uri("https://repo.onelitefeather.dev/releases")
                }
            }
        }
    }
}

The repository is the one thing all four published modules share, regardless of what they publish or how: a library module ships a jar built from components["java"], falco-bom ships only a POM built from components["javaPlatform"], but both land in the same Reposilite instance behind the same release/snapshot switch and the same credentials. Configuring that once here, rather than once per module, keeps a future change to the repository (a new host, a different credential scheme) a one-line edit instead of a four-line one — which is also why this block applies maven-publish itself, rather than leaving each module to apply it before configuring its own publication.

The two public Reposilite endpoints (/releases and /snapshots) require no credentials for a consumer; they are separate from the internal, credentialed repository the build resolves against (configured in settings.gradle.kts, see Dependency Management). Which of the two endpoints a build publishes to is decided purely by whether SNAPSHOT appears in the version string — see Versioning and Releases for how that string is produced.

What gets published differs by project kind

configure(listOf(project(":falco-anvil"), project(":falco-light"), project(":falco-instance"))) {
    extensions.configure<JavaPluginExtension> {
        withJavadocJar()
        withSourcesJar()
    }
    extensions.configure<PublishingExtension> {
        publications.create<MavenPublication>("maven") {
            from(components["java"])
        }
    }
}

project(":falco-bom") {
    extensions.configure<PublishingExtension> {
        publications.create<MavenPublication>("maven") {
            from(components["javaPlatform"])
        }
    }
}

This part of the configuration stays split from the shared repository block above because what gets published genuinely differs by project kind. The three library modules carry a JavaPluginExtension to request sources and Javadoc jars and publish the java software component. falco-bom has neither a JavaPluginExtension nor anything to document or compile — a platform module's only published file is the POM its javaPlatform component becomes, so asking it for withJavadocJar() / withSourcesJar() would fail outright.

falco-bom: pinning by project reference, not by version string

falco-bom/build.gradle.kts itself is short — a java-platform project carries no sources and no compiled output of its own, only constraints:

dependencies {
    constraints {
        api(project(":falco-anvil"))
        api(project(":falco-light"))
        api(project(":falco-instance"))
    }
}

These are written as project references rather than "net.onelitefeather:falco-anvil:<version>" string literals so the pinned version can never drift from the one the sibling module actually builds as. A hardcoded string would need to be kept in sync by hand on every release; a project reference makes Gradle read project(":falco-anvil").version itself when it writes the constraint — which, per the root build's subprojects block (see Build Setup), is exactly rootProject.version, the same single line Release Please rewrites.

Clone this wiki locally