Define and execute multi-step automation workflows that combine multiple CLI commands and shell scripts.
Overview
Workflows allow you to:
- Chain multiple
asc commands together
- Run shell scripts and commands
- Pass data between steps
- Handle errors with hooks
- Execute conditional steps
- Compose reusable sub-workflows
Workflows intentionally execute arbitrary shell commands. Only run workflow files you trust, especially when using --file. Treat .asc/workflow.json like code: review it before running.
Quick Start
Create a Workflow File
Create .asc/workflow.json in your project:
{
"env": {
"APP_ID": "123456789",
"VERSION": "1.0.0"
},
"workflows": {
"beta": {
"description": "Distribute latest build to beta testers",
"steps": [
{
"name": "get_latest_build",
"run": "asc builds list --app $APP_ID --sort -uploadedDate --limit 1 --output json"
},
{
"name": "add_to_group",
"run": "asc builds add-groups --build $BUILD_ID --group $GROUP_ID"
}
]
}
}
}
Run a Workflow
asc workflow run beta BUILD_ID:abc123 GROUP_ID:def456
List Available Workflows
Validate Workflow File
Workflow Structure
Basic Workflow
{
"env": {
"GLOBAL_VAR": "value"
},
"before_all": "echo Starting workflows",
"after_all": "echo All workflows complete",
"error": "echo Error occurred",
"workflows": {
"workflow_name": {
"description": "What this workflow does",
"env": {
"WORKFLOW_VAR": "value"
},
"steps": [
{
"name": "step_1",
"run": "command to execute"
}
]
}
}
}
Environment Variables
Global Environment (env at root):
- Available to all workflows
- Merged with system environment
Workflow Environment (env in workflow):
- Scoped to specific workflow
- Overrides global variables
Runtime Parameters:
- Passed via command line:
KEY:VALUE
- Override workflow environment
Precedence (highest to lowest):
- Runtime parameters
- Workflow
env
- Global
env
- System environment
Hooks
before_all: Runs before any workflow
"before_all": "asc auth status"
after_all: Runs after successful workflow
"after_all": "echo Success! && notify-send 'Workflow Complete'"
error: Runs when workflow fails
"error": "echo Failed! && notify-send 'Workflow Failed'"
Step Types
Command Steps
Execute shell commands:
{
"name": "list_builds",
"run": "asc builds list --app $APP_ID --limit 5"
}
Conditional Steps
Run only if a variable is set:
{
"name": "optional_step",
"if": "BUILD_ID",
"run": "asc builds get --build $BUILD_ID"
}
Skipped if BUILD_ID is empty or unset.
Sub-Workflow Steps
Call another workflow:
{
"workflow": "preflight",
"with": {
"EXTRA_VAR": "value"
}
}
The called workflow receives EXTRA_VAR in addition to its own environment.
Complete Workflow Examples
Beta Distribution Workflow
{
"env": {
"APP_ID": "123456789"
},
"workflows": {
"beta": {
"description": "Distribute latest build to TestFlight beta group",
"env": {
"GROUP_NAME": "External Beta"
},
"steps": [
{
"name": "validate_auth",
"run": "asc auth status"
},
{
"name": "get_latest_build",
"run": "asc builds list --app $APP_ID --sort -uploadedDate --limit 1 --output json > /tmp/latest_build.json"
},
{
"name": "extract_build_id",
"run": "BUILD_ID=$(jq -r '.data[0].id' /tmp/latest_build.json) && echo BUILD_ID=$BUILD_ID"
},
{
"name": "get_beta_group",
"run": "asc testflight beta-groups list --app $APP_ID --output json > /tmp/groups.json"
},
{
"name": "extract_group_id",
"run": "GROUP_ID=$(jq -r '.data[] | select(.attributes.name == \"'$GROUP_NAME'\") | .id' /tmp/groups.json) && echo GROUP_ID=$GROUP_ID"
},
{
"name": "add_build_to_group",
"if": "BUILD_ID",
"run": "asc builds add-groups --build $BUILD_ID --group $GROUP_ID"
},
{
"name": "notify_success",
"run": "echo Build distributed to $GROUP_NAME"
}
]
}
}
}
Run with:
App Store Submission Workflow
{
"env": {
"APP_ID": "123456789",
"PLATFORM": "IOS"
},
"before_all": "echo Starting submission workflow",
"after_all": "echo Submission complete!",
"error": "echo Submission failed - check logs",
"workflows": {
"submit": {
"description": "Submit latest build for App Store review",
"steps": [
{
"name": "validate_metadata",
"run": "asc localizations list --version $VERSION_ID --output json | jq -e '.data | length > 0'"
},
{
"name": "get_latest_build",
"run": "asc builds list --app $APP_ID --sort -uploadedDate --limit 1 --output json > /tmp/build.json"
},
{
"name": "extract_build_id",
"run": "BUILD_ID=$(jq -r '.data[0].id' /tmp/build.json) && echo BUILD_ID=$BUILD_ID >> $GITHUB_ENV"
},
{
"name": "submit_for_review",
"if": "BUILD_ID",
"run": "asc submit create --app $APP_ID --version $VERSION --build $BUILD_ID --platform $PLATFORM --confirm"
},
{
"name": "check_status",
"run": "asc submit status --version-id $VERSION_ID"
}
]
}
}
}
Run with:
asc workflow run submit VERSION:1.0.0 VERSION_ID:abc123
Complete Release Workflow
{
"env": {
"APP_ID": "123456789",
"PLATFORM": "IOS"
},
"before_all": "git fetch --tags && git status",
"after_all": "echo Release workflow complete!",
"error": "echo ERROR: Release failed",
"workflows": {
"release": {
"description": "Complete release: version creation, metadata, screenshots, submission",
"steps": [
{
"workflow": "create_version"
},
{
"workflow": "update_metadata"
},
{
"workflow": "upload_screenshots"
},
{
"workflow": "submit_for_review"
}
]
},
"create_version": {
"private": true,
"description": "Create App Store version",
"steps": [
{
"name": "create_version",
"run": "asc app-versions create --app $APP_ID --version $VERSION --platform $PLATFORM"
},
{
"name": "get_version_id",
"run": "VERSION_ID=$(asc app-versions list --app $APP_ID --output json | jq -r '.data[] | select(.attributes.versionString == \"'$VERSION'\") | .id') && echo VERSION_ID=$VERSION_ID"
}
]
},
"update_metadata": {
"private": true,
"description": "Update app metadata",
"steps": [
{
"name": "update_en_US",
"run": "asc localizations update --version $VERSION_ID --locale en-US --description \"$(cat metadata/en-US/description.txt)\" --keywords \"$(cat metadata/en-US/keywords.txt)\" --whats-new \"$(cat metadata/en-US/whats-new.txt)\""
},
{
"name": "update_es_ES",
"run": "asc localizations update --version $VERSION_ID --locale es-ES --description \"$(cat metadata/es-ES/description.txt)\" --keywords \"$(cat metadata/es-ES/keywords.txt)\" --whats-new \"$(cat metadata/es-ES/whats-new.txt)\""
}
]
},
"upload_screenshots": {
"private": true,
"description": "Upload screenshots",
"steps": [
{
"name": "get_en_localization",
"run": "EN_LOC=$(asc localizations list --version $VERSION_ID --output json | jq -r '.data[] | select(.attributes.locale == \"en-US\") | .id') && echo EN_LOC=$EN_LOC"
},
{
"name": "upload_iphone",
"run": "asc screenshots upload --version-localization $EN_LOC --path screenshots/en-US/iphone --device-type IPHONE_65"
},
{
"name": "upload_ipad",
"run": "asc screenshots upload --version-localization $EN_LOC --path screenshots/en-US/ipad --device-type IPAD_PRO_3GEN_129"
}
]
},
"submit_for_review": {
"private": true,
"description": "Submit for App Store review",
"steps": [
{
"name": "get_build",
"run": "BUILD_ID=$(asc builds list --app $APP_ID --sort -uploadedDate --limit 1 --output json | jq -r '.data[0].id') && echo BUILD_ID=$BUILD_ID"
},
{
"name": "submit",
"run": "asc submit create --app $APP_ID --version-id $VERSION_ID --build $BUILD_ID --platform $PLATFORM --confirm"
}
]
}
}
}
Run with:
asc workflow run release VERSION:2.0.0
CI/CD Integration
GitHub Actions
name: Release Workflow
on:
workflow_dispatch:
inputs:
version:
description: 'Version number (e.g., 1.0.0)'
required: true
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install asc CLI
run: |
curl -fsSL https://raw.githubusercontent.com/rudrankriyam/App-Store-Connect-CLI/main/install.sh | bash
- name: Configure credentials
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_PRIVATE_KEY: ${{ secrets.ASC_PRIVATE_KEY }}
ASC_APP_ID: ${{ secrets.ASC_APP_ID }}
run: |
echo "Credentials configured"
- name: Run release workflow
run: |
asc workflow run release VERSION:${{ github.event.inputs.version }}
- name: Upload workflow output
uses: actions/upload-artifact@v3
with:
name: workflow-output
path: /tmp/workflow-*.log
GitLab CI
stages:
- release
release:production:
stage: release
tags:
- linux
script:
- curl -fsSL https://raw.githubusercontent.com/rudrankriyam/App-Store-Connect-CLI/main/install.sh | bash
- asc workflow run release VERSION:$VERSION
variables:
VERSION: "1.0.0"
only:
- tags
when: manual
Advanced Features
Dry Run Mode
Preview workflow execution without running commands:
asc workflow run beta --dry-run
Shows:
- Steps that would be executed
- Environment variables
- Command interpolation
- Workflow order
Private Workflows
Mark workflows as private (only callable from other workflows):
{
"workflows": {
"helper": {
"private": true,
"description": "Helper workflow - not directly callable",
"steps": [
{"name": "help", "run": "echo Helping..."}
]
},
"main": {
"description": "Main workflow that calls helper",
"steps": [
{"workflow": "helper"}
]
}
}
}
# Works
asc workflow run main
# Fails - private workflow
asc workflow run helper
List including private workflows:
Custom Workflow File
Use a different workflow file:
asc workflow run beta --file ./custom-workflows.json
Pretty JSON Output
asc workflow run beta --pretty
Best Practices
-
Use descriptive names: Name workflows and steps clearly
-
Add descriptions: Document what each workflow does
-
Validate before running: Always run
asc workflow validate after editing
-
Use environment variables: Parameterize workflows for reusability
-
Handle errors: Define
error hooks to clean up on failure
-
Test with dry-run: Use
--dry-run to preview execution
-
Keep workflows focused: Break complex workflows into composable sub-workflows
-
Version control workflows: Store
.asc/workflow.json in git
-
Document required parameters: Note required
KEY:VALUE parameters in descriptions
-
Use private workflows: Extract common logic into private sub-workflows
Security Considerations
- Only run workflows from trusted sources
- Review workflow files before execution
- Avoid hardcoding secrets—use environment variables
- In CI/CD, use encrypted secrets for credentials
- Don’t run untrusted workflows on PRs with access to secrets
Safe Practices
// Good - uses environment variable
"run": "asc builds list --app $APP_ID"
// Bad - hardcoded sensitive data
"run": "asc builds list --app 123456789"
// Good - credentials from environment
"env": {
"ASC_KEY_ID": "$CI_ASC_KEY_ID"
}
// Bad - credentials in workflow file
"env": {
"ASC_KEY_ID": "ABC123XYZ"
}
Troubleshooting
Validation Errors
Problem: asc workflow validate reports errors.
Solution: Check for:
- Circular workflow dependencies
- Missing workflow definitions
- Invalid JSON syntax
- Unknown step types
”Workflow not found”
Problem: Workflow name doesn’t exist in file.
Solution: List available workflows:
Variable Not Interpolated
Problem: $VARIABLE appears literally in output.
Solution: Ensure the variable is:
- Defined in
env (global or workflow)
- Passed as runtime parameter:
VARIABLE:value
- Available in system environment
Step Fails Silently
Problem: Step executes but produces no output.
Solution:
- Check step output is written to stderr (workflow stdout is JSON-only)
- Enable verbose mode (if available)
- Add explicit
echo statements
Workflow Hangs
Problem: Workflow stops and doesn’t complete.
Solution:
- Check for interactive commands (not supported)
- Verify commands don’t wait for user input
- Add timeout to long-running commands