一、前置知识

CI\CD 即:持续集成(Continuous Integration)、持续交付(Continuous Delivery)、持续部署(Continuous Deployment)。GitHub Actions 是一个持续集成和持续交付 (CI/CD) 平台,可用于自动执行构建、测试和部署管道。

最近几个月拿Github Actions写了一些CI\CD,是看别人怎么写然后边学边敲得,比如定时执行脚本、自动化博客部署、打包pip、npm等等,自动化以后甚是好用(主要是懒)!故翻文档整理一则入门笔记,本以为我精通了,一翻文档翻出了一堆,写成了进阶,主要是jobs😭文档中分好细,实际生产工作中并没用到太多,感觉比较偏,剩下的on、evn、secret都是高频且只要有一定的git基础很容易搞懂并上手,但如果你是新手文档会显得晦涩,推荐两篇快速入门:

在阅读以前应该有一些基础:git常识,yml文件书写规范,善于查阅文档

参考文档:Workflow syntax for GitHub Actions - GitHub Docs

二、文件结构

Github项目路径下创建.github/workflows/xxx.yml,每一个.yml文件对应一个workflows

基本概念:

  • workflow(流程):持续集成一次运行的过程,就是一个 workflow

  • jobs(任务):一个 workflow 由一个或多个 jobs 构成,含义是一次持续集成的运行,可以完成多个任务

  • step(步骤):每个 job 由多个 step 构成,一步步完成

  • action(动作):每个 step 可以依次执行一个或多个命令

name

工作流名称,留空为文件名

name: hello-github-actions

on

触发的条件:Events that trigger workflows - GitHub Docs

基本用法

# push时触发
on: push

# 数组表示,push、fork时触发
on: [push, fork]

对事件细分,又可以增加事件活动类型(types)和筛选器(branchestagspaths规定事件的触发条件

on:
事件:
活动类型\筛选器:
条件

types

语法:on.<event_name>.types,定义事件活动类型

issues时,触发条件

  • 创建issues
  • 为issues做标签

当创建一个带两个标签的issues,则触发三个工作流

on:
issues:
types:
- opened
- labeled

# 可以表示为数组
on:
issues:
types: [opened,labeled]

『pull_request』:branches & branches-ignore

语法:on.<pull_request|pull_request_target>.<branches|branches-ignore>

如果同时定义 branches/branches-ignore 筛选器和 paths筛选器,则工作流将只在这两个筛选器都满足条件时运行

branchesbranches-ignore不能同时使用,可以使用!排除分支,当branches中使用!需要至少定义一个不带!的分支,支持glob模式(一种正则表达)

pull_request时,触发条件

  • releases/开头分支
  • releases/开头-alpha结尾分支
on:
pull_request:
branches:
- 'releases/**'
- '!releases/**-alpha'

pull_request时触发,但不包括

  • main分支
  • releases/开头-alpha结尾分支
on:
pull_request:
# Sequence of patterns matched against refs/heads
branches-ignore:
- 'main'
- 'releases/**-alpha'

pull_request时,触发条件

  • releases/开头分支
  • 但不包括releases/开头-alpha结尾分支
on:
pull_request:
branches:
- 'releases/**'
- '!releases/**-alpha'

『push』:branches & tags & branches-ignore & tags-ignore

语法:on.push.<branches|tags|branches-ignore|tags-ignore>

如果仅定义 tags/tags-ignorebranches/branches-ignore,则工作流不会针对影响未定义的 Git ref 的事件运行。如果两者 tags/tags-ignorebranches/branches-ignore 均未定义,则工作流将针对影响分支或标记的事件运行。 如果你同时定义 branches/branches-ignore 筛选器和 paths 筛选器,则工作流将只在这两个筛选器都满足条件时运行

branchesbranches-ignore不能同时使用, tagstags-ignore 不能同时使用,可以使用!排除分支|标签,当branches|tags中使用!需要至少定义一个不带!的分支,支持glob模式(一种正则表达)

push时,触发条件

  • main分支
  • releases/开头分支
  • v2标签
  • v1.开头的标签
on:
push:
# Sequence of patterns matched against refs/heads
branches:
- main
- 'releases/**'
# Sequence of patterns matched against refs/tags
tags:
- v2
- v1.*

push时触发,但不包括

  • main分支
  • releases/开头分支
  • v2标签
  • v1.开头的标签
on:
push:
# Sequence of patterns matched against refs/heads
branches-ignore:
- main
- 'releases/**'
# Sequence of patterns matched against refs/tags
tags-ignore:
- v2
- v1.*

push时,触发条件

  • releases/开头的分支
  • 但不包括releases/开头-alpha结尾的分支
on:
push:
branches:
- 'releases/**'
- '!releases/**-alpha'

『push & pull_request』:paths & paths-ignore

语法:on.<push|pull_request|pull_request_target>.<paths|paths-ignore>

如果同时定义 branches/branches-ignore 筛选器和 paths 筛选器,则工作流将只在这两个筛选器都满足条件时运行

pathspaths-ignore 不能同时使用,可以使用!排除标签,当paths中使用!需要至少定义一个不带!的路径,支持glob模式(一种正则表达)

push时,触发条件

  • 包含.js文件名
on:
push:
paths:
- '**.js'

push时触发,但不包括

  • docs目录下
on:
push:
paths-ignore:
- 'docs/**'

push时,触发条件

  • sub-project目录下,但不包括sub-project/docs
on:
push:
paths:
- 'sub-project/**'
- '!sub-project/docs/**'

schedule

定时cron,推荐在线验证网站:Crontab.guru - The cron schedule expression editor

on:
schedule:
# At 05:30 on Monday and Wednesday
- cron: '30 5 * * 1,3'
# At 05:30 on Tuesday and Thursday
- cron: '30 5 * * 2,4'

workflow

语法:on.workflow_call,调用其它工作流,但这部分没理解,也从未见过示例,先留个坑

语法:on.workflow_run.<branches|branches-ignore>:指定运行分支

仅当名为 Build 的工作流在名称以 releases/ 开头的分支上运行时,具有以下触发器的工作流才会运行

on:
workflow_run:
workflows: ["Build"]
types: [requested]
branches:
- 'releases/**'

仅当名为 Build 的工作流不在名为 canary 的分支上运行时,具有以下触发器的工作流才会运行

on:
workflow_run:
workflows: ["Build"]
types: [requested]
branches-ignore:
- "canary"

语法:on.workflow_dispatch:手动触发

on:
workflow_dispatch:

语法:on.workflow_dispatch.inputs:带表单的手动触发

# 格式
inputs:
变量名字:
description: 'Log level' # 描述
required: true # 必填
default: 'warning' # 默认值
type: choice # type: choice 选项,string 字符串,number 数值,boolean 布尔值
options: # 选项
- info
- warning
- debug
on:
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
type: choice
options:
- info
- warning
- debug
print_tags:
description: 'True to print to STDOUT'
required: true
type: boolean
tags:
description: 'Test scenario tags'
required: true
type: string

jobs:
print-tag:
runs-on: ubuntu-latest
# 如果print_tags为true就执行
if: ${{ inputs.print_tags }}
steps:
- name: Print the input tag to STDOUT
# 输出tags的值
run: echo The tags are ${{ inputs.tags }}

inputs

evn

语法:jobs.steps[*\].env,读取环境变量,其中GITHUB_TOKEN是一个特殊的变量,并不需要在仓库下『Setting->Secrets->Actions』定义的一个变量,而是工作流运行时自动创建的临时TOKEN,不需要自己配置,源自:Automatic token authentication - GitHub Docs

jobs:
steps:
- name: My first action
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FIRST_NAME: Mona
LAST_NAME: Octocat

jobs

jobs表示要执行的一项或多项任务。jobs可以包含一个或多个job,这个任务可以包含多个步骤(steps)

语法:

  • jobs.<job_id>:jobs的唯一标识符
  • jobs.<job_id>.name:作业名称(如果留空,则为job_id)

job_id 值为 my_first_jobmy_second_job。默认多个job是并发执行的

jobs:
my_first_job:
name: My first job
my_second_job:
name: My second job

语法:jobs.<job_id>.needs:等待前面的jobs成功完成才执行

job1 必须在 job2 开始之前成功完成,并且 job3 等待 job1job2 完成

jobs:
job1:
job2:
needs: job1
job3:
needs: [job1, job2]

语法:jobs.<job_id>.if:执行条件

job3 使用 always() 条件表达式,确保始终在 job1job2 完成(无论是否成功)后运行

jobs:
job1:
job2:
needs: job1
job3:
if: ${{ always() }}
needs: [job1, job2]

语法:

  • jobs.<job_id>.runs-on:运行镜像,查表:Workflow syntax for GitHub Actions - GitHub Docs
  • jobs.<job_id>.steps:作业步骤,步骤中可以包括多个命令
  • jobs.<job_id>.steps[*].name:步骤中又分小任务,每个任务的名称,将会展示在Actions
  • jobs.<job_id>.steps[*].run:执行shell命令
name: Greeting from Mona

on: push

jobs:
my-job:
name: My Job
runs-on: ubuntu-latest
steps:
- name: Print a greeting
env:
MY_VAR: Hi there! My name is
FIRST_NAME: Mona
MIDDLE_NAME: The
LAST_NAME: Octocat
run: |
echo $MY_VAR $FIRST_NAME $MIDDLE_NAME $LAST_NAME.
- name: end
run: |
echo test end

语法:jobs.<job_id>.steps[*].if:执行条件。if可取值:Expressions - GitHub Docs

# 仅当`pull_request`时且action为`unassigned`触发
steps:
- name: My first step
if: ${{ github.event_name == 'pull_request' && github.event.action == 'unassigned' }}
run: echo This event is a pull request that had an assignee removed.

# 仅当前一个任务失败,My backup step才执行
steps:
- name: My first step
uses: octo-org/action-name@main
- name: My backup step
if: ${{ failure() }}
uses: actions/heroku@1.0.0

语法:jobs.<job_id>.steps[*].uses:这个就很有意思了,可以减少我们重复造轮子,调用别人做好的Actions。可以在GitHub Marketplace · Actions 找到需要的轮子

# 指定uses的分支、版本
steps:
# Reference a specific commit
- uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675
# Reference the major version of a release
- uses: actions/checkout@v3
# Reference a specific version
- uses: actions/checkout@v3.2.0
# Reference a branch
- uses: actions/checkout@main

# 调用别人的公有仓库,{owner}/{repo}@{ref}
jobs:
my_first_job:
steps:
- name: My first step
# Uses the default branch of a public repository
uses: actions/heroku@main
- name: My second step
# Uses a specific version tag of a public repository
uses: actions/aws@v2.0.1

# 调用仓库下特定路径,{owner}/{repo}/{path}@{ref}
jobs:
my_first_job:
steps:
- name: My first step
uses: actions/aws/ec2@main

# 调用自己写的actions
jobs:
my_first_job:
steps:
- name: Check out repository
uses: actions/checkout@v3
- name: Use local my-action
uses: ./.github/actions/my-action

# 调用docker docker://{image}:{tag}
jobs:
my_first_job:
steps:
- name: My first step
uses: docker://alpine:3.8

# 指定docker地址 docker://{host}/{image}:{tag}
jobs:
my_first_job:
steps:
- name: My first step
uses: docker://ghcr.io/OWNER/IMAGE_NAME

语法:jobs.<job_id>.steps[*].shell:指定shell,默认bash

steps:
- name: Display the path
run: echo $PATH
shell: bash

steps:
- name: Display the path
run: echo %PATH%
shell: cmd

steps:
- name: Display the path
run: echo ${env:PATH}
shell: powershell

steps:
- name: Display the path
run: |
import os
print(os.environ['PATH'])
shell: python

语法:jobs.<job_id>.steps[*].with:定义变量,可以被hello_world所访问

jobs:
my_first_job:
steps:
- name: My first step
uses: actions/hello_world@main
with:
first_name: Mona
middle_name: The
last_name: Octocat

语法:

  • jobs.<job_id>.steps[*].with.args:文档解释『A string that defines the inputs for a Docker container. GitHub passes the args to the container’s ENTRYPOINT when the container starts up』,我的理解是给docker容器启动时传入参数?第二个坑
  • jobs.<job_id>.steps[*].with.entrypoint:覆盖Dockerfile中的ENTRYPOINT
steps:
- name: Explain why this job ran
uses: octo-org/action-name@main
with:
entrypoint: /bin/echo
args: The ${{ github.event_name }} event triggered this step.

语法:jobs.<job_id>.steps[*].envjobs.<job_id>.env:传入变量

steps:
- name: My first action
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FIRST_NAME: Mona
LAST_NAME: Octocat

语法:

  • jobs.<job_id>.steps[*].continue-on-error: true:表示,此步运行失败时,工作流仍继续执行下一个任务
  • jobs.<job_id>.steps[*].timeout-minutes:任务最大执行时间
  • jobs.<job_id>.timeout-minutes:作业最大执行时间,默认360min
  • jobs.<job_id>.strategy.matrix:使用矩阵策略

可以使用矩阵策略,两个操作系统会分别在三个版本下分别运行即6个作业

jobs:
example_matrix:
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
version: [10, 12, 14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.version }}

语法:jobs.<job_id>.strategy.matrix.include:include下是一个列表,如果对象中的键:值对均未覆盖任何原始矩阵值,则会将键:值对添加到每个矩阵组合中。 如果对象不能添加到任何矩阵组合中,将改为创建新的矩阵组合。

strategy:
matrix:
fruit: [apple, pear]
animal: [cat, dog]
include:
- color: pink
- color: green
animal: cat
- fruit: apple
shape: circle
- fruit: banana
- fruit: banana
animal: cat

解释

  • {color: green} 添加到所有原始矩阵组合,因为它可以添加,而不会覆盖原始组合的任何部分。
  • {color: pink, animal: cat} 仅将 color:pink 添加到包含 animal: cat 的原始矩阵组合中。 这会覆盖上一个 include 条目添加的 color: green
  • {fruit: apple, shape: circle} 仅将 shape: circle 添加到包含 fruit: apple 的原始矩阵组合中。
  • {fruit: banana} 添加到任何原始矩阵组合时都会覆盖值,因此会将其作为其他矩阵组合进行添加。
  • {fruit: banana, animal: cat} 添加到任何原始矩阵组合时都会覆盖值,因此会将其作为其他矩阵组合进行添加。 它不会添加到 {fruit: banana} 矩阵组合中,因为该组合不是原始矩阵组合之一

即生成六个作业

  • {fruit: apple, animal: cat, color: pink, shape: circle}
  • {fruit: apple, animal: dog, color: green, shape: circle}
  • {fruit: pear, animal: cat, color: pink}
  • {fruit: pear, animal: dog, color: green}
  • {fruit: banana}
  • {fruit: banana, animal: cat}

工作流将运行六个作业,其中针对每个 osnode 变量组合提供一个作业。 当对应于 windows-latestos 值和 16node 值的作业运行时,作业中将包含一个被称为 npm 且值为 6 的其他变量

jobs:
example_matrix:
strategy:
matrix:
os: [windows-latest, ubuntu-latest]
node: [12, 14, 16]
include:
- os: windows-latest
node: 16
npm: 6
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- if: ${{ matrix.npm }}
run: npm install -g npm@${{ matrix.npm }}
- run: npm --version

将运行 10 个作业,矩阵中每个 osversion 的组合一个作业,再加上一个用于 windows-latestos 值和 17version 值的作业

jobs:
example_matrix:
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
version: [12, 14, 16]
include:
- os: windows-latest
version: 17

工作流将运行两个作业,每个 include 一个作业。 这样你可以利用矩阵策略,而无需完全填充矩阵

jobs:
includes_only:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- site: "production"
datacenter: "site-a"
- site: "staging"
datacenter: "site-b"

语法:jobs.<job_id>.strategy.matrix.exclude:移除矩阵中定义的特定配置

工作流将运行 9 个作业:每 12 个配置一个作业,再减去一个与 {os: macos-latest, version: 12, environment: production} 匹配的排除作业,以及两个与 {os: windows-latest, version: 16} 匹配的排除作业

strategy:
matrix:
os: [macos-latest, windows-latest]
version: [12, 14, 16]
environment: [staging, production]
exclude:
- os: macos-latest
version: 12
environment: production
- os: windows-latest
version: 16
runs-on: ${{ matrix.os }}

语法:

  • jobs.<job_id>.strategy.fail-fast:设置为 true,则在矩阵中的任何作业失败的情况下,GitHub 将取消矩阵中所有正在进行和加入队列的作业。 此属性的默认值为 true
  • jobs.<job_id>.continue-on-error :适用于单个作业。 如果 jobs.<job_id>.continue-on-errortrue,即使具有 jobs.<job_id>.continue-on-error: true 的作业失败,矩阵中的其他作业也将继续运行

可以同时使用 jobs.<job_id>.strategy.fail-fastjobs.<job_id>.continue-on-error。 例如,以下工作流将启动四个作业。 对于每个作业,continue-on-error 都由 matrix.experimental 的值确定。 如果任何具有 continue-on-error: false 的作业失败,所有正在进行或加入队列的作业都将被取消。 如果具有 continue-on-error: true 的作业失败,则其他作业将不会受到影响

jobs:
test:
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: true
matrix:
version: [6, 7, 8]
experimental: [false]
include:
- version: 9
experimental: true

语法:jobs.<job_id>.strategy.max-parallel:GitHub 将根据运行器的可用性将并行运行的作业数最大化

工作流一次最多运行两个作业,即使运行器可同时运行六个作业

jobs:
example_matrix:
strategy:
max-parallel: 2
matrix:
version: [10, 12, 14]
os: [ubuntu-latest, windows-latest]

关于docker,这部分挺好理解的,跟compose.yaml差不多,所以简述了

jobs.<job_id>.container:创建一个容器

jobs.<job_id>.container.image:定义要用作运行操作的容器的 Docker 映像

jobs.<job_id>.container.credentials:映像的容器注册表需要身份验证才能拉取映像

jobs.<job_id>.container.env:容器中设置环境变量

jobs.<job_id>.container.ports:容器的端口

jobs.<job_id>.container.volumes:挂载卷

jobs.<job_id>.container.options:容器的其它选项

name: CI
on:
push:
branches: [ main ]
jobs:
container-test-job:
runs-on: ubuntu-latest
container:
# 验证身份
username: ${{ github.actor }}
password: ${{ secrets.github_token }}
image: node:14.16
env:
NODE_ENV: development
ports:
- 80
volumes:
- my_docker_volume:/volume_mount
options: --cpus 1
steps:
- name: Check for dockerenv file
run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv)

jobs.<job_id>.services:If you configure the job to run directly on the runner machine and your step doesn’t use a container action, you must map any required Docker service container ports to the Docker host (the runner machine). You can access the service container using localhost and the mapped port.译:如果您将作业配置为直接在运行程序机器上运行,并且您的步骤不使用容器操作,那么您必须将任何所需的Docker服务容器端口映射到Docker主机(运行程序机器)

services:
nginx:
image: nginx
# Map port 8080 on the Docker host to port 80 on the nginx container
ports:
- 8080:80
redis:
image: redis
# Map TCP port 6379 on Docker host to a random free port on the Redis container
ports:
- 6379/tcp

Secret

前文,写了很多类似于『secret.xxx』的东西,在写Actions时,文件或者仓库中可能会涉及一些密码不希望被泄露,可以在在仓库下『Setting->Secrets->Actions』定义的该变量,之后在Actions中读取

三、Rule

Github Actions并非完全免费,但对于日常使用足够

以官方最新说明为主:Usage limits, billing, and administration - GitHub Docs

  • Job execution time - Each job in a workflow can run for up to 6 hours of execution time. If a job reaches this limit, the job is terminated and fails to complete.

  • Workflow run time - Each workflow run is limited to 35 days. If a workflow run reaches this limit, the workflow run is cancelled. This period includes execution duration, and time spent on waiting and approval.

  • API requests - You can execute up to 1000 requests to the GitHub API in an hour across all actions within a repository. If requests are exceeded, additional API calls will fail which might cause jobs to fail.

  • Concurrent jobs - The number of concurrent jobs you can run in your account depends on your GitHub plan, as indicated in the following table. If exceeded, any additional jobs are queued.

    GitHub planTotal concurrent jobsMaximum concurrent macOS jobs
    Free205
    Pro405
    Team605
    Enterprise18050
  • Job matrix - A job matrix can generate a maximum of 256 jobs per workflow run. This limit applies to both GitHub-hosted and self-hosted runners.

  • Workflow run queue - No more than 500 workflow runs can be queued in a 10 second interval per repository. If a workflow run reaches this limit, the workflow run is terminated and fails to complete.

  • 作业时间:每一个作业运行时间不得超过6小时,如果超过六小时,这个作业将会终止而无法完成

  • 工作流时间:每一个工作流不得超过35天,如果超出此限制,这个工作流将被取消,此时间段包括执行持续时间以及等待和批准所花费的时间

  • API请求:在同一个仓库中一个小时内最多可以执行1000次API请求,如果请求超出,API将调用失败可能导致作业失败

  • 并发作业:账户中可以运行的并发数量取决于Github计划,如果超出将排队作业

    GitHub plan并发数量MacOS 最大并发数
    Free205
    Pro405
    Team605
    Enterprise18050
  • 作业矩阵:一个作业中的矩阵最多可以生成256个,此限制适用于 Github 托管(GitHub-hosted)和自托管运行(self-hosted runners)

  • 工作流队列:每一个仓库不超过500个工作流可以被排队,间隔10s。如果超出限制,这个工作流将终止且运行失败

四、自用整理常用Actions

善用GitHub Marketplace会减少我们做Actions的工作量,以下为自己常用的Actions

Clone From Github

需要对当前仓库操作时,手撕版

- name: Clone
run: |
git clone 仓库地址
cd 仓库名

Checkout:最常见的Actions,clone当前仓库的默认分支,指定仓库/分支详见文档

- name: Checkout
uses: actions/checkout@v2

Environment

Ubuntu自带py环境但没有node环境

Setup Python:python环境

Setup Node.js environment:nodejs

# 默认版本由 runs-on 决定
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.8

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "12.x"

Push To GitHub

当工作流对仓库工作区改动需要push时,手撕版

- name: Commit & Push
run: |
git config user.name github-actions[bot]
git config user.email github-actions[bot]@users.noreply.github.com
git add -A .
git commit -m "Commit & Push"
git push

EndBug/add-and-commit:简化push

参数说明默认示例
add添加暂存区文件add: ‘.’add: ‘src’
author_name用户名作者用户名
author_email邮箱作者邮箱
commit提交信息commit: ‘’commit: ‘Commit & Push’
- name: Push to GitHub
uses: EndBug/add-and-commit@v7.2.1
with:
message: 'Commit & Push'

主页美化

美化效果:GC-ZF/GC-ZF: My GitHub profile.

Blog Post Workflow:拉取最新博文

# 参考:https://github.com/CCKNBC/CCKNBC
# Actions1:https://github.com/marketplace/actions/delete-workflow-runs
# Actions2:https://github.com/marketplace/actions/blog-post-workflow
name: update blog

on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:

jobs:

build:
runs-on: ubuntu-latest
env:
TZ: Asia/Shanghai

steps:
- uses: actions/checkout@v3

# 具体参数看文档
# feed_list 必填 rss地址
# max_post_count 必填 获取文章数
# reade_path 选填 默认写入README
# template 选填 生成模版 emojikey随机表情 默认为[$title]($url)
# date_format 选填 修改模版中日期格式 默认英文
# committer_username和committer_email 选填 提交信息
# filter_dates 选填 daysAgo/10/代表只获取近10天博文 , currentMonth只获取当月博文, currentYear只获取当年博文
- name: blog-post-workflow
- uses: gautamkrishnar/blog-post-workflow@master
with:
feed_list: "https://zhsher.cn/feed.xml"
max_post_count: 5
readme_path: "./README.md"
template: "$newline - $emojiKey(💯,🔥,💫,🚀,🌮,💫) $date [$title]($url)"
date_format: "yyyy年mm月dd日"
committer_username: "github-actions[bot]"
committer_email: "github-actions[bot]@users.noreply.github.com"
filter_dates: "currentYear"

# 删除近retain_days天的Workflow日志
- name: Delete Workflow Runs
uses: Mattraks/delete-workflow-runs@main
with:
retain_days: 10
keep_minimum_runs: 1

GitHub-Profile-3D-Contrib:绘制3D贡献图

name: GitHub-Profile-3D-Contrib

on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
name: generate-github-profile-3d-contrib
steps:
- uses: actions/checkout@v2

- uses: yoshi389111/github-profile-3d-contrib@0.5.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
USERNAME: ${{ github.repository_owner }}

- name: Commit & Push
run: |
S=$(curl 'https://v1.hitokoto.cn/?c=a&encode=text')
git config user.name github-actions[bot]
git config user.email github-actions[bot]@users.noreply.github.com
git add -A .
git commit -m ":rocket: ${S}"
git push

Platane/snk:贪吃蛇版贡献图

name: Generate Snake

on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v2.3.4

- name: Generate Snake
uses: Platane/snk@master
id: snake-gif
with:
github_user_name: ${{ github.repository_owner }}
gif_out_path: ./contribution-snake/github-contribution-grid-snake.gif
svg_out_path: ./contribution-snake/github-contribution-grid-snake.svg

- name: Push to GitHub
uses: EndBug/add-and-commit@v7.2.1
with:
author_name: github-actions[bot]
author_email: github-actions[bot]@users.noreply.github.com
branch: main
message: ':rocket: Update'

其它美化Actions:

Github sync to other repo

Mirror a repository using SSH:同步Github中的仓库到其它平台

Gitee Pages Action · Actions:如果需要开启Gitee Page,参考此Actions

以Github同步Gitee为例:

  1. ssh-keygen -t rsa -C "任意命名" -f "id_rsa_github to gitee" 生成 SSH Key。(⚠️注意直接连续三次回车,此处不要设置密码,生成的公私钥用于下面 GitHub / Gitee 的配置,以保证公私钥成对,否则从 GitHub -> Gitee 的同步将会失败)。生成的 id_rsa_github to gitee 是私钥,id_rsa_github to gitee.pub 是公钥

  2. 在仓库 的「Settings -> Secrets」路径下配置好命名为 GITEE_RSA_PRIVATE_KEYGITEE_PASSWORD 的两个变量。其中:GITEE_RSA_PRIVATE_KEY 存放 id_rsa 私钥;GITEE_PASSWORD 存放 Gitee 帐号的密码

  1. 在 GitHub 的个人设置页面「Settings -> SSH and GPG keys」配置 SSH 公钥(即:id_rsa_github to gitee.pub),命名随意
  2. 在 Gitee 的个人设置页面「安全设置 -> SSH 公钥」配置 SSH 公钥(即:id_rsa_github to gitee.pub),命名随意
- name: Sync to Gitee
uses: wearerequired/git-mirror-action@master
env:
# 注意在 Settings->Secrets 配置 GITEE_RSA_PRIVATE_KEY
SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }}
with:
# 注意替换为你的 GitHub 源仓库地址
source-repo: git@github.com:doocs/leetcode.git
# 注意替换为你的 Gitee 目标仓库地址
destination-repo: git@gitee.com:Doocs/leetcode.git

操作云服务器

手撕版,DEPLOY_PRI为连接服务器的私钥

- name: ssh
env:
DEPLOY_PRI: ${{ secrets.DEPLOY_PRI }}
run: |
sudo timedatectl set-timezone "Asia/Shanghai"
mkdir -p ~/.ssh/
echo "$DEPLOY_PRI" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan 服务器ip >> ~/.ssh/known_hosts

ssh ubuntu@服务器ip
"
shell命令,一行一个
cd /xxx/
ls
"

ssh-pipeline:连接服务器并对服务器操作

参数说明默认
host*ip
user*用户
pass(与key二选一)密码
key(与pass二选一)私钥
port端口22
connect_timeout连接超时时间30s
script命令
- name: ssh pipelines
uses: cross-the-world/ssh-pipeline@master
env:
WELCOME: "ssh pipeline"
with:
host: ${{ secrets.DC_HOST }}
user: ${{ secrets.DC_USER }}
pass: ${{ secrets.DC_PASS }}
port: ${{ secrets.DC_PORT }}
connect_timeout: 10s
script: |
(rm -rf /home/github/test || true)
ls -la
echo $WELCOME
mkdir -p /home/github/test/test1 &&
mkdir -p /home/github/test/test2 &&

ssh-scp-ssh-pipelines:同一作者的优化版,与上表不同的是去除了script,新增

  • first_ssh:scp之前需要做的命令
  • scp:sync copy,复制本地到服务器中,支持正则
  • last_ssh:scp之后需要做的命令
- name: ssh scp ssh pipelines
uses: cross-the-world/ssh-scp-ssh-pipelines@latest
env:
WELCOME: "ssh scp ssh pipelines"
LASTSSH: "Doing something after copying"
with:
host: ${{ secrets.DC_HOST }}
user: ${{ secrets.DC_USER }}
pass: ${{ secrets.DC_PASS }}
port: ${{ secrets.DC_PORT }}
connect_timeout: 10s
first_ssh: |
rm -rf /home/github/test
ls -la \necho $WELCOME
mkdir -p /home/github/test/test1 &&
mkdir -p /home/github/test/test2 &&
scp: |
'./test/*' => /home/github/test/
./test/test1* => /home/github/test/test1/
./test/test*.csv => "/home/github/test/test2/"
last_ssh: |
echo $LASTSSH &&
(mkdir test1/test || true)
|| ls -la

ssh deploy:更倾向于服务器同步文件操作的工作流,最大的特点是利用 rsync(remote sync 远程同步)命令备份数据时,不会直接覆盖以前的数据,而是先判断已经存在的数据和新数据的差异,只有数据不同时才会把不相同的部分覆盖,所以速度上会很快

参数说明
SSH_PRIVATE_KEY*服务器私钥
ARGS*rsync的参数
SOURCE源路径
TARGET目标路径
REMOTE_HOST*服务器ip
REMOTE_USER*服务器用户名
EXCLUDE排除文件
SCRIPT_BEFORE同步前的操作
SCRIPT_AFTER同步后的操作
- name: Deploy to Staging server
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ARGS: "-rlgoDzvc -i"
SOURCE: "dist/"
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
TARGET: ${{ secrets.REMOTE_TARGET }}
EXCLUDE: "/dist/, /node_modules/"
SCRIPT_BEFORE: |
whoami
ls -al
SCRIPT_AFTER: |
whoami
ls -al
echo $RSYNC_STDOUT

小tips

一些不常用的Actions及使用技巧

waline-comments-backup@二花的数据库备份方案,使用了gpg对文件加密,不错的点子!

# 使用 gpg 加密备份文件,需要提前生成随机密码,保存到 github action secrets 中,环境变量名称为 `COMMENTS_DECRYPT_KEY`
# 建议使用密码管理器备份此 gpg 密码,方便在本地做数据恢复
# 将数据解密到 /tmp 文件夹中(建议在需要时,在本地执行):gpg --quiet --batch --yes --decrypt --passphrase="$COMMENTS_DECRYPT_KEY" --output /tmp/waline_comments.json data/waline_comments.json.gpg
gpg --quiet --batch --yes --passphrase="$COMMENTS_DECRYPT_KEY" --symmetric --cipher-algo AES256 data/waline_comments.json
# 删除明文的备份文件
rm -f data/waline_comments.json

dawidd6/action-send-mail:利用Actions发送邮件

justjavac/auto-green:自动保持 GitHub 提交状态常绿 a commit every day, keep your girlfriend far away. (仅定时运行脚本无提交,60天后会自动关闭Actions,可以借助这个)