跳转至内容
飞翔园地
返回

Github Actions 记录

更新于:

Table of contents

Open Table of contents

Docker镜像构建通用Actions脚本

创建.github/workflows/build-image.yml内容如下:

name: Build and Push Docker Image

on:
  push:
    branches: [ main ]
  workflow_dispatch: # 支持手动点击按钮构建

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write # 必须赋予写入 Packages 的权限

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Log in to the Container registry
        uses: docker/login-action@v4
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v6
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=raw,value=latest

      - name: Build and push Docker image
        uses: docker/build-push-action@v6
        with:
          context: . # 指定根目录的Dockerfile
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

这样每次push之后都会自动构建根目录下的Dockerfile并形成ghcr.io的镜像。

自动更新pnpm的Lockfile

添加.github/workflows/update-lockfile.yml如下:

name: Auto Update pnpm Lockfile

on:
  push:
    branches:
      - main # 如果你的默认分支是 master,请改为 master
    paths:
      - 'package.json' # 只有当 package.json 改变时才触发
  workflow_dispatch:

permissions:
  contents: write # 必须赋予写权限,否则无法推代码

jobs:
  update-lockfile:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Install Node.js
        uses: actions/setup-node@v6.4.0

      - name: Install pnpm
        uses: pnpm/action-setup@v6.0.8
        with:
          run_install: false

      - name: Update Lockfile
        run: pnpm install --no-frozen-lockfile

      - name: Commit and Push changes
        run: |
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@://github.com"
          
          # 检查是否有文件变动
          if [ -n "$(git status --porcelain pnpm-lock.yaml)" ]; then
            git add pnpm-lock.yaml
            git commit -m "chore: auto update pnpm-lock.yaml"
            git push
          else
            echo "Lockfile is already up to date."
          fi

这样,我们只管更新package.json(比如AstroPaper的),然后直接push就行了。彻底免除本地调试。

定期执行Actions

可以设置cron如下:

on:
  workflow_dispatch:
  schedule:
    - cron: '0 22 * * 5' # UTC+0时区下,每周五的22:00运行

Job运行于容器内

首先,声明容器:

jobs:
  build:
    runs-on: ubuntu-latest
    
    # 核心配置:指定该 Job 运行在你自定义的 Docker 容器中
    container:
      image: ghcr.io/user/repo:latest
      # 如果你的镜像是【私有】的,需要取消下方 credentials 的注释,并确保有权限读取镜像
      # credentials:
      #   username: ${{ github.actor }}
      #   password: ${{ secrets.GITHUB_TOKEN }} # 或者使用具备 read:packages 权限的个人访问令牌 (PAT)

其次,需要注意任何命令都要在Docker中存在。

向另一个仓库推送

首先,创建一个仓库PAT:

  1. 在 GitHub 右上角头像 -> Settings -> Developer settings -> Personal access tokens (Fine-grained)。
  2. 点击 Generate new token,给它起个名字。
  3. Repository access 选择 Only select repositories,并选择你的目标仓库。
  4. Permissions 中找到 Repository permissions -> 在添加的搜索框中输入 Contents 并勾选 -> 设置为 Read and write。
  5. 生成令牌后复制它(它只会显示一次)。
  6. 回到你当前运行 Actions 的源仓库 -> Settings -> Secrets and variables -> Actions -> 点击 New repository secret。
  7. Name 填入 TARGET_REPO_PAT (或者其他名称),Secret 填入刚才复制的令牌。

然后,Actions先checkout目标仓库:

- name: Checkout Target Repo
uses: actions/checkout@v6
with:
    repository: 'user/目标仓库名'
    token: ${{ secrets.TARGET_REPO_PAT }} # 使用刚才配置的密钥
    path: 'target-repo' # 将目标仓库克隆到该子目录下

执行完操作后,最终push目标仓库:

- name: Push to Target Repo
  run: |
      # 进入目标仓库
      cd target-repo
      
      # 配置 Git 用户信息(用于提交显示)
      git config --global user.name "github-actions[bot]"
      git config --global user.email "github-actions[bot]@://github.com"
      
      # 检查是否有文件变动,防止没有变动时报错
      if [ -n "$(git status --porcelain)" ]; then
      git add .
      git commit -m "[skip ci]"
      git push origin main # 推送到目标仓库的 main 分支
      else
      echo "No changes to commit"
      fi

Docker环境下的仓库推送

如果在Docker容器环境中,需要多加一句:

- name: Commit and Push changes
  run: |
    git config --global --add safe.directory /__w/[repo]/[repo] // [!code ++]
    git config --global user.name "github-actions[bot]"
    git config --global user.email "github-actions[bot]@://github.com"
    
    # 检查是否有json文件变动
    if [ -n "$(git status --porcelain)" ]; then
      git add --all
      git commit -m "[skip ci]"
      git push
    else
      echo "No changes to commit"
    fi

如果推向自己的仓库,需要多加一句:

permissions:
  contents: write # 必须赋予写权限,否则无法推

以yt-dlp为例,GitHub内部可执行文件下载

如代码所示:

- name: Download yt-dlp
  uses: robinraju/release-downloader@v1
  with:
    repository: 'yt-dlp/yt-dlp'
    latest: true
    fileName: 'yt-dlp_linux'

- name: Make the yt-dlp_linux executable
  run: chmod +x yt-dlp_linux

// ...

- name: Delete the yt-dlp_linux executable
  run: rm -f yt-dlp_linux

以yt-dlp为例,Docker内直接通过API解析下载Latest的Release文件

在Dockerfile中,以部署yt-dlp本体可执行文件为例

ARG ORG_NAME=yt-dlp
ARG REPO_NAME=yt-dlp
ARG FILE_NAME=yt-dlp_linux
RUN LATEST_VERSION=$(curl -s https://api.github.com/repos/${ORG_NAME}/${REPO_NAME}/releases | grep -m 1 "tag_name" | cut -d'"' -f4) && \
    echo "${ORG_NAME}/${REPO_NAME} 最新版本是: ${LATEST_VERSION}" && \
    curl -L "https://github.com/${ORG_NAME}/${REPO_NAME}/releases/download/${LATEST_VERSION}/${FILE_NAME}" -o /usr/local/bin/${FILE_NAME} && \
    chmod a+rx /usr/local/bin/${FILE_NAME}

由于ARG LATEST_VERSION=$(curl ……)在Actions里面这样不行,只能写进RUN里面了。

在bash脚本中,以部署yt-dlp插件zip文件为例

ORG_NAME=Brainicism
REPO_NAME=bgutil-ytdlp-pot-provider
LATEST_VERSION=$(curl -s https://api.github.com/repos/${ORG_NAME}/${REPO_NAME}/releases | grep -m 1 "tag_name" | cut -d'"' -f4)

FILE_NAME=bgutil-ytdlp-pot-provider.zip 

echo "${ORG_NAME}/${REPO_NAME} 最新版本是: ${LATEST_VERSION}"
mkdir -p ~/yt-dlp-plugins
curl -L "https://github.com/${ORG_NAME}/${REPO_NAME}/releases/download/${LATEST_VERSION}/${FILE_NAME}" -o ~/yt-dlp-plugins/${FILE_NAME}

echo "${FILE_NAME} ok!"

Docker环境下的actions/checkout分析

如果Docker里不安装git,就会导致只能通过API下载压缩包然后解压的方式获取仓库内的文件。

所以,给Docker镜像里安装git是必要的。其他的actions/checkout操作本质上都一样,除了:

- name: Check out repository ERROR in docker env
  uses: actions/checkout@v6
  with:
    repository: 'Brainicism/bgutil-ytdlp-pot-provider'
    path: '/git/home/bgutil-ytdlp-pot-provider'
    fetch-depth: 1

上面这类操作是禁止的。只能把目录放到工作目录下。

比如:

- name: Check out repository
  uses: actions/checkout@v6
  with:
    repository: 'Brainicism/bgutil-ytdlp-pot-provider'
    path: 'bgutil-ytdlp-pot-provider'
    fetch-depth: 1

实际跑下来,fetch-depth: 1在Github Actions环境下,其实提速并不明显,除非仓库真的臃肿。

Actions中使用Docker的动静结合

虽然Docker在Actions中并非最佳的运行选择,但是,当自动安装ffmpeg的Actions调用的API接口暂时把Github IP给封禁的时候,真的就直接死在环境安装上。

借助Github内部网络的便捷,一边打包环境成Docker镜像,一边运行脚本反而更加稳定。

以yt-dlp为例,ffmpeg和deno几乎是必装的环境依赖。而实际上,yt-dlp并不需要ffmpeg和deno一直保持最新,只要版本不是特别老旧就可以了。

而yt-dlp几乎需要nightly版本来保证及时的更新与可靠性。yt-dlp_linux --update-to nightly这条命令在Actions环境下执行反而异常便利。

所以,不能因为yt-dlp需要保持最新而不采用Docker:提前固定ffmpeg和deno的环境以便稳定运行。


分享这篇帖子:

前一篇帖子
2026年06月08日 全球新闻
下一篇帖子
MIT Scientist: “Your Brain Evolved To Ignore Aliens – They’re Everywhere!”