GitHub Actions 工作流程:静态部署、同步 Fork 与构建镜像
本文示例面向 GitHub.com 的 Ubuntu 托管运行器。每段 YAML 是独立工作流,放在目标仓库的 .github/workflows/ 目录;先替换分支、项目路径和镜像名称,再按需启用。自托管运行器需核对各 Action 的最低运行器要求,不能只把旧版本号替换掉。
自动化部署到腾讯云 COS
下面以 npm 管理的 VitePress 项目为例:仓库已提交 .nvmrc、package-lock.json,docs:build 脚本生成 docs/.vitepress/dist。使用其他构建工具时,一并替换安装命令、构建脚本和输出目录。
获取 API 密钥
为发布任务创建独立的腾讯云子用户,授权范围限定到目标存储桶或发布前缀,并按上传、列举等实际操作设置权限。将 SecretId 和 SecretKey 保存到 GitHub Secrets,不写入仓库或日志。
获取 COS 桶信息
记录存储桶完整名称(含 APPID 后缀)和地域,例如 ap-shanghai。另行配置 COS 静态网站、域名和 HTTPS;文件上传成功不代表域名、缓存及访问权限已经正确。
配置 Secrets
在仓库的 Settings → Secrets and variables → Actions 中创建以下 Secrets,名称与示例保持一致:
| Secret | 内容 |
|---|---|
SecretId | 发布子用户的 SecretId |
SecretKey | 对应 SecretKey |
Bucket | 目标存储桶完整名称 |
Region | 存储桶地域 |
创建工作流
将以下示例保存为 .github/workflows/deploy-cos.yml。默认只发布 main,并允许手动触发;BUILD_DIR 必须指向构建产物,不能直接上传整个仓库。
yaml
name: Deploy static site to COS
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: deploy-cos
cancel-in-progress: false
jobs:
deploy:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
env:
BUILD_DIR: docs/.vitepress/dist
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npm run docs:build
- name: Check output
run: test -f "$BUILD_DIR/index.html"
- uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install COSCMD
run: python -m pip install coscmd
- name: Upload build output
env:
SECRET_ID: ${{ secrets.SecretId }}
SECRET_KEY: ${{ secrets.SecretKey }}
BUCKET: ${{ secrets.Bucket }}
REGION: ${{ secrets.Region }}
run: |
coscmd config -a "$SECRET_ID" -s "$SECRET_KEY" -b "$BUCKET" -r "$REGION"
coscmd upload -r "$BUILD_DIR/" /示例会上传并更新同名对象,保留远端旧文件;删除已下线页面需要另外核对范围和执行清理。首次发布可用专用测试桶,检查首页、深层文章、资源路径和 HTTPS。长期使用时,将通过验证的 COSCMD 版本固定到依赖清单。
参数说明见 腾讯云 COSCMD 文档。
Fork 仓库后定时拉取原项目 Commits
如果 Fork 不维护自己的分叉提交,可以用 gh repo sync 做快进同步。以下示例不使用 --force:分支分叉时会失败并留下日志,便于人工处理。
yaml
name: Sync fork
on:
workflow_dispatch:
schedule:
- cron: '40 16 * * *'
permissions:
contents: write
concurrency:
group: sync-fork
cancel-in-progress: false
jobs:
sync:
if: github.event.repository.fork == true
runs-on: ubuntu-latest
steps:
- name: Fast-forward from parent
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DESTINATION: ${{ github.repository }}
SYNC_BRANCH: main
run: gh repo sync "$DESTINATION" --branch "$SYNC_BRANCH"40 16 * * * 是 UTC 16:40,即北京时间次日 00:40。将 SYNC_BRANCH 改为父仓库和 Fork 中需要同步的同名分支。工作流需存在于默认分支,Fork 的 Actions 和定时任务也需启用;定时运行不保证精确到秒。
自动同步 Fork 上游仓库的适用边界
上面的任务只适合允许直接快进的分支。以下情况应调整流程:
- Fork 保留独立修改:先把上游变更引入单独分支,解决冲突并通过 PR 审查,不自动用
ours隐藏冲突。 - 受保护分支要求 PR 或检查:遵守对应规则,改用同步 PR;不给机器人设置绕过规则的权限。
- 上游改动工作流文件时出现权限错误:核对 GitHub 对该凭据及文件的授权要求,不直接改成全权限令牌。
- 需要同步后触发下游 CI:
GITHUB_TOKEN产生的普通推送通常不会触发新的工作流;应明确设计后续任务或手动触发,而不假设同步等于部署。
手动运行一次后,对比父仓库与 Fork 的目标提交,再启用计划任务。参考 gh repo sync 与 工作流触发规则。
自动构建和上传镜像
以下示例将仓库根目录的 Dockerfile 构建为 Docker Hub 镜像。将 DOCKERHUB_USERNAME 设为仓库变量,把有推送权限的访问令牌保存为 DOCKERHUB_TOKEN Secret,并替换镜像名中的 example。
yaml
name: Build and push image
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: publish-image
cancel-in-progress: false
jobs:
image:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
push: true
tags: |
${{ vars.DOCKERHUB_USERNAME }}/example:latest
${{ vars.DOCKERHUB_USERNAME }}/example:${{ github.sha }}构建子目录时同时核对 context 与 Dockerfile 路径。这里使用工作区路径作为上下文,构建前生成的文件才会被读取;.dockerignore 应排除密钥和无关文件。发布后核对镜像摘要,并在自己的运行环境检查应用能否启动。
参考 Docker Build Push Action 官方示例。
自动合并拉取请求
先在仓库开启自动合并,并为目标分支配置所需检查和审核规则。下面仅为指定机器人作者的非草稿 PR 启用自动合并;是否最终合并由分支规则决定。
yaml
name: Enable auto-merge for image bot
on:
pull_request_target:
types: [opened, reopened, ready_for_review, synchronize]
permissions:
contents: write
pull-requests: write
jobs:
enable:
if: github.event.pull_request.user.login == 'imgbot[bot]' && github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- name: Enable auto-merge
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_HEAD: ${{ github.event.pull_request.head.sha }}
run: gh pr merge "$PR_URL" --auto --squash --match-head-commit "$PR_HEAD"此工作流只调用 GitHub API,不检出或运行 PR 分支中的代码。pull_request_target 使用目标仓库权限,不能在这里追加来自 PR 的构建脚本。作者白名单只决定是否启用自动合并,不能代替必需检查和审查;没有设置合并条件时,--auto 也可能直接合并。
若仓库强制使用合并队列,按队列规则调整合并参数与检查事件。参考 GitHub 事件说明、令牌权限 和 gh pr merge。