diff --git a/.github/workflows/check-toolchain.yml b/.github/workflows/check-toolchain.yml index 9dfd001e..538cda73 100644 --- a/.github/workflows/check-toolchain.yml +++ b/.github/workflows/check-toolchain.yml @@ -20,6 +20,8 @@ on: permissions: contents: read + # the libs/ guard below reads the pull request's changed file list + pull-requests: read jobs: check-toolchain: @@ -29,6 +31,30 @@ jobs: - name: Checkout uses: actions/checkout@v4 + # libs/ holds build outputs, not source. Only the "Update libs from + # CodeOnTheGo" workflow may change them. It builds the jars on JDK 17, + # which is the JDK every runner here uses, so what it commits always + # loads. A laptop on JDK 21 emits class file version 65 instead, and a + # JDK 17 runner reads only up to 61 -- that is what broke "Publish + # addons" after #87 shipped hand-built jars. That workflow pushes + # straight to main with an admin PAT and bypasses the main ruleset, so + # this check never sees it. + - name: Refuse hand-built libs/ jars + if: github.event_name == 'pull_request' + env: + GH_TOKEN: ${{ github.token }} + PR: ${{ github.event.pull_request.number }} + run: | + set -euo pipefail + changed="$(gh api --paginate \ + "repos/${GITHUB_REPOSITORY}/pulls/${PR}/files" \ + -q '.[].filename' | grep '^libs/' || true)" + if [ -n "$changed" ]; then + printf '%s\n' "$changed" + echo "::error::A pull request must not change libs/. Run the 'Update libs from CodeOnTheGo' workflow instead -- it builds the jars on the JDK the runners use." + exit 1 + fi + - name: Check toolchain versions run: ./scripts/check-toolchain.sh diff --git a/CLAUDE.md b/CLAUDE.md index f11790d4..90db18d9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,6 +26,8 @@ Build every plugin from scratch (after rebuilding libs): The script clones CoGo into `.cache/CodeOnTheGo/` on first run, rebuilds both jars, copies them into `libs/`, then runs `assemblePlugin` for every example. It auto-detects examples by scanning for `build.gradle.kts` files that apply `com.itsaky.androidide.plugins.build`. +**Never commit the jars this script writes.** Run it locally only to test a CoGo change before it lands; throw the `libs/` diff away afterwards (`git restore libs/`). `libs/` on `main` may only be changed by the **Update libs from CodeOnTheGo** workflow, which builds on JDK 17 — the JDK every runner and every other workflow here uses. A laptop on JDK 21 writes class file version 65 into `gradle-plugin.jar`; a JDK 17 runner reads only up to 61, so `assemblePlugin` dies with `UnsupportedClassVersionError` in CI while it still works on the laptop that produced it. PR #87 shipped such a jar and broke **Publish addons**. `Check toolchain` now fails any pull request that touches `libs/`. + `local.properties` must contain `sdk.dir=...`. The committed `local.properties` at the repo root is harmless leftover; each plugin needs its own. ## Git workflow @@ -44,7 +46,7 @@ The script clones CoGo into `.cache/CodeOnTheGo/` on first run, rebuilds both ja There is also **one shared Gradle wrapper at the repo root** (`gradlew` + `gradle/wrapper/`). New plugins should use it — build them with `cd plugins/ && ../../gradlew assemblePlugin` rather than bundling a per-plugin `gradlew`/`gradle/wrapper/` copy. (`flutter-template` follows this; most older plugins still carry their own local wrapper and can be migrated opportunistically.) -An addon under `plugins/` references the shared jars as `../../libs/*.jar`. **Always use the repo-root `libs/` jars and the repo-root Gradle wrapper — never bundle per-plugin copies.** A plugin that ships its own `libs/plugin-api.jar` / `libs/gradle-plugin.jar` (e.g. copied from another plugin) can drift out of sync with the rest of the repo; point `build.gradle.kts` (`compileOnly`) and `settings.gradle.kts` (buildscript `classpath`) at `../../libs/*.jar` and delete any local `libs/`. The root `plugin-api.jar` already carries the full API surface (including `IdeTemplateService`/`CgtTemplateBuilder`), so newer sub-APIs do not justify a local copy. **A plugin folder is not standalone in isolation** — copy the root `libs/` along if you move one elsewhere. When CoGo's API changes, refresh via the script above or the **Update libs from CodeOnTheGo** GitHub Action (which commits the refreshed jars and cuts a release). Publishing addons is a separate workflow, **Publish addons**, which uploads to Cloudflare R2. +An addon under `plugins/` references the shared jars as `../../libs/*.jar`. **Always use the repo-root `libs/` jars and the repo-root Gradle wrapper — never bundle per-plugin copies.** A plugin that ships its own `libs/plugin-api.jar` / `libs/gradle-plugin.jar` (e.g. copied from another plugin) can drift out of sync with the rest of the repo; point `build.gradle.kts` (`compileOnly`) and `settings.gradle.kts` (buildscript `classpath`) at `../../libs/*.jar` and delete any local `libs/`. The root `plugin-api.jar` already carries the full API surface (including `IdeTemplateService`/`CgtTemplateBuilder`), so newer sub-APIs do not justify a local copy. **A plugin folder is not standalone in isolation** — copy the root `libs/` along if you move one elsewhere. When CoGo's API changes, refresh with the **Update libs from CodeOnTheGo** GitHub Action (which commits the refreshed jars and cuts a release) — never by committing what `scripts/update-libs.sh` writes on your own machine, for the reason given above. Publishing addons is a separate workflow, **Publish addons**, which uploads to Cloudflare R2. ### Credentials: use the host's `KeystoreSecretStore`, never your own crypto diff --git a/libs/GUARD_TEST.txt b/libs/GUARD_TEST.txt new file mode 100644 index 00000000..fb188b9e --- /dev/null +++ b/libs/GUARD_TEST.txt @@ -0,0 +1 @@ +scratch