Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,18 @@ updates:
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 1
groups:
github-actions:
patterns:
- "*"

- package-ecosystem: "gradle"
directory: "/oss-licenses-plugin/testapp"
schedule:
interval: "weekly"
open-pull-requests-limit: 1
groups:
all-dependencies:
patterns:
- "*"
10 changes: 5 additions & 5 deletions .github/workflows/generate_release_rcs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name: Generate releaseble artifacts
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
branches: [main]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -30,20 +30,20 @@ jobs:
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- name: Set up JDK 17
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0
with:
java-version: '17'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # ratchet:gradle/actions/setup-gradle@v5.0.2
- name: Perform a Gradle build
working-directory: ./${{ matrix.project-dir }}
run: ./gradlew publish
- name: Upload generated artifacts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # ratchet:actions/upload-artifact@v7.0.0
with:
name: ${{ matrix.project-dir }}
path: ./${{ matrix.project-dir }}/build/repo
Expand Down
167 changes: 148 additions & 19 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ name: CI
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
branches: [main]
pull_request:
branches: [ main ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

Expand All @@ -19,46 +17,177 @@ jobs:
lint-and-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2
uses: gradle/actions/wrapper-validation@0723195856401067f7a2779048b490ace7a47d7c # ratchet:gradle/actions/wrapper-validation@v5.0.2
- name: Lint GitHub Actions
uses: abcxyz/actions/.github/actions/lint-github-actions@e32ec3bd6af6d87d79fe7c441f435eb7ad11d527 # main
uses: abcxyz/actions/.github/actions/lint-github-actions@e32ec3bd6af6d87d79fe7c441f435eb7ad11d527 # ratchet:abcxyz/actions/.github/actions/lint-github-actions@main
- name: Ratchet Check
uses: sethvargo/ratchet@8b4ca256dbed184350608a3023620f267f0a5253 # main
uses: sethvargo/ratchet@27f7515b4648e179168f8f8ae2257636fdb03c48 # ratchet:sethvargo/ratchet@main
with:
files: .github/workflows/*.yml

# This workflow contains a single job called "build"
# Build the simple plugins (no special test infrastructure needed)
build:
needs: lint-and-check
# The type of runner that the job will run on
runs-on: ubuntu-latest

# Runs this job in parallel for each sub-project
strategy:
matrix:
project-dir:
- strict-version-matcher-plugin
- google-services-plugin
- oss-licenses-plugin

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2

- name: Set up JDK 17
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0
with:
java-version: '17'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # ratchet:gradle/actions/setup-gradle@v5.0.2
with:
dependency-graph: generate-and-submit

# Runs a build which includes `check` and `test` tasks
- name: Perform a Gradle build
run: ./gradlew build
working-directory: ./${{ matrix.project-dir }}

# Build the oss-licenses plugin: unit tests + integration tests (no heavy E2E).
# Publishes the plugin artifact for downstream jobs.
oss-licenses-build:
needs: lint-and-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2

- name: Set up JDK 17 (For plugin build)
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0
with:
java-version: '17'
distribution: 'temurin'

- name: Set up JDK 21 (For plugin testing)
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0
with:
java-version: '21'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # ratchet:gradle/actions/setup-gradle@v5.0.2
with:
dependency-graph: generate-and-submit

# Cache GradleTestKit directories (downloaded Gradle distributions + dependency caches).
# These live inside build/testkit/ which isn't covered by setup-gradle's ~/.gradle cache.
# Main branch writes the cache; PR branches only read it.
- name: Restore GradleTestKit cache
if: github.event_name == 'pull_request'
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/restore@v4.2.3
with:
path: oss-licenses-plugin/build/testkit
key: testkit-${{ runner.os }}-${{ hashFiles('oss-licenses-plugin/build.gradle.kts', 'oss-licenses-plugin/src/test/**/*Test*.kt') }}
restore-keys: |
testkit-${{ runner.os }}-

- name: Cache GradleTestKit directories
if: github.event_name != 'pull_request'
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache@v4.2.3
with:
path: oss-licenses-plugin/build/testkit
key: testkit-${{ runner.os }}-${{ hashFiles('oss-licenses-plugin/build.gradle.kts', 'oss-licenses-plugin/src/test/**/*Test*.kt') }}
restore-keys: |
testkit-${{ runner.os }}-

# Build + unit/integration tests only (E2E tests run in a separate parallel job)
- name: Build and test
run: ./gradlew build -x e2eTestTask
working-directory: ./oss-licenses-plugin

- name: Publish to local repo
run: ./gradlew publish
working-directory: ./oss-licenses-plugin

- name: Upload local repo artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # ratchet:actions/upload-artifact@v7.0.0
with:
name: oss-licenses-local-repo
path: oss-licenses-plugin/build/repo/

# Heavy E2E tests that build the full testapp against multiple AGP versions.
# Runs in parallel with testapp-verification after the plugin is built and published.
oss-licenses-e2e:
needs: oss-licenses-build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2

- name: Download local repo artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8.0.1
with:
name: oss-licenses-local-repo
path: oss-licenses-plugin/build/repo/

- name: Set up JDK 17 (For plugin build)
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0
with:
java-version: '17'
distribution: 'temurin'

- name: Set up JDK 21 (For plugin testing)
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0
with:
java-version: '21'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # ratchet:gradle/actions/setup-gradle@v5.0.2

- name: Restore GradleTestKit cache
if: github.event_name == 'pull_request'
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/restore@v4.2.3
with:
path: oss-licenses-plugin/build/testkit
key: testkit-e2e-${{ runner.os }}-${{ hashFiles('oss-licenses-plugin/build.gradle.kts', 'oss-licenses-plugin/src/e2eTest/**/*Test*.kt') }}
restore-keys: |
testkit-e2e-${{ runner.os }}-

- name: Cache GradleTestKit directories
if: github.event_name != 'pull_request'
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache@v4.2.3
with:
path: oss-licenses-plugin/build/testkit
key: testkit-e2e-${{ runner.os }}-${{ hashFiles('oss-licenses-plugin/build.gradle.kts', 'oss-licenses-plugin/src/e2eTest/**/*Test*.kt') }}
restore-keys: |
testkit-e2e-${{ runner.os }}-

- name: Run E2E Tests
run: ./gradlew e2eTestTask
working-directory: ./oss-licenses-plugin

# Verify the plugin works with the standalone testapp.
oss-licenses-testapp:
needs: oss-licenses-build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2

- name: Download local repo artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8.0.1
with:
name: oss-licenses-local-repo
path: oss-licenses-plugin/build/repo/

- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0
with:
java-version: '21'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # ratchet:gradle/actions/setup-gradle@v5.0.2

- name: Run Test App Tests
run: ./gradlew build
working-directory: oss-licenses-plugin/testapp
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,11 @@ Helps apps to display open source software licenses and notices.

Required for firebase applications on android, converts google-services.json to a resource file for use by the app, and references the code in strict-version-matcher.

## Security & Maintenance

### Ratchet

This project uses [Ratchet](https://github.com/sethvargo/ratchet) to ensure all GitHub Actions are pinned to immutable SHA-256 checksums. This helps protect against supply chain attacks by ensuring that the actions used in CI/CD workflows are exactly the versions intended.

Developers are encouraged to run `ratchet pin .github/workflows/*.yml` locally before submitting pull requests that introduce or update GitHub Actions.

84 changes: 84 additions & 0 deletions oss-licenses-plugin/GEMINI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Gemini Developer Guide: OSS Licenses Plugin

This document provides essential information for AI agents and developers working on the `oss-licenses-plugin` and its tests.

## Test Architecture

The project uses a three-tier testing strategy to ensure both internal logic and full integration across the Android Gradle Plugin (AGP) and Gradle version matrix.

### 1. Unit Tests (`src/test/`)
These tests verify the logic of individual tasks and utility classes.

* **Files:** `DependencyTaskTest.java`, `LicensesTaskTest.java`, `GoogleServicesLicenseTest.java`.
* **Mechanism:** Uses `ProjectBuilder` to instantiate tasks in a lightweight, in-memory Gradle environment.
* **Focus:** Task-specific logic, input/output handling, and edge cases.
* **Execution:** `./gradlew test`

### 2. Integration Tests (`src/test/`)
These tests verify the plugin's integration with the Gradle lifecycle and its behavior in a real-world project structure.

* **File:** `IntegrationTest.kt`
* **Mechanism:** Uses `GradleTestKit` (`GradleRunner`) to execute the plugin against a set of static test projects.
* **Focus:** Task wiring, Configuration Cache compatibility, and relocatability.
* **Matrix:** Defined in `build.gradle.kts` (`integrationOnlyVersions` + `e2eVersions`).
* **Execution:** `./gradlew test` (runs alongside unit tests).

### 3. End-to-End Tests (`src/e2eTest/`)
These are heavy tests that build and test a full Android application against a matrix of AGP and Gradle versions.

* **File:** `EndToEndTest.kt`
* **Mechanism:** Uses `GradleTestKit` to build and run the `testapp` across multiple versions.
* **Focus:** Verifying the plugin's end-to-end behavior within a real Android project.
* **Matrix:** Defined in `build.gradle.kts` (`e2eVersions`).
* **Execution:** `./gradlew e2eTestTask` (also runs as part of `check` and `build`)

---

## Testing Infrastructure & Matrix

The complexity of testing across multiple AGP/Gradle versions is managed through a centralized configuration in `build.gradle.kts`.

### Centralized Version Matrix
The `build.gradle.kts` file is the **single source of truth** for all versions.
* It defines maps (`e2eVersions`, `integrationOnlyVersions`) of version pairs.
* It dynamically generates test subclasses by injecting these versions as **system properties** (e.g., `IntegrationTest_AGP74.agpVersion`).
* To add a new version to the matrix: Add the entry to the map in `build.gradle.kts` and create the corresponding empty subclass in `IntegrationTest.kt` or `EndToEndTest.kt`.

### Test Isolation
To allow safe parallel execution, each test subclass uses a dedicated `TestKit` directory (set via `.withTestKitDir()`). This prevents different AGP versions from clobbering each other's Gradle User Home caches.

### JVM & Toolchain Management
To ensure tests run consistently regardless of the host environment:
1. **Java 21 Injection:** The build script uses the `JavaToolchainService` to locate a Java 21 JDK. This path is injected into the tests via the `java21_home` system property.
2. **JAVA_HOME Override:** Both `IntegrationTest` and `EndToEndTest` use `.withEnvironment(mapOf("JAVA_HOME" to java21Home))` to force the Gradle Runner to use the correct JVM.
3. **Daemon Provisioning:** For older Gradle versions (like 8.11), the tests explicitly delete `gradle-daemon-jvm.properties` in the test workspace to prevent failing internal toolchain discovery.

---

## The Test Application (`testapp/`)

The `testapp/` directory is a standalone Gradle project used as the target for End-to-End tests.

### Dynamic Version Injection
The `EndToEndTest.kt` does not use the `testapp`'s `libs.versions.toml` as-is. Instead, it **rewrites the TOML file at runtime** to inject the specific AGP and Kotlin versions being tested in the current matrix iteration.

### Local Development Workflow
The `testapp` is configured to automatically pick up the locally built plugin.

1. **Publish Locally:** The main build automatically publishes the plugin to `oss-licenses-plugin/build/repo` before running tests.
2. **Standalone Run:** To run tests directly within the `testapp` environment:
```bash
cd oss-licenses-plugin/testapp
./gradlew clean :app:test
```

---

## Common Tasks

| Task | Command | Description |
| :--- | :--- | :--- |
| **Full Check** | `./gradlew check` | Runs all tests (Unit, Integration, and E2E). |
| **Unit & Integration** | `./gradlew test` | Runs internal plugin tests and `IntegrationTest`. |
| **E2E Matrix** | `./gradlew e2eTestTask` | Runs the full matrix suite against the `testapp`. |
| **Publish** | `./gradlew publish` | Publishes the plugin to the internal `build/repo`. |
Loading
Loading