使用Github Actions打包前端项目并自动上传到Releases
前言
应公司业务需求,最近在写一个谷歌插件,我本来想手动build后将dist目录打包成zip手动Releases一下,但leader说这样太浪费时间了,让我用github的Actions来做,我也是头一回接触这个,两眼一抹黑,花了点时间了解后,成功实现了该功能,可以理解为actions就是预先定义的操作步骤,将多个步骤组合成一个workflows工作流,每次通过触发条件触发这个工作流,有点类似CI/CD的感觉。
教程
创建workflows
首先我们需要在项目根目录创建文件夹:
.github
└─ workflows
创建一个.github
目录,在该目录下再创建一个workflows
目录,之后所有的工作流文件.yml都存放在workflows这个目录下。
创建yml文件
文件名是随意的,比如我这次是处理Releases的,所以我可以创建一个releases.yml
文件。
├─ .github
│ └─ workflows
│ └─ releases.yml
vscode 插件安装
建议安装下github官方插件: GitHub Actions
有了这个插件能在编写yml文件时有代码高亮和语法提示,本来官方还可以查看工作流的状态的,但是我实际使用发现一直在加载数据中,不知道什么原因。
配置工作流名称和触发条件
releases.yml
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
yml文件中,代码的缩进是非常重要的,不同的缩进长度表示的层级就不同,根就是0缩进,比如这里的name名称和on监听触发条件,都是根上的。
我的需求是当代码push到main主分支或者手动触发时才会调用这个工作流,所以这里on监听的就是push条件,分支为main,如果你有多个分支可以自动手动增加。
注意:合并分支也是push操作哦
增加工作jobs
一个yml文件可以配置很多个job工作,而工作下面就是具体的操作步骤,而管理所有job的入口,也就是父级,就是jobs。
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
job1:
job2:
增加build的job工作
我们增加一个打包项目的工作,但是在打包时我们需要一个代码的运行环境,我们采用github官方提供的:ubuntu-latest
系统,你可以理解为这个系统就是docker的系统,只不过github官方给你提供了这个镜像,当然你也可以自己上传,但是这个就跟本次教程无关了。
官方提供的镜像一般都会预装一些基础环境依赖,但是不可能所有要用到的依赖都会安装,比如node它就默认没有,如果你想了解官方的镜像有哪些,可以打开下面这个链接:
你可以看到针对开源的仓库和私有的仓库,镜像和对应的资源是略有不同的,开源的仓库硬件会更强一些,并且除了linux还有windows和mac环境。
如果你想了解对应的镜像里面有哪些预设依赖,可以查看这个仓库:
点击对应的Included Software列下面的链接,可以查看对应镜像的依赖列表。
了解完镜像后我们通过runs-on
来配置需要的镜像
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
前端用ubuntu-latest
就行了
创建步骤
工作创建好后还需要有相应的操作步骤来处理具体的事情,每个工作都可以有很多步骤,所以需要一个统一的入口来进行管理。
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- 具体步骤1
- 具体步骤2
...
步骤:克隆仓库代码
现在linux环境有了,我们还需要把当前仓库的代码clone到这个镜像里面去,如果仓库是一个开源的仓库,那就非常简单了。
开源仓库
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
run: |
git clone https://github.com/<your-username>/<your-repository>.git
cd <your-repository>
git checkout main
你需要把<your-username>
和<your-repository>
替换成具体的内容。
私有仓库
但是如果你是一个私有的仓库,就需要考虑token校验的问题,没有token是没法克隆的,甚至于你还需要配置下git全局配置。
对于token,我们有两种方式,一种是创建账号级的token,一种是github官方预设的仓库级token。
账号级的token可以用于该账号下的所有仓库,而官方预设的只能针对当前运行actions工作流的仓库。
如果你想要账号级的,就得去账号设置中,找到底部的Developer settings,打开该页面,找到Personal access tokens
选项下的tokens(classic)菜单,点击右上角的Generate new token
按钮自己生成一个。
创建成功后你会得到token字符串,复制后去到需要克隆的仓库页面,在仓库的Settings页面找到Secrets and variables
选项,点击里面的Actions菜单,在打开的页面中找到Repository secrets
,新增一个仓库密匙,记得Name就是到时候要用的变量名了,推荐大写加下划线,自己取名,Secret就填刚刚复制的token,保存即可。
假设我们这里的name为:MY_TOKEN
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: git全局设置
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: 克隆代码
env:
TOKEN: ${{ secrets.MY_TOKEN }}
run: |
git clone https://x-access-token:${TOKEN}@github.com/<your-username>/<your-repository>.git
cd <your-repository>
git checkout main
我们将git全局配置设置成github的机器人默认账号,这样你的操作显示就为显示为机器人,方便区分。
然后我们将刚刚设置的token设置成env变量,在clone的时候使用。
如果你只想使用仓库级的token,直接把MY_TOKEN
替换成GITHUB_TOKEN
就行了。
TOKEN: ${{ secrets.GITHUB_TOKEN}}
使用官方预设工作
克隆仓库这一步重复率非常高,为此github官方也提供了封装好的工作,我们可以在步骤中通过uses
来使用官方提供的工作,从而减少代码的重复编写。
- github仓库:checkout
目前这个仓库有v2、v3、v4版本,v4是目前推荐版本。
开源仓库
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
ref: main # 指定主分支
私有仓库
默认情况下该工作流会直接使用secrets.GITHUB_TOKEN
,如果只想使用仓库级token,那么就和上面开源仓库一样,不需要额外加什么代码,如果你一定要指定token,代码如下:
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
token: ${{ secrets.MY_TOKEN }}
ref: main # 指定主分支
步骤:安装node
由于环境中没有node,我们还需要手动安装,我们也别手搓了,github官方也给咱们预设了,仓库地址:
这个工作流也有好几个版本,其中V4版是目前推荐的,因为node16已经停止维护,所以v4适合新的node版本,如果是旧的,你可以使用v3看看,具体需要自己去测试一下,我没有具体去研究。
使用v3大概率会得到一个警告:
The following actions use a deprecated Node.js version and will be forced to run on node20: actions/checkout@v3, actions/setup-node@v3. For more info: https://github.blog/changelog/2024-03-07-github-actions-all-actions-will-run-on-node20-instead-of-node16-by-default/
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
ref: main # 指定主分支
- name: 指定Node.js版本
uses: actions/setup-node@v4
with:
node-version: "20" # 指定 Node.js 20 版本
如果你的项目根目录下就是开发文件,存在package.json
文件,那么你可以直接在指定node版本后增加一个run选项来安装你的依赖,这里我就直接引用下官方示例:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm test
步骤:安装pnpm
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
ref: main # 指定主分支
- name: 指定Node.js版本
uses: actions/setup-node@v4
with:
node-version: "20" # 指定 Node.js 20 版本
- name: 安装pnpm
run: npm install -g pnpm@latest
由于github的运行是在国外,所以我们不需要换源,简直不要太爽。
步骤:安装依赖
我的项目结构如下:
serverless-template
├─ chrome-extension
├─ README.md
├─ docs
└─ serverless-template
其中chrome-extension目录下才是我的开发文件,所以我们安装依赖前还需要进入到该目录。
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
ref: main # 指定主分支
- name: 指定Node.js版本
uses: actions/setup-node@v4
with:
node-version: "20" # 指定 Node.js 20 版本
- name: 安装pnpm
run: npm install -g pnpm@latest
- name: 安装依赖
run: |
cd chrome-extension
pnpm install
|符合是用于多行命令时才会用到
步骤:打包项目
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
ref: main # 指定主分支
- name: 指定Node.js版本
uses: actions/setup-node@v4
with:
node-version: "20" # 指定 Node.js 20 版本
- name: 安装pnpm
run: npm install -g pnpm@latest
- name: 安装依赖
run: |
cd chrome-extension
pnpm install
- name: 打包插件
run: |
cd chrome-extension
pnpm run build
需要注意的是,每次step步骤都是一次新的shell环境执行,所以我这里需要重新cd进入chrome-extension目录。
步骤:创建zip文件
我们需要将打包后的dist目录打成压缩包上传到Release,所以我们得用linux的zip命令制作压缩包文件。
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
ref: main # 指定主分支
- name: 指定Node.js版本
uses: actions/setup-node@v4
with:
node-version: "20" # 指定 Node.js 20 版本
- name: 安装pnpm
run: npm install -g pnpm@latest
- name: 安装依赖
run: |
cd chrome-extension
pnpm install
- name: 打包插件
run: |
cd chrome-extension
pnpm run build
- name: 创建谷歌浏览器扩展zip文件
run: |
cd chrome-extension
zip -r ../chrome-extension.zip ./dist
- name: 创建serverless模版zip文件
run: |
zip -r ./serverless-template.zip ./serverless-template
当我们命令太长也可以使用|
来实现换行效果。
这里我们可以看到,第一个path表示的是压缩包文件存放路径和文件名,第二个需要压缩的path。
../
和./
我就没必要解释了吧!
步骤:获取版本号
我们在发布Release时,一般都是将标题设置为:v0.0.0.x这种版本号形式,那么最简单便捷的就是从package.json
文件中获取它的version
,而package中的version,又可以通过插件bumpp
实现命令交互式更新。
我们在项目中安装这个依赖:
pnpm i bumpp -D
然后在package.json中配置一个scripts:
{
"scripts": {
"version:update": "npx bumpp --no-commit --no-tag --no-push"
}
}
我们在开发完成,确定没问题后就可以通过运行pnpm run version:update
来更新版本号,然后提交到git上去。
既然version的来源已经搞定,我们在步骤中就好办了。
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
ref: main # 指定主分支
- name: 指定Node.js版本
uses: actions/setup-node@v4
with:
node-version: "20" # 指定 Node.js 20 版本
- name: 安装pnpm
run: npm install -g pnpm@latest
- name: 安装依赖
run: |
cd chrome-extension
pnpm install
- name: 打包插件
run: |
cd chrome-extension
pnpm run build
- name: 创建谷歌浏览器扩展zip文件
run: |
cd chrome-extension
zip -r ../chrome-extension.zip ./dist
- name: 创建serverless模版zip文件
run: |
zip -r ./serverless-template.zip ./serverless-template
- name: 获取新版本号
id: get_chrome_extension_version
run: |
# 尝试从 package.json 中获取版本号
VERSION=$(node -p "require('./chrome-extension/package.json').version" 2>/dev/null || echo "v0.0.1")
echo "VERSION=${VERSION}" >> $GITHUB_ENV
echo "New version:${VERSION}"
读取package.json
的版本号,以防万一做个判空,为空时返回v0.0.1
,并将这个值设置成全局环境变量VERSION
。
步骤:创建Release
创建Release这个步骤也是高频操作,所以github官方也预设了工作流,仓库地址:
目前有v1和v2版本,v2是推荐版本。
我自己的创建逻辑相对简单,只要main有push操作,就进行一次构建发布,有的人可能需要更加精准,比如官方示例中的,他会判断这次push有tag变动才会发布,代码示例如下:
name: Main
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: echo ${{ github.sha }} > Release.txt
- name: Test
run: cat Release.txt
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: Release.txt
if条件判断,如果这次提交有tags标签,才会执行,如果你有其他条件,可以看文档自己调整。
其中with下的files表示需要上传的文件,是可以上传多个的,多个也是用|
管道符来编写。
对于token,默认也是会用secrets.GITHUB_TOKEN
,如果需要指定,也是配置token
属性。
name: 打包插件并发布到Releases
# 检测只有主分支的push操作会触发该工作流
on:
push:
branches:
- main
workflow_dispatch: # 允许手动触发该工作流
jobs:
build:
name: 打包工作
runs-on: ubuntu-latest
steps:
- name: 克隆代码
uses: actions/checkout@v4
with:
ref: main # 指定主分支
- name: 指定Node.js版本
uses: actions/setup-node@v4
with:
node-version: "20" # 指定 Node.js 20 版本
- name: 安装pnpm
run: npm install -g pnpm@latest
- name: 安装依赖
run: |
cd chrome-extension
pnpm install
- name: 打包插件
run: |
cd chrome-extension
pnpm run build
- name: 创建谷歌浏览器扩展zip文件
run: |
cd chrome-extension
zip -r ../chrome-extension.zip ./dist
- name: 创建serverless模版zip文件
run: |
zip -r ./serverless-template.zip ./serverless-template
- name: 获取新版本号
id: get_chrome_extension_version
run: |
# 尝试从 package.json 中获取版本号
VERSION=$(node -p "require('./chrome-extension/package.json').version" 2>/dev/null || echo "v0.0.1")
echo "VERSION=${VERSION}" >> $GITHUB_ENV
echo "New version:${VERSION}"
- name: 创建Release
id: create_release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.VERSION }}
name: v${{ env.VERSION }}
draft: false
prerelease: false
files: |
./chrome-extension.zip
./serverless-template.zip
指定token:
- name: 创建Release
id: create_release
uses: softprops/action-gh-release@v2
with:
token: ${{ secrets.MY_TOKEN }}
tag_name: ${{ env.VERSION }}
name: v${{ env.VERSION }}
draft: false
prerelease: false
files: |
./chrome-extension.zip
./serverless-template.zip
除了token,我还指定了tag_name
、name
,这两个都是创建Release必填的。
draft
的值为布尔值,表示这次是否为草稿;prerelease
的值为布尔值,表示这次是否为预发布版本;
当然with还有很多配置项,具体可以查看仓库文档。
步骤的id作用
关于步骤中的id,其实在本流程中可以要,也可以不要,配置了id可以被其他步骤通过id获取该步骤的echo输出。
示例:
- name: 获取版本号
id: get_version
run: echo "version=1.0.0" >>$GITHUB_ENV
- name: 使用版本号
run: echo "The version is ${{ steps.get_version.outputs.version }}"
触发
当我们给main分支push代码的时候,或者合并分支的时候,都会触发该工作流,我们可以在仓库的Actions中查看进展。
这是自动操作,我这里还配置了手动触发,我们点击具体的工作流,在该页面右上角可以手动运行。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据