用 commit message 触发 GitHub Actions 自动发版

在软件开发中,版本发布是一个重要但容易出错的环节。传统的流程往往包括:

  • 手动更新版本号
  • 手动打 tag
  • 手动编写 Release Notes
  • 手动上传构建产物

这不仅繁琐,还容易出错。每次都是一样的步骤,也每次都可能漏掉一步

现在的做法是把版本号写进 commit message,剩下的交给 GitHub Actions

约定

commit message 里带 [release/vX.Y.Z] 就是正式发布,否则是普通 CI 构建,只生成预发布版本

feat: 添加用户登录功能 [release/v1.2.0]

这样可以区分正式版本(用于发布)与 CI 版本(用于预览或测试),两者走同一条流水线,只在最后的发布和部署步骤上分开

判断发布类型

- name: Determine Release Type
  id: determine-release
  run: |
    if [[ "${{ github.event.head_commit.message }}" =~ \[release\/v([0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?)\] ]]; then
      echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT
      echo "TAG_NAME=v${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT
    else
      echo "RELEASE_TYPE=ci" >> $GITHUB_OUTPUT
      echo "TAG_NAME=ci-${GITHUB_RUN_NUMBER}" >> $GITHUB_OUTPUT
    fi

正则允许 -beta1 这类后缀。没有匹配到就用 run number 作为 tag,形如 ci-123

创建 Release 并上传构建产物

借助 GitHub CLI,可以在 CI 中直接创建 Release 并上传产物:

- name: Create Release
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    RELEASE_TYPE: ${{ steps.determine-release.outputs.RELEASE_TYPE }}
  run: |
    gh release create "${{ steps.determine-release.outputs.TAG_NAME }}" \
      --title="${{ github.repository }} ${{ steps.determine-release.outputs.TAG_NAME }}" \
      --generate-notes \
      $([[ "$RELEASE_TYPE" == "ci" ]] && echo "--prerelease") \
      ./release.tar.gz

这一步的好处:

  • --generate-notes 让 GitHub 根据两次 tag 之间的 commit 和 PR 自动生成 Release Notes,不用手写
  • CI 构建加上 --prerelease,在 Release 列表里和正式版分开显示
  • 产物直接跟在命令末尾,可以一次上传多个文件

GITHUB_TOKEN 就足够,不需要另外配置 Personal Access Token。仓库 Settings 里给 Actions 的权限至少要有 contents: write

与自动部署流程集成

只有正式发布才执行部署 job,产物从刚创建的 Release 里下载,而不是从上一个 job 的 artifact 里取:

deploy:
  needs: build
  runs-on: ubuntu-latest
  if: ${{ needs.build.outputs.release_type == 'release' }}
  steps:
    - name: Download Release
      uses: robinraju/release-downloader@v1
      with:
        repository: ${{ github.repository }}
        tag: ${{ needs.build.outputs.tag_name }}
        fileName: release.tar.gz

这样部署的产物和 Release 页面上挂的产物一定是同一份。随后用 rsync + 动态密码上传到服务器,做到:

  • 自动拉取构建产物
  • 使用临时密码安全上传
  • 成功后自动清理,失败自动重试

上传步骤的具体写法见 用 GitHub Actions + 动态密码部署构建产物

安全注意事项

  • 使用 GITHUB_TOKEN,避免在 Secrets 里存放 Personal Access Token
  • 给 Actions 配置最小权限,只开 repo 和 release 相关的写权限
  • 设置 PR 模板,提醒 commit message 规范
  • 日志中屏蔽 IP 和敏感信息
  • 配合动态密码机制,部署环节没有长期凭证

头图素材:Katie Moum on Unsplash

评论

评论加载中…

输入关键词开始搜索。

选择Enter 打开Esc 关闭CtrlK 唤起