Getting started

Introduction

This is a quick reference for using codemagic.yaml.

Reusing Sections

Define a section at the top of the .yaml file and reuse it later in different workflows.

definitions:
  instance_mac_mini_m2: &instance_mac_mini_m2
    instance_type: mac_mini_m2
    max_build_duration: 120
  env_versions: &env_versions
    flutter: stable
    xcode: latest
    cocoapods: default
  scripts:
    - &add_certs_to_keychain
      name: Add certs to keychain
      script: |
         keychain add-certificates

Reuse the defined section elsewhere by adding a * in front of it.

workflows:
  ios-release:
    name: iOS release
    <<: *instance_mac_mini_m2
    environment:
      <<: *env_versions
    scripts:
      - *add_certs_to_keychain

Decoding

base64 decoding during build time in your scripts section using command:

echo $ENV_VAR | base64 --decode > /path/afile

Encoding

base64 encoding the confidential file and copying the result to clipboard.

macOS:

cat your_file | base64 | pbcopy

Windows:

[Convert]::ToBase64String([IO.File]::ReadAllBytes("file.ext")) | \
Set-Clipboard

Linux:

sudo apt-get install xclip
cat your_file | \
base64 | \
xclip -selection clipboard

Syntax

workflows:
  hello-world-workflow:
    name: Hello world workflow
    scripts:
        - echo "Hello World!"

Workflow environment

Global Environment variable groups

environment:
  groups:             # Define your environment variables groups here
    - keystore_credentials
    - app_store_credentials
    - firebase_credentials

Tip: Store all the keystore variables in the same group so they can be imported to codemagic.yaml workflow at once.

Workflow specific variables

Define workflow-specific public environment variables:

environment:
  vars:             # Define your environment variables here
    PUBLIC_ENV_VAR: "value here"

Software versions

environment:
  flutter: stable  # Channel name or version (e.g. v1.13.4)
  xcode: latest    # Define latest, edge or version (e.g. 11.2)
  cocoapods: 1.9.1 # Define default or version
  node: 12.14.0    # Define default, latest, current, etc or version
  npm: 6.13.7      # Define default, latest, next, lts or version
  ndk: r21d        # Define default or ver, also define in build.gradle
  java: 1.8        # Define default or platform version (e.g. 11)
  ruby: 2.7.2      # Define default or version

Triggering

triggering: defines the events for automatic build triggering and watched branches. If no events are defined, you can only start builds manually.

Skip building a specific commit

Include [skip ci] or [ci skip] in a commit message to not build a particular commit.

Trigger on push to any branch

triggering:
  events:  
    - push
  branch_patterns:
    - pattern: '*'

Exclude dev* branch

triggering:
  events:  
    - push
  branch_patterns:
    - pattern: '*'		#default value for include is true
    - pattern: 'dev*'
    - include: false

Trigger on PR created from any branch to any branch

triggering:
  events:  
    - pull_request
  branch_patterns:
    - pattern: '*'

Trigger on PR created from the dev branch to any branch

triggering:
  events:  
    - pull_request
  branch_patterns:
    - pattern: 'dev*'
    - source: true		#source is true by default

Trigger on PR created from the dev branch to any branch excluding master

triggering:
  events:  
    - pull_request
  Branch_patterns:
    - pattern: 'dev*'
    - source: false
    - pattern: 'master'
    - include: false

Trigger on PR created from any branch to dev

triggering:
  events:  
    - pull_request
  branch_patterns:
    - pattern: 'dev*'
    - source: false		#source is true by default

Trigger on push and PR created from any branch and cancel outdated webhook builds

2 builds will start: for push and PR. cancel_previous_builds will cancel out-dated webhook builds but applies for the next webhook only.

triggering:
  events:  
    - push
    - pull_request
  branch_patterns:
    - pattern: '*'
  cancel_previous_builds: true

Avoid running builds on outdated commits by setting cancel_previous_builds to automatically cancel all ongoing and queued builds triggered by webhooks on push or pull request commit when a more recent build has been triggered for the same branch.

Conditional Build Triggers

Trigger on file changes

Specify the files to watch in the changeset using the includes and excludes keys. Example skips builds for any markdown files:

workflows:
  build-app:
    name: Build App
    triggering:
      events:
        - push
    when:
      changeset:
        includes:
          - '.'     # default value '.'
        excludes:
          - '**/*.md'

Trigger on push when change in a specific path

workflows:
  build-ios:
    name: Build iOS
    triggering:
      events:
        - push
    when:
      changeset:
        includes:
          - 'iOS/'

Trigger event using when condition

workflows:
  build:
    name: Build on PR update
    triggering:
      events:
        - pull_request
    when:
      condition: not event.pull_request.draft

Scripts

Using multiline scripts

scripts:
  - echo "single line script"
  - name: Flutter test
    script: flutter test
    ignore_failure: true
  - | # use pipe to write a script in multiple lines. 
    #!/usr/bin/env python3

    print('Multiline python script')

Build Versioning

Flutter

Increment build number and build name:

--build-name=1.0.$PROJECT_BUILD_NUMBER \
--build-number=$PROJECT_BUILD_NUMBER

Native iOS

set -e
set -x
cd $CM_BUILD_DIR/ios
agvtool new-version -all $(($BUILD_NUMBER + 1))

Get the latest build number from App Store

LATEST_BUILD=$(get-latest-app-store-build-number "$APP_STORE_APPLE_ID")
agvtool new-version -all $(($LATEST_BUILD + 1))

Get the latest build number from App Store or TestFlight

LATEST_BUILD=$(app-store-connect get-latest-build-number "$APP_STORE_APPLE_ID")
agvtool new-version -all $(($LATEST_BUILD + 1))

Get the latest build number from TestFlight

LATEST_BUILD=$(app-store-connect get-latest-testflight-build-number "$APP_STORE_APPLE_ID")
agvtool new-version -all $(($LATEST_BUILD + 1))

Artifacts & Publishing

Artifacts

All paths are relative to the clone directory, but absolute paths are supported as well. There are also environment variables for artifact patterns.

artifacts:
  - build/**/outputs/apk/**/*.apk  # path from root dir
  - subfolder_name/build/**/outputs/apk/**/*.apk # path from subdir
  - build/**/outputs/**/*.aab
  - build/**/outputs/**/mapping.txt
  - build/ios/ipa/*.ipa
  - build/macos/**/*.pkg
  - /tmp/xcodebuild_logs/*.log
  - flutter_drive.log
  - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM

Publishing

Codemagic has a number of integrations for publishing, but you can also publish elsewhere with custom scripts.

Note that the publishing scripts are run by default regardless of the build status. You can specify additional conditions with if statements.

publishing:
  email:
    recipients:
      - name@example.com
  scripts:
    name: Check for apk
    script: |
      apkPath=$(find build -name "*.apk" | head -1)
      if [[ -z ${apkPath} ]]
      then
        echo "No .apk were found"
      else
        echo "Publishing .apk artifacts"
      fi      

Report build status

scripts:
  - name: Report build start
    script: # build started

    . . .

  - name: Build finished successfully
    script: touch ~/SUCCESS
publishing:
  scripts:
    - name: Report build status
      script: |
        if [ -a "~/SUCCESS" ] ; then
           # build successful
        else
           # build failed
        fi