Add template app distribution workflow - #36136
Conversation
Adds a manually triggered workflow that packs local MAUI templates, generates variant apps, builds Android/iOS packages, and publishes through fastlane for store testing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Derive app versions and identifiers automatically, reduce manual workflow inputs, and remove unnecessary iOS signing secrets by generating the keychain password and discovering the imported signing identity. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds an early publish-job preflight that reports missing store signing secrets before expensive setup/build steps, and directs dry-run testing to publish=false. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keeps dry-run builds independent from store signing secrets while preserving early validation for publish=true runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Removes conditional TargetFrameworks entries from generated template apps so single-platform dry-run and publish jobs do not restore unrelated workloads such as MacCatalyst during iOS builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Select the newest installed Xcode that has both macOS and iPhoneOS SDKs before building iOS template apps. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Select Xcode by highest installed iPhoneOS SDK and ensure SDK convenience symlinks exist on hosted macOS runners. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use SDK-bundled workload manifests so dry-run and publish builds do not pull an iOS workload newer than the hosted runner Xcode SDK. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep normal workload manifest updates for Android while pinning iOS to SDK-bundled manifests for hosted runner Xcode compatibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Allow template app publishing to pass AndroidSigningStoreType when the upload keystore is PKCS12 or another explicit keystore type. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make the Google Play release status configurable so first uploads to draft Play apps can use draft while established apps keep completed by default. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Avoid showing unresolved matrix placeholders when the dry-run matrix job is skipped during publish runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Install Mac Catalyst provisioning profiles with the macOS profile extension and pass the profile UUID to MSBuild so the Mac signing task can locate the profile during package publishing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use fastlane's macOS app_platform value when uploading Mac Catalyst PKG packages to TestFlight. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Name Mac Catalyst artifacts as macOS, suppress avoidable Git/Xcode log noise, disable overeager Mac entitlement validation for App Store profiles, and update the sample template SQLite bundle dependency to avoid NuGet audit warnings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Avoid publish binlog artifacts, use validated immutable source SHAs for build jobs, pin fastlane dependencies, and harden publishing ref validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use conditional job-name expressions so skipped matrix jobs show static names instead of raw matrix placeholders. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Avoid raw matrix expressions on skipped workflow jobs; GitHub still appends matrix values to expanded jobs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Treat release/* branches as trusted publish sources, while still requiring tags and SHAs to be reachable from trusted branches. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36136Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36136" |
|
/azp run maui-pr |
|
Azure Pipelines successfully started running 1 pipeline(s). |
PureWeen
left a comment
There was a problem hiding this comment.
Adversarial code review — PR #36136
Methodology: 3 independent reviewers (different models) + adversarial consensus (3/3 → include at highest severity; 2/3 → include at lower severity; 1/3 → dispute round with 2 adjudicators). Inline placement validated against the head commit. This is a code-only review — CI status is out of scope. Posted as a COMMENT (never approve/request-changes; that's a human call).
Overall: a few things worth addressing before merge. The trust model itself is sound — all three reviewers independently verified that an untrusted source_ref cannot reach the secret-scoped publish job (Resolve-SourceRef.ps1 -Publish throws on untrusted refs, failing prepare, which publish depends on; checkouts pin to the resolved source_sha, so no TOCTOU).
Must-fix
- ❌ Unpinned GitHub Actions in the secret-scoped
publishjob (template-app-distribution.yml, inline) — floating tags including third-partyruby/setup-ruby@v1in the job that holds signing/store secrets. Repo convention pins every action to a full commit SHA.
Should-fix
⚠️ -replace$-substitution corrupts generated csproj (New-TemplateApp.ps1, inline) — XML-escaping doesn't neutralize$back-references in the replacement string.⚠️ preparejob can't see Environment-scopedvars.*(template-app-distribution.yml, inline) — silent fallback to default IDs → provisioning-profile mismatch at publish.⚠️ Unchecked nativedotnetexit codes (Pack-Templates.ps1/New-TemplateApp.ps1, inline) — build/pack failures masked by downstream guards.
Design-level / nits (lower confidence)
- 💡 Matrix values interpolated inline into
pwsh run:blocks rather than passed viaenv:(the pattern the workflow already uses forinputs.source_ref). Requires repo-variable write access, so not remotely exploitable — consistency / defense-in-depth. (3/3 on facts) - 💡
publishnever assertsneeds.prepare.outputs.trusted == 'true'— it relies onpreparethrowing. An explicitif:gate would keep the trust boundary structural across future refactors. (1/3) - 💡
source_refbuilds template content against the released MAUI workload, not framework binaries fromsource_ref— the input name could mislead; worth a doc note. (1/3) - 💡
SQLitePCLRaw.bundle_green2.1.10→2.1.11 inMauiApp.1.csprojis unrelated to this workflow — ideally a separate commit. (2/3)
Considered and dropped: the throwaway keychain password passed on the security argv — on an ephemeral single-tenant runner this isn't a meaningful exposure (both dispute adjudicators discarded it).
Tests
No automated tests added; reasonable here — this is CI/workflow + PowerShell glue that's inherently hard to unit-test. The $-substitution and exit-code items above are the parts most amenable to a small Pester test if you want regression coverage.
|
|
||
| - name: Setup Ruby and fastlane | ||
| if: ${{ matrix.platform == 'android' || matrix.platform == 'ios' || matrix.platform == 'maccatalyst' }} | ||
| uses: ruby/setup-ruby@v1 |
There was a problem hiding this comment.
❌ Security / Supply chain — This job runs with environment: template-app-distribution and signing/store secrets, yet ruby/setup-ruby@v1 (third-party, floating tag) — along with actions/checkout@v7, actions/setup-dotnet@v5, actions/setup-java@v5, and actions/upload-artifact@v7 elsewhere in this file — is pinned to a mutable tag. This repo's convention is to pin every action to a full commit SHA (see the existing workflows). A retagged or compromised action would execute in the job where store credentials are live. Recommend pinning all uses: to full commit SHAs.
Flagged by: 3/3 reviewers
| $content = $content.Remove($match.Index, $match.Length).Insert($match.Index, $replacement) | ||
| } | ||
|
|
||
| $content = $content -replace "<ApplicationTitle>[^<]+</ApplicationTitle>", "<ApplicationTitle>$(ConvertTo-XmlEscaped $DisplayName)</ApplicationTitle>" |
There was a problem hiding this comment.
[SecurityElement]::Escape() (via ConvertTo-XmlEscaped) does not neutralize $, which is special in a PowerShell -replace replacement string ($1, $&, $$). If a DisplayName / ApplicationId / version value that originates from TEMPLATE_APP_VARIANTS_JSON contains e.g. $& or $1, the replacement silently expands the back-reference and corrupts the generated csproj. The same applies to the ApplicationId, ApplicationDisplayVersion, and ApplicationVersion replacements immediately below. Recommend [regex]::Replace(...) with a MatchEvaluator, or doubling $→$$ in the replacement.
Flagged by: 3/3 reviewers
| $env:NUGET_PACKAGES = $NuGetPackages | ||
|
|
||
| Write-Host "Building MAUI templates from $templatesProject" | ||
| dotnet build -t:Rebuild $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false |
There was a problem hiding this comment.
$ErrorActionPreference = 'Stop' does not make PowerShell throw when a native command exits non-zero, so a failed dotnet build here (and dotnet pack on the next line) is not caught — execution continues to the Get-ChildItem / if (-not $package) guard, which masks the real build failure behind a generic "package not found". The same pattern appears with dotnet new install / dotnet new in New-TemplateApp.ps1. Recommend checking $LASTEXITCODE after each native call (as Invoke-DotNetPublish already does elsewhere).
Flagged by: 2/3 reviewers
| id: matrix | ||
| shell: pwsh | ||
| env: | ||
| TEMPLATE_APP_IDENTIFIER_PREFIX: ${{ vars.TEMPLATE_APP_IDENTIFIER_PREFIX }} |
There was a problem hiding this comment.
prepare job declares no environment:, so any of these vars.TEMPLATE_APP_* that are defined as Environment-scoped variables (rather than repo/org-level) resolve to empty here. The matrix then silently falls back to default bundle/application IDs, surfacing as a provisioning-profile mismatch only later at publish time. The header comments describe these as "variables" without noting they must be repo- or org-level to be visible in this job. Recommend documenting the required scope, or resolving IDs in an environment-gated step.
Flagged by: 3/3 reviewers
Use the selected template source branch's NuGet.config when installing MAUI workloads and when generating template apps so preview branches can resolve branch-specific packages. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a manually triggered GitHub Actions workflow to build distributable apps from the MAUI templates (blank + sample) across Android, iOS, Mac Catalyst, and Windows, with optional publishing via fastlane to Google Play test tracks and TestFlight. The PR title and description match the implementation and include the required NOTE block plus setup guidance for the protected environment/secrets.
Changes:
- Adds a new
template-app-distributionworkflow that builds template-generated apps (dry-run artifact build or publish mode). - Introduces supporting PowerShell scripts to pack templates, generate projects, build packages, and install Apple signing assets, plus a pinned fastlane bundle for store uploads.
- Updates the mobile template to consume
SQLitePCLRaw.bundle_green2.1.11.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Templates/src/templates/maui-mobile/MauiApp.1.csproj | Bumps SQLitePCLRaw.bundle_green dependency version used by the mobile template. |
| .github/workflows/template-app-distribution.yml | New workflow to build/upload (and optionally publish) generated template apps across platforms. |
| .github/scripts/template-app-distribution/Resolve-SourceRef.ps1 | Validates and resolves the source_ref, with trust checks for publish runs. |
| .github/scripts/template-app-distribution/Resolve-DotNetSdk.ps1 | Resolves the .NET SDK and derives a netX.Y TFM from global.json. |
| .github/scripts/template-app-distribution/Prepare-Matrix.ps1 | Builds a variant/platform matrix and derives app identifiers/display names. |
| .github/scripts/template-app-distribution/Pack-Templates.ps1 | Builds/packs the local template nupkg used for dotnet new generation. |
| .github/scripts/template-app-distribution/New-TemplateApp.ps1 | Generates a template app, patches identifiers/versions, and writes a per-app global.json. |
| .github/scripts/template-app-distribution/Install-AppleSigningAssets.ps1 | Installs Apple certs/profiles into a temp keychain for signing iOS/Mac Catalyst builds. |
| .github/scripts/template-app-distribution/Build-TemplateApp.ps1 | Publishes platform-specific artifacts (AAB/IPA/PKG/Windows zip) with optional signing. |
| .github/scripts/template-app-distribution/fastlane/Gemfile | Pins fastlane version for reproducible publish runs. |
| .github/scripts/template-app-distribution/fastlane/Gemfile.lock | Locked fastlane dependency graph for CI runs. |
| .github/scripts/template-app-distribution/fastlane/Fastfile | Fastlane lanes for Google Play uploads and TestFlight uploads with release notes support. |
| Write-Host "Building MAUI templates from $templatesProject" | ||
| dotnet build -t:Rebuild $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false | ||
|
|
||
| Write-Host "Packing MAUI templates with PackageVersion=$PackageVersion" | ||
| dotnet pack $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false -o $OutputPath |
| Write-Host "Installing template package $TemplatePackagePath" | ||
| dotnet new install $TemplatePackagePath |
| $dotnetNewArgs = @("new", $Template, "-n", $ProjectName, "-o", $projectDir, "--framework", $DotNetTfm, "--no-restore") + $templateArgs | ||
| Write-Host "Creating project: dotnet $($dotnetNewArgs -join ' ')" | ||
| & dotnet @dotnetNewArgs |
| function Write-Base64File([string]$Base64Value, [string]$Path) { | ||
| $bytes = [Convert]::FromBase64String($Base64Value) | ||
| [System.IO.File]::WriteAllBytes($Path, $bytes) | ||
| } |
| # - TEMPLATE_APP_ANDROID_KEYSTORE_BASE64 | ||
| # - TEMPLATE_APP_ANDROID_KEYSTORE_PASSWORD | ||
| # - TEMPLATE_APP_ANDROID_KEY_ALIAS | ||
| # - TEMPLATE_APP_ANDROID_KEY_PASSWORD |
Enable the existing implicit XAML namespace compatibility flag when generated net11 apps need it, and use CoreCLR for net11+ Apple targets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use NativeAOT for net11 iOS store packages and provide explicit Mac Catalyst runtime identifiers for net11 CoreCLR publishing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| Write-Host "Building MAUI templates from $templatesProject" | ||
| dotnet build -t:Rebuild $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false | ||
|
|
||
| Write-Host "Packing MAUI templates with PackageVersion=$PackageVersion" | ||
| dotnet pack $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false -o $OutputPath |
| Write-Host "Installing template package $TemplatePackagePath" | ||
| dotnet new install $TemplatePackagePath | ||
|
|
||
| $templateArgs = @() | ||
| if (-not [string]::IsNullOrWhiteSpace($TemplateArgsJson)) { | ||
| $templateArgs = @(ConvertFrom-Json $TemplateArgsJson | ForEach-Object { [string]$_ }) | ||
| } | ||
|
|
||
| $dotnetNewArgs = @("new", $Template, "-n", $ProjectName, "-o", $projectDir, "--framework", $DotNetTfm, "--no-restore") + $templateArgs | ||
| Write-Host "Creating project: dotnet $($dotnetNewArgs -join ' ')" | ||
| & dotnet @dotnetNewArgs | ||
|
|
| & security create-keychain -p $keychainPassword $keychainPath | ||
| & security set-keychain-settings -lut 21600 $keychainPath | ||
| & security unlock-keychain -p $keychainPassword $keychainPath | ||
|
|
||
| $existingKeychains = & security list-keychains -d user | ForEach-Object { $_.Trim().Trim('"') } | ||
| & security list-keychains -d user -s $keychainPath @existingKeychains | ||
| & security import $certificatePath -k $keychainPath -P $certificatePassword -T /usr/bin/codesign -T /usr/bin/security |
Pass the net11 Mac Catalyst RuntimeIdentifiers list through MSBuild escaping so it remains a single property value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use a single App Store-compatible Mac Catalyst RID for net11 publish builds and tolerate TestFlight beta-review conflicts after successful uploads. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| Write-Host "Building MAUI templates from $templatesProject" | ||
| dotnet build -t:Rebuild $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false | ||
|
|
||
| Write-Host "Packing MAUI templates with PackageVersion=$PackageVersion" | ||
| dotnet pack $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false -o $OutputPath |
| Write-Host "Installing template package $TemplatePackagePath" | ||
| dotnet new install $TemplatePackagePath |
| Write-Host "Creating project: dotnet $($dotnetNewArgs -join ' ')" | ||
| & dotnet @dotnetNewArgs |
| function Write-Base64File([string]$Base64Value, [string]$Path) { | ||
| $bytes = [Convert]::FromBase64String($Base64Value) | ||
| [System.IO.File]::WriteAllBytes($Path, $bytes) | ||
| } |
| function Invoke-DotNetPublish([string[]]$Arguments, [string]$Description) { | ||
| & dotnet @Arguments | ||
| if ($LASTEXITCODE -ne 0) { | ||
| throw "$Description failed with exit code $LASTEXITCODE." | ||
| } | ||
| } |
Apply a finite fastlane processing timeout and treat post-upload TestFlight processing timeouts as successful uploads so template distribution runs do not hang indefinitely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Recognize fastlane's BuildWatcher timeout text as a post-upload TestFlight processing timeout so Mac Catalyst uploads do not fail after the configured wait expires. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| permissions: | ||
| contents: read | ||
|
|
| Write-Host "Building MAUI templates from $templatesProject" | ||
| dotnet build -t:Rebuild $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false | ||
|
|
||
| Write-Host "Packing MAUI templates with PackageVersion=$PackageVersion" | ||
| dotnet pack $templatesProject -p:PackageVersion=$PackageVersion -p:GenerateCgManifest=false -o $OutputPath |
| $entry = "`t<key>$Key</key>`r`n`t<false/>`r`n" | ||
| $plistContent = $plistContent -replace "(?m)^</dict>", "$entry</dict>" | ||
| Set-Content -Path $Path -Value $plistContent -Encoding utf8 |
| function Write-Base64File([string]$Base64Value, [string]$Path) { | ||
| $bytes = [Convert]::FromBase64String($Base64Value) | ||
| [System.IO.File]::WriteAllBytes($Path, $bytes) | ||
| } |
PureWeen
left a comment
There was a problem hiding this comment.
Adversarial code review — PR #36136 (re-review of the 7 new commits)
Methodology: 3 independent reviewers (different models) + adversarial consensus (3/3 → highest severity; 2/3 → lower severity; 1/3 → dispute round). This round targets what changed since my 2026-07-01 review (f4898c9 → 742ef07): net11 support, NuGet.config sourcing, TestFlight timeout handling, and exit-code checks. Code-only review — CI status is out of scope. Findings already covered by my earlier review or the Copilot reviewer are not repeated.
Net-new findings
Build-TemplateApp.ps1:218 · 2/3
The matrix default RID is empty (runtimeIdentifier: "") on the macos-15 (Apple Silicon) runner, so the net11+ branch forces -r maccatalyst-x64 → an Intel-only artifact. The net10 path (empty RID, no -r) instead falls through to the template's Release default of maccatalyst-x64;maccatalyst-arm64 (universal), so net11 testers on Apple Silicon get a Rosetta-only build and lose native arm64. arm64-only is not the fix — the template csproj explicitly notes the Mac App Store rejects arm64-only builds. See inline for the suggested fix.
Fastfile:114 · 3/3
The upload rescue treats both a review conflict and a broad processing+timeout substring match as a successful upload, so an unrelated App Store Connect failure can turn the secret-scoped publish job green with nothing delivered to testers. See inline.
Lower-severity notes (💡)
Add-ProjectDefineConstant— new$-substitution sink (New-TemplateApp.ps1). Same class as my already-posted-replacefinding, but a distinct net-new location:[regex]::Replace($Content, pattern, "<DefineConstants>$value…", 1)treats$1/$&/$`/$'in the replacement string specially.$(DefineConstants)is safe, and it isn't triggerable with today's template (low likelihood), but the no-existing-property path is literal/safe, so the inconsistency is worth closing — escape via$value -replace '\$','$$'or use a literal string replace. (2/3)integer_environmentparses non-decimal radix (Fastfile).Integer(value)honors prefixes:"010"→ 8 (silent octal),"0900"→ ArgumentError (aborts the publish), and0x/0bare parsed. A zero-paddedTEMPLATE_APP_TESTFLIGHT_WAIT_TIMEOUT_SECONDSmisbehaves. Fix:Integer(value, 10). (2/3, verified empirically)
Status of my prior findings (all still open)
- ❌ Unpinned GitHub Actions — still floating (
@v7/@v5, incl. third-partyruby/setup-ruby@v1) in the secret-scoped publish job. Open. ⚠️ -replace$-substitution on theApplication*rewrites (New-TemplateApp.ps1) — unchanged. Open.⚠️ Unchecked native exit codes — partially addressed:dotnet workload installnow checks$LASTEXITCODE, butdotnet build/dotnet pack(Pack-Templates.ps1) anddotnet new install/dotnet new(New-TemplateApp.ps1) are still unchecked. Open.⚠️ preparejob has noenvironment:(Environment-scopedvars.*invisible during matrix prep) — unchanged. Open.
Notes
- Verified not bugs: the iOS-vs-MacCatalyst NativeAOT asymmetry (iOS requires AOT/no-JIT; MacCatalyst on CoreCLR without AOT is correct) and the net11 detection / implicit-xmlns XAML heuristics.
- No new automated tests (workflow + PowerShell/Ruby glue is inherently hard to unit-test); reasonable, though the
Integer()base-10 and$-substitution items are the parts most amenable to a small Pester/unit check. - Prior reviews already on the PR: my 2026-07-01 review + 4 rounds of the Copilot reviewer. This round intentionally avoids repeating them.
| if (-not [string]::IsNullOrWhiteSpace($RuntimeIdentifier)) { | ||
| $arguments += @("-r", $RuntimeIdentifier) | ||
| } elseif ($useNet11OrLater) { | ||
| $arguments += @("-r", "maccatalyst-x64") |
There was a problem hiding this comment.
runtimeIdentifier: "", and the runner is macos-15, i.e. Apple Silicon/arm64), this forces -r maccatalyst-x64, producing an Intel-only artifact. The net10 path (empty RID, no -r) instead falls through to the template's Release default maccatalyst-x64;maccatalyst-arm64 (universal), so net11 testers on Apple Silicon get a Rosetta-only build and lose native arm64.
Note arm64-only is not a valid fix — the template csproj comment states the Mac App Store rejects arm64-only builds. If a RID must be forced for net11, prefer the universal pair via -p:RuntimeIdentifiers=maccatalyst-x64;maccatalyst-arm64 (or omit -r and let the Release RuntimeIdentifiers apply). If x64-only is deliberate here, a short comment explaining why would help.
Flagged by: 2/3 reviewers
|
|
||
| begin | ||
| upload_to_testflight(upload_options) | ||
| rescue => error |
There was a problem hiding this comment.
rescue => error treats both "another build is in review" (testflight_review_conflict?) and a processing-wait timeout (testflight_processing_timeout?) as a successful upload. The timeout classifier is a broad substring match ("processing" AND any of timeout/timed out/waited), so an unrelated App Store Connect error whose text merely contains those tokens — e.g. "Error processing request … the request timed out" — is swallowed and the publish job goes green even though no build reached testers. Because this runs in the secret-scoped publish path, a genuine delivery failure is silently hidden.
Consider narrowing the timeout match to fastlane's specific "still processing after wait" signal (e.g. require the BuildWatcher exceeded phrasing rather than the generic processing+timeout combination), and always log the full underlying error even when downgrading to success so a masked real failure stays diagnosable.
Flagged by: 3/3 reviewers
|
🔍 Superseded by #36571 — closing this one. The install failures testers reported with the artifacts from this PR — Android had no APK, Windows showed a "install the .NET runtime" screen, iOS failed with #36571 rebuilds the same workflow on top of current
It also drops the incidental Comment posted by GitHub Copilot CLI on behalf of @kubaflo, standing in for @jfversluis while he is away. |
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Summary
Adds a manually triggered template app distribution workflow that builds the latest MAUI templates into tester apps for Android, iOS, Mac Catalyst, and Windows.
The workflow can generate blank and sample-content template apps, upload build artifacts, and optionally publish Android/iOS/Mac Catalyst builds to Google Play test tracks and TestFlight using fastlane.
Value
This lets us distribute accessibility test apps directly from the templates in this repository instead of keeping a separate sample app repository in sync.
Setup needed before publish runs work
The workflow still needs the
template-app-distributionGitHub Environment and its signing/store secrets created indotnet/maui. Dry-run artifact builds can run without those secrets./cc @PureWeen