apple build exports each build into build/ios/export/<version>-<build>/ (cleaned first), runs xcodebuild with Apple's tool folders first on PATH (Homebrew rsync 3.x broke Xcode's IPA step: exportArchive Copy failed), shows the IDEDistribution log's real error lines and exits non-zero on any export failure; apple upload fails with exit 1 when the IPA's build number is already on App Store Connect (stale IPA after a failed build), --allow-existing re-checks, --build N picks that build's IPA, release and beta flows use both; doctor flags a non-Apple rsync first on PATH; desktop publish calls rsync by absolute path without --chmod (publishSteps); site download notice per OS (macOS signed and notarized, Windows unsigned for now, Linux unsigned); game-report credential tests hermetic against a machine default profile (pitfalls 53, 54)

This commit is contained in:
CRTkafa 2026-10-13 09:45:48 +08:00
parent 8fd4ac741e
commit 0e4f579899
20 changed files with 338 additions and 48 deletions

View file

@ -9,6 +9,8 @@ fails without the fix.
| # | date | lesson | guard |
|---|---|---|---|
| 54 | 2026-10 | The second `apple build` of a Capacitor game archived fine, then `xcodebuild -exportArchive` failed with "exportArchive Copy failed" (exit 70). The IDEDistribution log had the real cause: `rsync error: syntax or usage error (code 1)` in IDEDistributionCreateIPAStep, because a Homebrew rsync 3.x, installed and linked that day by another session's release tool, came first on PATH. A tool changed a global binary on a shared machine as a side effect. | `apple build` runs xcodebuild with Xcode's and Apple's tool folders first on PATH (`xcodePath`) and prints a note when a non-Apple rsync is first (`foreignRsync`); an export failure shows the error lines of the newest IDEDistribution*.log (`distributionErrors`, `cli/lib/xcode.ts`, `cli/apple/build.ts`). `storebound doctor` flags a non-Apple rsync first on PATH. `tools/desktop-release.ts publish` calls rsync by absolute path (`/usr/bin/rsync` without `--chmod`, modes set on the server; else the Homebrew keg), never from PATH (`publishSteps`). Rule: tools never install or relink global binaries as a side effect. `tests/apple-build-export.test.ts`. |
| 53 | 2026-10 | After that failed export, `apple upload build/ios/export/App.ipa --yes` uploaded nothing: it read the stale IPA of build 1, found build 1 already VALID on App Store Connect and exited 0 ("build 1 is VALID"), so `build && upload` looked green. The export also wrote into the same folder every time. | `apple build` exports each build into its own folder `build/ios/export/<version>-<build>/` (removed first) and exits non-zero on any export failure or a missing IPA (`exportIpa`). `apple upload` fails with exit 1 when the IPA's build number is already on App Store Connect ("this ipa is build 1, which is already on App Store Connect (VALID): did the last build fail?"); only `--allow-existing` re-checks it. `--build N` picks / requires that build's IPA; the release and beta flows use `apple upload --no-wait --build ${BUILD} --allow-existing`, so a resumed flow still passes and a stale IPA never does (`existingBuild`, `exportedIpas`, `cli/apple/upload.ts`; `tests/apple-build-export.test.ts`). |
| 52 | 2026-10 | An iOS app that is live on the App Store but whose source is not on this machine could not appear in the desktop: the machine's app list (`~/.storebound/projects.json`) took only folders. | `storebound apps add --store apple\|play --app-id <id> --account <profile>` writes a store-only entry (`storeApps`, no path; `apps folders` shows "no local project", `apps remove apple:<id>`); the desktop adds it to the app list of the account with that profile (`registry::with_store_only`, `store_apps_cached` / `store_apps_refresh`), shown read-only as "Store only"; writing the folder list keeps the entries. `tests/onboard.test.ts`, `src-tauri/tests/machine.rs`, the boot check's `shared-profiles` case (zero uncaught errors). |
| 51 | 2026-10 | With several credential profiles the only way to have a machine default was naming one `default`. | `storebound accounts default <profile>` (and `--clear`) writes the pointer file `<credentials>/default-profile`; `accounts list` shows the default; order: env > a profile the project names > the project's own keys > the pointer > the only profile (or `default`) (`defaultProfile`, `setDefaultPointer` in `cli/lib/credentials.ts`; `tests/machine.test.ts`). |
| 50 | 2026-10 | Onboarding an app with sign-in left "account deletion URL" as an owner question although the app's own website had the page. | `storebound onboard` looks on the app's site before asking: /delete-account, /account/delete, /delete, /account-deletion on the website and the privacy policy's host, then links in the privacy policy that mention delete / deletion, then a deletion section of the privacy page; a page counts only when it answers 200 and speaks of deleting. Not found stays a finding ("a real gap, Play requires it"); never invented (`findDeletionUrl` in `cli/lib/onboard.ts`; `tests/onboard.test.ts`). |