GitHub Actions

GitHub Actions is an automation platform built into GitHub that allows you to define and run automated workflows directly in your code repository without relying on any external CI/CD tools.

Common use cases include: automatically running tests after code push, automatically deploying to servers after merging PRs, and running data scraping scripts on a schedule.

GitHub Actions vsPublic repositories are completely free., private repositories have a free quota of 2,000 minutes per month.


Core Concepts

Before writing the configuration file, you need to understand the following core concepts, and the relationships between them are as follows:

仓库(Repository)
└── Workflow(工作流)          ← 一个 .yml 文件 = 一个 Workflow
    ├── Event(触发事件)        ← 什么情况下启动这个 Workflow,如 push、PR
    └── Job(作业)× N          ← 一个 Workflow 可以包含多个并行或串行的 Job
        ├── Runner(运行器)     ← 执行 Job 的服务器,如 ubuntu-latest
        └── Step(步骤)× N     ← Job 内按顺序执行的一系列操作
            ├── Action          ← 可复用的封装好的操作,如 actions/checkout
            └── Run             ← 直接执行 Shell 命令
Concepts Description Analogy
Workflow The entire automated workflow is defined by a.ymlfile, stored in.github/workflows/under the directory a complete work plan.
Event Conditions that trigger the Workflow to run, such as code push, PR creation, scheduled tasks, etc. The start condition of the plan.
Job(do业) An independent task unit in a Workflow. Each Job runs on an independent virtual machine, and multiple Jobs execute in parallel by default. A section in the plan.
Step The smallest unit of operation executed sequentially within a Job, which can be a Shell command or an Action. Each specific step within a section.
Action Reusable packaged operations, from GitHub official, third-party, or self-written, viausesReference Ready-made tool templates
Runner Server that executes Jobs. GitHub provides three hosted environments: Ubuntu, Windows, and macOS. The worker who executes the plan.

Create your first Workflow.

1. Directory structure

All Workflow files must be stored in the.github/workflows/directory at the repository root, and the file names must end with.ymlor.yamlThe file name can be customized:

your-repo/
├── .github/
│   └── workflows/
│       ├── ci.yml          ← 持续集成流程(如运行测试)
│       ├── deploy.yml      ← 部署流程
│       └── scheduled.yml   ← 定时任务
├── src/
├── package.json
└── README.md

A repository can have multiple Workflow files, which are independent of each other and are triggered by their respective defined events.

2. The Simplest Workflow

The following is a most basic example: every time code is pushed to the repository, print a line "Hello, GitHub Actions!":

Example

# .github/workflows/hello.yml

name
: Hello World                  # Name of the Workflow, displayed on the GitHub Actions page

on
: push                           # Trigger condition: triggered when code is pushed to any branch

jobs
:                             # Define all jobs
  say-hello
:                      # Job ID (custom name, unique within the same Workflow)
    name
: Print greeting# Job display name (optional; if blank, displays Job ID)
    runs-on
: ubuntu-latest         # Specify the runtime environment: use the latest Ubuntu virtual machine provided by GitHub

    steps
:                        # All steps under this Job are executed in order
      - name
: printMessage# The name of the Step (optional, used to identify this step in logs)
        run
: echo "Hello, GitHub Actions!"   # run: directly execute Shell commands

YAML files are very sensitive to indentation, and must usespaceindentation, and cannot use the Tab key. It is recommended to use VS Code and install the YAML plugin, which can detect format errors in real time.


Trigger events (on)

onThe field defines which events trigger this Workflow. It can be a single event or a combination of multiple events.

1. Common Trigger Events

Events Trigger timing Common uses
push When code is pushed to the repository. Run tests, code checks
pull_request When a Pull Request is created or updated. Automated review and testing before PR merge.
schedule Triggered on a schedule using a Cron expression. Scheduled backups, scheduled data scraping.
workflow_dispatch Manually trigger on the GitHub web page On-demand deployment, manual script execution.
release When publishing a new version (creating a Release) Automatic packaging and publishing to production.
workflow_call When called by other Workflows Reuse public workflows (such as public testing workflows)

2. Branch or Path Filtering

Example

span style="color: #0053A6;">
on:
  push
:
    branches
:
     - main            # Trigger only when pushing to the main branch
      - develop         # Or trigger when pushing to the develop branch
      - 'release/**'    # Or trigger when pushing to any branch starting with release/ (** matches any characters)
    paths
:
     - 'src/**'        # Further filtering: trigger only when files in the src/ directory change.
      - 'package.json'  # Or trigger when the package.json file changes
                        # The two are in an 'OR' relationship; either one triggers

  pull_request
:
    branches
:
     - main            # Trigger only on PRs whose target branch is main (i.e., PRs to be merged into main)
    types
:
     - opened          # When a PR is created
      - synchronize     # When a new commit is pushed to the PR
      - reopened        # When PR is reopened

3. Scheduled Triggers (schedule)

Use a standard Cron expression to define the execution time, with the time zone being UTC (Beijing time = UTC+8, conversion required):

Example

span style="color: #0053A6;">
on:
  schedule
:
   # Cron format: minute hour day month week
    - cron
: '0 2 * * *'       # Run once every day at 02:00 UTC (i.e., 10:00 Beijing time)
    - cron
: '0 9 * * 1'       # Execute once every Monday at 09:00 UTC (i.e., 17:00 Beijing time)
    - cron
: '*/30 * * * *'    # Run every 30 minutes

# Common Cron Expression Quick Reference:
# '0 0 * * *' Every day at midnight (UTC 00:00)
# '0 * * * *' every hour on the hour
# '0 0 * * 0' every Sunday at midnight
# '0 0 1 * *' Midnight on the 1st of every month

4. Manual trigger (workflow_dispatch)

workflow_dispatchAllows manually clicking a button on the Actions tab of the GitHub web page to start the Workflow, and you can also define input parameters:

Example

span style="color: #0053A6;">
on:
  workflow_dispatch
:
    inputs
:
      environment
:             # Input parameter name (can be referenced in steps via ${{ inputs.environment }})
        description
: 'Deployment Target Environment'# Parameter description, displayed in the manual trigger form
        required
: true          # Is it required?
        default
: 'staging'      # Default value
        type
: choice            # Parameter type: choice (dropdown selection)
        options
:
         - staging             # Optional values
          - production

      run_tests
:
        description
: 'Whether to run tests'
        required
: false
        type
: boolean           # Parameter type: boolean (checkbox)
        default
: true

jobs
:
  deploy
:
    runs-on
: ubuntu-latest
    steps
:
      - name
: Display deployment parameters
        run
: |
echo "Target environment: ${{ inputs.environment }}"
echo "Run tests: ${{ inputs.run_tests }}"


Detailed explanation of Jobs and Steps

1. Basic Structure of a Job

Example

span style="color: #0053A6;">
jobs:
  build
:                         # Job ID, must be unique within the same Workflow
    name
: structurebuildProject# Display name of the Job (optional)
    runs-on
: ubuntu-latest        # Runtime environment (required)

    # Optional: Set environment variables for the entire Job, accessible by all Steps in the Job
    env
:
      NODE_ENV
: production
      APP_PORT
: 8080

    # Optional: Set timeout in minutes. Job will be automatically cancelled after timeout to prevent hanging.
    timeout-minutes
: 30

    steps
:
     # Step method 1: use an Action (reference with uses)
      - name
: 拉replacecode
        uses
: actions/checkout@v4         # Reference the official checkout Action (@v4 indicates that the v4 version is used)

      # Step syntax 2: Execute Shell command (specified with run)
      - name
: Output Node version
        run
: node --version

      # Step 3: Executing multi-line Shell commands (using | for multiple lines)
      - name
: Install dependenciesandstructurebuild
        run
: |
         npm install
          npm run build
echo "Build complete"

2. Runtime environment (runs-on)

GitHub provides the following free hosted runners, which you can choose from as needed:

Tags Operating system Description
ubuntu-latest Ubuntu (Latest LTS) Most commonly used, fast, and has the most generous free quota. Recommended for priority use.
ubuntu-22.04 Ubuntu 22.04 Specify a fixed version to avoid incompatibility issues introduced by latest upgrades.
windows-latest Windows Server (Latest) Used for testing or building that requires a Windows environment.
macos-latest macOS (latest) Used for iOS/macOS application builds, consumes free quota the fastest (about 10 times that of Ubuntu).

3. Dependencies between Jobs (needs)

By default, multiple Jobs run in parallel. UseneedsYou can set the execution order of Jobs, forming serial dependency relationships:

Example

span style="color: #0053A6;">
jobs:
  test
:                          # Step 1: Run tests
    runs-on
: ubuntu-latest
    steps
:
      - uses
: actions/checkout@v4
      - run
: npm test

  build
:                         # Step 2: Build the project
    runs-on
: ubuntu-latest
    needs
: test                   # build will start only after the test Job completes successfully
    steps
:
      - uses
: actions/checkout@v4
      - run
: npm run build

  deploy
:                        # Step 3: Deploy
    runs-on
: ubuntu-latest
    needs
: [test, build]          # Deploy must wait until both test and build complete successfully
    steps
:
      - run
: echo Start deploying...

# Execution order: test → build → deploy (sequential)
# If needs is removed, the three Jobs will run in parallel.

4. Conditional Execution (if)

ThroughifYou can control whether a Job or Step executes, commonly used to distinguish branches, determine whether the previous step succeeded, etc.:

Example

span style="color: #0053A6;">
jobs:
  deploy
:
    runs-on
: ubuntu-latest
    # if written at the Job level: the entire Job only runs when pushed to the main branch
    if
: github.ref == 'refs/heads/main'
    steps
:
      - uses
: actions/checkout@v4

      - name
: DeploymenttoProduction Environment
        run
: ./deploy.sh

      # if can also be written at the Step level to control whether a specific step runs
      - name
: Send success notification
        if
: success()             # success(): runs only when all the above Steps succeed
        run
: echo "Deployment successful, send notification"

      - name
: Send failure notification
        if
: failure()             # failure(): Execute only when any Step fails
        run
: echo Deployment failed, send alert

      - name
: Cleanup steps always executed
        if
: always()              # always(): Execute regardless of success or failure (often used to clean up temporary files)
        run
: rm -rf ./tmp

Environment Variables and Secrets

1. Environment Variables (env)

Environment variables can be defined at three levels in the Workflow, with the scope decreasing in order:

Example

# Level 1: Workflow level (accessible to all Jobs and Steps)
env
:
  APP_NAME
: my-app
  NODE_VERSION
: '18'

jobs
:
  build
:
    runs-on
: ubuntu-latest

    # Level 2: Job level (only Steps within the current Job can access)
    env
:
      BUILD_MODE
: production

    steps
:
      - name
: Display environment variables
        # Level 3: Step level (only the current Step can access)
        env
:
          STEP_VAR
: hello
        run
: |
echo "Application name: $APP_NAME" # Access Workflow-level variable
echo "Build mode: $BUILD_MODE" # Access Job-level variable
echo "Step variable: $STEP_VAR" # Access Step-level variable
echo "Node version: $NODE_VERSION"

2. GitHub built-in variables (github context)

GitHub Actions provides a set of built-in context variables, which can be accessed anywhere via${{ }}Syntax reference:

Example

span style="color: #0053A6;">
steps:
  - name
: Print common built-in variables
    run
: |
echo "仓Library name称:${{ github.repository }}"       # For example:your-user/your-repo
echo "Trigger event: ${{ github.event_name }}" # e.g., push, pull_request
echo "Current branch: ${{ github.ref_name }}" # e.g., main, develop
echo "Submit SHA:${{ github.sha }}"               # currentSubmitofComplete SHA Hash value
echo "Committer: ${{ github.actor }}" # Username who triggered this Workflow
echo "Working directory: ${{ github.workspace }}" # The directory path where the code is located after checkout
echo "Run ID:${{ github.run_id }}"             # booktimes Workflow Runofunique ID
echo "RuneditNumber:${{ github.run_number }}"        # booktimesRunYesthat Workflow of the几timesExecute

3. Secrets (sensitive information management)

Sensitive information such as passwords, API keys, server addresses, etc.Cannot be written directly in the yml file.(Because the code is public), they must be stored in the Secrets of the GitHub repository.

Setup steps: go to the repository page →Settings → Secrets and variables → Actions→ ClickNew repository secretfill in the name and value, then save.

Example

span style="color: #0053A6;">
steps:
 # In the Step, reference the configured Secret via ${{ secrets.secret_name }}
  # Secret values are automatically masked with *** in logs and will not be leaked
  - name
: Deploy to server
    env
:
      SSH_KEY
: ${{ secrets.SSH_PRIVATE_KEY }}       # Server SSH private key
      SERVER_IP
: ${{ secrets.DEPLOY_SERVER_IP }}    # Server IP address
    run
: |
     echo "$SSH_KEY" > ~/.ssh/id_rsa
      chmod 600 ~/.ssh/id_rsa
      ssh user@$SERVER_IP "cd /app && git pull && pm2 restart all"

  # GitHub automatically provides GITHUB_TOKEN for operating on this repository (e.g., pushing code, creating Releases)
  # No need to create manually, just use it directly
  - name
: 推sendChangeto仓library
    run
: |
     git config user.name "github-actions[bot]"
      git config user.email "github-actions[bot]@users.noreply.github.com"
      git add .
git commit -m "Auto update [skip ci]"
      git push

    env
:
      GITHUB_TOKEN
: ${{ secrets.GITHUB_TOKEN }}     # GitHub provides automatically, no need to create manually

Introduction to Common Actions

GitHub official and the community provide a large number of ready-to-use Actions, throughuses: action名称@版本references, you can avoid repeatedly writing common operations.

1. actions/checkout (pull code)

Almost the first step of every Workflow is to pull the repository code, using the officialactions/checkout:

Example

span style="color: #0053A6;">
steps:
 # The most basic usage: pull the latest code of the current branch into the working directory
  - uses
: actions/checkout@v4

  # Advanced usage: customizing by passing parameters with 'with'
  - uses
: actions/checkout@v4
    with
:
      ref
: develop              # Pull the specified branch (default pulls the branch where the triggering event is located)
      fetch-depth
: 0            # Fetch the full git history (by default, only the latest commit is fetched)
                                # Set to 0 to fetch all history, so commands like git log can work properly.
      submodules
: true          # Also initialize and update git submodules

2. actions/setup-node (configure Node.js environment)

Example

span style="color: #0053A6;">
steps:
  - uses
: actions/checkout@v4

  - name
: Configure Node.js environment
    uses
: actions/setup-node@v4
    with
:
      node-version
: '20'        # Specify Node.js version

  # After configuration is complete, npm and node commands can be used directly
  - run
: node --version
  - run
: npm install
  - run
: npm test

3. actions/setup-python (Configure Python environment)

Example

span style="color: #0053A6;">
steps:
  - uses
: actions/checkout@v4

  - name
: Configure Python environment
    uses
: actions/setup-python@v5
    with
:
      python-version
: '3.11'   # Specify Python version

  - name
: Install dependencies
    run
: pip install -r requirements.txt

  - name
: Run tests
    run
: pytest tests/

4. actions/cache (cache dependencies to accelerate builds)

Downloading dependencies every time the Workflow runs can be slow. Using the cache Action allows dependencies to be cached and directly used on the next run, greatly reducing build time:

Example

span style="color: #0053A6;">
steps:
  - uses
: actions/checkout@v4

  - uses
: actions/setup-node@v4
    with
:
      node-version
: '20'

  - name
: Cache node_modules
    uses
: actions/cache@v4
    with
:
      path
: ~/.npm                            # Specify the directory to cache
      key
: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
      # key: unique identifier for the cache
      # hashFiles('**/package-lock.json'): generate hash value based on the lock file content
      # If the lock file is unchanged, the key is unchanged, and the cache is directly hit; if the lock file changes, dependencies are reinstalled.

      restore-keys
: |
       ${{ runner.os }}-node-
      # restore-keys: fallback matching strategy when key misses, using the most recent valid cache

  - run
: npm ci                              # npm ci is more suitable for CI scenarios than npm install, faster and stricter
  - run
: npm test

5. actions/upload-artifact / download-artifact (transfer files between jobs)

Different Jobs run on independent virtual machines, so files cannot be shared directly. Using artifacts, you can pass one Job's output files to another Job:

Example

span style="color: #0053A6;">
jobs:
  build
:
    runs-on
: ubuntu-latest
    steps
:
      - uses
: actions/checkout@v4
      - run
: npm install && npm run build     # Build artifacts will be output to the ./dist directory

      - name
: Upload build artifacts
        uses
: actions/upload-artifact@v4
        with
:
          name
: dist-files                   # Name of the artifact (referenced by this name when downloading)
          path
: ./dist                       # The directory or file path to upload
          retention-days
: 7                  # Artifact retention days (max 90 days)

  deploy
:
    runs-on
: ubuntu-latest
    needs
: build                             # Execute after the build Job completes
    steps
:
      - name
: Download build artifacts
        uses
: actions/download-artifact@v4
        with
:
          name
: dist-files                   # Same as the name at upload
          path
: ./dist                       # Directory to download to local

      - name
: DeploymentFile
        run
: rsync -avz ./dist/ user@server:/var/www/html/

Matrix Builds (Matrix)

Matrix builds allow you to run a single Job configuration across multiple environments in parallel, commonly used for compatibility testing across versions and operating systems:

Example

span style="color: #0053A6;">
jobs:
  test
:
    name
: Test Node ${{ matrix.node-version }} on ${{ matrix.os }}
    runs-on
: ${{ matrix.os }}         # Read runtime environment from matrix variables

    strategy
:
      matrix
:
        os
: [ubuntu-latest, windows-latest, macos-latest]   # 3 Operating Systems
        node-version
: ['18', '20', '22']                    # 3 Node versions
        # The above combinations produce 3 × 3 = 9 parallel Jobs

      fail-fast
: false                # Default true: cancel all remaining Jobs if one Job fails.
                                      # Set to false: even if a combination fails, other combinations continue to run,
                                      # Convenient to see test results for all environments

    steps
:
      - uses
: actions/checkout@v4

      - name
: Configure Node.js ${{ matrix.node-version }}
        uses
: actions/setup-node@v4
        with
:
          node-version
: ${{ matrix.node-version }}   # Reference matrix variables

      - run
: npm ci
      - run
: npm test

Example

# Advanced usage: use exclude to exclude certain unwanted combinations, and use include to append special configurations
strategy
:
  matrix
:
    os
: [ubuntu-latest, windows-latest]
    node-version
: ['18', '20']
    exclude
:
      - os
: windows-latest
        node-version
: '18'    # Exclude the windows + Node 18 combination

    include
:
      - os
: ubuntu-latest
        node-version
: '20'
        experimental
: true    # Append additional variables for specific combinations (can be referenced in steps using matrix.experimental)

Practical Examples

Example 1: Node.js project CI (automated testing)

Every time code is pushed or a PR is created, automatically install dependencies and run code checks and tests:

Example

# .github/workflows/ci.yml
name
: Node.js CI

on
:
  push
:
    branches
: [main, develop]
  pull_request
:
    branches
: [main]

jobs
:
  test
:
    name
: CodeChecksandTesting
    runs-on
: ubuntu-latest

    steps
:
      - name
: 拉replacecode
        uses
: actions/checkout@v4

      - name
: Configure Node.js environment
        uses
: actions/setup-node@v4
        with
:
          node-version
: '20'
          cache
: 'npm'                       # setup-node has built-in caching support, which is more concise than using the cache Action separately

      - name
: Install dependencies
        run
: npm ci                          # npm ci will install strictly according to package-lock.json,
                                             # More suitable for CI scenarios than npm install

      - name
: Run code linting (ESLint)
        run
: npm run lint

      - name
: Run unit tests
        run
: npm test -- --coverage          # Also generate test coverage report

      - name
: Upload覆盖率Report
        uses
: actions/upload-artifact@v4
        if
: always()                         # Upload the report regardless of whether the test passes (to make it easy to view failure reasons)
        with
:
          name
: coverage-report
          path
: ./coverage

Example 2: Python project CI

Example

# .github/workflows/python-ci.yml
name
: Python CI

on
:
  push
:
    branches
: [main]
  pull_request
:

jobs
:
  test
:
    runs-on
: ubuntu-latest

    steps
:
      - uses
: actions/checkout@v4

      - name
: Configure Python environment
        uses
: actions/setup-python@v5
        with
:
          python-version
: '3.11'
          cache
: 'pip'                       # Cache pip dependencies

      - name
: Install dependencies
        run
: |
         python -m pip install --upgrade pip
          pip install -r requirements.txt
pip install flake8 pytest # Install code linting and testing tools

      - name
: Run code format check (flake8)
        run
: |
# Check for syntax errors and undefined variables (E9, F63, F7, F82 series), and exit with an error directly if any problem is found
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# Check code style (max line length 120), only count the number of issues, do not exit with error.
          flake8 . --count --max-line-length=120 --statistics

      - name
: Run tests
        run
: pytest tests/ -v                # -v outputs detailed test results

Example 3: Build and push Docker image(s)

Example

# .github/workflows/docker.yml
name
: Build and push Docker image

on
:
  push
:
    branches
: [main]
    tags
:
     - 'v*'                               # Trigger when pushing tags starting with v, such as v1.0.0

jobs
:
  docker
:
    runs-on
: ubuntu-latest
    steps
:
      - uses
: actions/checkout@v4

      # Use official Docker metadata Action to automatically generate image tags.
      # E.g., when pushing tag v1.2.3, automatically generate multiple tags such as 1.2.3, 1.2, 1, latest
      - name
: Extract Docker metadata (image tags, etc.)
        id
: meta                           # Set an ID for this Step so subsequent Steps can reference its output.
        uses
: docker/metadata-action@v5
        with
:
          images
: your-dockerhub-username/your-image-name

      - name
: Log in to Docker Hub
        uses
: docker/login-action@v3
        with
:
          username
: ${{ secrets.DOCKERHUB_USERNAME }}
          password
: ${{ secrets.DOCKERHUB_TOKEN }}   # Use an Access Token instead of a password for better security

      - name
: structurebuildandPush image
        uses
: docker/build-push-action@v5
        with
:
          context
: .                       # Directory where the Dockerfile is located (current directory)
          push
: true                       # true: push to Registry after the build completes
          tags
: ${{ steps.meta.outputs.tags }}       # Reference the tag list generated by meta Step
          labels
: ${{ steps.meta.outputs.labels }}   # Reference the tag information generated by meta Step

Example 4: Automatically deploy to a server after build

Example

# .github/workflows/deploy.yml
name
: Build and deploy

on
:
  push
:
    branches
: [main]                       # Deployment triggered only on push to main branch

jobs
:
  build-and-deploy
:
    runs-on
: ubuntu-latest

    steps
:
      - uses
: actions/checkout@v4

      - uses
: actions/setup-node@v4
        with
:
          node-version
: '20'
          cache
: 'npm'

      - name
: Install dependenciesandstructurebuild
        run
: |
         npm ci
npm run build # Build artifacts are output to the ./dist directory

      - name
: Deploy to server via SSH
        uses
: appleboy/ssh-action@v1.0.3   # Third-party SSH Action, no need to manually configure SSH
        with
:
          host
: ${{ secrets.SERVER_HOST }}       # Server IP or domain
          username
: ${{ secrets.SERVER_USER }}   # SSH login username
          key
: ${{ secrets.SSH_PRIVATE_KEY }}    # SSH private key content (corresponding to the public key on the server)
          port
: 22                               # SSH port, default 22
          script
: |
# The following commands are executed on the remote server
            cd /var/www/my-app
            git pull origin main
            npm ci --production
pm2 restart my-app # Restart the Node.js application with pm2
echo "Deployment completed: $(date)"

Example 5: Scheduled task (automatically back up database)

Example

# .github/workflows/backup.yml
name
: decidewhen备份database

on
:
  schedule
:
    - cron
: '0 2 * * *'                    # Run daily at 02:00 UTC (10:00 Beijing time)
  workflow_dispatch
:                       # Also supports manual triggering for temporary backups

jobs
:
  backup
:
    runs-on
: ubuntu-latest

    steps
:
      - name
: Execute backup script via SSH
        uses
: appleboy/ssh-action@v1.0.3
        with
:
          host
: ${{ secrets.SERVER_HOST }}
          username
: ${{ secrets.SERVER_USER }}
          key
: ${{ secrets.SSH_PRIVATE_KEY }}
          script
: |
           TIMESTAMP=$(date +%Y%m%d_%H%M%S)
            BACKUP_FILE="/backup/db_$TIMESTAMP.sql"

# Perform Database Backup
            mysqldump -u root -p${{ secrets.DB_PASSWORD }} my_database > $BACKUP_FILE

# Compress backup files
            gzip $BACKUP_FILE

# Delete backup files older than 30 days to prevent the disk from filling up
            find /backup -name "*.sql.gz" -mtime +30 -delete

echo "Backup complete: ${BACKUP_FILE}.gz"


Debug技巧

1. Enabling Debug Logs

When a Workflow run fails but the log information is insufficient, you can enable detailed debug mode. Method: go to the repositorySettings → Secrets and variables → Actions, add the following two Secrets (set both values totrue):

  • ACTIONS_RUNNER_DEBUGEnable runner verbose logs
  • ACTIONS_STEP_DEBUG: Enable detailed debug logging for each Step.

2. Printing Context Information to Aid Troubleshooting

Example

span style="color: #0053A6;">
steps:
  - name
: Print all context information (for debugging; add when troubleshooting, remove after resolution)
    run
: |
echo "=== github context ==="
echo '${{ toJson(github) }}'           # toJson() willObjectFormattingtransformis JSON StringOutput
echo "=== env context ==="
      echo '${{ toJson(env) }}'
echo "=== job context ==="
      echo '${{ toJson(job) }}'

3. Locally testing Workflow (using act)

Testing the Workflow only by pushing code every time is very inefficient.actis an open-source tool that can simulate running GitHub Actions locally, greatly improving debugging efficiency:

# 安装 act(需要本地已安装 Docker)
# macOS
brew install act

# Linux
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash

# 在仓库根目录运行所有 Workflow
act

# 只运行指定事件触发的 Workflow
act push

# 只运行指定的 Job
act -j build

When running local tests,actIt uses Docker containers to simulate the GitHub runtime environment, but some Actions (such asactions/cache) may behave differently when simulated locally compared to the real environment. The final results are subject to what actually runs on GitHub.


Common Issues and Notes

1. Permission issue (Permission denied)

If the Workflow needs to push code to the repository or operate on Issues, you need to explicitly declare permissions in the configuration file:

Example

# Set permissions at the Workflow top level or Job level
permissions
:
  contents
: write       # Allows read/write repository content (code, files)
  issues
: write         # Allow creating and modifying Issues
  pull-requests
: write  # Allow operations on Pull Requests

# Principle of least privilege: only grant the permissions actually needed, the rest default to read or none

2. Avoiding Workflow loop triggers

If the Workflow automatically pushes code to the repository, it may trigger a new push event, causing an infinite loop. Solution: in the commit message of the automatic commit, add[skip ci]keyword, and GitHub will skip the Workflow trigger for that commit:

git commit -m "自动格式化代码 [skip ci]"

3. YAML Special Character Escaping

InrunIn the Shell command of the field, use${{ }}expression, if the expression contains a colon (:) and other YAML special characters, you need to wrap the entire value in quotes, or instead assign it to an environment variable first and then use it:

Example

span style="color: #0053A6;">
steps:
 # Not recommended: Directly embedding complex commands in ${{ }} expressions may cause YAML parsing errors.
  - run
: echo ${{ github.event.pull_request.title }}

  # Recommended: first assign the value to an environment variable, then use the environment variable in Shell
  - name
: Print PR title
    env
:
      PR_TITLE
: ${{ github.event.pull_request.title }}
    run
: echo "PR title: $PR_TITLE"

For more complete documentation, please refer to the official documentation:https://docs.github.com/zh/actions

other extensions