这篇脚本通过 **GitHub Actions** 实现了 **CI/CD(持续

这篇脚本通过 GitHub Actions 实现了 CI/CD(持续集成/持续部署)

通俗地说,你是在 GitHub 的服务器上雇佣了一个“虚拟机器人”。每当你把代码推送到 main 分支时,这个机器人就会醒来,在一台全新的、干净的 Linux 电脑上,把你手动原本要做的所有事情(改版本号、提交、发布)快速执行一遍。

下面我将从流程拆解底层原理两个维度为你详细剖析。


一、 流程拆解:机器人具体干了什么?

这个脚本是按顺序执行的,我们可以把它看作一条流水线:

1. 触发机制 (Trigger)

on:  
  push:  
    branches:  
      - main  
  • 动作:你在本地执行了 git push
  • 原理:GitHub 接收到 push 事件,检查分支匹配 main,于是分配一台 Linux 虚拟机(Runner)开始工作。

2. 赋予权限 (Permissions)

permissions:  
  contents: write  # 允许修改仓库代码  
  id-token: write  # 允许生成身份令牌  
  • 原理:默认情况下,机器人只有“读”代码的权限。因为我们需要它修改版本号并写回仓库git push),所以必须给 contents: write 权限。id-token 是为了 npm 的来源证明(Provenance)。

3. 准备环境 (Setup)

  • Checkout: 下载你的代码。注意这里用了 token: ${{ secrets.GITHUB_TOKEN }},这是机器人自带的一把“万能钥匙”,让它有权代表你操作仓库。
  • Setup Node: 安装 Node.js v18 环境。
  • Git Config: 告诉 git “我是谁”。机器人需要配置用户名(GitHub Action)和邮箱,否则无法生成 commit。

4. 核心魔法:自动升级版本 (npm version)

run: |  
  npm version patch -m "chore(release): bump version to %s [skip ci]"  

这是最关键的一步,底层发生了连锁反应:

  1. 修改文件:它读取 package.json,把 version 从 1.3.5 改成 1.3.6
  2. Git Commit:它自动执行 git add package.jsongit commit
  3. Git Tag:它自动打了一个 v1.3.6 的标签。
  4. 生成提交信息:提交信息里包含了 [skip ci](这一点至关重要,后面细说)。

5. 写回仓库 (Sync Back)

run: git push  
  • 动作:机器人把刚才生成的 Commit(包含新版本号)和 Tag 推送回你的 GitHub 仓库。
  • 结果:你的 GitHub 仓库现在的代码版本变成了 1.3.6

6. 发布到 npm (Publish)

run: npm publish --provenance  
env:  
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}  
  • 原理:机器人拿着你存好的 NPM_TOKEN(相当于你的 npm 账号密码),向 npm 官方服务器发起请求,上传文件。
  • --provenance:这是一个安全功能,它告诉 npm:“这个包是由 GitHub 仓库的自动化脚本构建的,不是某个黑客在地下室偷偷上传的”,这会给你的 npm 包页面增加一个绿色的“来源可信”徽章。

二、 底层原理与关键技术点

1. 身份认证:它是怎么登录的?

整个过程涉及两个系统的认证:

  • 对 GitHub 的认证:使用 GITHUB_TOKEN。这是一个临时的、自动生成的令牌。它让脚本有权把修改后的 package.json 推送回仓库。
  • 对 npm 的认证:使用 NPM_TOKEN。这是你手动从 npm 生成并填入 GitHub Secrets 的。环境变量 NODE_AUTH_TOKEN.npmrc 文件读取,从而完成登录。

2. 防止“无限死循环” ([skip ci])

这是一个非常巧妙的机制。

  • 风险

    1. 你 Push 代码 -> 触发 Action。
    2. Action 改版本号并 Push 回去 -> GitHub 认为又有新代码来了
    3. 再次触发 Action -> 改版本号 -> Push...
    4. 死循环,版本号瞬间爆炸。
  • 原理
    GitHub 系统在检查触发条件时,会扫描 Commit Message。如果你在 npm version 的 message 里写了 [skip ci](或者 [ci skip]),GitHub 就会知道:“哦,这次提交是机器人自己干的,不用再触发流水线了。”
    这就是打断无限循环的熔断器。

3. 为什么用 npm ci 而不是 npm install

脚本里写的是 npm ci

  • npm install:可能会修改 package-lock.json,比较慢,适合人写代码时用。
  • npm ci (Clean Install)严格按照 package-lock.json 安装依赖,速度快,不修改文件。这是 CI/CD 环境的标准做法,保证了“你在本地测的是什么,发布的就是什么”。

三、 总结

这个脚本构建了一个闭环

  1. :负责写业务代码。
  2. GitHub Action:负责脏活累活(改版本、打标签、发包)。
  3. npm:负责分发。

你实际上是把**“发布经理”**这个职位,外包给了这一段 50 行的代码。这就是 DevOps(开发运维一体化)的魅力。