仅当在 gitlab ci 中未缓存或 package.json 更改时,我如何才能运行依赖项安装作业?

Bli*_*air 8 caching gitlab-ci npm-install

我在 gitlab 中有一个带有角度前端和 nestjs 后端的 monorepo。我每个人都有 package.json ,根中有 1 个。我的管道由多个阶段组成,如下所示:

stages:
  - build
  - verify
  - test
  - deploy
Run Code Online (Sandbox Code Playgroud)

我在.pre安装依赖项的阶段有一份工作。我想在作业之间和分支之间缓存那些,如果有任何package-lock.json更改,但如果node_modules当前没有缓存。我有一份看起来像这样的工作:

prepare:
  stage: .pre
  script:
    - npm run ci-deps # runs npm ci in each folder
  cache:
    key: $CI_PROJECT_ID
    paths:
      - node_modules/
      - frontend/node_modules/
      - backend/node_modules/
    only:
      changes:
        - '**/package-lock.json'
Run Code Online (Sandbox Code Playgroud)

现在的问题是,如果缓存以某种方式被清除,或者如果我没有package-lock.json在第一次推送时引入更改,我将根本不会运行此作业,因此其他一切都会失败,因为它需要node_modules. 如果我changes:从那里删除,那么它会为每个管道运行作业。当然,我仍然可以在作业之间共享它,但是如果我再次提交并推送它需要近 2 分钟来安装所有依赖项,即使我没有更改任何关于应该存在的内容......我错过了什么吗?如何以某种方式缓存它,以便仅在缓存过时或不存在时才重新安装依赖项?

Cal*_*mmm 6

Rules:Exists 在缓存被拉下之前运行,因此这对我来说不是一个可行的解决方案。

在 GitLab v12.5 中我们现在可以使用cache:key:files

如果我们将其与 Blind Despair 的条件逻辑的一部分结合起来,我们会得到一个很好的解决方案

prepare:
  stage: .pre
  image: node:12
  script:
    - if [[ ! -d node_modules ]];
      then
        npm ci;
      fi
  cache:
    key:
      files:
        - package-lock.json
      prefix: nm-$CI_PROJECT_NAME
    paths:
      - node_modules/
Run Code Online (Sandbox Code Playgroud)

然后我们可以在后续的构建作业中使用它

# let's keep it dry with templates
.use_cached_node_modules: &use_cached_node_modules
  cache:
    key:
      files:
        - package-lock.json
      prefix: nm-$CI_PROJECT_NAME
    paths:
      - node_modules/
    policy: pull # don't push unnecessarily

build:
  <<: *use_cached_node_modules
  stage: build
  image: node:12
  script:
    - npm run build
Run Code Online (Sandbox Code Playgroud)

我们通过共享缓存在多个分支中成功地使用了它。


Bli*_*air 4

最后我认为我可以在不依赖 gitlab ci 功能的情况下做到这一点,但我自己进行检查,如下所示:

prepare:
  stage: .pre
  image: node:12
  script:
    - if [[ ! -d node_modules ]] || [[ -n `git diff --name-only HEAD~1 HEAD | grep "\package.json\b"` ]];
      then
      npm ci;
      fi
    - if [[ ! -d frontend/node_modules ]] || [[ -n `git diff --name-only HEAD~1 HEAD | grep "\frontend/package.json\b"` ]];
      then
      npm run ci-deps:frontend;
      fi
    - if [[ ! -d backend/node_modules ]] || [[ -n `git diff --name-only HEAD~1 HEAD | grep "\backend/package.json\b"` ]];
      then
      npm run ci-deps:backend;
      fi
  cache:
    key: '$CI_COMMIT_REF_SLUG-$CI_PROJECT_DIR'
    paths:
      - node_modules/
      - frontend/node_modules
      - backend/node_modules
Run Code Online (Sandbox Code Playgroud)

这样做的好处是,如果项目还没有 node_modules 或 package.json 发生更改,它只会安装项目特定部分的依赖项。然而,如果我推送多个提交并且 package.json 不会在最后一个提交中更改,则这可能是错误的。在这种情况下,我仍然可以手动清除缓存并重新运行管道,但我将尝试进一步改进我的脚本并更新我的答案。