使用NPM缓存加速GitHub动作
#javascript #教程 #cicd #githubactions

GitHub Actions是GitHub的功能,它允许您根据GitHub主机为您提供的安全VM中的某些触发器运行各种操作。它有很多用途,但主要是用于构建,测试和部署应用程序的CI/CD工具。

我喜欢它。我们将其用于所有项目。它是免费的(好吧,您每月免费获得2,000分钟的VM运行时间),它的运行效果很好,并且已经整合到GitHub中。

我们还在我们的网站上讨论了how to cache npm effectively on GitHub Actions,请务必检查一下,因为它包含了一些额外的提示。

我们如何使用github动作

有很多用于GitHub动作的应用程序,但我将介绍我们每天在这里使用的应用程序。

我们的核心用例是CI/CD。我们有以下内容:

  1. push是对master(或main,或您的中央分支机构)完成的。
  2. github动作触发我们的工作流程。
  3. github旋转一个运行最新版本Ubuntu的VM。
  4. 它为我们的应用程序安装了一堆先决条件(在我们的情况下,accreditly.io是PHP,Imagick和Node之类的东西)。
  5. 它已经可以访问我们的代码,因此它设置了该项目(复制我们的.env文件,生成新的密钥,设置一些权限等)。
  6. 通过PHP软件包管理器作曲家安装我们的依赖项。
  7. 创建一个本地的SQLite数据库,并配置应用程序。
  8. 运行迁移以设置我们的数据库,然后运行播种机以使用假数据填充它。
  9. 运行npm install以安装我们的依赖项。
  10. 运行我们的完整测试套件。
  11. 假设一切都过去了,然后部署。

所有这些都在我们的.github/workflows/laravel.yml文件中定义。

它的工作原理非常好。从第二个开始,将提交推向部署开始大约需要5分钟。启动VM,安装操作系统,设置具有大量依赖项的项目并运行测试套件还不错。

但是,我们可以做得更好。

优化npm install

到目前为止,我们的GitHub动作工作流程中最慢的部分是npm installnpm run prod(建立我们的资产),约为30秒左右。它的每一侧约为40秒,因此必须取决于可用的带宽或在任何给定时间VM的位置。无论哪种方式,这都是我们〜5min 30sec总构建时间的大量数量。

在我的本地机器上,安装和构建大约需要30秒钟。当然,我有一台不错的机器,但这是一个巨大的差距。这样做的主要原因是我们使用了大量的软件包,每个软件包都附有一系列依赖关系。那是一个很大的开销。

让我们缓存。

操作缓存

github保持一组名为actions的存储库。其中之一称为cache

让我们从整个文件开始。

# Name of our workflow
name: Laravel

# When to run it
on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

# Define our jobs
jobs:
  laravel-tests:

    runs-on: ubuntu-latest
    # Setup
    steps:
    - uses: actions/checkout@v3
    - name: Update apt
      run: sudo apt-get update
    - name: Install imagick
      run: sudo apt-get install php-imagick
    - uses: actions/setup-node@v3
      with:
        node-version: 16
    - uses: nanasess/setup-php@master
      with:
        php-version: '8.1'

    - name: Copy .env
      run: php -r "file_exists('.env') || copy('.env.example', '.env');"

    - name: Install Dependencies
      run: composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --ignore-platform-req=ext-imagick

    - name: Generate key
      run: php artisan key:generate

    - name: Directory Permissions
      run: chmod -R 777 storage bootstrap/cache

    - name: Create Database
      run: |
        mkdir -p database
        touch database/database.sqlite
    - name: Migrate
      env:
        DB_CONNECTION: sqlite
        DB_DATABASE: database/database.sqlite
      run: php artisan migrate
      run: php artisan db:seed

好吧,看起来很多事情正在进行中,但是它只是在上面列表中的第1-8点遵循。它设置了我们的VM,安装了一些依赖关系,软件包并设置了我们的数据库。

现在我们需要处理NPM。我们接下来要做的是:

  1. 安装缓存动作模块。
  2. ~/.npm中创建一个包含我们的包装的缓存。
  3. 检查是否有缓存命中(例如,我们已经有包装的缓存版本吗?)
  4. 继续编译。
    - name: Cache node modules
      id: cache-npm
      uses: actions/cache@v3

      env:
        cache-name: cache-node-modules
      with:
        # npm cache files are stored in `~/.npm` on Linux/macOS
        path: ~/.npm
        key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-build-${{ env.cache-name }}-
          ${{ runner.os }}-build-
          ${{ runner.os }}-

    - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
      name: List the state of node modules
      continue-on-error: true
      run: npm list

    - name: Compile assets
      run: |
        npm install
        npm run production

然后,我们继续运行测试和部署(我们使用Forge进行部署,因此这只是击中Webhook的一种情况):

    - name: Execute tests (Unit and Feature tests) via PHPUnit
      run: vendor/bin/phpunit
    - name: Deploy to Laravel Forge
      run: curl ${{ secrets.FORGE_DEPLOYMENT_WEBHOOK }}

将它们放在一起:

# Name of our workflow
name: Laravel

# When to run it
on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

# Define our jobs
jobs:
  laravel-tests:

    runs-on: ubuntu-latest
    # Setup
    steps:
    - uses: actions/checkout@v3
    - name: Update apt
      run: sudo apt-get update
    - name: Install imagick
      run: sudo apt-get install php-imagick
    - uses: actions/setup-node@v3
      with:
        node-version: 16
    - uses: nanasess/setup-php@master
      with:
        php-version: '8.1'

    - name: Copy .env
      run: php -r "file_exists('.env') || copy('.env.example', '.env');"

    - name: Install Dependencies
      run: composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --ignore-platform-req=ext-imagick

    - name: Generate key
      run: php artisan key:generate

    - name: Directory Permissions
      run: chmod -R 777 storage bootstrap/cache

    - name: Create Database
      run: |
        mkdir -p database
        touch database/database.sqlite
    - name: Migrate
      env:
        DB_CONNECTION: sqlite
        DB_DATABASE: database/database.sqlite
      run: php artisan migrate
      run: php artisan db:seed

    - name: Cache node modules
      id: cache-npm
      uses: actions/cache@v3

      env:
        cache-name: cache-node-modules
      with:
        # npm cache files are stored in `~/.npm` on Linux/macOS
        path: ~/.npm
        key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-build-${{ env.cache-name }}-
          ${{ runner.os }}-build-
          ${{ runner.os }}-

    - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
      name: List the state of node modules
      continue-on-error: true
      run: npm list

    - name: Compile assets
      run: |
        npm install
        npm run production

    - name: Execute tests (Unit and Feature tests) via PHPUnit
      run: vendor/bin/phpunit
    - name: Deploy to Laravel Forge
      run: curl ${{ secrets.FORGE_DEPLOYMENT_WEBHOOK }}

我们的新完整构建时间约为3分钟,这是简单地缓存NPM依赖性的巨大节省。

我们可以通过与作曲家一起做同样的事情来进一步改善这一点,但是作曲家依赖项已经很快安装。

我们目前正在考虑搬到害虫进行测试,这要快得多,尤其是在并行模式下运行时。