36

Using Github Actions to Automate Our Release Process

 3 years ago
source link: https://riggaroo.dev/using-github-actions-to-automate-our-release-process/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Using Github Actions to Automate Our Release Process

github_action_header-1200x400.png

At Over, we’ve recently translated our app into 12 new languages. This meant that our release process started to get a bit more tedious as more steps were introduced into making a new release for the Google Play Store. We were starting to feel the fatigue of manually completing the exact same steps for every release. 

My goal was to make this process as seamless as possible for the engineer on release duty. I decided to turn to using Github Actions to automate as much of the process as possible. In this blog post, I’ll explain different parts of our process and show you how I setup Github Actions to achieve what we needed to. 

Our Release Process 

We use Git Flow for our release process, which means when we are ready to release, we create a release/v5.4.0 branch from develop. We would manually create this branch, change the version code and version name, push the changes and create two PRs for this (One for the merge into main and one for the merge back into develop). Once a release was merged, we needed to do some release note creation, tagging on Github and notifying the team on Slack what the latest release contains. 

This process, although cumbersome, wasn’t too unpleasant to manage manually. Then a new requirement was added to our process: Submit the strings.xml file for translation when a new release is made. We also needed automation when the translations were received back from the translation system. 

This diagram below describes Git Flow (adapted from here), with our added step of submitting translations for the application:

Release-Process-Android.003-1024x576.jpeg

Automating more of our release process 🤖

Although we had automatic builds set up to submit releases to Google Play and Firebase, a large chunk of our release process was still a manual process. We used Github Actions to automate more of this. 

We now have three workflows setup on Github actions:

  • Starting a release and submitting strings.xml for translation.
  • Getting translations back from translators.
  • Tagging a release on Github and notifying a slack channel.

Note: We aren’t automating the actual builds on Github Actions yet, the different builds happen on a separate build server when pushes to the relevant branches are created, I won’t be covering those configs in this post. 

Starting a release 🚝

The first workflow I created is a manual trigger to create the release branch and submit the strings.xml for translation.

Using the workflow_dispatch trigger, this offers a UI in the Github Actions tab, to enter in some user input. For our release workflow, I added versionName and versionCode to be entered in by the release engineer. 

We also introduced using a CHANGELOG.md file for documenting the new features and release notes that’ll be generated at the end of the process, so we no longer need to cobble together release notes when we make a new release. 

This is the create_release_branch.yml file, checked into git at the following location .github/workflows/create_release_branch.yml(you can call your yml anything, but they need to be located in .github/workflows/ folder in order for Github to find them):

name: Create Release Branch on: workflow_dispatch: inputs: versionName: description: 'Name of version (ie 5.5.0)' required: true versionCode: description: 'Version number (50500)' required: true jobs: createrelease: runs-on: ubuntu-latest

steps: – name: Check out code uses: actions/checkout@v2 – name: Create release branch run: git checkout -b release/v${{ github.event.inputs.versionName }} – name: Initialize mandatory git config run: | git config user.name "GitHub Actions" git config user.email [email protected] – name: Change version number and name run: printf 'ext.version_code = ${{ github.event.inputs.versionCode }}\next.version_name = "${{ github.event.inputs.versionName }}"\n' > app_versions.gradle – name: Update Changelog uses: thomaseizinger/keep-a-changelog-new-release@v1 with: version: ${{ github.event.inputs.versionName }} – name: Commit changelog and manifest files id: make-commit run: | git add app_versions.gradle git add CHANGELOG.md git commit –message "Prepare release ${{ github.event.inputs.versionName }}" echo "::set-output name=commit::$(git rev-parse HEAD)" – name: Push new branch run: git push origin release/v${{ github.event.inputs.versionName }} – name: Submit strings.xml for translation uses: andstor/copycat-action@v3 with: personal_token: ${{ secrets.ANDROID_I18N_PAT }} src_path: resources/src/main/res/values/strings.xml src_branch: release/v${{ github.event.inputs.versionName }} dst_path: en/strings.xml dst_owner: your-repo-owner dst_repo_name: android-i18n dst_branch: master clean: true commit_message: release/v${{ github.event.inputs.versionName }} BOT New Strings for translation submitted. – name: Create pull request into main uses: thomaseizinger/[email protected] with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} head: release/v${{ github.event.inputs.versionName }} base: main title: v${{ github.event.inputs.versionName }} into main reviewers: ${{ github.event.issue.user.login }} body: | Hi! This PR was created in response workflow running. I've updated the version name and code commit: ${{ steps.make-commit.outputs.commit }}. – name: Create pull request to develop uses: thomaseizinger/[email protected] with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} head: release/v${{ github.event.inputs.versionName }} base: develop title: v${{ github.event.inputs.versionName }} into develop reviewers: ${{ github.event.issue.user.login }} body: | Hi! This PR was created in response workflow running. I've updated the version name and code commit: ${{ steps.make-commit.outputs.commit }}.

Using the workflow_dispatch trigger, this is a manual trigger that allows for user input. 

This release workflow does the following steps:

  1. Check out code from app repo.
  2. Create new release branch named release/v{versionName}
  3. Change the version name and version code of release.
  4. Update the changelog using this action
  5. Commit and push changelog changes and version name changes to the branch. 
  6. Copy strings.xml file to the other repository that we use for translations using this action. This action requires setting up a PAT (Personal Access Token) and putting the variable in the “Settings” -> “Secrets” .
  7. Create two PRs, one into main and one into develop . This triggers our build server to see if these builds pass. 

After this point, the release branch will be waiting for translations before we merge the PRs. 

Now to actually run this Action: Log onto Github and select “Actions” tab, click on the “Create Release Branch”, there is a little “Run workflow” button that we can click to trigger this workflow with our inputs. 

create_release_branch_github_actions.png
The manual trigger now on Github actions, where we can enter in the version name and number of the release to create.

Getting translations back from translators 🌎

We have a separate repository where our translations for the application live, the new translations are submitted to us via new commits on that repository. The repository also lives on Github, so I created a new workflow trigger on that repository to process the translations. 

name: Translation Export to Android Repo on: push: branches: [ master ] workflow_dispatch: jobs: push_strings_to_over: runs-on: ubuntu-latest if: "contains(github.event.head_commit.message, 'Automated checkin')" steps: – name: Check out code uses: actions/checkout@v2 with: path: 'android-i18n' – name: Check out my other private repo uses: actions/checkout@v2 with: path: 'android-app' repository: repo-owner/android-app token: ${{ secrets.I18N_TO_OVER_PAT }} – name: Run rename script (renameall.sh) and commit to Android repo run: | cd android-app/ git fetch releaseBranchToCheckout=$(git branch -a | grep release | head -n 1 | xargs | cut -c 16-) git checkout $releaseBranchToCheckout echo "BASE_RELEASE_BRANCH=$releaseBranchToCheckout" >> $GITHUB_ENV cd .. cd android-i18n/ ./renameall.sh cd .. cp -R android-i18n/values-* android-app/resources/src/main/res/ cd android-app/ git config user.name "GitHub Actions" git config user.email [email protected] date=$(date '+%Y-%m-%d%H%M%S') newBranchName=feature/new-translations-$date echo "NEW_BRANCH_NAME=$newBranchName" >> $GITHUB_ENV – name: Create Pull Request id: cpr uses: peter-evans/create-pull-request@v3 with: token: ${{ secrets.I18N_TO_OVER_PAT }} path: android-app base: ${{ env.BASE_RELEASE_BRANCH }} commit-message: Update translations committer: GitHub <[email protected]> author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> branch: ${{ env.NEW_BRANCH_NAME }} title: '🤖 Automation – New translations received for ${{ env.BASE_RELEASE_BRANCH }}' body: | New translations received from GoLF. draft: false – name: Slack notify uses: rtCamp/action-slack-notify@master env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: #android-bots SLACK_TITLE: New translations have been received! 🌎 SLACK_MESSAGE: Translation system has submitted new translations. Check them out here – ${{ steps.cpr.outputs.pull-request-url }} MSG_MINIMAL: true

This workflow does the following steps:

  1. Check out translations repo (android-i18n) and checkout app repo (android-app). 
  2. On android-app repo, switch to the latest release branch. 
  3. On android-i18n repo, run renameall.sh script. This script changes the folder names from the translation system names to android resource folder names (ie from de to values-de).
  4. Copy the renamed folders (with their string changes) to the android-app repo from the android-i18n repo. 
  5. Create Pull Request into release branch on the main android-app repository.
  6. Notify on slack that the new translation PR is available. 

This workflow really helped ease some of the pain of manual string copying back and forth between repositories. 

Tagging a release 🔖

Once a release has been merged into our main branch, we had the next manual step of creating a release on Github, copying release notes from CHANGELOG.md and tagging it. We would also need to at this point, notify a certain slack channel of the new release build. As you can tell, this was also a perfect candidate for automation since it was the same process every single time. 

This is the workflow for tagging a release, getting the CHANGELOG.md release notes, and notifying the relevant slack channel:

name: Tag Release on: push: branches: [ main ] jobs: tag_release: runs-on: ubuntu-latest steps: – name: Check out code uses: actions/checkout@v2 – name: Initialize mandatory git config run: | git config user.name "GitHub Actions" git config user.email [email protected] – name: Setup release information #get version name from app_versions.gradle file (5.6.2) run: | versionName=`sed '2q;d' app_versions.gradle | cut -d "=" -f2 | xargs` export VERSION_NAME=$versionName echo "::set-env name=VERSION_NAME::$VERSION_NAME" – name: Extract release notes id: extract_release_notes uses: ffurrer2/extract-release-notes@v1 – name: Create Release id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ env.VERSION_NAME }} release_name: v${{ env.VERSION_NAME }} body: ${{ steps.extract_release_notes.outputs.release_notes }} draft: false prerelease: false – name: Slack notify uses: rtCamp/action-slack-notify@master env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_OVER_APP }} SLACK_CHANNEL: #over-app-android SLACK_TITLE: 🚨 Version ${{ env.VERSION_NAME }} is being published to Google Play Internal Test SLACK_MESSAGE: ${{ steps.extract_release_notes.outputs.release_notes }} MSG_MINIMAL: true

This workflow runs when a new push has happened on the main branch. It does the following:

  1. Check out code.
  2. Get the version name from app_versions.gradle file. Set an environment variable for use in later steps.
  3. Extract release notes from the CHANGELOG.md file, using this action
  4. Create a Github Release with the tag_name set to the VERSION_NAME extracted from step 2. 
  5. Notify slack channel with that a new version is going to be published on Google Play with the release notes from CHANGELOG.md.
automated_release_github.png
Shiny new release on Github.

Summary

I found Github Actions to be simple enough to set up and get started. The part that convinced me to use Github Actions was the amount of existing Github Actions that you can leverage really easily by just using the uses tag. For instance, finding actions that deal with CHANGELOG.md files, creating PRs and copying files, really helped ease the process of creating these new automations easier. 

Github Actions are really powerful, ActionsFlow is a great example of what can be built on-top of Github Actions. It is basically a Zapier/IFTTT replacement, all running off Github Actions. 

I can’t wait to automate more of my life with Github Actions. What have you built with Github actions? Let me know on Twitter — @riggaroo

References:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK