Skip to content
Open
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
42 changes: 42 additions & 0 deletions .claude/skills/prepare-release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: prepare-release
description: Use when cutting a new release of this plugin — bumping the version, updating the changelog, and refreshing the README compatibility tables before opening the release PR. Triggers on "prepare a release", "cut X.Y.Z", "bump the version", "release prep".
---

# Prepare a release

Stage the release changes on a branch and stop for human approval before
committing/pushing. See `CLAUDE.md` for the version/tag facts.

## Steps

1. **Branch** off `master`: `chore/release-X.Y.Z` (or extend an existing
release-prep branch).

2. **Bump the version** in `src/main/resources/VERSION` to `X.Y.Z` (repo-root
`VERSION` is a symlink to it). `release.yml` asserts this equals the git tag,
so it must match the tag you will push (no `v` prefix).

3. **CHANGELOG.md** — rename the `## Unreleased` section to `## ver X.Y.Z`. List
user-facing changes and a `### Breaking Changes` subsection if any. Reference
PRs as `[#NNN](...)`. (Do not list dev-only tooling like Spotless bumps.)

4. **README.md and README_JP.md (keep both in sync):**
- Version-compatibility table: set the right-hand column for newly
unsupported AGP rows to `\>=2.4.0,\<X.Y.0`; add Android Studio code names
for new AGP rows from the official AGP compatibility table
(https://developer.android.com/build/releases/about-agp).
- Update the Gradle-compatibility and Binary-compatibility (min JRE) tables
and the requirement note if the minimums changed.
- When editing the table, keep columns aligned (a small reformat script that
pads each column to its max width is the reliable way).

5. **Verify**: run the relevant checks via the `verify-locally` skill.

6. **Stop and confirm with the user** before committing. Then commit in logical
units (e.g. `chore: bump up version to X.Y.Z` for VERSION+CHANGELOG, separate
docs commit), open the PR, and watch CI.

## After merge

- Tag `X.Y.Z` exactly (matches `VERSION`); `release.yml` publishes on the tag.
46 changes: 46 additions & 0 deletions .claude/skills/verify-locally/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: verify-locally
description: Use when reproducing this plugin's CI checks locally before pushing — running its unit tests, Spotless, or the AGP/Gradle acceptance specs against the DeployGate mock server. Triggers on "verify locally", "run the tests like CI", "check before pushing", NetworkFailure/Connection reset in ApiClientSpec, or "'null' is not a valid Gradle version".
---

# Verify locally (CI-equivalent)

Reproduce the `build-and-test.yml` jobs on your machine. See `CLAUDE.md` for the
underlying facts and gotchas; this is the runnable procedure.

## Steps

1. **Run outside the command sandbox** — Gradle writes `~/.gradle` and hits the
network. Use a JDK 17 (the build baseline). `export JAVA_HOME=<jdk17>`.
Comment on lines +13 to +14

2. **Start the mock server** (required for `ApiClientSpec` and the upload specs;
without it they hit `https://deploygate.com` and fail with `NetworkFailure` /
`Connection reset`):
```bash
docker run -d --name dg-mock -p 3000:3000 ghcr.io/deploygate/deploygate-mock-server:main
# Apple Silicon: add --platform linux/amd64. If the port is taken, use another and adjust the URL.
export TEST_SERVER_URL=http://localhost:3000
until curl -fsI "$TEST_SERVER_URL" >/dev/null 2>&1; do sleep 2; done
```

3. **Pick the job to mirror:**
| CI job | Command |
|---|---|
| `unit-test` | `./gradlew publishToMavenLocal test` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Running publishToMavenLocal is redundant for unit tests. The test task runs unit tests using the plugin's classes directly on the classpath (configured via createClasspathManifest in build.gradle), so publishing to Maven Local is unnecessary and slows down local verification. Consider updating the command to ./gradlew test.

| `lint` | `./gradlew spotlessApply` |
| `acceptance-test` | `./gradlew testUnrollAcceptanceTest` |
| `acceptance-test-runtime-env` (one row) | `TEST_AGP_VERSION=<agp> TEST_GRADLE_VERSION=<gradle> ./gradlew --no-daemon testPluginAcceptanceTest` |

Add `--tests "*SomeSpec*"` to narrow a run.

4. **Clean up:** `docker rm -f dg-mock`.

## Gotchas

- **`--no-daemon` is mandatory when setting `TEST_GRADLE_VERSION`** — a reused
daemon caches the env from its first start, so GradleRunner reads a stale value
and throws `'null' is not a valid Gradle version string`.
- ProjectBuilder unit specs fail with `Problems service is not initialized` on
Gradle 8.12/8.13 (gradle/gradle#31862) — the wrapper must avoid those.
- To exercise a different build-Gradle without touching the committed wrapper,
download that distribution and run `gradle -p <projectDir> <task>` from it.
67 changes: 67 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# CLAUDE.md — gradle-deploygate-plugin

Project-specific knowledge for working in this repo. Version numbers (minimum
AGP/Gradle/JRE, wrapper version) live in `README.md` / `build.gradle` — treat
those as the source of truth rather than duplicating them here.

## Local verification (reproducing CI)

Gradle commands need to write `~/.gradle` and reach the network, so run them
**outside the command sandbox**. Use a JDK that satisfies the wrapper's Gradle
version (the build/dev baseline is JDK 17).
Comment on lines +9 to +11

- **Mock server (required for HTTP specs).** `ApiClientSpec` and the upload
acceptance specs talk to `TEST_SERVER_URL`; without it they hit
`https://deploygate.com` and fail with `NetworkFailure` / `Connection reset`.
Comment on lines +13 to +15
Start it and export the URL:
```
docker run -d --name dg-mock -p 3000:3000 ghcr.io/deploygate/deploygate-mock-server:main
# Apple Silicon: add --platform linux/amd64
export TEST_SERVER_URL=http://localhost:3000
```
- **Unit tests:** `./gradlew test` (needs `TEST_SERVER_URL`). These are
`ProjectBuilder`-based and run on the wrapper's Gradle.
- **Plugin acceptance vs a specific AGP/Gradle:**
```
TEST_AGP_VERSION=8.0.0 TEST_GRADLE_VERSION=8.0 \
./gradlew --no-daemon testPluginAcceptanceTest --tests "*ConfigurationCacheSpec*"
```
**`--no-daemon` is mandatory** when setting `TEST_GRADLE_VERSION`: the Gradle
daemon caches env vars from its first start, so a reused daemon reads a stale
value and GradleRunner throws `'null' is not a valid Gradle version string`.
- **Unroll acceptance:** `./gradlew testUnrollAcceptanceTest`.
- **Format/lint:** `./gradlew spotlessApply`.

## Build / version gotchas

- **ProjectBuilder + Gradle 8.12/8.13** throws `Problems service is not
initialized` in the unit tests (gradle/gradle#31862); fixed in 8.14. Keep the
wrapper off 8.12/8.13.
- **Spotless 8.x** requires Gradle 8.1+ and Java 17. It is applied only on
Gradle 8.1+ (guard in `build.gradle`) so the lowest acceptance-matrix Gradle
row still validates the stated minimum.
Comment on lines +40 to +42

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The description of Spotless here is inaccurate. The project actually uses Spotless version 7.2.1 (configured in build.gradle line 10), which requires Java 11 (as noted in the comment on line 267 of build.gradle). Furthermore, there is no guard in build.gradle restricting Spotless to Gradle 8.1+; it is applied unconditionally to allprojects.

Suggested change
- **Spotless 8.x** requires Gradle 8.1+ and Java 17. It is applied only on
Gradle 8.1+ (guard in `build.gradle`) so the lowest acceptance-matrix Gradle
row still validates the stated minimum.
- **Spotless 7.2.1** is used and requires Java 11 (as noted in build.gradle). It is applied unconditionally to all projects, so Java 11+ is required to run the build/lint tasks.

Comment on lines +40 to +42
- The **wrapper Gradle is the build toolchain**, intentionally separate from the
minimum Gradle that *users* of the plugin need.
- CI's `.github/actions/setup-java` installs Java 11 for `sdkmanager`, then the
`java-version` input becomes the active JDK; build jobs pass `java-version: 17`.

## Release

- The version is in `src/main/resources/VERSION` (repo-root `VERSION` is a
symlink). Bump it in a `chore: bump up version to X.Y.Z` commit.
- `.github/workflows/release.yml` asserts `VERSION` equals the pushed tag (no
`v` prefix) — tag exactly `X.Y.Z`.
- Keep **both** `README.md` and `README_JP.md` in sync (compatibility tables,
notes). Android Studio code names come from the official AGP compatibility
table.
- `CHANGELOG.md`: add a `## Unreleased` section only when there are entries;
rename it to `## ver X.Y.Z` at release time.

## PR / review conventions

- Reply to review comments — **including bots (devin, gemini, Copilot)** — in
the comment thread with an `@mention` of the author:
`gh api repos/{owner}/{repo}/pulls/{pr}/comments/{id}/replies -f body=...`
(not as a top-level PR comment).
Comment on lines +62 to +65
- Bot findings are suggestions to verify, not orders. Push back with evidence
when they are wrong for this codebase.
Loading