GitHub Actions
GitHub Actions is GitHub’s CI/CD automation tool. It can automatically run workflows for building, testing, deployment, and more.
Public repositories are free to use, while private repositories come with a monthly free quota.
Basic Concepts
- Workflow: an automated process made up of one or more jobs
- Job(Task):a set of steps executed on the same runner
- Step: a single task, which can be either an action or a shell command
- Action(Action):reusable smallest unit
- Runner: the server that executes the workflow
Basic Syntax
Workflow configuration files use YAML and live in the .github/workflows/ directory.
Simplest workflow
name: Hello World
on: [push]
jobs:
built:
runs-on: ubuntu-latest
steps:
- name: Say hello
run: echo "Hello, World!"
Complete example
name: CI
# 触发条件
on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * 0' # 每周日午夜
workflow_dispatch: # 手动触发
# Environment Variables
env:
NODE_VERSION: 18
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
Trigger events
Push Event
on:
push:
branches:
- main
- 'releases/**'
paths:
- '**.js'
- '!docs/**'
tags:
- v1.*
Pull Request Event
on:
pull_request:
types: [opened, synchronize, reopened]
branches: [ main ]
Scheduled tasks
on:
schedule:
- cron: '30 5 * * 1-5' # 工作日早上5:30
Manual trigger
on:
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy'
required: true
default: 'staging'
type: choice
options:
- staging
- production
Common actions
Checkout code
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整History
Set up Node.js
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
Set up Python
- uses: actions/setup-python@v4
with:
python-version: '3.11'
cache: 'pip'
CachingDependency
- uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
Upload build artifacts
- uses: actions/upload-artifact@v3
with:
name: built-files
path: dist/
Download build artifacts
- uses: actions/download-artifact@v3
with:
name: built-files
path: dist/
Automatically publish a release
Create a release
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: |
npm install
npm run built
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: dist/*
body: |
## Changes
- Feature 1
- Feature 2
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
automatically generates Release Notes
- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
generate_release_notes: true
Self-hosted Runner
Self-hosted runners let you run workflows on your own servers.
Add a runner
- Go to Repository Settings → Actions → Runners → New self-hosted runner.
- Follow the prompts to install and configure it on your server.
- Start the runner.
Installation(Linux)
# 创建目录
mkdir actions-runner && cd actions-runner
# Download
curl -o actions-runner-linux-x64-2.311.0.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz
# 解压
tar xzf ./actions-runner-linux-x64-2.311.0.tar.gz
# Configuration
./config.sh --url https://github.com/user/repo --token YOUR_TOKEN
# Run
./run.sh
# 作为服务Run
sudo ./svc.sh install
sudo ./svc.sh start
Use a self-hosted runner
jobs:
built:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- run: ./build.sh
Label selection
jobs:
built:
runs-on: [self-hosted, linux, x64]
Secrets management
Add a secret
Settings → Secrets and variables → Actions → New repository secret
Use a secret
steps:
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
run: ./deploy.sh
Matrix builds
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [16, 18, 20]
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm test
Conditional execution
steps:
- name: Only on main
if: github.ref == 'refs/heads/main'
run: echo "Main branch"
- name: Only on success
if: success()
run: echo "Previous steps succeeded"
- name: Always run
if: always()
run: echo "Cleanup"
Practical examples
Automatically deploy to a server
name: Deploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/myapp
git pull
npm install
pm2 restart myapp
Build and push Docker images
name: Docker Build
on:
push:
branches: [ main ]
jobs:
built:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: user/app:latest
Code checks
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- run: npm install
- run: npm run lint
Best Practices
- Use caching to speed up dependency installation.
- Use matrix builds for multi-environment testing.
- Run jobs in parallel when they are independent.
- Use
if wisely to save resources with conditional execution.
- Protect secrets and never print them in logs.
- Prefer official actions because they are more reliable and better maintained.
- Limit permissions and grant only what each workflow needs.
References
Last modified on April 17, 2026