[GH-ISSUE #246] Add CLI support for Alternative Distribution #74

Closed
opened 2026-02-26 21:33:11 +03:00 by kerem · 5 comments
Owner

Originally created by @rudrankriyam on GitHub (Jan 28, 2026).
Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/246

Overview

Add CLI support for Alternative Distribution resources including domains, keys, packages, package versions, variants, and deltas using the App Store Connect API. This enables full management of alternative distribution configuration from the CLI with JSON-first output and explicit flags.

Scope

Primary resources from the OpenAPI spec:

  • alternativeDistributionDomains (GET list/instance, POST create, DELETE)
  • alternativeDistributionKeys (GET list/instance, POST create, DELETE)
  • alternativeDistributionPackages (GET instance, POST create)
  • alternativeDistributionPackageVersions (GET instance, GET deltas/variants relationships)
  • alternativeDistributionPackageVariants (GET instance)
  • alternativeDistributionPackageDeltas (GET instance)
  • App relationships: apps/{id}/alternativeDistributionKey, appStoreVersions/{id}/alternativeDistributionPackage

Endpoints:

  • GET /v1/alternativeDistributionDomains
  • GET /v1/alternativeDistributionDomains/{id}
  • POST /v1/alternativeDistributionDomains
  • DELETE /v1/alternativeDistributionDomains/{id}
  • GET /v1/alternativeDistributionKeys
  • GET /v1/alternativeDistributionKeys/{id}
  • POST /v1/alternativeDistributionKeys
  • DELETE /v1/alternativeDistributionKeys/{id}
  • GET /v1/alternativeDistributionPackages/{id}
  • POST /v1/alternativeDistributionPackages
  • GET /v1/alternativeDistributionPackageVersions/{id}
  • GET /v1/alternativeDistributionPackageVersions/{id}/deltas
  • GET /v1/alternativeDistributionPackageVersions/{id}/variants
  • GET /v1/alternativeDistributionPackageVariants/{id}
  • GET /v1/alternativeDistributionPackageDeltas/{id}
  • GET /v1/apps/{id}/alternativeDistributionKey
  • GET /v1/appStoreVersions/{id}/alternativeDistributionPackage

Proposed CLI

Top-level group:

  • asc alternative-distribution <subcommand> [flags]

Subcommands (all support list/get/create/update/delete unless noted):

  • alternative-distribution domains (list/get/create/delete)
  • alternative-distribution keys (list/get/create/delete)
  • alternative-distribution packages (get/create)
  • alternative-distribution packages versions (get)
  • alternative-distribution packages versions deltas (get)
  • alternative-distribution packages versions variants (get)
  • alternative-distribution packages variants (get)
  • alternative-distribution packages deltas (get)

Examples:

  • asc alternative-distribution domains list
  • asc alternative-distribution domains create --domain example.com
  • asc alternative-distribution keys list --app APP_ID
  • asc alternative-distribution keys create --app APP_ID --public-key-path key.pem
  • asc alternative-distribution packages get --package-id PACKAGE_ID
  • asc alternative-distribution packages create --app APP_ID --version-id VERSION_ID
  • asc alternative-distribution packages versions get --version-id VERSION_ID
  • asc alternative-distribution packages versions deltas --version-id VERSION_ID
  • asc alternative-distribution packages versions variants --version-id VERSION_ID

Flag patterns

Common:

  • --app, --output, --pretty, --limit, --next, --paginate
  • --confirm for destructive operations

Resource-specific examples:

  • --domain, --public-key-path, --public-key
  • --package-id, --version-id, --variant-id, --delta-id
  • --app-store-version-id (for package creation)

Output

  • JSON minified by default
  • --pretty for JSON
  • --output table/markdown for list commands

Acceptance criteria

  • Commands appear in asc --help and asc alternative-distribution --help
  • CRUD works for domains and keys
  • Package get/create works
  • Package version, variant, and delta get works
  • App and app store version relationships work
  • Pagination flags work (--paginate, --next, --limit)
  • Delete requires --confirm
  • JSON-first output matches existing conventions
  • Table and markdown output for list commands

Tests

  • Unit tests for command flag validation and error cases
  • HTTP client tests for list/get/create/delete
  • Output tests for table/markdown
  • Relationship tests for app and app store version linkages

Implementation notes

  • Add cmd/alternative_distribution*.go and internal/asc/client_alternative_distribution*.go
  • Add output helpers in internal/asc/output_alternative_distribution.go
  • Register command in cmd/root.go
  • Add resource type constants in internal/asc/client_types.go
  • Follow patterns in cmd/apps.go, cmd/bundle_ids.go, and output helpers in internal/asc/output_*
  • Note: Package versions, variants, and deltas are read-only (GET only)
Originally created by @rudrankriyam on GitHub (Jan 28, 2026). Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/246 # Overview Add CLI support for Alternative Distribution resources including domains, keys, packages, package versions, variants, and deltas using the App Store Connect API. This enables full management of alternative distribution configuration from the CLI with JSON-first output and explicit flags. # Scope Primary resources from the OpenAPI spec: - `alternativeDistributionDomains` (GET list/instance, POST create, DELETE) - `alternativeDistributionKeys` (GET list/instance, POST create, DELETE) - `alternativeDistributionPackages` (GET instance, POST create) - `alternativeDistributionPackageVersions` (GET instance, GET deltas/variants relationships) - `alternativeDistributionPackageVariants` (GET instance) - `alternativeDistributionPackageDeltas` (GET instance) - App relationships: `apps/{id}/alternativeDistributionKey`, `appStoreVersions/{id}/alternativeDistributionPackage` Endpoints: - GET /v1/alternativeDistributionDomains - GET /v1/alternativeDistributionDomains/{id} - POST /v1/alternativeDistributionDomains - DELETE /v1/alternativeDistributionDomains/{id} - GET /v1/alternativeDistributionKeys - GET /v1/alternativeDistributionKeys/{id} - POST /v1/alternativeDistributionKeys - DELETE /v1/alternativeDistributionKeys/{id} - GET /v1/alternativeDistributionPackages/{id} - POST /v1/alternativeDistributionPackages - GET /v1/alternativeDistributionPackageVersions/{id} - GET /v1/alternativeDistributionPackageVersions/{id}/deltas - GET /v1/alternativeDistributionPackageVersions/{id}/variants - GET /v1/alternativeDistributionPackageVariants/{id} - GET /v1/alternativeDistributionPackageDeltas/{id} - GET /v1/apps/{id}/alternativeDistributionKey - GET /v1/appStoreVersions/{id}/alternativeDistributionPackage # Proposed CLI Top-level group: - `asc alternative-distribution <subcommand> [flags]` Subcommands (all support list/get/create/update/delete unless noted): - `alternative-distribution domains` (list/get/create/delete) - `alternative-distribution keys` (list/get/create/delete) - `alternative-distribution packages` (get/create) - `alternative-distribution packages versions` (get) - `alternative-distribution packages versions deltas` (get) - `alternative-distribution packages versions variants` (get) - `alternative-distribution packages variants` (get) - `alternative-distribution packages deltas` (get) Examples: - `asc alternative-distribution domains list` - `asc alternative-distribution domains create --domain example.com` - `asc alternative-distribution keys list --app APP_ID` - `asc alternative-distribution keys create --app APP_ID --public-key-path key.pem` - `asc alternative-distribution packages get --package-id PACKAGE_ID` - `asc alternative-distribution packages create --app APP_ID --version-id VERSION_ID` - `asc alternative-distribution packages versions get --version-id VERSION_ID` - `asc alternative-distribution packages versions deltas --version-id VERSION_ID` - `asc alternative-distribution packages versions variants --version-id VERSION_ID` # Flag patterns Common: - `--app`, `--output`, `--pretty`, `--limit`, `--next`, `--paginate` - `--confirm` for destructive operations Resource-specific examples: - `--domain`, `--public-key-path`, `--public-key` - `--package-id`, `--version-id`, `--variant-id`, `--delta-id` - `--app-store-version-id` (for package creation) # Output - JSON minified by default - `--pretty` for JSON - `--output table/markdown` for list commands # Acceptance criteria - [ ] Commands appear in `asc --help` and `asc alternative-distribution --help` - [ ] CRUD works for domains and keys - [ ] Package get/create works - [ ] Package version, variant, and delta get works - [ ] App and app store version relationships work - [ ] Pagination flags work (`--paginate`, `--next`, `--limit`) - [ ] Delete requires `--confirm` - [ ] JSON-first output matches existing conventions - [ ] Table and markdown output for list commands # Tests - Unit tests for command flag validation and error cases - HTTP client tests for list/get/create/delete - Output tests for table/markdown - Relationship tests for app and app store version linkages # Implementation notes - Add `cmd/alternative_distribution*.go` and `internal/asc/client_alternative_distribution*.go` - Add output helpers in `internal/asc/output_alternative_distribution.go` - Register command in `cmd/root.go` - Add resource type constants in `internal/asc/client_types.go` - Follow patterns in `cmd/apps.go`, `cmd/bundle_ids.go`, and output helpers in `internal/asc/output_*` - Note: Package versions, variants, and deltas are read-only (GET only)
kerem closed this issue 2026-02-26 21:33:11 +03:00
Author
Owner

@rudrankriyam commented on GitHub (Jan 29, 2026):

@cursor here’s a concrete, no-credentials implementation plan for #246.

High-level approach (no live creds needed)

  • Use docs/openapi/paths.txt + docs/openapi/latest.json for endpoints/schemas.
  • Follow patterns from recent CLIs: internal/cli/backgroundassets, internal/cli/marketplace, internal/cli/webhooks.
  • Ship with mocked HTTP client tests + CLI flag validation tests; no live API calls required.

Scope checkpoints

  1. Types + resource constants
  • Add alternativeDistribution types in internal/asc/alternative_distribution.go (attrs + requests + responses).
  • Add ResourceTypeAlternativeDistribution* constants in internal/asc/client_types.go.
  1. Client methods
  • New file: internal/asc/client_alternative_distribution.go.
  • Implement list/get/create/delete for:
    • domains: /v1/alternativeDistributionDomains (GET/POST/DELETE)
    • keys: /v1/alternativeDistributionKeys (GET/POST/DELETE)
  • Implement get for:
    • packages /v1/alternativeDistributionPackages/{id} + versions relationship GETs
    • package versions /v1/alternativeDistributionPackageVersions/{id} + variants/deltas list
    • variants /v1/alternativeDistributionPackageVariants/{id}
    • deltas /v1/alternativeDistributionPackageDeltas/{id}
  • Relationship GETs:
    • app → key: /v1/apps/{id}/alternativeDistributionKey
    • appStoreVersion → package: /v1/appStoreVersions/{id}/alternativeDistributionPackage
  1. Query options
  • Add list query options for domains + keys in client_options.go and client_queries.go.
  • Support --limit, --next, --paginate.
  1. CLI commands (internal/cli)
  • New package: internal/cli/alternativedistribution (not cmd/).
  • Top-level asc alternative-distribution with subcommands:
    • domains list/get/create/delete
    • keys list/get/create/delete
    • packages get/create
    • packages versions get
    • packages versions deltas|variants list/get
    • packages variants get
    • packages deltas get
  • Use explicit flags (--app, --package-id, --version-id, etc.).
  • Destructive ops require --confirm.
  • Default JSON output, optional --output table|markdown for list commands.
  1. Output formatting
  • Add internal/asc/output_alternative_distribution.go.
  • Wire into output_core.go (table + markdown).
  1. Registration + docs
  • Register in internal/cli/registry/registry.go (ordering matters).
  • Update README examples.
  1. Tests (no credentials)
  • CLI flag validation: follow internal/cli/*/*_test.go patterns (fail on missing flags/confirm).
  • HTTP client tests: add internal/asc/client_http_alternative_distribution_test.go mirroring other client tests (validate method/path/query/body).
  • Output tests for table/markdown for list endpoints.
  • Query tests in internal/asc/client_test.go (build query strings).

Notes / gotchas

  • Issue body mentions cmd/…; project standard is internal/cli/… + registry.
  • Keep JSON minified by default; no prompts.
  • Don’t implement update endpoints unless OpenAPI defines them.

Good definition of done

  • make test green; CLI help shows new group; list/get/create/delete behave per tests.
  • No live tests needed.

If you want a branch name: issue-246-alternative-distribution.

<!-- gh-comment-id:3819603630 --> @rudrankriyam commented on GitHub (Jan 29, 2026): @cursor here’s a concrete, no-credentials implementation plan for #246. High-level approach (no live creds needed) - Use `docs/openapi/paths.txt` + `docs/openapi/latest.json` for endpoints/schemas. - Follow patterns from recent CLIs: `internal/cli/backgroundassets`, `internal/cli/marketplace`, `internal/cli/webhooks`. - Ship with mocked HTTP client tests + CLI flag validation tests; no live API calls required. Scope checkpoints 1) Types + resource constants - Add `alternativeDistribution` types in `internal/asc/alternative_distribution.go` (attrs + requests + responses). - Add `ResourceTypeAlternativeDistribution*` constants in `internal/asc/client_types.go`. 2) Client methods - New file: `internal/asc/client_alternative_distribution.go`. - Implement list/get/create/delete for: - domains: `/v1/alternativeDistributionDomains` (GET/POST/DELETE) - keys: `/v1/alternativeDistributionKeys` (GET/POST/DELETE) - Implement get for: - packages `/v1/alternativeDistributionPackages/{id}` + versions relationship GETs - package versions `/v1/alternativeDistributionPackageVersions/{id}` + variants/deltas list - variants `/v1/alternativeDistributionPackageVariants/{id}` - deltas `/v1/alternativeDistributionPackageDeltas/{id}` - Relationship GETs: - app → key: `/v1/apps/{id}/alternativeDistributionKey` - appStoreVersion → package: `/v1/appStoreVersions/{id}/alternativeDistributionPackage` 3) Query options - Add list query options for domains + keys in `client_options.go` and `client_queries.go`. - Support `--limit`, `--next`, `--paginate`. 4) CLI commands (internal/cli) - New package: `internal/cli/alternativedistribution` (not `cmd/`). - Top-level `asc alternative-distribution` with subcommands: - `domains` list/get/create/delete - `keys` list/get/create/delete - `packages` get/create - `packages versions` get - `packages versions deltas|variants` list/get - `packages variants` get - `packages deltas` get - Use explicit flags (`--app`, `--package-id`, `--version-id`, etc.). - Destructive ops require `--confirm`. - Default JSON output, optional `--output table|markdown` for list commands. 5) Output formatting - Add `internal/asc/output_alternative_distribution.go`. - Wire into `output_core.go` (table + markdown). 6) Registration + docs - Register in `internal/cli/registry/registry.go` (ordering matters). - Update README examples. 7) Tests (no credentials) - CLI flag validation: follow `internal/cli/*/*_test.go` patterns (fail on missing flags/confirm). - HTTP client tests: add `internal/asc/client_http_alternative_distribution_test.go` mirroring other client tests (validate method/path/query/body). - Output tests for table/markdown for list endpoints. - Query tests in `internal/asc/client_test.go` (build query strings). Notes / gotchas - Issue body mentions `cmd/…`; project standard is **`internal/cli/…`** + registry. - Keep JSON minified by default; no prompts. - Don’t implement update endpoints unless OpenAPI defines them. Good definition of done - `make test` green; CLI help shows new group; list/get/create/delete behave per tests. - No live tests needed. If you want a branch name: `issue-246-alternative-distribution`.
Author
Owner

@cursor[bot] commented on GitHub (Jan 29, 2026):

Thanks for the concrete plan — this lines up with the repo conventions and the PR scope. I’ll follow the internal/cli patterns (backgroundassets/marketplace/webhooks), implement the types + resource constants, then add the client methods and query options for domains/keys with pagination flags.

I’ll build the CLI in internal/cli/alternativedistribution with explicit flags, JSON-first output, --confirm for deletes, and wire in table/markdown list output via output_core.go. I’ll also register the commands and update README examples as noted.

For tests, I’ll mirror the existing HTTP client and CLI flag validation tests (plus output + query tests), then run make test before committing. If anything in the OpenAPI snapshot differs from the assumptions above, I’ll flag it in the PR comment.

Create PR
Open in Cursor Open in Web

<!-- gh-comment-id:3819604168 --> @cursor[bot] commented on GitHub (Jan 29, 2026): Thanks for the concrete plan — this lines up with the repo conventions and the PR scope. I’ll follow the internal/cli patterns (backgroundassets/marketplace/webhooks), implement the types + resource constants, then add the client methods and query options for domains/keys with pagination flags. I’ll build the CLI in `internal/cli/alternativedistribution` with explicit flags, JSON-first output, `--confirm` for deletes, and wire in table/markdown list output via `output_core.go`. I’ll also register the commands and update README examples as noted. For tests, I’ll mirror the existing HTTP client and CLI flag validation tests (plus output + query tests), then run `make test` before committing. If anything in the OpenAPI snapshot differs from the assumptions above, I’ll flag it in the PR comment. <a href="https://github.com/rudrankriyam/App-Store-Connect-CLI/compare/main...cursor/alternative-distribution-cli-e201?expand=1&title=Alternative%20distribution%20CLI&body=Add%20comprehensive%20support%20for%20the%20Alternative%20Distribution%20API%20to%20enable%20management%20of%20domains%2C%20keys%2C%20packages%2C%20and%20versions%20via%20the%20%60asc%60%20CLI.%0A%0A---%0A%3Ca%20href%3D%22https%3A%2F%2Fcursor.com%2Fbackground-agent%3FbcId%3Dbc-cb30d42a-5379-4657-addf-d5c81511355d%22%3E%3Cpicture%3E%3Csource%20media%3D%22(prefers-color-scheme%3A%20dark)%22%20srcset%3D%22https%3A%2F%2Fcursor.com%2Fopen-in-cursor-dark.svg%22%3E%3Csource%20media%3D%22(prefers-color-scheme%3A%20light)%22%20srcset%3D%22https%3A%2F%2Fcursor.com%2Fopen-in-cursor-light.svg%22%3E%3Cimg%20alt%3D%22Open%20in%20Cursor%22%20src%3D%22https%3A%2F%2Fcursor.com%2Fopen-in-cursor.svg%22%3E%3C%2Fpicture%3E%3C%2Fa%3E%26nbsp%3B%3Ca%20href%3D%22https%3A%2F%2Fcursor.com%2Fagents%3Fid%3Dbc-cb30d42a-5379-4657-addf-d5c81511355d%22%3E%3Cpicture%3E%3Csource%20media%3D%22(prefers-color-scheme%3A%20dark)%22%20srcset%3D%22https%3A%2F%2Fcursor.com%2Fopen-in-web-dark.svg%22%3E%3Csource%20media%3D%22(prefers-color-scheme%3A%20light)%22%20srcset%3D%22https%3A%2F%2Fcursor.com%2Fopen-in-web-light.svg%22%3E%3Cimg%20alt%3D%22Open%20in%20Web%22%20src%3D%22https%3A%2F%2Fcursor.com%2Fopen-in-web.svg%22%3E%3C%2Fpicture%3E%3C%2Fa%3E"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/create-pr-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/create-pr-light.svg"><img alt="Create PR" src="https://cursor.com/create-pr-light.svg"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-cb30d42a-5379-4657-addf-d5c81511355d"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/open-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/open-in-cursor-light.svg"><img alt="Open in Cursor" src="https://cursor.com/open-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?id=bc-cb30d42a-5379-4657-addf-d5c81511355d"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/open-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/open-in-web-light.svg"><img alt="Open in Web" src="https://cursor.com/open-in-web.svg"></picture></a>
Author
Owner

@rudrankriyam commented on GitHub (Jan 29, 2026):

@cursor please implement #246 and open a PR once build/lint/test are green (run make build, make lint, make test).

<!-- gh-comment-id:3819625107 --> @rudrankriyam commented on GitHub (Jan 29, 2026): @cursor please implement #246 and open a PR once build/lint/test are green (run make build, make lint, make test).
Author
Owner

@cursor[bot] commented on GitHub (Jan 29, 2026):

Summary:

  • I added full alternative distribution support across ASC types/clients, CLI commands (domains/keys/packages/versions/deltas/variants + app/app-store-version relationships), output tables/markdown, and registry wiring, plus README examples. I also added pagination handling and new resource constants.
  • I wrote CLI validation tests, HTTP client request tests, query builder tests, and output formatting tests for the new resources.

Tests:

  • make build
  • make lint
  • make test

Artifacts & PR:

View PR
Open in Cursor Open in Web

<!-- gh-comment-id:3819625445 --> @cursor[bot] commented on GitHub (Jan 29, 2026): Summary: - I added full alternative distribution support across ASC types/clients, CLI commands (domains/keys/packages/versions/deltas/variants + app/app-store-version relationships), output tables/markdown, and registry wiring, plus README examples. I also added pagination handling and new resource constants. - I wrote CLI validation tests, HTTP client request tests, query builder tests, and output formatting tests for the new resources. Tests: - `make build` - `make lint` - `make test` Artifacts & PR: - Walkthrough video (shows `./asc alternative-distribution --help` with new subcommands): /opt/cursor/artifacts/alternative_distribution_help/recording_demo.mp4 - I pushed commit `4d3fe79` to `cursor/alternative-distribution-cli-376e`. PRs are managed by the environment, but GitHub suggests creating one here: https://github.com/rudrankriyam/App-Store-Connect-CLI/pull/new/cursor/alternative-distribution-cli-376e <a href="https://github.com/rudrankriyam/App-Store-Connect-CLI/pull/304"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/view-pr-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/view-pr-light.svg"><img alt="View PR" src="https://cursor.com/view-pr-light.svg"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-fe0e128e-635e-45fd-8d4c-f153bedc44c2"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/open-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/open-in-cursor-light.svg"><img alt="Open in Cursor" src="https://cursor.com/open-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?id=bc-fe0e128e-635e-45fd-8d4c-f153bedc44c2"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/open-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/open-in-web-light.svg"><img alt="Open in Web" src="https://cursor.com/open-in-web.svg"></picture></a>
Author
Owner

@rudrankriyam commented on GitHub (Jan 29, 2026):

Closed via #304 (Alternative distribution CLI), plus fixes in #305 and cleanup in #306.

<!-- gh-comment-id:3820459142 --> @rudrankriyam commented on GitHub (Jan 29, 2026): Closed via #304 (Alternative distribution CLI), plus fixes in #305 and cleanup in #306.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/App-Store-Connect-CLI#74
No description provided.