Pin by commit in the docs, tags trip pub up

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013F4NWNvYcdeSgqbWMT1VQ7
This commit is contained in:
ImBenji
2026-09-23 18:53:41 +01:00
co-authored by Claude Opus 5.5
parent b269201919
commit 21c380595f
3 changed files with 31 additions and 14 deletions
+13 -7
View File
@@ -30,7 +30,7 @@ Everything here is MIT licensed, see [LICENSE](LICENSE).
## Install ## Install
The packages arent on pub.dev. Git-depend on this repo, pick the package with The packages arent on pub.dev. Git-depend on this repo, pick the package with
`path:`, and pin a tag: `path:`, and pin the commit of a release tag:
```yaml ```yaml
dependencies: dependencies:
@@ -38,20 +38,26 @@ dependencies:
git: git:
url: https://git.imbenji.dev/IMBENJI.NET/Garage-SDKs.git url: https://git.imbenji.dev/IMBENJI.NET/Garage-SDKs.git
path: garage_auth path: garage_auth
ref: v0.1.0 ref: b2692019197e60d44ddd3ecab4917caf71ff45c3 # v0.1.0
garage_entitlements: garage_entitlements:
git: git:
url: https://git.imbenji.dev/IMBENJI.NET/Garage-SDKs.git url: https://git.imbenji.dev/IMBENJI.NET/Garage-SDKs.git
path: garage_entitlements path: garage_entitlements
ref: v0.1.0 ref: b2692019197e60d44ddd3ecab4917caf71ff45c3 # v0.1.0
``` ```
Pin a tag, dont float `main`. `garage_entitlements` decides who gets the paid Pin, dont float `main`. `garage_entitlements` decides who gets the paid
features, and "it changed under us" is not a fun thing to debug. features, and "it changed under us" is not a fun thing to debug.
`garage_entitlements` and `garage_iap` layer on `garage_auth`. You get it Use the tag's **full commit hash**, not the tag name. `garage_entitlements` and
transitively, but declare it too — you'll be constructing a `GarageAuth` `garage_iap` pull in `garage_auth` by relative path, which pub turns into a git
yourself anyway, and keep all of them on the same `ref`. dep at the resolved commit hash — so if your app asks for `garage_auth` at
`v0.1.0`, pub sees two different sources for the same package and refuses to
resolve. Same hash on every garage package and it just works. Keep the tag name
in a comment so you can tell which release it is.
You'll be constructing a `GarageAuth` yourself, so declare `garage_auth`
directly even when you only really want entitlements or iap.
**Working on the SDKs at the same time as an app?** Point the app at a local **Working on the SDKs at the same time as an app?** Point the app at a local
checkout with a gitignored `pubspec_overrides.yaml`, so edits hot reload with checkout with a gitignored `pubspec_overrides.yaml`, so edits hot reload with
+2 -2
View File
@@ -15,7 +15,7 @@ dependencies:
git: git:
url: https://git.imbenji.dev/IMBENJI.NET/Garage-SDKs.git url: https://git.imbenji.dev/IMBENJI.NET/Garage-SDKs.git
path: garage_ui path: garage_ui
ref: v0.1.0 ref: b2692019197e60d44ddd3ecab4917caf71ff45c3 # v0.1.0
``` ```
Leave that alone. Clone this repo somewhere, then next to the app's Leave that alone. Clone this repo somewhere, then next to the app's
@@ -109,7 +109,7 @@ Once the change works locally:
1. Commit and push it in this repo. 1. Commit and push it in this repo.
2. Tag a new version, e.g. `v0.1.1`, and push the tag. 2. Tag a new version, e.g. `v0.1.1`, and push the tag.
3. In each app that should get it, bump `ref:` to the new tag. Do it on purpose, 3. In each app that should get it, bump `ref:` to the new tag's full commit hash. Do it on purpose,
per app — dont float `main`. per app — dont float `main`.
4. Check the app builds **without** the override. Move it aside, resolve against 4. Check the app builds **without** the override. Move it aside, resolve against
the real tag, and analyze: the real tag, and analyze:
+16 -5
View File
@@ -585,7 +585,9 @@ class SelectPopup<T> extends StatefulWidget {
/// whether the search field is shown (only in builder mode). /// whether the search field is shown (only in builder mode).
final bool enableSearch; final bool enableSearch;
/// whether the list shrink-wraps (static lists do, builder lists scroll). /// whether the rows are a plain Column (static lists) or a lazy ListView
/// (builder lists, which can be long). Both only take the height they
/// need - see [_listView].
final bool shrinkWrap; final bool shrinkWrap;
const SelectPopup({ const SelectPopup({
@@ -657,9 +659,9 @@ class _SelectPopupState<T> extends State<SelectPopup<T>> {
// nothing to measure - asking a column how wide it wants to be and then // nothing to measure - asking a column how wide it wants to be and then
// ignoring the answer is just a layout pass nobody reads. // ignoring the answer is just a layout pass nobody reads.
// //
// [shrinkWrap] still decides the VERTICAL: a static list is a scrolling // [shrinkWrap] picks which list: a static one is a scrolling Column, the
// Column that takes only the height it needs, the builder path is a lazy // builder path is a lazy ListView. Either way the popup ends up as tall
// ListView. // as its rows and no taller.
return _popupSurface(theme, column); return _popupSurface(theme, column);
} }
@@ -729,10 +731,19 @@ class _SelectPopupState<T> extends State<SelectPopup<T>> {
); );
} }
// shrinkWrap regardless of [widget.shrinkWrap] - that flag is about which
// list we build, not how tall it ends up. A ListView left to expand eats
// every pixel of popupMaxHeight its handed, so a one-row "Search lines"
// popup opened a 312px wall of empty surface under its single row.
//
// This stays lazy: the incoming maxHeight is bounded (the overlay's
// ConstrainedBox, then Flexible), so the shrink wrapping viewport still
// only lays out as far as that extent and stops. Its the *unbounded* case
// that forces a full layout pass, and we never hand it one.
return ListView.separated( return ListView.separated(
controller: _scrollController, controller: _scrollController,
padding: EdgeInsets.all(inset), padding: EdgeInsets.all(inset),
shrinkWrap: widget.shrinkWrap, shrinkWrap: true,
itemCount: count, itemCount: count,
separatorBuilder: (context, _) => Gap(_popupRowGap(theme)), separatorBuilder: (context, _) => Gap(_popupRowGap(theme)),
itemBuilder: (context, index) => itemBuilder: (context, index) =>