Skip to content

Migrate from Google OSS Licenses plugin to cashapp/licensee#2076

Open
suman9259 wants to merge 2 commits intoandroid:mainfrom
suman9259:migrate-oss-licenses-to-licensee
Open

Migrate from Google OSS Licenses plugin to cashapp/licensee#2076
suman9259 wants to merge 2 commits intoandroid:mainfrom
suman9259:migrate-oss-licenses-to-licensee

Conversation

@suman9259
Copy link

Google's OSS Licenses plugin flags its task as
notCompatibleWithConfigurationCache(), which causes the entire configuration cache to be discarded on each build that triggers it. The plugin also does not support edge-to-edge and uses old AppCompat UI.

This replaces the plugin with cashapp/licensee, which:

  • Is configuration-cache compatible
  • Has no runtime dependency (build-time only Gradle plugin)
  • Enables a Compose-based licenses screen with Material 3 support
  • Adds license validation via an allow-list

Changes:

  • Replace oss-licenses-plugin with cashapp/licensee in Gradle config
  • Remove play-services-oss-licenses runtime dependency
  • Remove OssLicensesMenuActivity/OssLicensesActivity declarations
  • Add licensee configuration with allowed SPDX licenses
  • Add Gradle task to copy licensee artifacts.json to app assets
  • Create Compose LicensesScreen to display license data
  • Update SettingsDialog to navigate to new LicensesScreen

Fixes #1022

Test: ./gradlew installDemoDebug, manual verification of licenses screen

DO NOT CREATE A PULL REQUEST WITHOUT READING THESE INSTRUCTIONS

Instructions

Thanks for submitting a pull request. To accept your pull request we need you do a few things:

If this is your first pull request

Ensure tests pass and code is formatted correctly

  • Run local tests on the DemoDebug variant by running ./gradlew testDemoDebug
  • Fix code formatting: ./gradlew spotlessApply

Add a description

We need to know what you've done and why you've done it. Include a summary of what your pull request contains, and why you have made these changes. Include links to any relevant issues which it fixes.

Here's an example.

NOW DELETE THIS LINE AND EVERYTHING ABOVE IT

What I have done and why

<add your PR description here>

Google's OSS Licenses plugin flags its task as
notCompatibleWithConfigurationCache(), which causes the entire
configuration cache to be discarded on each build that triggers it.
The plugin also does not support edge-to-edge and uses old AppCompat UI.

This replaces the plugin with cashapp/licensee, which:
- Is configuration-cache compatible
- Has no runtime dependency (build-time only Gradle plugin)
- Enables a Compose-based licenses screen with Material 3 support
- Adds license validation via an allow-list

Changes:
- Replace oss-licenses-plugin with cashapp/licensee in Gradle config
- Remove play-services-oss-licenses runtime dependency
- Remove OssLicensesMenuActivity/OssLicensesActivity declarations
- Add licensee configuration with allowed SPDX licenses
- Add Gradle task to copy licensee artifacts.json to app assets
- Create Compose LicensesScreen to display license data
- Update SettingsDialog to navigate to new LicensesScreen

Fixes android#1022

Test: ./gradlew installDemoDebug, manual verification of licenses screen
@suman9259 suman9259 requested a review from dturner as a code owner February 25, 2026 15:40
@google-cla
Copy link

google-cla bot commented Feb 25, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link

Summary of Changes

Hello @suman9259, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the application's open-source license management by migrating from Google's OSS Licenses plugin to cashapp/licensee. This change resolves critical build performance issues related to the configuration cache and modernizes the license display experience by introducing a new Compose-based screen with Material 3 styling. The migration also streamlines dependencies and integrates license validation directly into the build process.

Highlights

  • License Plugin Migration: The Google OSS Licenses plugin has been replaced with cashapp/licensee to address configuration cache incompatibility, lack of edge-to-edge support, and outdated AppCompat UI.
  • Configuration Cache Compatibility: The new licensee plugin is compatible with Gradle's configuration cache, preventing it from being discarded on each build that triggers license checks.
  • Compose-based Licenses Screen: A new Compose-based LicensesScreen has been implemented to display license information, offering Material 3 support and a modern UI.
  • License Validation and Artifacts: The licensee configuration now includes an allow-list for SPDX licenses, and a Gradle task has been added to copy generated artifacts.json to app assets for runtime access.
  • Dependency and UI Cleanup: The play-services-oss-licenses runtime dependency and its associated OssLicensesMenuActivity/OssLicensesActivity declarations have been removed, simplifying the project's dependencies and manifest.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • app/build.gradle.kts
    • Replaced google.osslicenses plugin alias with cashapp.licensee.
    • Added licensee configuration block with an allow-list of SPDX licenses and specific URLs.
    • Introduced an abstract CopyLicenseeReportTask to copy artifacts.json from licensee reports to app assets.
    • Configured androidComponents to register and link the CopyLicenseeReportTask for each variant, ensuring license data is available at runtime.
  • app/dependencies/prodReleaseRuntimeClasspath.txt
    • Removed the com.google.android.gms:play-services-oss-licenses entry.
  • app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt
    • Imported LicensesScreen.
    • Added showLicensesScreen state variable to control the visibility of the new licenses screen.
    • Modified the main NiaApp composable to conditionally render LicensesScreen or the main app content.
    • Introduced an onShowLicenses callback to NiaApp to trigger the display of the LicensesScreen.
  • build.gradle.kts
    • Replaced google-osslicenses plugin alias with cashapp-licensee in the root build.gradle.kts.
  • core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/Tabs.kt
    • Replaced TabRow with SecondaryTabRow for improved Material 3 compliance.
    • Adjusted the TabRowDefaults.SecondaryIndicator modifier to use selectedTabIndex directly.
  • feature/settings/impl/build.gradle.kts
    • Removed implementation(libs.androidx.appcompat) and implementation(libs.google.oss.licenses) dependencies.
  • feature/settings/impl/src/main/AndroidManifest.xml
    • Removed the OssLicensesMenuActivity and OssLicensesActivity declarations from the application manifest.
  • feature/settings/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/impl/LicensesScreen.kt
    • Added a new Compose screen, LicensesScreen, to parse and display license information from licenses.json.
    • Implemented data classes LicenseArtifact and LicenseInfo to structure license data.
    • Included a parseLicensesJson utility function to read and process license data from app assets.
  • feature/settings/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/settings/impl/SettingsDialog.kt
    • Removed unused imports related to android.content.Intent and OssLicensesMenuActivity.
    • Added an onShowLicenses callback parameter to SettingsDialog and LinksPanel.
    • Updated the 'Licenses' button in LinksPanel to invoke the new onShowLicenses callback instead of launching an activity.
  • gradle/libs.versions.toml
    • Removed googleOss and googleOssPlugin version references.
    • Added licensee version reference.
    • Removed google-oss-licenses library definition.
    • Replaced google-osslicenses plugin definition with cashapp-licensee.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request successfully migrates the project from Google's OSS Licenses plugin to cashapp/licensee, addressing several performance and UI compatibility issues. The changes include updating Gradle configurations, removing old dependencies, and introducing a new Compose-based licenses screen. The implementation of the new LicensesScreen and its integration into the SettingsDialog are well-handled. There are a few minor improvements that could be made regarding accessibility and performance in the new LicensesScreen and a small idiomatic improvement in the Gradle task.

Comment on lines 174 to 177
inputFile.get().asFile.copyTo(
File(outputDirectory.get().asFile, "licenses.json"),
overwrite = true,
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The copyTo function on File is a standard Java I/O operation. For better integration with Gradle's DirectoryProperty and RegularFileProperty, it's often more idiomatic to use the copy method provided by ProjectLayout or FileSystemOperations if available, or at least outputDirectory.get().file("licenses.json") to create the destination file within the DirectoryProperty context. While the current approach works, using Gradle's built-in APIs can sometimes offer better build cacheability or dependency tracking.

        inputFile.get().asFile.copyTo(
            outputDirectory.get().file("licenses.json").asFile,
            overwrite = true,
        )

IconButton(onClick = onBackClick) {
Icon(
imageVector = NiaIcons.ArrowBack,
contentDescription = null,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For an interactive icon like a back button, providing a meaningful contentDescription is crucial for accessibility. Setting it to null means screen readers won't announce its purpose, making it difficult for visually impaired users to navigate.

Suggested change
contentDescription = null,
contentDescription = stringResource(R.string.feature_settings_impl_back_button_content_description),

modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val artifacts = remember { parseLicensesJson(context) }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The parseLicensesJson function is called directly within the remember block of the LicensesScreen composable. While remember caches the result, the initial parsing of a potentially large JSON file can be a heavy operation that might block the UI thread during the first composition. Consider moving this parsing logic to a ViewModel and exposing the artifacts as a StateFlow or LiveData to handle loading states and perform the operation off the main thread, improving UI responsiveness.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Configuration cache disabled due to *OssLicensesTask

1 participant