From 00886ebf6951ed098e426cf9d026d9909bc6c820 Mon Sep 17 00:00:00 2001 From: slamhan Date: Wed, 23 Sep 2026 11:47:16 +0800 Subject: [PATCH] fix(profiles): show each profile's bundle id in the unfiltered list profiles list without --bundle-id-id returned bundleIdId "" for every profile: the mapper reads the bundle ID from relationship data, which Apple only sends when the request asks for it with include=bundleId. Verified live: 6/6 profiles now carry their bundle ID, and each matches the profiles returned by --bundle-id-id for that bundle. Co-Authored-By: Claude Opus 5.5 (1M context) --- CHANGELOG.md | 1 + .../CodeSigning/SDKProfileRepository.swift | 4 +++- .../CodeSigning/SDKProfileRepositoryTests.swift | 12 ++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1898a5f4..6b0c777c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **The other per-territory price lists no longer stop at 50** — the same truncation affected `iap-price-schedule get` (manual prices), `iap-offer-codes prices list`, `subscription-offer-codes prices list`, `subscription-promotional-offers prices list` and `win-back-offers prices list`. They called Apple without a `limit` and read one page, so any territory past Apple's default 50 was missing. They now request `limit=200` and follow every page through a shared `APIClient.requestAllPages(_:nextCursor:)` helper, which `subscription-price-schedule get` uses too. - **Offer price lists now show each price's territory and price point** — `iap-offer-codes prices list`, `subscription-offer-codes prices list`, `subscription-promotional-offers prices list` and `win-back-offers prices list` returned entries with only `id` and the offer ID, because Apple sends a price's territory and price point only when the request asks for them with `include=`. The requests now include both, so `territory` and the price-point ID are filled in, over CLI and REST. - **More list commands no longer stop at Apple's first page** — `reviews list`, `devices list`, `bundle-ids list`, `profiles list` (with and without `--bundle-id-id`), `users list`, `versions list`, `builds uploads list`, `xcode-cloud builds list` and `diagnostics list` read a single page with no `limit`, so anything past Apple's default page size (50 for most endpoints, 20 for bundle IDs) was silently dropped. They now request `limit=200` and follow every page through `APIClient.requestAllPages`. On a real account, `builds uploads list` went from 50 to 122 entries and `bundle-ids list` from 20 to 85. +- **`profiles list` shows each profile's bundle ID again** — without `--bundle-id-id`, every profile came back with `bundleIdId: ""` (and a broken `listProfiles` affordance), because the bundle ID linkage is only returned when the request asks for it with `include=bundleId`. The request now includes it. --- diff --git a/Sources/Infrastructure/CodeSigning/SDKProfileRepository.swift b/Sources/Infrastructure/CodeSigning/SDKProfileRepository.swift index de162b00..3edaa72d 100644 --- a/Sources/Infrastructure/CodeSigning/SDKProfileRepository.swift +++ b/Sources/Infrastructure/CodeSigning/SDKProfileRepository.swift @@ -21,9 +21,11 @@ public struct SDKProfileRepository: ProfileRepository, @unchecked Sendable { APIEndpoint.V1.Profiles.GetParameters.FilterProfileType(rawValue: $0.rawValue) } let pages = try await client.requestAllPages( + // `include` makes Apple return each profile's bundle ID linkage. APIEndpoint.v1.profiles.get(parameters: .init( filterProfileType: filterType.map { [$0] }, - limit: 200 + limit: 200, + include: [.bundleID] )), nextCursor: { $0.meta?.paging.nextCursor } ) diff --git a/Tests/InfrastructureTests/CodeSigning/SDKProfileRepositoryTests.swift b/Tests/InfrastructureTests/CodeSigning/SDKProfileRepositoryTests.swift index 004c00b3..d27e3a37 100644 --- a/Tests/InfrastructureTests/CodeSigning/SDKProfileRepositoryTests.swift +++ b/Tests/InfrastructureTests/CodeSigning/SDKProfileRepositoryTests.swift @@ -95,4 +95,16 @@ struct SDKProfileRepositoryTests { #expect(result.count == 75) #expect(result.last?.id == "item-74") } + + @Test func `profiles list asks Apple for each profile's bundle id`() async throws { + // Apple only links a profile to its bundle ID when asked via `include`. + let stub = StubAPIClient() + stub.willReturn(ProfilesResponse(data: [], links: .init(this: ""))) + + let repo = SDKProfileRepository(client: stub) + _ = try await repo.listProfiles(bundleIdId: nil, profileType: nil) + + let query = Dictionary(uniqueKeysWithValues: (stub.lastQuery ?? []).map { ($0.0, $0.1 ?? "") }) + #expect(query["include"] == "bundleId") + } }