仅当未缓存或 package.json 在 gitlab ci 中更改时,我如何 运行 依赖项安装作业?
How can I run dependency install job only when it's not cached or package.json changed in gitlab ci?
我在 gitlab 中有一个带有 angular 前端和 nestjs 后端的 monorepo。我对它们每个都有 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 分钟,即使我没有改变任何应该存在的东西......我错过了什么吗?我怎样才能以某种方式缓存它,以便它只在缓存过时或不存在时才重新安装依赖项?
最后我认为我可以在不依赖 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
这样做的好处是它只会为项目的 specific 部分安装 dependencies,如果它还没有 node_modules 或者什么时候package.json 已更改。但是,如果我推送多个提交并且 package.json 不会在最后一个中更改,这可能是错误的。在那种情况下,我仍然可以手动清除缓存并重新运行管道,但我会尝试进一步改进我的脚本并更新我的答案。
我遇到了同样的问题,我可以使用关键字 rules
而不是 only|except
来解决它。使用它,您可以声明更复杂的情况,例如使用 if
、exists
、changes
。另外,这个:
Rules can't be used in combination with only/except because it is a replacement for that functionality. If you attempt to do this, the linter returns a key may not be used with rules error.
更有理由切换到 rules
。这是我的解决方案,它执行 npm ci
:
- 如果
package-lock.json
文件被修改
或
- 或者如果
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
希望对您有所帮助!
规则: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
我们通过共享缓存在多个分支上成功地使用了它。
我在 gitlab 中有一个带有 angular 前端和 nestjs 后端的 monorepo。我对它们每个都有 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 分钟,即使我没有改变任何应该存在的东西......我错过了什么吗?我怎样才能以某种方式缓存它,以便它只在缓存过时或不存在时才重新安装依赖项?
最后我认为我可以在不依赖 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
这样做的好处是它只会为项目的 specific 部分安装 dependencies,如果它还没有 node_modules 或者什么时候package.json 已更改。但是,如果我推送多个提交并且 package.json 不会在最后一个中更改,这可能是错误的。在那种情况下,我仍然可以手动清除缓存并重新运行管道,但我会尝试进一步改进我的脚本并更新我的答案。
我遇到了同样的问题,我可以使用关键字 rules
而不是 only|except
来解决它。使用它,您可以声明更复杂的情况,例如使用 if
、exists
、changes
。另外,这个:
Rules can't be used in combination with only/except because it is a replacement for that functionality. If you attempt to do this, the linter returns a key may not be used with rules error.
更有理由切换到 rules
。这是我的解决方案,它执行 npm ci
:
- 如果
package-lock.json
文件被修改
或
- 或者如果
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
希望对您有所帮助!
规则: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
我们通过共享缓存在多个分支上成功地使用了它。