Github Actions is Github’s free automated build implementation, especially for continuous integration and continuous delivery scenarios, with the ability to automate many different tasks, such as build, test, and deploy.

A brief introduction

Github provides a marketplace for developers to submit or reference acitons written by others. So a lot of the time when developers are using Github Actions, they are actually choosing and combining Actions in the marketplace. Of course, there are pros and cons to this, which we’ll talk about later.

To use Github Actions in the Github repository, you first need to create a directory. Github /workflows/ and then create different.yml files in the workflows folder to respond to or execute different events. Git push request git push request git push request

name: GitHub Actions Demo
on: [push]
jobs:
  Explore-GitHub-Actions:
    runs-on: ubuntu-latest
    steps:
      - run: echo 🎉 The job was automatically triggered by a ${{ github.event_name }} event."
      - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
      - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
      - name: Check out repository code
        uses: actions/checkout@v2
      - run: echo The "💡 ${{ github.repository }} repository has been cloned to the runner."
      - run: echo "🖥️ The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: | ls ${{ github.workspace }}      - run: echo "🍏 This job's status is ${{ job.status }}."
Copy the code

Github Doc is a simple workflow yML file for Action.

  • Name: This represents the name of the workflow file, which will be displayed as a name in Github’s Actions TAB;
  • on: This will trigger the event name of the workflow, which can contain a list of events, such as the one being listened for herepush;
  • Jobs: Each workflow may contain one or more Jobs. In this case, only one is used to represent different tasks.
  • Explore-GitHub-Actions: This is the job ID, which you can name as you like, and which will be displayed during the execution of the action;
  • runs-o: Jobs needs to run on a virtual machine, which is used hereubuntu-latestOf course you can use itwindows-latest ormacos-latest;
  • Steps: Each Job can divide the content that needs to be performed into steps;
  • run: used to provide execution commands, such as the one used hereechoPrint logs;
  • Name: The name in steps is optional and is mainly used for marking in the log;
  • uses: Use some official or third party actions, such as official hereactions/checkout@v2, it checks out our repO, and then the workflow can directly access the files in the REPO;

After the corresponding.github/workflows/ci.yml file is added to the GitHub repository, the automatic execution of actions can be triggered for each subsequent push to achieve sustainable automatic integration and build capabilities.

Build Flutter and publish to Github Release

Github Actions can be used to build Flutter and publish APK to Github Release. The github action script used in the gsy_github_app_flutter project is shown below:

name: CI

on:
  push:
    branches:
      - master
    tags:
      - The '*'
  pull_request:
    paths-ignore:
      - '**/*.md'
      - '**/*.txt'
      - '**/*.png'
      - '**/*.jpg'

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-java@v2
        with:
          distribution: 'zulu'
          java-version: 11
      - uses: subosito/flutter-action@v1
        with:
          flutter-version: '2.8.1'
      - uses: finnp/create-file-action@master
        env:
          FILE_NAME: lib/common/config/ignoreConfig.dart
          FILE_DATA: class NetConfig { static const CLIENT_ID = "${{ secrets.CLIENT_ID }}"; static const CLIENT_SECRET = "${{ secrets.CLIENT_SECRET }}";}
      - run: flutter pub get
      - run: flutter build apk --release --target-platform=android-arm64 --no-shrink

  apk:
    name: Generate APK
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup JDK
        uses: actions/setup-java@v2
        with:
          distribution: 'zulu'
          java-version: 8
      - uses: subosito/flutter-action@v1
        with:
          flutter-version: '2.5.3'
      - uses: finnp/create-file-action@master
        env:
          FILE_NAME: lib/common/config/ignoreConfig.dart
          FILE_DATA: class NetConfig { static const CLIENT_ID = "${{ secrets.CLIENT_ID }}"; static const CLIENT_SECRET = "${{ secrets.CLIENT_SECRET }}";}
      - run: flutter pub get
      - run: flutter build apk --release --target-platform=android-arm64 --no-shrink
      - name: Upload APK
        uses: actions/upload-artifact@v2
        with:
          name: apk
          path: build/app/outputs/apk/release/app-release.apk
  release:
    name: Release APK
    needs: apk
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - name: Download APK from build
        uses: actions/download-artifact@v2
        with:
          name: apk
      - name: Display structure of downloaded files
        run: ls -R

      - name: Create Release
        id: create_release
        uses: The actions/[email protected]
        env:
          GITHUB_TOKEN: The ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: The ${{ github.ref }}
          release_name: The ${{ github.ref }}
      - name: Upload Release APK
        id: upload_release_asset
        uses: The actions/[email protected]
        env:
          GITHUB_TOKEN: The ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: The ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./app-release.apk
          asset_name: app-release.apk
          asset_content_type: application/zip
Copy the code

Based on the above script, you can first see:

  • In the push event we specify that we only listen for the master branch and tags related commits;

  • Then the.md,.text and pictures will be ignored in the pull_request event, that is, the submission of this part of content will not trigger action, depending on your own needs;

  • The push or pull_request will be executed to the Build event, running on the Ubuntu-latest VM, and then using the Actions /checkout@v2 checkout code.

  • Next, use Actions /setup-java@v2 to configure the Java environment. Here, Zulu OpenJDK version 11 is used. The table below shows the optional Java types supported by Setup-Java.

    Keyword Distribution Official site License
    temurin Eclipse Temurin Link Link
    zulu Zulu OpenJDK Link Link
    adopt or adopt-hotspot Adopt OpenJDK Hotspot Link Link
    adopt-openj9 Adopt OpenJDK OpenJ9 Link Link
    liberica Liberica JDK Link Link
    microsoft Microsoft Build of OpenJDK Link Link
  • Subosito /flutter-action@v1 is used to configure the flutter environment, specifying the flutter version directly via the flutter-version: ‘2.8.1’.

  • The gsy_github_app_FLUTTER project has a configuration file that needs to be manually created by users based on their ID and SECRET. So create-file-action creates the file and enters the content;

  • In the input content above, there is a parameter of secrets. XXX, as shown in the following figure, you can add the corresponding content in the secrets of Settings, because you need to configure some of your own key information into the action during construction. You can read it in action via secrets. XXX.

  • Then, after the environment is configured, you can execute the flutter pub GET and flutter Build APK to perform the build.

After completing the logic of the Build task, you can see that there is an APK task under the Build task, which is basically the same as the Build task, except that:

  • One moreif: startsWith(github.ref, 'refs/tags/'), that is, the task will be triggered only when the tag exists.
  • One moreactions/upload-artifact@v2Used to buildbuild/app/outputs/apk/release/app-release.apkUpload and wait for use in the Release task;

After completing the APK task, we enter the Release task, which is also specified by if to run only on tag commits:

  • The task will pass firstactions/download-artifact@v2Download the apK you just uploaded;
  • And then it goes throughThe actions/[email protected]Create a release version, which is used heresecrets.GITHUB_TOKEN Is the official built-in secrets, we can directly use it;
  • At last,The actions/[email protected]Upload the APK to the release you just created, and from there you complete the action publishing process;

As you can see, the whole process is actually combining different actions, which can be flexibly configured to build logic. For example, if your project is a pure Android SDK project, you can also use the following script for release management:

name: CI

on:
  push:
    branches:
      - master
    paths-ignore:
      - '.idea/**'
      - '.gitattributes'
      - '.github/**.json'
      - '.gitignore'
      - '.gitmodules'
      - '**.md'
      - '**/*.txt'
      - '**/*.png'
      - '**/*.jpg'
      - 'LICENSE'
      - 'NOTICE'
  pull_request:
    paths-ignore:
      - '.idea/**'
      - '.gitattributes'
      - '.github/**.json'
      - '.gitignore'
      - '.gitmodules'
      - '**.md'
      - '**/*.txt'
      - '**/*.png'
      - '**/*.jpg'
      - 'LICENSE'
      - 'NOTICE'

jobs:
  publish:
    name: Publish to MavenLocal
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: 17
      - uses: gradle/gradle-build-action@v2
        with:
          arguments: publishToMavenLocal

  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: 17
      - uses: gradle/gradle-build-action@v2
        with:
          arguments: app:assembleDebug
Copy the code

Of course, if you need to package iOS, you will need to use macOS-latest environment and configure the relevant developer certificate. This process can be uncomfortable, as can be seen in the “Flutter Setup iOS Command Line Service Packaging Process”.

Third, privacy security issues

Finally, Github Actions have been known to leak sensitive data, such as Github tokens. For example, the script above requires a secret key to perform tasks. If you use a third party action that gets your key and does something “illegal” during execution, you can have an abnormal leak problem.

It is generally recommended that you checkout unofficial script implementations to see if they are secure, but since tag and branch can be modified, it is recommended that you do not use the @ branch or tag, but instead use the checkout corresponding commit hash. This will help you check if the script is secure when you use it.

In addition, for example, some people mentioned the pull_request malicious attack to obtain corresponding privacy:

  • Fork a public code base that is using GitHub Actions;

  • 2. Create a pull request based on the project.

  • Create a malicious Actions workflow using the pull_request_target event and commit to the fork library separately.

  • Update the pull request from the base branch in Step 2 to the COMMIT hash in Step 3.

The malicious Actions workflow is then run and sensitive execution data is retrieved from the target Repos, at which point the attacker will have write access to the target repository, in addition to any services associated with the repository via GitHub.

So while GitHub actions are convenient, you need to be careful about security if you’re doing it for business reasons.