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

时间:2020-02-06 10:24:25

标签: caching gitlab-ci npm-install

我在gitlab中有一个monorepo,它带有有角度的前端和nestjs后端。我每个人都有package.json,根目录中有1个。我的管道包括以下多个阶段:

stages:
  - build
  - verify
  - test
  - deploy

我在.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'

现在的问题是,如果以某种方式清除了高速缓存,或者如果我没有在第一次推送时对package-lock.json进行更改,那么我将根本无法运行此作业,因此其他所有操作都会失败,因为这需要node_modules。如果我从此处删除changes:,则它将为每个管道运行作业。当然,我仍然可以在作业之间共享它,但是如果我再进行一次提交并推送,即使我没有更改应该存在的内容,安装所有依赖项也要花费近2分钟的时间。我该如何缓存它,使其仅在缓存已过期或不存在时才重新安装依赖项?

3 个答案:

答案 0 :(得分:2)

最后,我发现我可以不依赖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

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

答案 1 :(得分:2)

我遇到了同样的问题,我能够使用关键字rules而不是only|except来解决它。使用它,您可以声明更复杂的情况,例如使用ifexistschanges。另外,这个:

规则不能仅与// 结合使用,因为是该功能的替代品。如果尝试执行此操作,则linter返回的键可能不会与规则错误一起使用。

-https://docs.gitlab.com/ee/ci/yaml/#rules

所有更多原因切换到rules。这是我的解决方案,它执行npm ci

  • 如果package-lock.json文件已被修改

OR

  • 或者如果node-modules文件夹不存在(如果有新分支或清理缓存):
npm-ci:
  image: node:lts
  cache:
    key: $CI_COMMIT_REF_SLUG-$CI_PROJECT_DIR
    paths:
      - node_modules/
  script:
    - npm ci
  rules:
    - changes:
        - package-lock.json
    - exists:
        - node_modules
      when: never

希望有帮助!

答案 2 :(得分:1)

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/

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

# 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

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