[GitHub Actions] Removing duplication in GitHub Actions using Composite Action

2024-11-13 hit count image

Let's see how to use Composite Action to remove duplication in GitHub Actions and increase the reusability of Actions.

Outline

When using GitHub Actions for development, there may be parts that are commonly used in multiple Actions. In this case, using Composite Action allows you to consolidate the common parts used in multiple Actions into one Action to increase reusability.

In this blog post, I will introduce how to use Composite Action to increase the reusability of GitHub Actions.

What is Composite Action

Composite Action is a feature that allows you to use multiple Actions as one Action. By using Composite Action, you can consolidate the common parts used in multiple Actions into one Action to increase reusability.

Example of GitHub Action with duplicate code

You can use the following GitHub Actions in a project using React.

name: 'Check code'

on:
  pull_request:

jobs:
  cspell:
    name: CSpell
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 20.3.0
      - name: Enable Yarn 3.7.0
        run: corepack enable
      - name: Install dependencies
        run: yarn install --frozen-lockfile
      - name: CSpell
        run: yarn cspell
  remark:
    name: Remark-lint
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 20.3.0
      - name: Enable Yarn 3.7.0
        run: corepack enable
      - name: Install dependencies
        run: yarn install --frozen-lockfile
      - name: Remark-lint
        run: yarn remark
  eslint:
    name: ESLint
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 20.3.0
      - name: Enable Yarn 3.7.0
        run: corepack enable
      - name: Install dependencies
        run: yarn install --frozen-lockfile
      - name: ESLint
        run: yarn lint
  stylelint:
    name: Stylelint
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 20.3.0
      - name: Enable Yarn 3.7.0
        run: corepack enable
      - name: Install dependencies
        run: yarn install --frozen-lockfile
      - name: Stylelint
        run: yarn stylelint
  test:
    name: Test
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 20.3.0
      - name: Enable Yarn 3.7.0
        run: corepack enable
      - name: Install dependencies
        run: yarn install --frozen-lockfile
      - name: Test
        run: yarn test

This is a GitHub Actions that runs CSpell, Linters, and Test in a React project. You can see that the part of installing Dependencies is duplicated.

      ...
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 20.3.0
      - name: Enable Yarn 3.7.0
        run: corepack enable
      - name: Install dependencies
        run: yarn install --frozen-lockfile
      ...

In the next section, I will introduce how to use Composite Action to consolidate this part and increase reusability.

Creating Composite Action

To create a Composite Action, create the .github/actions/install-dependencies.yml file and modify it as follows.

name: 'Install Dependencies'
description: 'Install Dependencies'

runs:
  using: 'composite'
  steps:
    - name: Setup node
      uses: actions/setup-node@v4
      with:
        node-version: 20.3.0
    - name: Enable Yarn 3.7.0
      shell: bash
      run: corepack enable
    - name: Install dependencies
      shell: bash
      run: yarn install --frozen-lockfile

To use Composite Action, set composite to the using keyword to indicate that it is a Composite Action. Then, write the steps to execute the Composite Action in steps.

When executing a command, you need to set bash to the shell keyword to use the bash shell.

Using Composite Action

To use the Composite Action, modify the GitHub Actions as follows.

name: 'Check code'

on:
  pull_request:

jobs:
  cspell:
    name: CSpell
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Install dependencies
        uses: ./.github/actions/install_dependencies
      - name: CSpell
        run: yarn cspell
  remark:
    name: Remark-lint
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Install dependencies
        uses: ./.github/actions/install_dependencies
      - name: Remark-lint
        run: yarn remark
  eslint:
    name: ESLint
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Install dependencies
        uses: ./.github/actions/install_dependencies
      - name: ESLint
        run: yarn lint
  stylelint:
    name: Stylelint
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Install dependencies
        uses: ./.github/actions/install_dependencies
      - name: Stylelint
        run: yarn stylelint
  test:
    name: Test
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Install dependencies
        uses: ./.github/actions/install_dependencies
      - name: Test
        run: yarn test

I have modified the GitHub Actions to use the Composite Action like following.

      ...
       - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Install dependencies
        uses: ./.github/actions/install_dependencies
      ...

Since the Composite Action is managed in the .github folder, you need to check out the code first using actions/checkout. Then, you can use the Composite Action by writing the path of the Composite Action in the uses keyword.

inputs of Composite Action

Sometimes, you need to pass a specific value to the Composite Action when using the Composite Action. In this case, you can use the inputs of the Composite Action to pass the value.

To use the inputs of the Composite Action, modify the Composite Action as follows.


name: 'Composite Action with inputs'
description: 'Composite Action with inputs'
inputs:
  variable_name:
    description: 'Description of the variable'
    required: true
    default: 'variabel_default_value'
runs:
  using: 'composite'
  steps:
    - name: Print Composite Action inputs variable
      run: echo ${{ inputs.variable_name }}
      shell: bash

If you use inputs, you can make Composite Action execute differently depending on the condition.

To use the inputs of the Composite Action, modify the GitHub Actions as follows.


      ...
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Composite Action with inputs
        uses: ./.github/actions/composite_action
        with:
          variable_name: 'test_input_value'
      ...

outputs of Composite Action

Sometimes, you need to receive a specific value from the Composite Action to execute the Action. In this case, you can use the outputs of the Composite Action to pass the value.

To use the outputs of the Composite Action, modify the Composite Action as follows.


name: 'Composite Action with outputs'
description: 'Composite Action with outputs'
outputs:
  variable_name:
    description: "variable description"
    value: ${{ steps.output_step.outputs.output_variable_name }}
runs:
  using: 'composite'
  steps:
    - name: Set outputs
      id: output_step
      run: echo "output_variable_name=test_output_value" >> $GITHUB_OUTPUT
      shell: bash

After making Composite Action like this, you can use the outputs of the Composite Action as follows.


      ...
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Composite Action with outputs
        id: composite_action
        uses: ./.github/actions/composite_action
      - name: Print Composite Action outputs variable
        run: echo ${{ steps.composite_action.outputs.variable_name }}
      ...

If you use outputs, you can create an Action that uses the results of the Composite Action.

Completed

Done! We’ve seen how to use Composite Action to remove duplication in GitHub Actions and increase the reusability of Actions.

If you want to remove duplication and increase the reusability of Actions, try using Composite Action.

Was my blog helpful? Please leave a comment at the bottom. it will be a great help to me!

App promotion

You can use the applications that are created by this blog writer Deku.
Deku created the applications with Flutter.

If you have interested, please try to download them for free.

Posts