Skip to content

Commit

Permalink
support buf generate (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewparmet authored Apr 10, 2022
1 parent 6aff908 commit 6827fe5
Show file tree
Hide file tree
Showing 32 changed files with 581 additions and 28 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 11

- name: Set up JDK 17
uses: actions/setup-java@v2
with:
distribution: adopt
java-version: 11
java-version: 17

- name: Build
run: ./gradlew build --info

- name: Publish unit test results
uses: EnricoMi/publish-unit-test-result-action@v1
if: always()
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Publish

on:
push:
tags:
tags:
- "[0-9]+.[0-9]+.[0-9]+"

workflow_dispatch:

jobs:
Expand All @@ -25,11 +25,11 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 11

- name: Set up JDK 17
uses: actions/setup-java@v1
with:
java-version: 11
java-version: 17

- name: Publish
run: ./gradlew publishToRemote closeAndReleaseRepository publishPlugins -Dorg.gradle.internal.http.socketTimeout=120000 -Dorg.gradle.internal.network.retry.max.attempts=1 -Dorg.gradle.internal.publish.checksums.insecure=true
Expand Down
46 changes: 43 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

Linting and breakage-check integration for [Buf](https://github.com/bufbuild/buf) with Gradle. Supports integration purely between Buf and Gradle or additionally with the [protobuf-gradle-plugin](https://github.com/google/protobuf-gradle-plugin).

This plugin supports straightforward usage of `buf lint` and a self-contained integration between `buf build` and `buf breaking`. It does not (yet) integrate with `buf generate`.
This plugin supports straightforward usage of `buf lint` and `buf generate` and a self-contained integration between `buf build` and `buf breaking`.

## Usage

By default this plugin assumes that Buf is configured for the project root (with or without a workspace `buf.work.yaml`). It will scan all top-level directories for protobuf sources.

If the project includes the `protobuf-gradle-plugin`, then this plugin will use an implicit Buf workspace that includes all specified protobuf source set directories, the `include` dependencies that the protobuf-gradle-plugin extracts into `"${project.buildDir}/extracted-include-protos"`, and the dependencies that the protobuf-gradle-plugin has been told to generate that are extracted into `"${project.buildDir}/extracted-protos"`.
If the project includes the `protobuf-gradle-plugin`, then this plugin will use an implicit Buf workspace that includes all specified protobuf source set directories, the `include` dependencies that the protobuf-gradle-plugin extracts into `"$buildDir/extracted-include-protos"`, and the dependencies that the protobuf-gradle-plugin has been told to generate that are extracted into `"$buildDir/extracted-protos"`.

This plugin does not support usage of both a Buf workspace and the `protobuf-gradle-plugin`; determining ownership of dependency resolution in that case would be complicated and error-prone.

Expand All @@ -35,9 +35,10 @@ buildscript {
apply(plugin = "com.parmet.buf")
```

When applied the plugin creates two useful tasks:
When applied the plugin creates several tasks:
- `bufLint` lints protobuf code
- `bufBreaking` checks protobuf against a previous version for backwards-incompatible changes
- `bufGenerate` generates protobuf code

## Configuration

Expand Down Expand Up @@ -170,6 +171,45 @@ buf {
}
```

### `bufGenerate`

`bufGenerate` is configured as described in the Buf docs. Create a `buf.gen.yaml` in the project root and `bufGenerate` will generate code in the project's build directory at `"$buildDir/bufbuild/generated/<out path from buf.gen.yaml>"`.

An example for Java code generation using the remote plugin:

``` yaml
version: v1
plugins:
- remote: buf.build/protocolbuffers/plugins/java:<version>
out: java
```
If you want to use generated code in your build you must add the generated code as a source directory and configure a task dependency to ensure code is generated before compilation:
``` kotlin
// build.gradle.kts

import com.parmet.buf.gradle.BUF_GENERATED_DIR

plugins {
`java`
id("com.parmet.buf") version "<version>"
}

// Add a task dependency for compilation
tasks.named("compileJava").configure { dependsOn("bufGenerate") }

// Add the generated code to the main source set
sourceSets["main"].java { srcDir("$buildDir/$BUF_GENERATED_DIR/java") }

// Configure dependencies for protobuf-java:
repositories { mavenCentral() }

dependencies {
implementation("com.google.protobuf:protobuf-java:<protobuf version>")
}
```

## Additional Configuration

The version of Buf used can be configured using the `toolVersion` property on the extension:
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ tasks {
dependencies {
signature(libs.java8Signature) { artifact { type = "signature" } }

testImplementation(libs.junit)
testImplementation(libs.junit) { version { branch = "main" } }
testImplementation(libs.truth)
}

Expand Down
3 changes: 1 addition & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ spotless = "6.3.0"
java8Signature = "1.0"

# test
junit = "5.8.2"
truth = "1.1.3"

[plugins]
Expand All @@ -34,5 +33,5 @@ spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
java8Signature = { module = "org.codehaus.mojo.signature:java18", version.ref = "java8Signature" }

# test
junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
junit = { module = "org.junit.jupiter:junit-jupiter" }
truth = { module = "com.google.truth:truth", version.ref = "truth" }
8 changes: 8 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* limitations under the License.
*/

import java.net.URI

buildscript {
repositories {
gradlePluginPortal()
Expand All @@ -25,3 +27,9 @@ buildscript {
apply(plugin = "net.vivin.gradle-semantic-build-versioning")

rootProject.name = "buf-gradle-plugin"

sourceControl {
gitRepository(URI.create("https://github.com/andrewparmet/junit5.git")) {
producesModule("org.junit.jupiter:junit-jupiter")
}
}
2 changes: 1 addition & 1 deletion src/main/kotlin/com/parmet/buf/gradle/Breaking.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private fun Project.configureBreakingTask(ext: BufExtension, bufBreakingFile: La
buf(
ext,
"breaking",
qualifyFile(BUF_BUILD_PUBLICATION_FILENAME),
qualifyFile(BUF_BUILD_PUBLICATION_FILE_NAME),
"--against",
qualifyFile { "$BREAKING_DIR/${bufBreakingFile.fileName}" }
)
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/com/parmet/buf/gradle/BufPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class BufPlugin : Plugin<Project> {
If you have multiple protobuf source directories and you would like to
use the protobuf-gradle-plugin, configure the protobuf-gradle-plugin to use
those directories as source directories in the appropriate source set. If you
would like to use Buf workspaces, you must configure dependency resolution and
would like to use a Buf workspace, you must configure dependency resolution and
code generation using Buf. There is no (easy) way to reconcile the two
configurations for linting, breakage, and code generation steps.
""".trimIndent().replace('\n', ' ')
Expand All @@ -59,6 +59,7 @@ class BufPlugin : Plugin<Project> {
private fun Project.configureBuf(ext: BufExtension) {
configureLint(ext)
configureBuild(ext)
configureGenerate(ext)

afterEvaluate {
getArtifactDetails(ext)?.let {
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/com/parmet/buf/gradle/Build.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.the

const val BUF_BUILD_TASK_NAME = "bufBuild"
const val BUF_BUILD_PUBLICATION_FILENAME = "image.json"
const val BUF_BUILD_PUBLICATION_FILE_NAME = "image.json"
const val BUF_IMAGE_PUBLICATION_NAME = "bufImagePublication"

internal fun Project.configureBuild(ext: BufExtension) {
Expand All @@ -36,7 +36,7 @@ internal fun Project.configureBuild(ext: BufExtension) {
createsOutput()
}

buf(ext, "build", "--output", qualifyFile(BUF_BUILD_PUBLICATION_FILENAME))
buf(ext, "build", "--output", qualifyFile(BUF_BUILD_PUBLICATION_FILE_NAME))
}
}

Expand All @@ -49,7 +49,7 @@ internal fun Project.configureImagePublication(artifactDetails: ArtifactDetails)
artifactId = artifactDetails.artifactId
version = artifactDetails.version

artifact(file("$bufbuildDir/$BUF_BUILD_PUBLICATION_FILENAME")) {
artifact(file("$bufbuildDir/$BUF_BUILD_PUBLICATION_FILE_NAME")) {
builtBy(tasks.named(BUF_BUILD_TASK_NAME))
}
}
Expand Down
37 changes: 37 additions & 0 deletions src/main/kotlin/com/parmet/buf/gradle/Generate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2022 Andrew Parmet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.parmet.buf.gradle

import org.gradle.api.Project
import org.gradle.api.tasks.Exec
import org.gradle.kotlin.dsl.register

const val BUF_GENERATE_TASK_NAME = "bufGenerate"

private const val GENERATED_DIR = "generated"
const val BUF_GENERATED_DIR = "$BUF_BUILD_DIR/$GENERATED_DIR"

internal fun Project.configureGenerate(ext: BufExtension) {
if (hasGenerate()) {
tasks.register<Exec>(BUF_GENERATE_TASK_NAME) {
createsOutput()
buf(ext, "generate", "--output", qualifyFile(GENERATED_DIR))
}
}
}

private fun Project.hasGenerate() =
file("buf.gen.yaml").let { it.exists() && it.isFile }
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,26 @@ import com.google.common.truth.Truth.assertWithMessage
import org.gradle.testkit.runner.GradleRunner
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestInfo
import org.junit.jupiter.api.io.CleanupMode.NEVER
import org.junit.jupiter.api.io.TempDir
import java.io.File
import java.nio.file.Paths

abstract class AbstractBufIntegrationTest : IntegrationTest {
@TempDir
@TempDir(cleanup = NEVER)
lateinit var projectDir: File

private lateinit var settingsFile: File
lateinit var buildFile: File
lateinit var protoDir: File
private val settingsFile
get() = File(projectDir, "settings.gradle")

val buildFile
get() = File(projectDir, "build.gradle").takeIf { it.exists() } ?: File(projectDir, "build.gradle.kts")

val protoDir
get() = Paths.get(projectDir.path, "src", "main", "proto").toFile()

@BeforeEach
fun setup(testInfo: TestInfo) {
settingsFile = File(projectDir, "settings.gradle")
buildFile = File(projectDir, "build.gradle")
protoDir = Paths.get(projectDir.path, "src", "main", "proto").toFile()

settingsFile.writeText("rootProject.name = 'testing'")

val fixture = File("src/test/resources/${testInfo.testClass.get().simpleName}/${testInfo.testMethod.get().name}")
Expand Down
30 changes: 30 additions & 0 deletions src/test/kotlin/com/parmet/buf/gradle/AbstractGenerateTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2022 Andrew Parmet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.parmet.buf.gradle

import org.junit.jupiter.api.Test

abstract class AbstractGenerateTest : AbstractBufIntegrationTest() {
@Test
fun `generate java`() {
gradleRunner().withArguments("build").build()
}

@Test
fun `generate java with kotlin dsl`() {
gradleRunner().withArguments("build").build()
}
}
18 changes: 18 additions & 0 deletions src/test/kotlin/com/parmet/buf/gradle/GenerateTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2022 Andrew Parmet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.parmet.buf.gradle

class GenerateTest : AbstractGenerateTest()
18 changes: 18 additions & 0 deletions src/test/kotlin/com/parmet/buf/gradle/GenerateWithWorkspaceTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2022 Andrew Parmet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.parmet.buf.gradle

class GenerateWithWorkspaceTest : AbstractGenerateTest()
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) 2022 Andrew Parmet
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

version: v1
plugins:
- remote: buf.build/protocolbuffers/plugins/java:v3.20.0-1
out: java
Loading

0 comments on commit 6827fe5

Please sign in to comment.