diff --git a/README.md b/README.md index 2eb5438..0b66c54 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,12 @@ which secrets/permissions) and a copy-paste example. Start with the `List` (run a command, write/copy/delete a file…) that's *planned* then *executed* — so behaviour is testable without spawning a process. Run any command with `--dry-run` to print its plan. -- **Prebuilt CLI, not resolved at runtime.** Most actions download a +- **Prebuilt CLI, not resolved at runtime.** Every action downloads a self-contained, **checksum-verified** binary of the CLI for the runner's - OS/arch (Linux x64/arm64, macOS arm64) — no Dart SDK, no `dart pub get` on - every run. Only `codegen` / `android-setup` / `ios-setup` still use `dart run`, - since they set up Flutter anyway. See [Releasing the CLI](#releasing-the-cli). + OS/arch (Linux x64/arm64, macOS arm64) — no `dart pub get` on every run. The + build/codegen actions still set up Flutter (the CLI shells out to + `dart`/`flutter`/`build_runner`); the rest need nothing on PATH. See + [Releasing](docs/RELEASING.md). - **Quiet by default.** Command output is captured and shown **only on failure** (chronic-style) — a green run is one tick per step. Turn on GitHub step-debug (`RUNNER_DEBUG=1`) or pass `--verbose` to stream everything. No `moreutils` @@ -163,19 +164,13 @@ dart test An optional `workflow_call` that composes setup → version-stamp → build → release-cut → submit → publish end-to-end, so a consumer calls one thing. -## Releasing the CLI +## Releasing -The actions download a prebuilt CLI binary from a GitHub Release; the version is -pinned per action ref by [`cli-version.txt`](cli-version.txt) (consumers don't -manage it). To cut a release: - -1. Bump the version in [`cli-version.txt`](cli-version.txt) and merge it to `main`. -2. **Actions** tab → **release-cli** → **Run workflow**. - -The workflow compiles the binary on each runner (Linux x64/arm64, macOS arm64), -then creates the `cli-v` tag + GitHub Release with the binaries and a -`SHA256SUMS`. No local `git tag` needed; re-running for the same version updates -the existing release. +There are two artifacts — the **prebuilt CLI binary** (`release-cli`) and the +**action version tags** (`release-actions`) — both cut from the Actions tab, no +local `git tag`. The ordering matters (binary first). The full step-by-step, +including when to bump [`cli-version.txt`](cli-version.txt) and how to verify and +roll back, is in **[docs/RELEASING.md](docs/RELEASING.md)**. ## Contributing diff --git a/actions/android-setup/action.yml b/actions/android-setup/action.yml index 8632480..c3c96c0 100644 --- a/actions/android-setup/action.yml +++ b/actions/android-setup/action.yml @@ -66,10 +66,15 @@ runs: bundler-cache: true working-directory: ${{ inputs.project-dir }} + - name: Install flutter-tools CLI + if: ${{ inputs.run-codegen == 'true' }} + id: install + shell: bash + run: bash "${{ github.action_path }}/../../scripts/install-cli.sh" + - name: Layered codegen if: ${{ inputs.run-codegen == 'true' }} shell: bash - working-directory: ${{ github.action_path }}/../.. env: INPUT_WORKSPACE: ${{ inputs.workspace }} INPUT_PROJECT_DIR: ${{ inputs.project-dir }} @@ -79,7 +84,7 @@ runs: INPUT_CLEAN: ${{ inputs.clean }} INPUT_UPGRADE_DART_STYLE: ${{ inputs.upgrade-dart-style }} run: >- - dart pub get && dart run bin/flutter_tools.dart codegen + "${{ steps.install.outputs.cli }}" codegen --workspace "$INPUT_WORKSPACE" --project-dir "$INPUT_PROJECT_DIR" --api-dir "$INPUT_API_DIR" diff --git a/actions/codegen/action.yml b/actions/codegen/action.yml index 4e2353d..7ef9543 100644 --- a/actions/codegen/action.yml +++ b/actions/codegen/action.yml @@ -66,14 +66,15 @@ runs: distribution: temurin java-version: ${{ inputs.java-version }} - - name: Resolve flutter-tools CLI dependencies + # Fetch the prebuilt CLI binary (no `dart pub get`). The CLI still shells out + # to `dart`/`flutter` for the actual codegen, which the setup above provides. + - name: Install flutter-tools CLI + id: install shell: bash - working-directory: ${{ github.action_path }}/../.. - run: dart pub get + run: bash "${{ github.action_path }}/../../scripts/install-cli.sh" - name: Run layered codegen shell: bash - working-directory: ${{ github.action_path }}/../.. env: INPUT_WORKSPACE: ${{ inputs.workspace }} INPUT_PROJECT_DIR: ${{ inputs.project-dir }} @@ -84,7 +85,7 @@ runs: INPUT_CLEAN: ${{ inputs.clean }} INPUT_UPGRADE_DART_STYLE: ${{ inputs.upgrade-dart-style }} run: >- - dart run bin/flutter_tools.dart codegen + "${{ steps.install.outputs.cli }}" codegen --workspace "$INPUT_WORKSPACE" --project-dir "$INPUT_PROJECT_DIR" --api-dir "$INPUT_API_DIR" diff --git a/actions/ios-setup/action.yml b/actions/ios-setup/action.yml index 022db8c..573e1af 100644 --- a/actions/ios-setup/action.yml +++ b/actions/ios-setup/action.yml @@ -49,17 +49,22 @@ runs: distribution: temurin java-version: ${{ inputs.java-version }} + - name: Install flutter-tools CLI + if: ${{ inputs.run-codegen == 'true' }} + id: install + shell: bash + run: bash "${{ github.action_path }}/../../scripts/install-cli.sh" + - name: Layered codegen if: ${{ inputs.run-codegen == 'true' }} shell: bash - working-directory: ${{ github.action_path }}/../.. env: INPUT_WORKSPACE: ${{ inputs.workspace }} INPUT_PROJECT_DIR: ${{ inputs.project-dir }} INPUT_API_PUBSPEC_TEMPLATE: ${{ inputs.api-pubspec-template }} INPUT_CLEAN: ${{ inputs.clean }} run: >- - dart pub get && dart run bin/flutter_tools.dart codegen + "${{ steps.install.outputs.cli }}" codegen --workspace "$INPUT_WORKSPACE" --project-dir "$INPUT_PROJECT_DIR" --api-pubspec-template "$INPUT_API_PUBSPEC_TEMPLATE" diff --git a/docs/RELEASING.md b/docs/RELEASING.md new file mode 100644 index 0000000..0524ade --- /dev/null +++ b/docs/RELEASING.md @@ -0,0 +1,102 @@ +# Releasing flutter-tools + +How to ship a new version. Everything is driven from the **Actions tab** +(`workflow_dispatch`) — no local `git tag` or push. + +## The two artifacts + +flutter-tools ships **two independently-versioned things**. Keep them straight: + +| Artifact | What it is | Versioned by | Cut by | +|---|---|---|---| +| **CLI binary** | The compiled `flutter-tools` executable the actions download at runtime (per OS/arch). | [`cli-version.txt`](../cli-version.txt) → `cli-v` GitHub Release | `release-cli` workflow | +| **Action version** | The `vX.Y.Z` tag (and moving `v0`) that consumers reference as `…/actions/@v0`. | git tags | `release-actions` workflow | + +**The link between them:** every action calls +[`scripts/install-cli.sh`](../scripts/install-cli.sh), which reads +`cli-version.txt` **from the checked-out action ref** and downloads the matching +`cli-v` release. So an action tag and the binary it pulls are bound by +whatever `cli-version.txt` said at that commit. That binding is the reason +ordering matters (below). + +## Decision: what do I need to run? + +| What changed | Bump `cli-version.txt`? | Run `release-cli`? | Run `release-actions`? | +|---|---|---|---| +| Dart code (`lib/`, `bin/`) | **Yes** | **Yes** | Yes | +| Action YAML, scripts, docs, workflows only | No | No | Yes | +| Nothing shippable (tests, internal docs) | No | No | No | + +> **Bumping `cli-version.txt` and running `release-cli` are a pair.** If you bump +> it without publishing the matching binary, every `@v0` consumer 404s on the +> download. If you change Dart code without bumping it, you'd have to *overwrite* +> an existing immutable `cli-v*` release — don't; bump instead. + +## Flow A — you changed the Dart CLI (most common) + +1. **Bump the binary version.** Edit [`cli-version.txt`](../cli-version.txt) + (e.g. `0.1.0` → `0.2.0`). Open a PR with your code change, get it green, merge + to `main`. +2. **Publish the binary.** Actions tab → **release-cli** → **Run workflow** (from + `main`). It compiles for `linux-x64`, `linux-arm64`, `macos-arm64` and creates + the `cli-v0.2.0` Release + `SHA256SUMS`. Wait for it to finish. +3. **Cut the action version.** Actions tab → **release-actions** → **Run + workflow**: `version = 0.7.0`, `move_major = true`. It tags `v0.7.0` at `main` + and advances `v0` → `main`. + +The instant `v0` moves, `@v0` consumers resolve to the new actions, whose +`cli-version.txt` is `0.2.0`, whose binary (step 2) exists. ✅ + +**Order is load-bearing:** run `release-cli` **before** `release-actions`. If you +move `v0` first, `@v0` consumers briefly point at actions that want a binary that +isn't published yet. + +## Flow B — you only changed action YAML / scripts / docs + +No new binary needed (the current `cli-v*` release still matches). Just: + +- Actions tab → **release-actions** → **Run workflow**: `version = `, + `move_major = true`. + +## Versioning conventions + +- **Action tags** are `v0.x` while the project is pre-1.0; `v0` is the moving + major most consumers pin. Bump the **minor** for features, **patch** for fixes. + `release-actions` refuses to overwrite an existing `vX.Y.Z`. +- **Binary** `cli-vX.Y.Z` just needs to be a fresh, unique version each time the + Dart code changes so each release stays immutable. Simplest is to move it in + lockstep with the action minor, but they need not match. +- The two numbers are **independent** — `cli-version.txt` is the only thing that + must be internally consistent. + +## Verify + +After a release, confirm a real consumer picks it up. In a repo that pins `@v0` +(e.g. vymalo-shop), trigger a workflow and check the logs: + +- A migrated action shows an **`install-cli.sh`** step that downloads + checksums + the binary into a `…/_temp/vymalo-flutter-tools.XXXX/flutter-tools` path, then + execs it — **no `dart pub get`**. +- The run is green on each runner OS/arch you target (the published assets must + cover them: `linux-x64`/`linux-arm64`/`macos-arm64` today). + +## Roll back + +- **Bad action release:** re-run **release-actions** with `version` pointing at a + known-good commit, or repoint `v0` to the previous tag. `@v0` consumers recover + with no change on their side. +- **Bad binary:** bump `cli-version.txt` to a new version, fix, and re-run + **release-cli** + **release-actions**. Don't overwrite a published `cli-v*` + (consumers on older action refs may still pull it). + +## Gotchas + +- **Self-hosted runners need egress** to `objects.githubusercontent.com` for the + binary download. (They already needed network for `dart pub get`, so this is + usually a non-issue — but it's the first thing to check if a download fails.) +- **Moving `v0` affects every `@v0` consumer**, not just one repo. It's instantly + reversible, but coordinate if several repos pin `@v0`. +- **New runner arch?** Add a matrix leg in + [`.github/workflows/release-cli.yml`](../.github/workflows/release-cli.yml) + (`dart compile exe` can't cross-compile) and re-release, or + `install-cli.sh` will 404 for that OS/arch.