
终于写到第 4 部分了,这个系列也该收尾了。简单回顾一下我们之前折腾的东西:
到这一步,你的流程已经比很多中小厂要专业了。但如果你盯着 Action 的执行日志看,会发现一个让人血压飙升的瓶颈:依赖安装那叫一个慢。
每次 push,机器人都在老老实实地重新下载 node_modules(这玩意儿被戏称为"宇宙黑洞")和 NuGet 包,从零开始。这篇把缓存配上,再给 main 分支加个保护锁。
在 CI/CD 语境下,缓存就是把上一次构建的依赖包存起来。如果你的 package-lock.json 或者 .csproj 没变,GitHub Actions 直接把缓存目录恢复出来,几秒钟搞定,省掉下载那一步。
如果你用的是最新版的 setup-node action,缓存已经内置了,只需要打开开关、告诉它 lock 文件在哪。因为项目在 /frontend 子目录下,路径要对应上。
打开 Part 1 的 yml 文件,找到 Node.js 那步,改成这样:
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' # 开启缓存! cache-dependency-path: './frontend/package-lock.json' # 指向子目录 完事。就加这两行,npm ci 的执行时间能降一大截。
C# 这边要用专门的缓存 action(actions/cache)。它需要三个参数:存什么(路径)、怎么命名(key)、找不到精确匹配时用什么回退(restore-keys)。
在 dotnet restore 之前加这段:
- name: Cache NuGet Packages uses: actions/cache@v4 with: path: ~/.nuget/packages # 根据操作系统和项目文件生成唯一 key key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/packages.lock.json') }} restore-keys: | ${{ runner.os }}-nuget- 第一次跑还是正常下载,但跑完会把缓存存起来。之后再看日志,你就会体验到什么叫"秒恢复"。
假设你在做一个工具库,需要兼容 Node 18、20、22 三个版本,或者要在多个操作系统上同时验证,怎么办?
不用复制粘贴 YAML,用 Matrix 策略就行:
jobs: build-frontend: runs-on: ubuntu-latest strategy: matrix: node-version: [18.x, 20.x, 22.x] # GitHub 会同时跑 3 个 Job! steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} 用了 matrix,GitHub Actions 会自动生成并行任务。如果某个版本翻车了,其他两个正常跑,一眼就能看出是哪个版本的兼容性问题。
流水线跑得再漂亮,有个毛用?万一哪个急性子开发者直接点"Merged"把没跑完的 PR 合进去了呢?
自动化必须强制执行才有效。GitHub 的 Branch Protection Rules 就是干这个的。
搞定之后,GitHub 那个绿油油的 Merge 按钮会变成灰的、点不动。只有当流水线完整跑完、Angular 编译通过、.NET 测试全绿,才会解锁。
恭喜你把这个四部曲跟完了。如果每一步都落地了,你已经从"FTP 拖文件上线"选手进化成了具备专业、安全、敏捷交付能力的工程师。
流水线编排、Secret 管理、自建 Runner、语义化版本——这些能力在任何团队都是稀缺货。GitHub Actions 的上限远不止"push 代码触发构建"这么简单。
你的 CI/CD 流水线现在耗时多少?上了缓存之后省了多少时间?欢迎在评论区晒一下你的配置,或者吐槽踩过的坑。