/github-actions-practice

Github Actions Practice

Primary LanguageDockerfile

github-actions-practice

  • Last Updated: 2024-05-26
  • Last Merged PR: #960

Github Actions Table

1. pull_request

  • github.sha is not the latest commit sha ref <- you can use this sha for the closed type to get the latest commit on the main branch.
  • github.event.pull_request.head.sha is the sha of the lastest commit on the pr branch ref
  • github.event.pull_request.head.ref: pr branch name. e.g. BRANCH: ${{ github.event_name == 'push' && github.ref_name || github.event.pull_request.head.ref }}: branch name for push and pull_request event (need to set in env)
  • github.event.number: pull request number. e.g. ${{ github.event_name == 'push' && github.ref_name || format('pr-{0}', github.event.number) }} get tag name (branch name for push and pr-xxx for pr)
GitHub Actions Trigger Description
actionlint pull_request actionlint lint for GitHub Actions workflows
artifact pull_request Upload github-sha.txt to artifact. Wanted to download if exists but not worked -> commented out.
auto-approve pull_request If change is under automatic-approval, any PR will be automatically approved.
auto-assign pull_request Set PR author to the assignee when a PR is created.
auto-merge pull_request If change is under automatic-merge, any PR will be automatically merged.
auto-release-when-pr-is-merged pull_request If a PR is merged, create a draft release (publish a release if there's release label) and leave a comment on the PR.
conditional-auto-approve pull_request If PR's changed files and changes match AUTO_APPROVE_ALLOWED_REGEX and AUTO_APPROVE_FILE_PATH_REGEX respectively, the pr will be automatically merged.
check-actions-name pull_request Check actions file name and the name in yaml file are same.
context pull_request Echo GitHub context toJson(github) for checking.
default-commands pull_request Check default commands (e.g. zip, aws, jq, yq)
docker-layer-cache pull_request Use satackey/action-docker-layer-caching.
envvar pull_request How to set env var and use it.
keep-only-one-comment-on-pr pull_request Create a comment if not exist. Otherwise, update the existing comment.
labeler pull_request Add label to a pr based on the title.
poetry-cache pull_request cache poetry and python dependencies managed by poetry.
pre-commit pull_request Run pre-commit.
s3-local pull_request Use minio for s3 mock in GitHub Actions. This workflow is broken❌.
terrraform-fmt pull_request Run terraform fmt for **.tf.
changed-files pull_request do sth for changed files/dir using https://github.com/tj-actions/changed-files

2. release

GitHub Actions Trigger Description
auto-pr release When a release is published from main branch, update a kubernetes yaml file in another repository nakamasato/k8s-deploy-test and create a pr in the repository.
prereleased release When release is prereleased from main branch, echo "prereleased".
released release If a release is published from main branch, echo the release version
release-with-environment release If a release is published from main branch, the workflow needs to be reviewed.
k8s-ci release Build docker image, push it to Github Packages, and update manifest file.

3. push

  • BRANCH: ${{ github.event_name == 'push' && github.ref_name || github.event.pull_request.head.ref }}: branch name for push and pull_request event (need to set in env)
GitHub Actions Trigger Description
branch-and-tag push If change is pushed to merge branch or tagged as v1.*, the branch will be merged to main branch. disabled due to branch protection in #1348
pip-cache push Use actions/cache for caching ~/.cache/pip
pip-no-cache push For comparison with pip-cache
python-semantic-release push ❌ not compatible with branch protection ref

4. schedule

GitHub Actions Trigger Description
schedule schedule Echo "test" at 00:00 every Monday.
create-pr-if-outdated schedule create a pr when last update in readme is outdated

5. workflow_dispatch

GitHub Actions Trigger Description
workflow-dispatch workflow_dispatch You can run this workflow from here

6. workflow_call

GitHub Actions Trigger Description
print-workflow-dispatch-inputs workflow_call You can reuse this workflow to print inputs of workflow_dispatch (inputs: environment & logLevel)
  1. env cannot be used for matrix.
  2. The matrix value cannot be used in if for its job.
  3. fromJson is often used to generate matrix (ref: https://docs.github.com/en/actions/learn-github-actions/expressions)
GitHub Actions Trigger Description
matrix-from-previous-job-output pull_request matrix execution from the output of the previous step. fromJson
matrix-from-previous-job-output-2 pull_request, push matrix execution from the output of the previous step. fromJson
matrix-from-previous-job-output-3 pull_request, push do something for both prod and dev for push event and do sth only for dev for pull_request event
matrix-by-condition pull_request, push run for dev and prod when merged to main. run only for dev for pull_request.

CheatSheet

  • Available commands by default (default-commands.yml)

    • zip, aws, jq, yq

    • gh

      example
      - uses: actions/checkout@v3 # to get the context
      
      - name: gh
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: gh pr comment $PR_NUMBER --body "Hi from GitHub CLI"
  • Events to Trigger workflow

    • pull_request
      • default types: opened, synchronize, or reopened.
      • specify types:
        on:
          pull_request:
            types: [assigned, opened, synchronize, reopened, ready_for_review]
        • action: ${{ github.event.action }}: You can get edited, synchronize, ready_for_review, (opened ❌)
      • Get PR number: PR_NUMBER=${{ github.event.number }}
      • Get sha: ${{ github.sha }}
      • Get repository: ${{ github.repository }}
      • Get label name for labeled type: ${{ github.event.label.name }}
      • Get source branch: ${{ github.head_ref }}
      • Get base branch: ${{ github.base_ref }}
      • Whether the PR is draft: github.event.pull_request.draft
      • Whether the label is in the whitelist: if: ${{ github.event.action == 'labeled' && contains(toJson('["test", "build"]'), github.event.label.name) }}
      • If merged pr has label release: if: ${{ github.event.pull_request.merged == true && contains( github.event.pull_request.labels.*.name, 'release') }}
      • Whether pull_request has 'test' label: if: ${{ contains( github.event.pull_request.labels.*.name, 'test') }}
    • release
      • Whether release is from main branch: if: github.event.release.target_commitish == 'main'
    • push ...
  • Context

  • Outputs

    • Set output: echo "<your var name>=<value>" >> "$GITHUB_OUTPUT"

    • Use output: ${{ steps.<step_id>.outputs.<your var name> }}

    • Skip next job based on the result of a dependent job

        skipci:
          runs-on: ubuntu-18.04
          outputs:
            is_skip: ${{ steps.is_skip.outputs.is_skip }}
          steps:
            - name: Set is_skip
              id: is_skip
              run: echo "is_skip=${{ contains(github.event.head_commit.message, '[skip ci]') }}" >> "$GITHUB_OUTPUT"
            - run: echo "[skip ci] ${{ steps.is_skip.outputs.is_skip }}"
      
        test:
          runs-on: ubuntu-18.04
          needs: skipci
          if: ${{ ! needs.skipci.outputs.is_skip }}
          steps:
  • Environment variable

    • default environment variables

    • source branch and base brach of PR

      env:
        SOURCE_BRANCH: ${{ github.head_ref }}
        BASE_BRANCH: ${{ github.base_ref }}
  • Caching

  • Failure

    name: status
    
    on: pull_request
    
    jobs:
      just-fail:
        if: github.event.pull_request.draft == true
        runs-on: ubuntu-latest
        steps:
          - id: fail_step
            run: exit 1
    
          - run: echo ${{ steps.fail_step.outcome }} # not called
    
      fail-with-post-process:
        if: github.event.pull_request.draft == true
        runs-on: ubuntu-latest
        steps:
          - id: fail_step
            continue-on-error: true
            run: exit 1
    
          - name: post process regardless of sucess or failure
            run: echo ${{ steps.fail_step.outcome }} # failure
    
          - name: make it fail when the first step failed
            if: steps.fail_step.outcome == 'failure'
            run: exit 1
    
      succeed-with-post-process:
        if: github.event.pull_request.draft == true
        runs-on: ubuntu-latest
        steps:
          - id: succeed_step
            continue-on-error: true
            run: echo succeed
    
          - name: post process regardless of sucess or failure
            run: echo ${{ steps.fail_step.outcome }} # success
    
          - name: make it fail when the first step failed
            if: steps.fail_step.outcome == 'failure'
            run: exit 1
    
      fail-with-post-process-for-failure:
        if: github.event.pull_request.draft == true
        runs-on: ubuntu-latest
        steps:
          - id: fail_step
            run: exit 1
    
          - if: failure()
            name: post process only called when the first step fails
            run: echo ${{ steps.fail_step.outcome }} # failure
    
      succeed-with-post-process-for-failure:
        if: github.event.pull_request.draft == true
        runs-on: ubuntu-latest
        steps:
          - id: succeed_step
            run: echo succeed
    
          - if: failure()
            name: post process only called when the first step fails
            run: echo ${{ steps.fail_step.outcome }}
    
      succeed:
        runs-on: ubuntu-latest
        steps:
          - id: suceed_step
            continue-on-error: true
            run: echo succeed
    
          - run: echo ${{ steps.suceed_step.outcome }} # success
    
          - if: steps.fail_step.outcome == 'failure'
            run: exit 1
  • Example

    • Test mvn with MySQL

        test:
          runs-on: ubuntu-latest
      
          services:
            mysql:
              image: mysql:5.7
              options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10
              ports:
                - 3306
              env:
                MYSQL_ROOT_PASSWORD: root_password
                MYSQL_DATABASE: test_db
      
          steps:
            - uses: actions/checkout@v1
            - uses: actions/cache@v1
              with:
                path: ~/.m2/repository
                key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
                restore-keys: |
                  ${{ runner.os }}-maven-
            - name: Set up JDK 1.8
              uses: actions/setup-java@v1
              with:
                java-version: 1.8
            - name: Test with Maven
              env:
                MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
                MYSQL_HOST: 127.0.0.1
                MYSQL_USERNAME: root
                MYSQL_PASSWORD: root_password
                MYSQL_DB: test_db
              run: mvn test