🚀 Flutter CI/CD using Git Tags in 5 minutes
Tags: flutter, git, codemagic, android
Published: 2021-05-14 09:50:20

## Table of contents
  * [What you will need](#what-you-need)
  * [What you will do](#what-you-do)
  * [Step 1: Deployment script](#step-1)
  * [Step 2: Git push with tag](#step-2)

## What you will need <a name="what-you-need"></a>

- 📲 A Flutter app (obviously)
- 📦 A Github, Gitlab or Bitbucket account
- ✨ A [Codemagic](https://codemagic.io/start/) account (linked to your app repository)
- 😁 Your best smile


## What you will do <a name="what-you-do"></a>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1a378jsuikoj6q03ilil.png)

*You will create a git tag containing your new app version, then push it to your repository. It will automatically trigger a Codemagic build, and release your app on the Play Store 🚀*


## Step 1: Create a deployment script 🛠 <a name="step-1"></a>

Below you'll find code to configure the CI/CD. You just have to add it to the root of your repository in a file named **codemagic.yaml**
*I've used a script instead of the workflow editor (Codemagic GUI) for multiple reasons (versioned, faster...) but mainly because the version handling isn't possible using the editor.*

```yaml
# codemagic.yaml

# ... <- Here you will include the "reusable" parts that are described afterward

workflows:
  play-store:
    name: Play Store Release
    max_build_duration: 30
    cache: *caching
    
    environment:
      flutter: *flutter_version
      xcode: latest
      cocoapods: default
      vars:
        <<: *gcp_service_credentials
        <<: *keystore_release

    # ! THE IMPORTANT PART IS HERE !
    triggering:
      events:
        - tag
      branch_patterns:
        - pattern: "master"
          include: true
          source: true
      tag_patterns:
        - pattern: "*"
          include: true

    scripts:
      - *android_key_properties_setup
      - *flutter_android_properties_setup
      - *flutter_pub_get
      - *flutter_test
      - *flutter_build_play_store_release

    artifacts:      
      - build/**/outputs/**/*.aab

    publishing:
      google_play:
        credentials: *play_console_credentials
        track: alpha
        in_app_update_priority: 0      
```

Next are the reusable parts, to be clean and not repeat yourself ✨. Replace the encrypted variables using your credentials and the [Codemagic encrypting tool](https://docs.codemagic.io/building/encrypting/).


```yaml
# codemagic.yaml

reusable:
  flutter_version: &flutter_version 1.22.6

  environment-variables:
    - &keystore_release
      FCI_KEYSTORE_PATH: /tmp/keystore.keystore
      FCI_KEYSTORE: Encrypted(...)
      FCI_KEYSTORE_PASSWORD: Encrypted(...)
      FCI_KEY_PASSWORD: Encrypted(...)
      FCI_KEY_ALIAS: Encrypted(...)

    - &gcp_service_credentials
      GCLOUD_SERVICE_ACCOUNT_CREDENTIALS: Encrypted(...)      

    - &play_console_credentials Encrypted(...)

  scripts:
    - &android_key_properties_setup
      name: Android - Setup key.properties
      script: |
        echo $FCI_KEYSTORE | base64 --decode > $FCI_KEYSTORE_PATH
        cat >> "$FCI_BUILD_DIR/android/key.properties" <<EOF
        storePassword=$FCI_KEYSTORE_PASSWORD
        keyPassword=$FCI_KEY_PASSWORD
        keyAlias=$FCI_KEY_ALIAS
        storeFile=/tmp/keystore.keystore
        EOF

    - &flutter_android_properties_setup
      name: Flutter x Android - Setup local.properties
      script: echo "flutter.sdk=$HOME/programs/flutter" > "$FCI_BUILD_DIR/android/local.properties"

    - &flutter_pub_get
      name: Flutter - Get dependencies
      script: flutter packages pub get

    - &flutter_test
      name: Flutter - Run tests
      script: flutter test --machine

    # ! THE IMPORTANT PART IS HERE !
    - &flutter_build_play_store_release
      name: Build AAB for Play Store release
      script: |
        GCLOUD_SERVICE_ACCOUNT_CREDENTIALS=$(echo $GCLOUD_SERVICE_ACCOUNT_CREDENTIALS | base64 --decode)
        NEW_BUILD_NUMBER=$(($(google-play get-latest-build-number --package-name 'com.company.example') + 1))
        NEW_VERSION_NAME=$(git describe --tags)

        echo $NEW_VERSION_NAME
        echo $NEW_BUILD_NUMBER

        flutter build appbundle --build-name=$NEW_VERSION_NAME --build-number=$NEW_BUILD_NUMBER  --obfuscate --split-debug-info=$FCI_BUILD_DIR/debug_files

  caching: &caching
    cache_paths:
      - $HOME/.gradle/caches
      - $FLUTTER_ROOT/.pub-cache

# ... <- The workflow part described before should be here
```

In the previous script, the **"flutter_build_play_store_release"** script handle the versioning :
- **Version** is retrieved from the tag.
- **Build number** is retrieved from the play console (fetching the highest build number, and incrementing it for this release).

*Don't forget to replace __com.company.example__ with your app package name*

You can now push this script onto your repository. It should then be visible from Codemagic and you should be able to trigger it manually.


## Step 2: Add git tag 🔖 -> push it 🚀 <a name="step-2"></a>

Creating a git tag is very easy. We will use 1.0.0 as our version, and tag.
You just have to run the following commands :

```bash
git tag -a 1.0.0 -m "Release 1.0.0"
git push origin 1.0.0
```

That's it! You should see a build running in Codemagic 🏄‍♂️


### What's next?

You can add as many workflows as you want using Codemagic! You can use the GUI editor, and then extract to code to have more control over the code. 

Here we deploy on Alpha, so you can change to Production when you feel ready. And then, you can add an iOS workflow with mostly the same code.

**Leave a comment, a like or even a unicorn 🦄 if you've achieved this tutorial! 🚀🔖**