基本概念

  • Workflows
    • 工作流,可以添加到存储库中的自动化过程。工作流由一个或多个作业组成,可以由事件调度或触发。
  • Event
    • 事件,触发工作流的特定动作。例如,向存储库提交 pr 或 pull 请求。
  • Jobs
    • 作业,在同一跑步器上执行的一组步骤。默认情况下,具有多个作业的工作流将并行运行这些作业。
  • Steps
    • 步骤,可以在作业中运行命令的单个任务。步骤可以是操作,也可以是 shell 命令。作业中的每个步骤都在同一个运行程序上执行,从而允许该作业中的操作彼此共享数据。
  • Actions
    • 操作是独立的命令,它们被组合成创建作业的步骤。操作是工作流中最小的可移植构建块。你可以创建自己的动作,或者使用 GitHub 社区创建的动作。
  • Runners
    • 运行器,安装了 GitHub Actions 运行器应用程序的服务器。。Github 托管的运行器基于 Ubuntu Linux、Microsoft Windows 和 macOS,工作流中的每个作业都在一个新的虚拟环境中运行。

Action

从基础概念不难得知,Action是最基础的操作之一,而Action实际上有一个市场GitHub Marketplace · Tools to improve your workflow,可以从这个市场里选择自己需要的Action去组合成Steps

选择对应的Action使用@指定对应版本,以actions/checkout为例,使用v2版本就是actions/checkout@v2Action一般需要指定名称Action及版本输入参数,当然Action完成后会输出一部分的参数,输入参数使用with指定,一个示例如下:

  - name: Login Registry
    id: login-docker
	uses: docker/login-action@v1
	with: 
	  registry: registry.cn-shanghai.aliyuncs.com
	  username: ${{ secrets.ALIYUN_USER }}
	  password: ${{ secrets.ALIYUN_PASSWORD }}

需要注意的是,名称可以任意,但是id则必须符合规范,禁止使用空格等特殊符号,可以参考常规变量命名规则。

如果不选择对应的Action,则可以直接执行命令来完成部分操作,如下:

  - name: Echo
	id: echo
	run: |
	  echo "msg=OK" >> $GITHUB_OUTPUT

获取对应Action的输出需要通过id指定,如:

  - name: Echo result
	id: echo-result
	run: |
	  echo ${{ steps.echo.outputs.msg }}

说明

直接以示例会更好理解

事件触发

Github Action是在指定事件发生后触发的,而事件有很多,这里只介绍常用的几种,其余可以参考文档Events that trigger workflows - GitHub Docs

Push

事件通过on关键字指定,譬如,在push后运行Github Action,则可以:

on:
  push

如果还需要指定对应的分支,则可以:

on:
  push:
    branches:
      - 'main'
      - 'releases/**'

注意这里可以使用通配符;而一般来说,我们可能在发布一个Release时,会push一个tag,而只想在发布Release时才运行Action的话,则可以:

on:
  push:
    tags:
      - v1.**

又或者,只需要在push了指定的文件的时候才运行Action,则可以:

on:
  push:
    paths:
      - '**.js'

这表明只有在pushjs文件时才会运行Action。

上面的条件实际可以组合起来,譬如只有在releases/**分支下push了js文件才运行Action:

on:
  push:
    branches:
      - 'releases/**'
    paths:
      - '**.js'

workflow_dispatch

Note: This event will only trigger a workflow run if the workflow file is on the default branch.

这个实际上是提供一个手动调用Github Action的事件,它仅会被手动触发。

schedule

这是一个定时的事件,在指定事件触发,如下格式:

on:
  schedule:
    # * is a special character in YAML so you have to quote this string
    - cron:  '30 5,17 * * *'

定时可以组合起来:

on:
  schedule:
    - cron: '30 5 * * 1,3'
    - cron: '30 5 * * 2,4'

你可以在Workflow中取到具体的定时时间,通过github.event.schedule获取,例如:

on:
  schedule:
    - cron: '30 5 * * 1,3'
    - cron: '30 5 * * 2,4'
 
jobs:
  test_schedule:
    runs-on: ubuntu-latest
    steps:
      - name: Not on Monday or Wednesday
        if: github.event.schedule != '30 5 * * 1,3'
        run: echo "This step will be skipped on Monday and Wednesday"
      - name: Every time
        run: echo "This step will always run"

Docker登陆

使用Docker的官方Action即可:

  - name: Login Registry
	uses: docker/login-action@v1
	with: 
	  registry: ${{ secrets.REGISTRY }}
	  username: ${{ secrets.USER }}
	  password: ${{ secrets.PASSWORD }}

将账密保存到仓库的Secrets中,不要直接写到文件里。

配置环境

Java环境

使用actions/setup-java@v3进行配置,如下:

- uses: actions/setup-java@v3
  with:
    distribution: 'zulu' # See 'Supported distributions' for available options
    java-version: '17'

支持的分支如下:

KeywordDistributionOfficial siteLicense
temurinEclipse TemurinLinkLink
zuluAzul Zulu OpenJDKLinkLink
adopt or adopt-hotspotAdoptOpenJDK HotspotLinkLink
adopt-openj9AdoptOpenJDK OpenJ9LinkLink
libericaLiberica JDKLinkLink
microsoftMicrosoft Build of OpenJDKLinkLink
correttoAmazon Corretto Build of OpenJDKLinkLink
semeruIBM Semeru Runtime Open EditionLinkLink
oracleOracle JDKLinkLink
dragonwellAlibaba Dragonwell JDKLinkLink

支持的版本如下:

  • 主版本: 8111617
  • 指定小版本: 17.011.011.0.48.0.2328.0.282+8
  • EA(Early Access)版本: 15-ea15.0.0-ea15.0.0-ea.215.0.0+2-ea

Nodejs

使用actions/setup-node@v3,如下:

- uses: actions/setup-node@v3
  with:
    node-version: 18

支持的版本如下:

  • 主版本: 141618
  • 指定小版本: 10.1516.15.1 , 18.4.0
  • NVM LTS语法: lts/erbiumlts/fermiumlts/*lts/-n
  • 使用最新版: * or latest/current/node

Golang

使用actions/setup-go@v4,如下:

steps:
  - uses: actions/checkout@v4
  - uses: actions/setup-go@v4
    with:
      go-version: '^1.13.1' # The Go version to download (if necessary) and use.
  - run: go version

支持的版本如下:

  • 指定版本: 1.151.16.11.17.0-rc.21.16.0-beta.1
  • SemVer版本范围语法: ^1.13.1>=1.18.0-rc.1

元数据提取

使用docker/metadata-action@v3提取:

  - name: Get Tag
	id: meta
	uses: docker/metadata-action@v3
	with:
	  images: |
		xxx/yyy

提取出来的元数据实例如下:

EventRefDocker Tags
pull_requestrefs/pull/2/mergepr-2
pushrefs/heads/mastermaster
pushrefs/heads/releases/v1releases-v1
push tagrefs/tags/v1.2.3v1.2.3latest
push tagrefs/tags/v2.0.8-beta.67v2.0.8-beta.67latest
workflow_dispatchrefs/heads/mastermaster

推送仓库

使用ad-m/github-push-action@master,如下:

  - name: Push changes
	uses: ad-m/github-push-action@master
	with: 
	  github_token: ${{ secrets.GITHUB_TOKEN }}
	  branch: ${{ github.ref }}

这里的secrets.GITHUB_TOKEN,不需要自己去定义,这是在Github Action中默认存在的,在推送前需要有commit操作,如下:

  - name: Commits files
	run: |
	  echo "Update repo version file..."
	  git config --local user.email "github-actions[bot]@users.noreply.github.com"
	  git config --local user.name "github-actions[bot]"
	  git add .
	  git commit -m "commment"
	  echo "File has been committed"

直接推送是默认禁用的,如果确实有需要,可以在仓库设置中的Actions/General设置成为可写:

示例

静态博客构建镜像并推送到Registry

直接看配置:

name: Blog CI
 
on:
  push:
    tags:
      - "*-build"
 
jobs:
  build:
    name: Build Docker image and auto deploy
    runs-on: ubuntu-latest
 
    steps:
      - name: Check out
        uses: actions/checkout@v2
 
      - name: Get Tag
        id: meta
        uses: docker/metadata-action@v3
        with:
          images: |
            registry.cn-shanghai.aliyuncs.com/evalexp-private/blog
 
      - name: Setup Nodejs
        uses: actions/setup-node@v3
        with:
          node-version: 16
 
      - name: Install Hexo
        run: npm install hexo -g
 
      - name: Install dependencies
        run: npm install
 
      - name: Generate Blog
        run: hexo g
 
      - name: Login Registry
        uses: docker/login-action@v1
        with:
          registry: registry.cn-shanghai.aliyuncs.com
          username: ${{ secrets.ALIYUN_USER }}
          password: ${{ secrets.ALIYUN_PASSWORD }}
 
      - name: Build and push
        uses: docker/build-push-action@v3
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

定时检查基础镜像是否更新并更新本镜像

直接看配置:

name: Auto Build Latest DERP
 
on:
  push:
  workflow_dispatch: 
  schedule:
    - cron: '0 0 * * *'
 
jobs:
  build:
    name: Build Docker image and push
    runs-on: ubuntu-latest
 
    steps:
      - name: Check out
        uses: actions/checkout@v2
 
      - name: Login Registry
        uses: docker/login-action@v1
        with: 
          registry: registry.cn-shanghai.aliyuncs.com
          username: ${{ secrets.ALIYUN_USER }}
          password: ${{ secrets.ALIYUN_PASSWORD }}
 
      - name: Check version
        id: check-version
        run: |
          docker pull ghcr.io/tailscale/tailscale:latest
          REMOTE_VER=$(docker inspect ghcr.io/tailscale/tailscale | grep -oE "\"Id\": \"sha256:([0-9a-f]+)\"" | sed "s/\"Id\": \"sha256://g" | sed "s/\"//g")
          CURRENT_VER=$(cat current_ver)
          echo "Remote Latest Verion is SHA256:$REMOTE_VER"
          echo "Current built verion is SHA256:$CURRENT_VER"
          if [ "$REMOTE_VER" != "$CURRENT_VER" ];then
            echo $REMOTE_VER > current_ver
            echo "build=true" >> $GITHUB_OUTPUT
            echo "push=true" >> $GITHUB_OUTPUT
            echo "version=$REMOTE_VER" >> $GITHUB_OUTPUT
            echo "Version is outdated, build latest version..."
          else
            echo "Version is latest."
          fi
 
      - name: Build Image and Push
        if: ${{ steps.check-version.outputs.build == 'true' }}
        run: |
          echo "Build Latest Version Right now: "
          docker build . -t registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:${{steps.check-version.outputs.version}}
          docker tag registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:${{steps.check-version.outputs.version}} registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:latest
          docker push registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:${{steps.check-version.outputs.version}}
          docker push registry.cn-shanghai.aliyuncs.com/evalexp-private/tailscale-derper:latest
          echo "Build done."
 
      - name: Commits files
        if: ${{ steps.check-version.outputs.push == 'true' }}
        run: |
          echo "Update repo version file..."
          git config --local user.email "github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add .
          git commit -m "Update tailscale version to SHA256:${{steps.check-version.outputs.version}}"
          echo "File has been committed"
 
      - name: Push changes
        if: ${{ steps.check-version.outputs.push == 'true' }}
        uses: ad-m/github-push-action@master
        with: 
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.ref }}
      
      - name: Done
        if: ${{ steps.check-version.outputs.push == 'true' }}
        run: |
          echo "Changes have been push to repo."