GitHub Actions CI流水线构建 #
本节通过一个完整的CI流水线示例,展示如何构建自动化测试和构建流程。
项目准备 #
项目结构 #
text
my-project/
├── .github/
│ └── workflows/
│ └── ci.yml
├── src/
│ └── index.js
├── tests/
│ └── index.test.js
├── package.json
├── .eslintrc.json
├── .prettierrc
└── jest.config.js
package.json #
json
{
"name": "my-project",
"version": "1.0.0",
"scripts": {
"lint": "eslint src/",
"lint:fix": "eslint src/ --fix",
"format": "prettier --write src/",
"format:check": "prettier --check src/",
"test": "jest",
"test:coverage": "jest --coverage",
"build": "webpack --mode production"
},
"devDependencies": {
"eslint": "^8.57.0",
"jest": "^29.7.0",
"prettier": "^3.2.5",
"webpack": "^5.90.0"
}
}
基础CI工作流 #
yaml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run format:check
test:
name: Test
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run test:coverage
- uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
build:
name: Build
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
进阶CI工作流 #
多版本测试 #
yaml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CI: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run format:check
test:
name: Test (Node ${{ matrix.node }})
needs: lint
runs-on: ubuntu-latest
strategy:
matrix:
node: [16, 18, 20]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm run test:coverage
- name: Upload coverage
if: matrix.node == '20'
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
build:
name: Build
needs: test
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.value }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- id: version
run: echo "value=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
report:
name: Report
needs: [lint, test, build]
if: always()
runs-on: ubuntu-latest
steps:
- name: Generate Summary
run: |
echo "## CI Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Lint | ${{ needs.lint.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Test | ${{ needs.test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build | ${{ needs.build.result }} |" >> $GITHUB_STEP_SUMMARY
完整CI工作流 #
带代码检查和覆盖率 #
yaml
name: CI
on:
push:
branches: [main, develop]
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * *'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CI: true
NODE_VERSION: '20'
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Check formatting
run: npm run format:check
type-check:
name: Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run type-check
test:
name: Test (Node ${{ matrix.node }})
needs: [lint, type-check]
runs-on: ${{ matrix.os }}
strategy:
matrix:
node: [16, 18, 20]
os: [ubuntu-latest]
include:
- node: 20
os: windows-latest
- node: 20
os: macos-latest
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm run test:coverage
- name: Upload coverage
if: matrix.node == '20' && matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
retention-days: 7
coverage:
name: Coverage Report
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: coverage
path: coverage/
- name: Upload to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage/lcov.info
fail_ci_if_error: true
security:
name: Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Run npm audit
run: npm audit --audit-level=high
continue-on-error: true
- name: Run Snyk
uses: snyk/actions/node@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
build:
name: Build
needs: [test, coverage]
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.value }}
artifact: ${{ steps.artifact.outputs.name }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run build
- id: version
run: echo "value=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
- id: artifact
run: echo "name=dist-${{ github.sha }}" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
with:
name: dist-${{ github.sha }}
path: dist/
retention-days: 7
notify:
name: Notify
needs: [lint, type-check, test, security, build]
if: always()
runs-on: ubuntu-latest
steps:
- name: Determine status
id: status
run: |
if [ "${{ needs.build.result }}" == "success" ]; then
echo "status=success" >> $GITHUB_OUTPUT
echo "emoji=✅" >> $GITHUB_OUTPUT
else
echo "status=failure" >> $GITHUB_OUTPUT
echo "emoji=❌" >> $GITHUB_OUTPUT
fi
- name: Generate Summary
run: |
echo "## CI Pipeline Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.status.outputs.emoji }} Overall Status: ${{ steps.status.outputs.status }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Job Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Lint | ${{ needs.lint.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Type Check | ${{ needs.type-check.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Test | ${{ needs.test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Coverage | ${{ needs.coverage.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Security | ${{ needs.security.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build | ${{ needs.build.result }} |" >> $GITHUB_STEP_SUMMARY
添加状态徽章 #
在README.md中添加:
markdown


最佳实践 #
1. 使用并发控制 #
yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
2. 使用缓存加速 #
yaml
- uses: actions/setup-node@v4
with:
cache: 'npm'
3. 使用矩阵测试多版本 #
yaml
strategy:
matrix:
node: [16, 18, 20]
4. 使用路径过滤 #
yaml
on:
push:
paths-ignore:
- '**.md'
5. 生成步骤摘要 #
yaml
- name: Generate Summary
run: |
echo "## Results" >> $GITHUB_STEP_SUMMARY
下一步学习 #
- CD自动部署 - 学习自动部署
- 完整DevOps流程 - 查看完整流程
- 安全最佳实践 - 了解安全配置
小结 #
- CI流水线包括lint、test、build等步骤
- 使用矩阵测试多版本
- 使用缓存加速构建
- 使用并发控制避免冲突
- 生成步骤摘要便于查看结果
- 添加状态徽章展示项目质量
最后更新:2026-03-28