Introduction
In the previous article, we saw how to set up Fastlane and GitHub Actions for the sample app. In this article, we will see how to further automate the release process further with versioning, GitHub Releases and promotion using Fastlane and GitHub Actions.
Repository: Flutter App CI/CD using Fastlane and GitHub Actions
Prerequisites
- Follow the first part of the guide to set up Fastlane and GitHub Actions.
Creating the Tag
workflow
We will create a new workflow that will bumps the pubspec.yaml
version, creates a new tag, and pushes the changes to the repository.
- Create a new file in the
.github/workflows
directory, e.g.tag.yml
. - Add the following content to the
tag.yml
file:This workflow can be triggered manually and accepts an input on what action you want to perform. There are four options:name: Tag Release on: workflow_dispatch: inputs: action: type: choice description: Action type default: none options: - major - minor - patch - none jobs: tag: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true name: Tag runs-on: self-hosted permissions: # Give the default GITHUB_TOKEN write permission to commit and push the # added or changed files to the repository. contents: write steps: - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} fetch-depth: 0 # Fetch the complete history for tags and branches - uses: stikkyapp/update-pubspec-version@v2 id: update-pubspec-version with: strategy: ${{ github.event.inputs.action }} bump-build: true - uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: "Bump version to ${{ steps.update-pubspec-version.outputs.new-version }}" commit_user_name: GitHub Actions tagging_message: release/v${{ steps.update-pubspec-version.outputs.new-version }}
major
,minor
,patch
andnone
. Each action will bump the version accordingly. See this for more information on semantic versioning. We use theupdate-pubspec-version
action to bump the version in thepubspec.yaml
file and thegit-auto-commit-action
to commit the changes and create a new tag with the formatrelease/v1.0.0
. Each run of the workflow will always bump the build number. - Trigger the workflow manually by going to the Actions tab in your GitHub repository and selecting the
Tag Release
workflow. Click on theRun workflow
button and select the branch you want to tag. - Sit back and watch the magic happen! ✨ You should see a new commit and tag in your repository.
Creating the Release
workflow
- Create a new file in the
.github/workflows
directory, e.g.release.yml
. - Add the following content to the
release.yml
file:This workflow is triggered whenever a new tag with the formatname: Create Release on: push: tags: - 'release/*' jobs: release: concurrency: group: ${{ github.workflow }}-${{ github.ref }}-release cancel-in-progress: true runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Create Release uses: ncipollo/release-action@v1 with: name: ${{ github.ref_name }} tag: ${{ github.ref }} generateReleaseNotes: true
release/*
is pushed to the repository. The action will create a new release with the tag name and generate the release notes based on the commit messages and merged branches since the last tag. - We are not done yet. Triggering the
Tag
workflow doesn’t trigger the release workflow yet. This is due to a limitation of GitHub. Follow this guide to create a token with the scoperepo
. Add the token to your repository as a secret with the namePAT
. Now we need to add the token to thecheckout
action in thetag.yml
file:Since the# Remove from here permissions: # Give the default GITHUB_TOKEN write permission to commit and push the # added or changed files to the repository. contents: write # Until here steps: - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} fetch-depth: 0 # Fetch the complete history for tags and branches token: ${{ secrets.PAT }}
checkout
action uses theGITHUB_TOKEN
by default, we need to add thePAT
token to the action to trigger theRelease
workflow. We can then remove thepermissions
part. It is better to trigger the workflow manually only, otherwise the workflow will run in a loop. - Now trigger the
Tag
workflow again and you should see a new release in your repository after theRelease
workflow` has finished successfully. - To trigger the
Build and Deploy
workflow whenever a new tag is created. Add this to yourdeploy.yml
file:This will trigger theon: workflow_dispatch: push: tags: - 'release/*'
Build and Deploy
workflow whenever theTag
workflow creates a new tag. This way you can automate the whole process from versioning to deployment.
Creating the Promote
workflow
The idea is to have a workflow that promotes a release to a specific track in the PlayStore. This can be useful if you want to promote a release from the internal track to the production track, or from TestFlight to the AppStore for example.
-
Add this lane to
android/fastlane/Fastfile
:Add this lane toplatform :android do # ... desc "Promote version" lane :promote do |options| skip = options[:skip] || true version = flutter_version() upload_to_play_store( track: "internal", track_promote_to: "production", skip_upload_metadata: false, skip_upload_images: skip, skip_upload_screenshots: skip, track_promote_release_status: "draft", version_code: version["version_code"], version_name: version["version_name"], ) end end
ios/fastlane/Fastfile
:We added a promote lane for both Android and iOS. The lane will promote the release from the internal track or TestFlight to the production track in the PlayStore and AppStore respectively. We also added an option to skip the screenshots upload.platform :ios do # ... desc "Promote version" lane :promote do |options| skip = options[:skip] || true version = flutter_version() deliver( submit_for_review: false, automatic_release: true, force: true, skip_screenshots: skip, skip_binary_upload: true, overwrite_screenshots: true, app_version: version["version_name"], precheck_include_in_app_purchases: false ) end end
-
Before you can promote a release, you must have uploaded and published at least one release manually already. Make sure you have a release on the production track in the PlayStore and the app published in the AppStore.
-
Run
fastlane promote skip:true
to start the lane and promote your version to the respective track. Make sure to run the command in the respective platform folder. -
After successfully promoting the release, you can now automate the process using GitHub Actions.
-
Create a new file in the
.github/workflows
directory, e.g.promote.yml
. -
Paste this content into the
promote.yml
file:This workflow can be triggered manually and accepts an input if you want to upload screenshots as well. The workflow will take a release and promote it to the respective track in the PlayStore or AppStore.name: Promote Release on: workflow_dispatch: inputs: skip: type: boolean description: skip screenshots default: true jobs: android: concurrency: group: ${{ github.workflow }}-${{ github.ref }}-android cancel-in-progress: true name: Promote Android runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Decode sec json file run: echo "${{ secrets.SEC_JSON }}" | openssl base64 -d -out ./android/sec.json - name: Promote Release on Play Store uses: maierj/fastlane-action@v2.3.0 with: subdirectory: android lane: promote ios: concurrency: group: ${{ github.workflow }}-${{ github.ref }}-ios cancel-in-progress: true name: Promote iOS runs-on: self-hosted env: FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }} steps: - uses: actions/checkout@v4 - name: Promote Release on App Store uses: maierj/fastlane-action@v2.3.0 with: subdirectory: ios lane: promote skip:${{ github.event.inputs.skip }}
-
Trigger the workflow manually by going to the Actions tab in your GitHub repository and selecting the
Promote Release
workflow. Click on theRun workflow
button and select the branch or tag you want to promote. Make sure that the version you want to promote has already been uploaded and published to the respective track. You can do this with theDeploy
workflow.
Recap
So how does the whole process look like now? Whenever you want to release a new version of your app, you can manually trigger the Tag Release
workflow. You can choose between major
, minor
and patch
. The workflow will bump the version in the pubspec.yaml
file, create a new commit and tag, and push the changes to the repository. This will trigger the Release
workflow which will create a new release with the tag name and generated release notes. This will also trigger the Build and Deploy
workflow which will build and deploy the app to the AppStore and PlayStore. After you have successfully deployed the app, you can manually trigger the Promote Release
workflow. This will promote the release to the respective track in the PlayStore and AppStore.
Conclusion
And that’s it! You’ve now set up a CI/CD pipeline for your Flutter app using Fastlane and GitHub Actions. This setup will automatically build and deploy your app to the AppStore and PlayStore. You’ve also automated the versioning, tagging and release process with GitHub Actions. Time to kick back, relax, and let automation take care of the repetitive tasks.
Credits
Title image by Igor Dashko on iStock