diff --git a/.github/workflows/warn-version-bump.yml b/.github/workflows/warn-version-bump.yml new file mode 100644 index 00000000..bc479050 --- /dev/null +++ b/.github/workflows/warn-version-bump.yml @@ -0,0 +1,48 @@ +name: Warn Version Bump + +on: pull_request + +jobs: + warn-version-bump: + runs-on: ubuntu-latest + steps: + - name: Checkout target branch + uses: actions/checkout@v3.5.3 + with: + ref: ${{ github.base_ref }} + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: temurin + cache: gradle + + - name: Generate the api file + run: | + ./gradlew exportApi --no-daemon + + - name: Save public.api from target branch + run: | + mkdir ~/common/ && \ + mkdir ~/generativeai/ && \ + mv generativeai/public.api ~/generativeai/public.api && \ + mv common/public.api ~/common/public.api + + - name: Checkout branch + uses: actions/checkout@v3.5.3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: temurin + cache: gradle + + - name: Copy saved api to branch + run: | + mv ~/generativeai/public.api generativeai/public.api && \ + mv ~/common/public.api common/public.api + - name: Run API versioning check + run: | + if ! test -d .changes || git diff --quiet ${{ github.event.pull_request.base.sha }}..HEAD .changes ; then ./gradlew warnVersionBump ; else exit 0 ; fi diff --git a/plugins/src/main/java/com/google/gradle/plugins/ChangelogPlugin.kt b/plugins/src/main/java/com/google/gradle/plugins/ChangelogPlugin.kt index fb6b7d86..7a79c3a0 100644 --- a/plugins/src/main/java/com/google/gradle/plugins/ChangelogPlugin.kt +++ b/plugins/src/main/java/com/google/gradle/plugins/ChangelogPlugin.kt @@ -20,6 +20,7 @@ import com.google.gradle.tasks.FindChangesTask import com.google.gradle.tasks.MakeChangeTask import com.google.gradle.tasks.MakeReleaseNotesTask import com.google.gradle.tasks.WarnAboutApiChangesTask +import com.google.gradle.tasks.WarnVersionBumpTask import com.google.gradle.types.Changelog import com.google.gradle.types.RandomWordsGenerator import com.google.gradle.util.apply @@ -34,6 +35,7 @@ import com.google.gradle.util.regularOutputFile import com.google.gradle.util.tempFile import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.Delete import org.gradle.api.tasks.Optional @@ -85,14 +87,22 @@ abstract class ChangelogPlugin : Plugin { tasks.register("makeChange") { val changeMessage = provideProperty("changeMessage") - val changeName = RandomWordsGenerator.generateString() - val changeOutput = extension.outputDirectory.childFile("$changeName.json") + val changeName = provideProperty("changeName") + .orElse(RandomWordsGenerator.generateString()) + val changeOutput = extension.outputDirectory.childFile("${changeName.get()}.json") changesFile.set(fileChanges) message.set(changeMessage) outputFile.set(changeOutput) } + tasks.register("warnVersionBump") { + if (export.isPresent) { + export.set(apiPlugin.exportFile) + } + changesFile.set(fileChanges) + } + tasks.register("warnAboutApiChanges") { changesFile.set(fileChanges) outputFile.set(extension.apiChangesFile) diff --git a/plugins/src/main/java/com/google/gradle/tasks/WarnVersionBumpTask.kt b/plugins/src/main/java/com/google/gradle/tasks/WarnVersionBumpTask.kt new file mode 100644 index 00000000..1b281828 --- /dev/null +++ b/plugins/src/main/java/com/google/gradle/tasks/WarnVersionBumpTask.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2024 Google LLC + * + * 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.google.gradle.tasks + +import com.google.gradle.types.LinesChanged +import com.google.gradle.types.VersionType.* +import org.gradle.api.DefaultTask +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.TaskExecutionException + +/** + * A Gradle task to warn about API version bumps beyond what is expected + * + * The task uses the provided [changesFile] to infer if merging the changes currently present in the + * repo will have an impact on the public api. + * + * @property changesFile a file containing a [LinesChanged]; representing the changes made in this + * repo + * @throws TaskExecutionException if changes cause an minor or major API bump + */ +abstract class WarnVersionBumpTask : DefaultTask() { + @get:[Optional InputFile] abstract val export: RegularFileProperty + + @get:InputFile abstract val changesFile: RegularFileProperty + + @TaskAction + fun add() { + val diff = LinesChanged.fromFile(changesFile.asFile.get()) + + if (diff.bump == MAJOR || diff.bump == MINOR) { + if (export.isPresent) { + throw TaskExecutionException(this, Exception("Based on exported API, changes are ${diff.bump}, higher than PATCH. If this is intended, add a changelog entry. Otherwise, revert the changes.")) + } else { + throw TaskExecutionException(this, Exception("Based on last release API, changes are ${diff.bump}, higher than PATCH. If this is intended, add a changelog entry. Otherwise, revert the changes. To compare local changes, run exportApi on a commit first.")) + } + } + } +}