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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 logsACTIONS_STEP_DEBUG: Enable detailed debug logging for each Step.
2. Printing Context Information to Aid Troubleshooting
Example
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
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
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