Invoke onProgress callback in SdkManager.InstallPackagesAsync#40
Invoke onProgress callback in SdkManager.InstallPackagesAsync#40jfversluis merged 2 commits intomainfrom
Conversation
When an onProgress callback is provided, install packages one at a time and report progress for each package. When no callback is provided, install all packages in a single batch call (preserving existing behavior). Also update FakeAndroidProvider to invoke onProgress and add a test verifying the callback receives correct (package, index, total) args. Fixes #38 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes missing per-package progress reporting for Android SDK package installation by ensuring SdkManager.InstallPackagesAsync invokes the provided onProgress callback, enabling the Spectre live-progress UI to display package-level progress.
Changes:
- Update
SdkManager.InstallPackagesAsyncto install packages one-by-one whenonProgressis provided, while preserving batch install behavior otherwise. - Update
FakeAndroidProvider.InstallPackagesAsyncto invokeonProgressfor improved test fidelity. - Add a unit test validating
onProgressis called once per package.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/Client/Microsoft.Maui.Client/Providers/Android/SdkManager.cs | Adds per-package install loop and invokes onProgress callback. |
| src/Client/Microsoft.Maui.Client.UnitTests/Fakes/FakeAndroidProvider.cs | Updates fake implementation to emit per-package progress callbacks. |
| src/Client/Microsoft.Maui.Client.UnitTests/AndroidProviderTests.cs | Adds test asserting progress callback invocation per package. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for (var i = 0; i < packageList.Count; i++) | ||
| { | ||
| cancellationToken.ThrowIfCancellationRequested(); | ||
| onProgress(packageList[i], i + 1, packageList.Count); |
There was a problem hiding this comment.
onProgress is currently invoked with idx as i + 1 (1-based). The only in-repo caller (AndroidCommands.Install) formats ({idx + 1}/{total}), which will display 2..(total+1) and can show 4/3 on the last package. Either change the callback contract to be 0-based here (pass i) or update the caller (and document the contract) so all consumers agree on the indexing semantics.
| onProgress(packageList[i], i + 1, packageList.Count); | |
| // onProgress index is 0-based; callers can display (idx + 1)/total | |
| onProgress(packageList[i], i, packageList.Count); |
| var packageList = packages.ToList(); | ||
|
|
||
| try | ||
| { |
There was a problem hiding this comment.
packages.ToList() is executed before the try/catch. If packages is null or its enumerator throws, the exception will bypass the existing error translation (UnauthorizedAccessException/MauiToolException) and change behavior compared to the previous implementation. Consider moving the ToList() inside the try block and/or validating packages with an explicit ArgumentNullException to keep error handling consistent.
| var packageList = packages.ToList(); | |
| try | |
| { | |
| if (packages is null) | |
| throw new System.ArgumentNullException(nameof(packages)); | |
| try | |
| { | |
| var packageList = packages.ToList(); |
| if (onProgress is not null) | ||
| { | ||
| for (var i = 0; i < pkgList.Count; i++) | ||
| onProgress(pkgList[i], i + 1, pkgList.Count); |
There was a problem hiding this comment.
The fake invokes onProgress with idx as i + 1 (1-based). If production code/callers expect 0-based indexing (as AndroidCommands.Install currently does), this will cause tests to pass while the UI is off-by-one. Align the fake with the chosen contract (0-based vs 1-based) and keep it consistent with SdkManager.InstallPackagesAsync.
| onProgress(pkgList[i], i + 1, pkgList.Count); | |
| onProgress(pkgList[i], i, pkgList.Count); |
| Assert.Equal(("platform-tools", 1, 3), progressCalls[0]); | ||
| Assert.Equal(("build-tools;35.0.0", 2, 3), progressCalls[1]); | ||
| Assert.Equal(("platforms;android-35", 3, 3), progressCalls[2]); |
There was a problem hiding this comment.
This test asserts 1-based idx values (1..N). However, the CLI formatting in AndroidCommands.Install uses idx + 1 when displaying ({idx + 1}/{total}), implying it expects 0-based indexing. Update the test expectations to match the finalized onProgress contract (and ensure the production caller aligns), otherwise the UI can end up off-by-one while tests still pass.
| Assert.Equal(("platform-tools", 1, 3), progressCalls[0]); | |
| Assert.Equal(("build-tools;35.0.0", 2, 3), progressCalls[1]); | |
| Assert.Equal(("platforms;android-35", 3, 3), progressCalls[2]); | |
| Assert.Equal(("platform-tools", 0, 3), progressCalls[0]); | |
| Assert.Equal(("build-tools;35.0.0", 1, 3), progressCalls[1]); | |
| Assert.Equal(("platforms;android-35", 2, 3), progressCalls[2]); |
jfversluis
left a comment
There was a problem hiding this comment.
this completes the last open item from the PR #24 review by properly invoking the onProgress callback in InstallPackagesAsync. Clean implementation with batch vs one-at-a-time logic and good test coverage.LGTM
Summary
SdkManager.InstallPackagesAsyncaccepts anAction<string, int, int>? onProgressparameter but never invoked it, making the Spectre live-progress UI inAndroidCommands.Installunable to show per-package installation progress.Fix
When
onProgressis provided, install packages one at a time and report progress for each:When no callback is provided, the existing batch behavior is preserved (all packages in a single
InstallAsynccall).Changes
SdkManager.cs— iterate packages individually whenonProgressis setFakeAndroidProvider.cs— updated fake to invokeonProgressfor test fidelityAndroidProviderTests.cs— addedInstallPackagesAsync_InvokesOnProgressForEachPackagetestFixes #38