Skip to content
Merged
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
19 changes: 10 additions & 9 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Forma CI — plugins, sample app, and adjacent tooling.
# F-004: pin JDK 17 on every job; install Android SDK for the sample app.
# F-018: pin JDK 21 on every job (Gradle 8.7+); install Android SDK for the sample app.
# App bytecode / jvmTarget stays at project settings (not raised with the daemon JDK).
name: CI

on:
Expand All @@ -17,11 +18,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
java-version: "21"
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build plugins
Expand All @@ -33,11 +34,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
java-version: "21"
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build includer
Expand All @@ -49,11 +50,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
java-version: "21"
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build depgen
Expand All @@ -65,11 +66,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
java-version: "21"
# Sample app: compileSdk 34 (Compose AAR metadata), targetSdk 33.
# setup-android accepts licenses, installs cmdline-tools + listed packages,
# and exports ANDROID_HOME / ANDROID_SDK_ROOT for AGP.
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Ship Forma as a **working Android product**, then **forma-core** extraction, the
5. Do **not** create new cron jobs from a cron run.
6. Do **not** force-push `master` or `v2` on upstream. Prefer branch + PR to `formatools/forma` (or stepango fork if permissions require).
7. Ground reports in tool output (builds, git, gh). Never invent green builds.
8. If JDK/Android SDK missing, work F-001 first (install Temurin 17+ via brew/sdkman; document exact commands in PROGRESS).
8. If JDK/Android SDK missing, bootstrap first (`brew install openjdk@21` + `source scripts/env-mac.sh`; document exact commands in PROGRESS).
9. **Base of operations is `v2`** (not `master`). Feature branches and PRs target `v2`. Promote `v2` → `master` only when the user asks or CI is ready for public default.

## Git workflow
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ androidUtil(

## Development environment

Worker / contributor host setup (JDK 17+, Android SDK platform **34** for
Worker / contributor host setup (JDK **21** build JVM, Android SDK platform **34** for
`compileSdk`, 33 still useful for target): see [`docs/ENV.md`](docs/ENV.md) and
`source scripts/env-mac.sh`.

Expand Down
2 changes: 1 addition & 1 deletion TICKETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Update this file when picking or finishing work. Cron workers must pick the **hi
| F-002 | done | Audit build graph: plugins, sample app, CI workflows | Map modules → forma-core candidates; capture in `docs/ARCHITECTURE.md` |
| F-003 | done | Get plugins + sample `application/` building on modern toolchain | Plugins compile AGP 8.1.2 matches sample; Gradle 8.3 (plugins) / 8.4 (app); host builds green |
| F-004 | done | CI green on GitHub Actions for plugins + application | Temurin 17 all jobs + Android SDK 33 for app; PR #153 GHA green |
| F-018 | in_progress | JDK 21 + Gradle/AGP staged modernization | **Phase 1 done (this PR):** all wrappers → **Gradle 8.7**; KSP **1.9.22-1.0.16**; Compose compiler **1.5.10**; kotlin-stdlib forces for failOnVersionConflict. Next: host/CI JDK 21; AGP 8.5.2+. Plan: `~/.hermes/plans/2026-07-13_024508-forma-gradle-agp-upgrade.md` |
| F-018 | in_progress | JDK 21 + Gradle/AGP staged modernization | **Phase 1 + JDK 21 done:** wrappers **8.7** (#180); host/CI **JDK 21**; KSP **1.9.22-1.0.16**; Compose compiler **1.5.10**. AGP still **8.1.2** — next: AGP 8.5.2 → 8.7 → 8.13. AGP 9 = optional F-019. Plan: `~/.hermes/plans/2026-07-13_024508-forma-gradle-agp-upgrade.md` |

## P1 — Android working product

Expand Down
23 changes: 12 additions & 11 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,17 +271,17 @@ Display name **CI** (`on: push`, `pull_request`, `workflow_dispatch`).

| Job | Directory | Java | Notes |
|-----|-----------|------|-------|
| `build_application` | `application/` | Temurin **17** | `android-actions/setup-android@v3` (SDK 33 + build-tools 33/34); `./gradlew build --stacktrace --console=plain` |
| `build_plugins` | `plugins/` | Temurin **17** | `./gradlew build --stacktrace --console=plain` |
| `build_includer` | `includer/` | Temurin **17** | same |
| `build_depgen` | `depgen/` | Temurin **17** | same |
| `build_application` | `application/` | Temurin **21** | `android-actions/setup-android@v3` (SDK 33 + build-tools 33/34); `./gradlew build --stacktrace --console=plain` |
| `build_plugins` | `plugins/` | Temurin **21** | `./gradlew build --stacktrace --console=plain` |
| `build_includer` | `includer/` | Temurin **21** | same |
| `build_depgen` | `depgen/` | Temurin **21** | same |

Concurrency group `ci-${{ github.workflow }}-${{ github.ref }}` cancels in-progress runs on the same ref.

F-004 fixes applied (2026-07-11):
CI pins (evolved F-004 → F-018):

1. **All jobs** pin Temurin 17 via `actions/setup-java@v4`.
2. **Application** installs Android SDK packages matching sample `compileSdk` 33.
1. **All jobs** pin Temurin **21** via `actions/setup-java@v4` (was 17; requires Gradle ≥8.5 — wrappers are **8.7**).
2. **Application** installs Android SDK packages matching sample `compileSdk` 34 / target 33.
3. README badge → `formatools/forma` + `actions/workflows/main.yml/badge.svg`.
4. Gradle setup via `gradle/actions/setup-gradle@v4` (successor of `gradle-build-action`).
5. Dropped unconditional `--scan` (no build-scan account coupling in CI).
Expand All @@ -295,10 +295,11 @@ keys) or full Portal publish via secrets; deeper Gradle remote cache.

| Component | Declared / observed |
|-----------|---------------------|
| JDK | 17 (all CI jobs Temurin; host OpenJDK 17 via Homebrew) |
| Gradle | **8.7** (all wrappers; F-018 Phase 1) |
| AGP | **8.1.2** sample runtime + plugins compile (aligned F-003) |
| Kotlin | embeddedKotlin from Gradle distribution |
| JDK (daemon / CI) | **21** (CI Temurin 21; host OpenJDK 21 via Homebrew `openjdk@21`) |
| App bytecode / `jvmTarget` | unchanged (sample default `JavaVersion.VERSION_1_8`) — not raised with daemon JDK |
| Gradle | **8.7** (all wrappers; F-018 Phase 1 / PR #180) |
| AGP | **8.1.2** sample runtime + plugins compile (aligned F-003; AGP ladder = later F-018) |
| Kotlin | embeddedKotlin from Gradle 8.7 (**1.9.22**); Compose compiler default **1.5.10** |
| Android SDK | sample compileSdk **34** / target 33; host platforms 34+33 + build-tools 33/34 |
| Forma version | 0.1.3 |

Expand Down
55 changes: 35 additions & 20 deletions docs/ENV.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# Worker host environment (macOS)

Forma workers need **JDK 17+** and an **Android SDK** with platform **34**
(sample `compileSdk`; Compose AAR metadata) and optionally **33** (`targetSdk`).
Forma workers need **JDK 21** (build/daemon JVM; F-018) and an **Android SDK**
with platform **34** (sample `compileSdk`; Compose AAR metadata) and optionally
**33** (`targetSdk`). Android app language level / `jvmTarget` stays at the
project’s configured `JavaVersion` (sample default still 1.8) — raising bytecode
is a separate decision from the daemon JDK.

## Quick start (this Mac)

```bash
# Already installed on the Forma worker host (no sudo):
# brew install openjdk@17
# brew install openjdk@21
# brew install --cask android-commandlinetools
# sdk packages: platforms;android-34, platforms;android-33, platform-tools,
# build-tools 33.0.2 + 34.0.0
Expand All @@ -18,8 +21,9 @@ source scripts/env-mac.sh
printf 'sdk.dir=%s\n' "$ANDROID_HOME" > application/local.properties

# Verify
java -version
cd plugins && ./gradlew build
java -version # expect 21.x
cd plugins && ./gradlew --version # Gradle 8.7 + JVM 21
cd ../plugins && ./gradlew build
cd ../application && ./gradlew build
cd ../includer && ./gradlew build
cd ../depgen && ./gradlew build
Expand All @@ -29,19 +33,27 @@ cd ../depgen && ./gradlew build

| Tool | Location |
|------|----------|
| JDK 17 | `/usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home` |
| JDK 21 (Intel Homebrew) | `/usr/local/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home` |
| JDK 21 (Apple Silicon) | `/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home` |
| Android SDK root | `/usr/local/share/android-commandlinetools` |
| cmdline-tools | `$ANDROID_HOME/cmdline-tools/latest` |

`openjdk@17` is Homebrew **keg-only** (not on system `PATH` until you export `JAVA_HOME`). Prefer it over `brew install --cask temurin@17`, which requires **sudo** for the `.pkg` installer and fails in non-interactive cron.
`scripts/env-mac.sh` probes both Homebrew prefixes. `openjdk@21` is Homebrew
**keg-only** (not on system `PATH` until you export `JAVA_HOME`). Prefer it over
`brew install --cask temurin@21`, which requires **sudo** for the `.pkg`
installer and fails in non-interactive cron.

## One-time install (fresh machine)

```bash
brew install openjdk@17
brew install openjdk@21
brew install --cask android-commandlinetools

export JAVA_HOME="/usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home"
# Intel:
export JAVA_HOME="/usr/local/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home"
# Apple Silicon:
# export JAVA_HOME="/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home"

export ANDROID_HOME="/usr/local/share/android-commandlinetools"
export ANDROID_SDK_ROOT="$ANDROID_HOME"
export PATH="$JAVA_HOME/bin:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH"
Expand All @@ -60,21 +72,24 @@ printf 'sdk.dir=%s\n' "$ANDROID_HOME" > application/local.properties
Optional system-wide JVM registration (needs sudo, not required for Gradle):

```bash
sudo ln -sfn /usr/local/opt/openjdk@17/libexec/openjdk.jdk \
/Library/Java/JavaVirtualMachines/openjdk-17.jdk
sudo ln -sfn /usr/local/opt/openjdk@21/libexec/openjdk.jdk \
/Library/Java/JavaVirtualMachines/openjdk-21.jdk
```

## Verified on 2026-07-10 (F-001) / re-verified 2026-07-11 (F-003, F-013)
## Verified on 2026-07-19 (F-018 Phase 1 + JDK 21)

- `java` / `javac` 17.0.19 (Homebrew OpenJDK)
- `plugins/`: `./gradlew build` → **BUILD SUCCESSFUL** (AGP compile dep **8.1.2**)
- `includer/`: `./gradlew build` → **BUILD SUCCESSFUL**
- `depgen/`: `./gradlew build` → **BUILD SUCCESSFUL**
- `application/`: `./gradlew build` → **BUILD SUCCESSFUL** (compileSdk **34**,
targetSdk 33, Compose compiler **1.5.10** / Kotlin **1.9.22**, F-018)
- Gradle wrappers: **8.7** (all roots; was 8.3/8.4 split)
- `java` / `javac` **21.x** (Homebrew OpenJDK 21) via `scripts/env-mac.sh`
- Gradle wrappers: **8.7** (all roots; was 8.3/8.4 split — PR #180)
- Compose compiler default **1.5.10** (Kotlin **1.9.22** / Gradle 8.7 embedded)
- AGP still **8.1.2** (Phase 2+ climb is later F-018 work)
- CI: Temurin **21** all jobs (`.github/workflows/main.yml`)
- Toolchain note: plugins compile AGP matches sample forced AGP (no 7.4.2 skew)

See `docs/PROGRESS.md` for the latest host build tails.

## Shell profile

`~/.zshrc` on the worker exports `JAVA_HOME` / `ANDROID_HOME` so interactive shells pick them up. Cron / Hermes sessions should still `source scripts/env-mac.sh` (or set the same vars) because non-interactive jobs may not load `.zshrc`.
`~/.zshrc` on the worker should export `JAVA_HOME` / `ANDROID_HOME` so interactive
shells pick them up (prefer openjdk@21). Cron / Hermes sessions should still
`source scripts/env-mac.sh` (or set the same vars) because non-interactive jobs
may not load `.zshrc`.
4 changes: 2 additions & 2 deletions docs/GETTING-STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ structure and boundaries, not business logic.

| Tool | Version / notes |
|------|-----------------|
| JDK | **17+** |
| JDK | **21** build/daemon (F-018); app language level unchanged |
| Android SDK | Platform **34** (`compileSdk`; required for modern Compose AARs), **33** useful for `targetSdk` |
| Build tools | 33.0.2 / 34.0.0 as used by the sample |
| Gradle | Use the wrapper in the project (`./gradlew`); sample uses **8.4**, plugins build **8.3** |
| Gradle | Use the wrapper in the project (`./gradlew`); **8.7** all roots |

Worker / macOS install steps: [ENV.md](ENV.md) (`source scripts/env-mac.sh`).

Expand Down
25 changes: 23 additions & 2 deletions docs/PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,41 @@

Newest entries first.

## 2026-07-19 — F-018 Phase 1b: host + CI → JDK 21

- **Ticket:** F-018 remains `in_progress` (wrappers #180 + JDK 21 done; AGP ladder remains)
- **Branch / PR:** `forma/F-018-jdk21` → new PR base `v2` (Phase 1 already on tip via #180)
- **Host:** `brew install openjdk@21` → OpenJDK **21.0.11** at `/usr/local/opt/openjdk@21/...`
- **Code / config:**
- `scripts/env-mac.sh` default `JAVA_HOME` → openjdk@21 (probes `/usr/local` + `/opt/homebrew`)
- `.github/workflows/main.yml` all jobs Temurin **17 → 21**
- Docs: `ENV.md`, `ARCHITECTURE.md` CI/toolchain snapshot, `SAMPLE-APP.md`, `GETTING-STARTED.md`, `README.md`, `AGENTS.md`
- App bytecode / `jvmTarget` **not** raised (sample still `JavaVersion.VERSION_1_8`)
- **Verify (real host, `source scripts/env-mac.sh`):**
- `java -version` → **21.0.11** (Homebrew)
- `plugins/ ./gradlew --version` → **Gradle 8.7** + **JVM 21.0.11** + Kotlin 1.9.22
- `plugins/ ./gradlew build` → **BUILD SUCCESSFUL** (89 tasks)
- `application/ ./gradlew build` → **BUILD SUCCESSFUL** (2203 tasks, 4m16s)
- `includer/ ./gradlew build` → **BUILD SUCCESSFUL**
- `depgen/ ./gradlew build` → **BUILD SUCCESSFUL**
- **Not in this slice:** AGP still **8.1.2** (Phase 2 = 8.5.2+); no F-019
- **Next:** AGP lockstep 8.5.2 (separate PR preferred)

## 2026-07-19 — F-018 Phase 1: unify Gradle wrappers → 8.7

- **Ticket:** F-018 → `in_progress` (Phase 1 shipped; JDK 21 + AGP climb remain)
- **PR:** #180 merged to `v2` (`7464d3e`)
- **Why delayed:** Jul 12 session wrote the plan + asked priority buttons instead of implementing; F-018 was not on `TICKETS.md` until 2026-07-19, so 4h workers continued forma-core/Bazel/flat-structure. User call-out: do the work, don't re-plan.
- **Code:**
- All `gradle-wrapper.properties` (plugins, application, includer, depgen, jvm-application, bazel-adapter, examples/*, build-*, root) → **Gradle 8.7**
- `application/settings.gradle.kts`: force full kotlin-stdlib family to `$embeddedKotlinVersion` (1.9.22) under `failOnVersionConflict`; KSP **1.9.22-1.0.16** (1.0.18 caused kapt↔ksp task cycle)
- Default Compose compiler **1.5.3 → 1.5.10** (Kotlin 1.9.22 map); example 06-compose aligned
- **Verify (real, OpenJDK 17 + env-mac.sh):**
- **Verify (real, OpenJDK 17 at Phase 1 commit; re-verified on 21 in Phase 1b):**
- `plugins/ ./gradlew --version` → **8.7** / Kotlin 1.9.22
- `plugins/ ./gradlew build` → **BUILD SUCCESSFUL**
- `application/ ./gradlew build` → **BUILD SUCCESSFUL** (2203 tasks)
- `includer`, `depgen`, `bazel-adapter`, `jvm-application` builds → **BUILD SUCCESSFUL**
- **Next:** F-018 Phase 1b host/CI JDK 21; Phase 2 AGP 8.5.2 lockstep
- **Next:** F-018 Phase 1b host/CI JDK 21 (this run); Phase 2 AGP 8.5.2 lockstep

## 2026-07-19 — F-018 scheduled (JDK 21 + toolchain ladder)

Expand Down
3 changes: 2 additions & 1 deletion docs/SAMPLE-APP.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ cd application && ./gradlew build
```

Toolchain: AGP **8.1.2**, compileSdk **34**, targetSdk **33**, Gradle **8.7**,
JDK **17**. See [ENV.md](ENV.md), [COMPOSE.md](COMPOSE.md), [ARCHITECTURE.md](ARCHITECTURE.md).
build JDK **21** (app language level unchanged). See [ENV.md](ENV.md),
[COMPOSE.md](COMPOSE.md), [ARCHITECTURE.md](ARCHITECTURE.md).

## What “gold standard” means here

Expand Down
31 changes: 26 additions & 5 deletions scripts/env-mac.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,47 @@
# source scripts/env-mac.sh
#
# Install (one-time, no sudo required for these paths):
# brew install openjdk@17
# brew install openjdk@21
# brew install --cask android-commandlinetools
# export JAVA_HOME="/usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home"
# export JAVA_HOME="/usr/local/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home"
# # Apple Silicon Homebrew prefix is /opt/homebrew instead of /usr/local
# export ANDROID_HOME="/usr/local/share/android-commandlinetools"
# yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --licenses
# "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --install \
# "platforms;android-34" "platforms;android-33" "platform-tools" \
# "build-tools;33.0.2" "build-tools;34.0.0"
# printf 'sdk.dir=%s\n' "$ANDROID_HOME" > application/local.properties
#
# Note: brew install --cask temurin@17 needs sudo for the system pkg installer;
# openjdk@17 (formula) is keg-only and does not need sudo.
# Note: brew install --cask temurin@21 needs sudo for the system pkg installer;
# openjdk@21 (formula) is keg-only and does not need sudo.
#
# Build JVM is JDK 21 (F-018). Android/app bytecode stays at the project's
# configured JavaVersion (sample still 1.8 / jvmTarget from settings) — do not
# confuse the daemon JDK with language level.

_forma_java_home_candidates=(
/usr/local/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home
/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home
)

if [[ -z "${JAVA_HOME:-}" ]]; then
for _candidate in "${_forma_java_home_candidates[@]}"; do
if [[ -x "$_candidate/bin/java" ]]; then
export JAVA_HOME="$_candidate"
break
fi
done
fi
unset _candidate _forma_java_home_candidates

export JAVA_HOME="${JAVA_HOME:-/usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home}"
export JAVA_HOME="${JAVA_HOME:-/usr/local/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home}"
export ANDROID_HOME="${ANDROID_HOME:-/usr/local/share/android-commandlinetools}"
export ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-$ANDROID_HOME}"
export PATH="$JAVA_HOME/bin:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH"

if [[ ! -x "$JAVA_HOME/bin/java" ]]; then
echo "env-mac.sh: java not found at $JAVA_HOME/bin/java" >&2
echo "env-mac.sh: install with: brew install openjdk@21" >&2
return 1 2>/dev/null || exit 1
fi

Expand Down
Loading