Files
asc-client/README.md
Kerem Erkan 1dfcc1c27b Add builds await-processing, workflow build tracking, and processing-aware attach
- Add builds await-processing command to poll until a build finishes processing
- Track uploaded build version across workflow steps via lastUploadedBuildVersion
- attach-latest-build now waits for a just-uploaded build to appear and process
- attach-latest-build prompts to wait when the latest build is still processing
- Shared awaitBuildProcessing helper eliminates duplicated polling logic
- Dot-based progress indicator for builds not yet available in the API
- Note on builds list about recently uploaded builds taking time to appear
- Bump version to 0.2.1
2026-02-13 18:46:17 +01:00

333 lines
12 KiB
Markdown

# asc-client
A command-line tool for building, archiving, and publishing apps to the App Store — from Xcode archive to App Review submission. Built with Swift on the [App Store Connect API](https://developer.apple.com/documentation/appstoreconnectapi).
> **Note:** Covers the core app release workflow: archiving, uploading builds, managing versions and localizations, screenshots, and review submission. More API coverage is planned.
## Requirements
- macOS 13+
- Swift 6.0+ (only for building from source)
## Installation
### Homebrew
```bash
brew tap keremerkan/tap
brew install asc-client
```
The tap provides a pre-built binary for Apple Silicon Macs, so installation is instant.
### Download the binary
Download the latest release from [GitHub Releases](https://github.com/keremerkan/asc-client/releases):
```bash
curl -L https://github.com/keremerkan/asc-client/releases/latest/download/asc-client-macos-arm64.tar.gz -o asc-client.tar.gz
tar xzf asc-client.tar.gz
mv asc-client /usr/local/bin/
```
Since the binary is not signed or notarized, macOS will quarantine it on first download. Remove the quarantine attribute:
```bash
xattr -d com.apple.quarantine /usr/local/bin/asc-client
```
> **Note:** Pre-built binaries are provided for Apple Silicon (arm64) only. Intel Mac users should build from source.
### Build from source
```bash
git clone https://github.com/keremerkan/asc-client.git
cd asc-client
swift build -c release
strip .build/release/asc-client
cp .build/release/asc-client /usr/local/bin/
```
> **Note:** The release build takes a few minutes because the [asc-swift](https://github.com/aaronsky/asc-swift) dependency includes ~2500 generated source files covering the entire App Store Connect API surface. `strip` removes debug symbols, reducing the binary from ~175 MB to ~59 MB.
### Shell completions
Set up tab completion for subcommands, options, and flags (supports zsh and bash):
```bash
asc-client install-completions
```
This detects your shell and configures everything automatically. Restart your shell or open a new tab to activate.
## Setup
### 1. Create an API Key
Go to [App Store Connect > Users and Access > Integrations > App Store Connect API](https://appstoreconnect.apple.com/access/integrations/api) and generate a new key. Download the `.p8` private key file.
### 2. Configure
```bash
asc-client configure
```
This will prompt for your **Key ID**, **Issuer ID**, and the path to your `.p8` file. The private key is copied into `~/.asc-client/` with strict file permissions (owner-only access).
## Usage
### Apps
```bash
# List all apps
asc-client apps list
# Show app details
asc-client apps info <bundle-id>
# List App Store versions
asc-client apps versions <bundle-id>
# Create a new version
asc-client apps create-version <bundle-id> <version-string>
asc-client apps create-version <bundle-id> 2.1.0 --platform ios --release-type manual
# Check review submission status
asc-client apps review-status <bundle-id>
# Submit for review
asc-client apps submit-for-review <bundle-id>
asc-client apps submit-for-review <bundle-id> --version 2.1.0
```
### Build Management
```bash
# Interactively select and attach a build to a version
asc-client apps attach-build <bundle-id>
asc-client apps attach-build <bundle-id> --version 2.1.0
# Attach the most recent build automatically
asc-client apps attach-latest-build <bundle-id>
# Remove the attached build from a version
asc-client apps detach-build <bundle-id>
```
### Localizations
```bash
# View localizations (latest version by default)
asc-client apps localizations <bundle-id>
asc-client apps localizations <bundle-id> --version 2.1.0 --locale en-US
# Export localizations to JSON
asc-client apps export-localizations <bundle-id>
asc-client apps export-localizations <bundle-id> --version 2.1.0 --output my-localizations.json
# Update a single locale
asc-client apps update-localization <bundle-id> --whats-new "Bug fixes" --locale en-US
# Bulk update from JSON file
asc-client apps update-localizations <bundle-id> --file localizations.json
```
The JSON format for export and bulk update:
```json
{
"en-US": {
"description": "My app description.\n\nSecond paragraph.",
"whatsNew": "- Bug fixes\n- New dark mode",
"keywords": "productivity,tools,utility",
"promotionalText": "Try our new features!",
"marketingURL": "https://example.com",
"supportURL": "https://example.com/support"
},
"de-DE": {
"whatsNew": "- Fehlerbehebungen\n- Neuer Dunkelmodus"
}
}
```
Only fields present in the JSON are updated -- omitted fields are left unchanged.
### Screenshots & App Previews
```bash
# Download all screenshots and preview videos
asc-client apps download-media <bundle-id>
asc-client apps download-media <bundle-id> --folder my-media/ --version 2.1.0
# Upload screenshots and preview videos from a folder
asc-client apps upload-media <bundle-id> --folder media/
# Upload to a specific version
asc-client apps upload-media <bundle-id> --folder media/ --version 2.1.0
# Replace existing media in matching sets before uploading
asc-client apps upload-media <bundle-id> --folder media/ --replace
```
Organize your media folder with locale and display type subfolders:
```
media/
├── en-US/
│ ├── APP_IPHONE_67/
│ │ ├── 01_home.png
│ │ ├── 02_settings.png
│ │ └── preview.mp4
│ └── APP_IPAD_PRO_3GEN_129/
│ └── 01_home.png
└── de-DE/
└── APP_IPHONE_67/
├── 01_home.png
└── 02_settings.png
```
- **Level 1:** Locale (e.g. `en-US`, `de-DE`, `ja`)
- **Level 2:** Display type folder name (see table below)
- **Level 3:** Media files -- images (`.png`, `.jpg`, `.jpeg`) become screenshots, videos (`.mp4`, `.mov`) become app previews
- Files are uploaded in alphabetical order by filename
- Unsupported files are skipped with a warning
#### Display types
| Folder name | Device | Screenshots | Previews |
|---|---|---|---|
| `APP_IPHONE_67` | iPhone 6.7" (iPhone 16 Pro Max, 15 Pro Max, 14 Pro Max) | Yes | Yes |
| `APP_IPHONE_61` | iPhone 6.1" (iPhone 16 Pro, 15 Pro, 14 Pro) | Yes | Yes |
| `APP_IPHONE_65` | iPhone 6.5" (iPhone 11 Pro Max, XS Max) | Yes | Yes |
| `APP_IPHONE_58` | iPhone 5.8" (iPhone 11 Pro, X, XS) | Yes | Yes |
| `APP_IPHONE_55` | iPhone 5.5" (iPhone 8 Plus, 7 Plus, 6s Plus) | Yes | Yes |
| `APP_IPHONE_47` | iPhone 4.7" (iPhone SE 3rd gen, 8, 7, 6s) | Yes | Yes |
| `APP_IPHONE_40` | iPhone 4" (iPhone SE 1st gen, 5s, 5c) | Yes | Yes |
| `APP_IPHONE_35` | iPhone 3.5" (iPhone 4s and earlier) | Yes | Yes |
| `APP_IPAD_PRO_3GEN_129` | iPad Pro 12.9" (3rd gen+) | Yes | Yes |
| `APP_IPAD_PRO_3GEN_11` | iPad Pro 11" | Yes | Yes |
| `APP_IPAD_PRO_129` | iPad Pro 12.9" (1st/2nd gen) | Yes | Yes |
| `APP_IPAD_105` | iPad 10.5" (iPad Air 3rd gen, iPad Pro 10.5") | Yes | Yes |
| `APP_IPAD_97` | iPad 9.7" (iPad 6th gen and earlier) | Yes | Yes |
| `APP_DESKTOP` | Mac | Yes | Yes |
| `APP_APPLE_TV` | Apple TV | Yes | Yes |
| `APP_APPLE_VISION_PRO` | Apple Vision Pro | Yes | Yes |
| `APP_WATCH_ULTRA` | Apple Watch Ultra | Yes | No |
| `APP_WATCH_SERIES_10` | Apple Watch Series 10 | Yes | No |
| `APP_WATCH_SERIES_7` | Apple Watch Series 7 | Yes | No |
| `APP_WATCH_SERIES_4` | Apple Watch Series 4 | Yes | No |
| `APP_WATCH_SERIES_3` | Apple Watch Series 3 | Yes | No |
| `IMESSAGE_APP_IPHONE_67` | iMessage iPhone 6.7" | Yes | No |
| `IMESSAGE_APP_IPHONE_61` | iMessage iPhone 6.1" | Yes | No |
| `IMESSAGE_APP_IPHONE_65` | iMessage iPhone 6.5" | Yes | No |
| `IMESSAGE_APP_IPHONE_58` | iMessage iPhone 5.8" | Yes | No |
| `IMESSAGE_APP_IPHONE_55` | iMessage iPhone 5.5" | Yes | No |
| `IMESSAGE_APP_IPHONE_47` | iMessage iPhone 4.7" | Yes | No |
| `IMESSAGE_APP_IPHONE_40` | iMessage iPhone 4" | Yes | No |
| `IMESSAGE_APP_IPAD_PRO_3GEN_129` | iMessage iPad Pro 12.9" (3rd gen+) | Yes | No |
| `IMESSAGE_APP_IPAD_PRO_3GEN_11` | iMessage iPad Pro 11" | Yes | No |
| `IMESSAGE_APP_IPAD_PRO_129` | iMessage iPad Pro 12.9" (1st/2nd gen) | Yes | No |
| `IMESSAGE_APP_IPAD_105` | iMessage iPad 10.5" | Yes | No |
| `IMESSAGE_APP_IPAD_97` | iMessage iPad 9.7" | Yes | No |
> **Note:** Watch and iMessage display types support screenshots only -- video files in those folders are skipped with a warning. The `--replace` flag deletes all existing assets in each matching set before uploading new ones.
>
> `download-media` saves files in this same folder structure (defaults to `<bundle-id>-media/`), so you can download, edit, and re-upload.
#### Verify and retry stuck media
Sometimes screenshots or previews get stuck in "processing" after upload. Use `verify-media` to check the status of all media at once and optionally retry stuck items:
```bash
# Check status of all screenshots and previews
asc-client apps verify-media <bundle-id>
# Check a specific version
asc-client apps verify-media <bundle-id> --version 2.1.0
# Retry stuck items using local files from the media folder
asc-client apps verify-media <bundle-id> --folder media/
```
Without `--folder`, the command shows a read-only status report. Sets where all items are complete show a compact one-liner; sets with stuck items expand to show each file and its state. With `--folder`, it prompts to retry stuck items by deleting them and re-uploading from the matching local files, preserving the original position order.
### Builds
```bash
# List all builds
asc-client builds list
asc-client builds list --bundle-id <bundle-id>
# Archive an Xcode project
asc-client builds archive
asc-client builds archive --scheme MyApp --output ./archives
# Validate a build before uploading
asc-client builds validate MyApp.ipa
# Upload a build to App Store Connect
asc-client builds upload MyApp.ipa
# Wait for a build to finish processing
asc-client builds await-processing <bundle-id>
asc-client builds await-processing <bundle-id> --build-version 903
```
The `archive` command auto-detects the `.xcworkspace` or `.xcodeproj` in the current directory and resolves the scheme if only one exists. It accepts `.ipa`, `.pkg`, or `.xcarchive` files for `upload` and `validate`. When given an `.xcarchive`, it automatically exports to `.ipa` before uploading.
### Workflows
Chain multiple commands into a single automated run with a workflow file:
```bash
asc-client run-workflow release.txt
asc-client run-workflow release.txt --yes # skip all prompts (CI/CD)
```
A workflow file is a plain text file with one command per line (without the `asc-client` prefix). Lines starting with `#` are comments, blank lines are ignored.
**Example** -- `release.txt` for submitting version 2.1.0 of a sample app:
```
# Release workflow for MyApp v2.1.0
# Create the new version on App Store Connect
apps create-version com.example.MyApp 2.1.0
# Build, validate, and upload
builds archive --scheme MyApp
builds validate --latest --bundle-id com.example.MyApp
builds upload --latest --bundle-id com.example.MyApp
# Wait for the build to finish processing
builds await-processing com.example.MyApp
# Update localizations and attach the build
apps update-localizations com.example.MyApp --file localizations.json
apps attach-latest-build com.example.MyApp
# Submit for review
apps submit-for-review com.example.MyApp
```
Without `--yes`, the workflow asks for confirmation before starting, and individual commands still prompt where they normally would (e.g., before submitting for review). With `--yes`, all prompts are skipped for fully unattended execution.
### Automation
Most commands that prompt for confirmation support `--yes` / `-y` to skip prompts, making them suitable for CI/CD pipelines and scripts:
```bash
asc-client apps attach-latest-build <bundle-id> --yes
asc-client apps submit-for-review <bundle-id> --yes
```
## Acknowledgments
Built on top of [asc-swift](https://github.com/aaronsky/asc-swift) by Aaron Sky.
Developed with [Claude Code](https://claude.ai/code).
## License
MIT