Workflows allow you to define multi-step automation sequences in a .asc/workflow.json file. This is useful for complex release processes that involve multiple commands.
Workflow file structure
Create a .asc/workflow.json file in your project root:
{
"env" : {
"APP_ID" : "123456789" ,
"VERSION" : "1.2.0"
},
"before_all" : "echo 'Starting workflow'" ,
"after_all" : "echo 'Workflow complete'" ,
"error" : "echo 'Workflow failed' && exit 1" ,
"workflows" : {
"testflight" : {
"description" : "Upload build to TestFlight" ,
"steps" : [
"asc builds upload --app $APP_ID --file MyApp.ipa" ,
"asc builds list --app $APP_ID --limit 1" ,
"asc testflight builds list --app $APP_ID --limit 1"
]
},
"submit" : {
"description" : "Submit build for App Store review" ,
"steps" : [
"asc validate --app $APP_ID --version $VERSION" ,
"asc submit --app $APP_ID --version $VERSION"
]
}
}
}
Running workflows
Execute a workflow by name:
asc workflow run --file .asc/workflow.json --workflow testflight
Or use the short form:
asc workflow run testflight
When --file is omitted, the CLI looks for .asc/workflow.json in the current directory.
Workflow schema
Top-level fields
Global environment variables available to all workflows "env" : {
"APP_ID" : "123456789" ,
"API_KEY" : "secret-value"
}
Command to run before any workflow executes Useful for validation or setup tasks.
Command to run after a workflow completes successfully Useful for cleanup or notifications.
Command to run if a workflow fails Useful for error notifications or rollback.
Map of workflow names to workflow definitions
Workflow fields
Human-readable description of the workflow
Hide this workflow from asc workflow list Default: false
Workflow-specific environment variables These override global env variables.
List of steps to execute (see step format below)
Steps can be defined in two formats:
Short form (string):
"steps" : [
"asc apps list" ,
"asc builds list --app 123456789"
]
Long form (object):
"steps" : [
{
"name" : "Upload build" ,
"run" : "asc builds upload --app $APP_ID --file MyApp.ipa"
},
{
"name" : "Verify upload" ,
"run" : "asc builds list --app $APP_ID --limit 1" ,
"if" : "$VERIFY == true"
},
{
"name" : "Run sub-workflow" ,
"workflow" : "notify" ,
"with" : {
"MESSAGE" : "Build uploaded"
}
}
]
Step fields
Step name (displayed during execution)
Name of another workflow to run (sub-workflow) Mutually exclusive with run.
Condition expression (evaluated as shell command) Step runs only if the command exits with code 0.
Environment variables passed to the step Only applies to workflow steps.
Environment variable precedence
Environment variables are resolved in this order (highest to lowest):
Runtime parameters (--with flag)
Step with field (for sub-workflows)
Workflow env field
Global env field
System environment variables
Example:
asc workflow run testflight --with APP_ID= 987654321
This overrides the APP_ID defined in the workflow file.
Conditional steps
Use the if field to conditionally execute steps:
{
"steps" : [
{
"name" : "Upload build" ,
"run" : "asc builds upload --app $APP_ID --file MyApp.ipa"
},
{
"name" : "Submit for review" ,
"run" : "asc submit --app $APP_ID --version $VERSION" ,
"if" : "test \" $AUTO_SUBMIT \" = \" true \" "
}
]
}
The if condition is evaluated as a shell command. The step runs only if the command exits with code 0.
Sub-workflows
Call other workflows from within a workflow:
{
"workflows" : {
"notify" : {
"description" : "Send notification" ,
"steps" : [
"asc notify slack --message \" $MESSAGE \" "
]
},
"release" : {
"description" : "Full release process" ,
"steps" : [
"asc builds upload --app $APP_ID --file MyApp.ipa" ,
{
"workflow" : "notify" ,
"with" : {
"MESSAGE" : "Build uploaded to TestFlight"
}
},
"asc submit --app $APP_ID --version $VERSION" ,
{
"workflow" : "notify" ,
"with" : {
"MESSAGE" : "Submitted for App Store review"
}
}
]
}
}
}
Lifecycle hooks
Workflow hooks run at specific points during execution:
before_all : Runs before any workflow starts
after_all : Runs after a workflow completes successfully
error : Runs if any step fails
Example with Slack notifications:
{
"before_all" : "asc notify slack --message 'Starting release workflow'" ,
"after_all" : "asc notify slack --message 'Release complete'" ,
"error" : "asc notify slack --message 'Release failed' && exit 1" ,
"workflows" : {
"release" : {
"steps" : [
"asc builds upload --app $APP_ID --file MyApp.ipa" ,
"asc submit --app $APP_ID --version $VERSION"
]
}
}
}
Complete example
Here’s a comprehensive workflow for a full release process:
{
"env" : {
"APP_ID" : "123456789" ,
"VERSION" : "1.2.0" ,
"BUILD_DIR" : "build" ,
"SLACK_WEBHOOK" : "https://hooks.slack.com/services/..."
},
"before_all" : "echo 'Starting release for v$VERSION'" ,
"after_all" : "echo 'Release complete for v$VERSION'" ,
"error" : "curl -X POST $SLACK_WEBHOOK -d '{ \" text \" : \" Release failed for v$VERSION \" }' && exit 1" ,
"workflows" : {
"beta" : {
"description" : "Upload build to TestFlight" ,
"steps" : [
{
"name" : "Validate build" ,
"run" : "test -f $BUILD_DIR/MyApp.ipa"
},
{
"name" : "Upload to TestFlight" ,
"run" : "asc builds upload --app $APP_ID --file $BUILD_DIR/MyApp.ipa"
},
{
"name" : "Wait for processing" ,
"run" : "sleep 60"
},
{
"name" : "Verify build available" ,
"run" : "asc builds list --app $APP_ID --limit 1 --output json | jq -e '.data[0]'"
},
{
"name" : "Notify team" ,
"workflow" : "notify" ,
"with" : {
"MESSAGE" : "New TestFlight build available: v$VERSION"
}
}
]
},
"submit" : {
"description" : "Submit to App Store" ,
"steps" : [
{
"name" : "Validate version" ,
"run" : "asc validate --app $APP_ID --version $VERSION"
},
{
"name" : "Submit for review" ,
"run" : "asc submit --app $APP_ID --version $VERSION"
},
{
"name" : "Notify team" ,
"workflow" : "notify" ,
"with" : {
"MESSAGE" : "v$VERSION submitted for App Store review"
}
}
]
},
"notify" : {
"description" : "Send Slack notification" ,
"private" : true ,
"steps" : [
"curl -X POST $SLACK_WEBHOOK -d '{ \" text \" : \" $MESSAGE \" }'"
]
}
}
}
CI/CD integration
GitHub Actions
name : Release
on :
push :
tags :
- 'v*'
jobs :
release :
runs-on : macos-latest
steps :
- uses : actions/checkout@v3
- uses : rudrankriyam/setup-asc@v1
with :
key-id : ${{ secrets.ASC_KEY_ID }}
issuer-id : ${{ secrets.ASC_ISSUER_ID }}
private-key : ${{ secrets.ASC_PRIVATE_KEY }}
- name : Build app
run : xcodebuild -scheme MyApp -archivePath build/MyApp.xcarchive archive
- name : Run release workflow
run : asc workflow run release --with VERSION=${{ github.ref_name }}
GitLab CI
release :
stage : deploy
script :
- asc workflow run release --with VERSION=$CI_COMMIT_TAG
only :
- tags
variables :
ASC_KEY_ID : $ASC_KEY_ID
ASC_ISSUER_ID : $ASC_ISSUER_ID
ASC_PRIVATE_KEY_B64 : $ASC_PRIVATE_KEY_B64
Security considerations
Workflow files execute arbitrary shell commands. Ensure:
.asc/workflow.json is added to .gitignore if it contains secrets
Use environment variables for sensitive values
Review workflow files before execution
Run workflows in trusted environments only
Troubleshooting
Workflow not found
asc workflow list # List all available workflows
asc workflow run --file .asc/workflow.json testflight # Specify file explicitly
Environment variable not expanded
Ensure variables are defined in the workflow file or passed via --with:
asc workflow run testflight --with APP_ID= 123456789
Step fails silently
Check exit codes and stderr:
asc workflow run testflight --debug
Workflow command Workflow command reference
Automation guide Workflow automation patterns