12

Composite github action to improve CI time with yarn 3+ / node-modules linker.

 1 year ago
source link: https://gist.github.com/belgattitude/042f9caf10d029badbde6cf9d43e400a
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

Not using yarn ? see the corresponding pnpm action gist

While @setup/node has a built-in cache parameter for popular package managers, it discards the cache on every lock file update. This composite action allows to run install with (almost always) warm cache. Depending on repo usage, that might reduces the monthly ci-time and decrease the carbon emissions. See also actions/setup-node#325.

Bench

Based on the nextjs-monorepo-example. A cold cache install on the ci is more than 2 minutes. With warmed cache: 1 minute. Crafted from benchmarks results in https://gist.github.com/belgattitude/0ecd26155b47e7be1be6163ecfbb0f0b. Depending on repo (renovatebot...), the slight complexity increase in ci setup might worth it.

Structure

.
└── .github
    ├── actions
    │   └── yarn-nm-install/action.yml (composite action)    
    └── workflows
        └── ci.yml (uses: ./.github/actions/yarn-nm-install)    

Composite action

Create a file in .github/actions/yarn-nm-install/action.yml and paste

########################################################################################
# "yarn install" composite action for yarn 2/3/4+ and "nodeLinker: node-modules"       #
#--------------------------------------------------------------------------------------#
# Cache:                                                                               #
#   - Downloaded zip archive (multi-arch, preserved across yarn.lock changes)          #
#   - Yarn install state (discarded on yarn.lock changes)                              #
# References:                                                                          #
#   - bench: https://gist.github.com/belgattitude/0ecd26155b47e7be1be6163ecfbb0f0b     #
#   - vs @setup/node: https://github.com/actions/setup-node/issues/325                 #
########################################################################################

name: 'Yarn install'
description: 'Run yarn install with node_modules linker and cache enabled'
inputs:
  skip-prisma-postinstall-generate:
    description: 'Avoid prisma to automatically generate schema on postinstall'
    required: false
    default: 'false'

runs:
  using: 'composite'
  steps:
    - name: Expose yarn config as "$GITHUB_OUTPUT"
      id: yarn-config
      shell: bash
      run: |
        echo "CACHE_FOLDER=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT

    # Yarn rotates the downloaded cache archives, @see https://github.com/actions/setup-node/issues/325
    # Yarn cache is also reusable between arch and os.
    - name: Restore yarn cache
      uses: actions/cache@v3
      id: yarn-download-cache
      with:
        path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }}
        key: yarn-download-cache-${{ hashFiles('yarn.lock') }}
        restore-keys: |
          yarn-download-cache-

    # Invalidated on yarn.lock changes
    - name: Restore yarn install state
      id: yarn-install-state-cache
      uses: actions/cache@v3
      with:
        path: .yarn/ci-cache/
        key: ${{ runner.os }}-yarn-install-state-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}

    - name: Install dependencies
      shell: bash
      run: |
        yarn install --immutable --inline-builds
      env:
        # CI optimizations. Overrides yarnrc.yml options (or their defaults) in the CI action.
        YARN_ENABLE_GLOBAL_CACHE: 'false' # Use local cache folder to keep downloaded archives
        YARN_NM_MODE: 'hardlinks-local' # Hardlinks-(local|global) reduces io / node_modules size
        YARN_INSTALL_STATE_PATH: .yarn/ci-cache/install-state.gz # Very small speedup when lock does not change
        # Other environment variables
        HUSKY: '0' # By default do not run HUSKY install
        PRISMA_SKIP_POSTINSTALL_GENERATE: ${{ inputs.skip-prisma-postinstall-generate }}       

Workflow action

To use it in the workflows

    steps:
      - uses: actions/checkout@v3

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}

      - name: 📥 Monorepo install
        uses: ./.github/actions/yarn-nm-install

yarnrc.yml

# .yarnrc.yml
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.0.0-rc.24.cjs # or v3...

Results

On install, when only few deps changed

image

Cost of action/cache compression

image

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK