176 lines
5.7 KiB
YAML
176 lines
5.7 KiB
YAML
# App Expo 统一部署 Pipeline
|
||
#
|
||
# 环境映射(按触发源自动推断):
|
||
# main → dev (开发 + 内部测试)
|
||
# staging → stage (预发布)
|
||
# v*.*.* → prod (正式发布)
|
||
#
|
||
# 手动触发:workflow_dispatch 可选择环境
|
||
|
||
name: App Expo Deploy
|
||
|
||
on:
|
||
push:
|
||
branches: [main, staging]
|
||
tags: ['v*.*.*']
|
||
paths:
|
||
- "app-expo/**"
|
||
- ".github/workflows/app-expo-deploy.yml"
|
||
workflow_dispatch:
|
||
inputs:
|
||
environment:
|
||
description: '部署环境'
|
||
required: true
|
||
type: choice
|
||
options:
|
||
- dev
|
||
- stage
|
||
- prod
|
||
default: dev
|
||
version:
|
||
description: '版本号 (prod 时使用,如 1.0.0)'
|
||
required: false
|
||
type: string
|
||
|
||
concurrency:
|
||
group: app-expo-deploy-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
env:
|
||
APP_NAME: app-expo
|
||
|
||
jobs:
|
||
deploy:
|
||
name: Build & Deploy
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: read
|
||
# GitHub Environments: 在 Repo Settings → Environments 中创建 dev/staging/production,可配置独立 secrets
|
||
environment: ${{
|
||
(github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'prod') && 'production' ||
|
||
(github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'stage') && 'staging' ||
|
||
startsWith(github.ref, 'refs/tags/v') && 'production' ||
|
||
github.ref == 'refs/heads/staging' && 'staging' ||
|
||
'dev'
|
||
}}
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: ${{ startsWith(github.ref, 'refs/tags/') && '0' || '1' }}
|
||
|
||
- name: Determine environment
|
||
id: env
|
||
run: |
|
||
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||
echo "env=prod"
|
||
elif [[ "${{ github.ref }}" == refs/heads/staging ]]; then
|
||
echo "env=stage"
|
||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||
echo "env=${{ github.event.inputs.environment }}"
|
||
else
|
||
echo "env=dev"
|
||
fi >> $GITHUB_OUTPUT
|
||
|
||
- name: Set up Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 20
|
||
cache: npm
|
||
cache-dependency-path: app-expo/package-lock.json
|
||
|
||
- name: Install dependencies
|
||
working-directory: app-expo
|
||
run: npm ci
|
||
|
||
- name: Quality checks (dev only)
|
||
if: steps.env.outputs.env == 'dev'
|
||
working-directory: app-expo
|
||
run: |
|
||
npm run format:check
|
||
npm run lint
|
||
npm run test:ci
|
||
|
||
- name: Export web build
|
||
working-directory: app-expo
|
||
run: npx expo export -p web
|
||
|
||
- name: Determine version (prod)
|
||
if: steps.env.outputs.env == 'prod'
|
||
id: version
|
||
run: |
|
||
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||
VERSION="${GITHUB_REF#refs/tags/v}"
|
||
TAG_NAME="${GITHUB_REF#refs/tags/}"
|
||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]] && [[ -n "${{ github.event.inputs.version }}" ]]; then
|
||
VERSION="${{ github.event.inputs.version }}"
|
||
TAG_NAME="v${VERSION}"
|
||
else
|
||
VERSION=$(node -p "require('./app-expo/package.json').version")
|
||
TAG_NAME="v${VERSION}"
|
||
fi
|
||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||
echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT
|
||
|
||
- name: Create release zip (prod)
|
||
if: steps.env.outputs.env == 'prod'
|
||
run: |
|
||
cd app-expo/dist
|
||
zip -r ../${{ env.APP_NAME }}-v${{ steps.version.outputs.version }}-web.zip .
|
||
|
||
- name: Generate Release Notes (prod)
|
||
if: steps.env.outputs.env == 'prod' && startsWith(github.ref, 'refs/tags/')
|
||
id: release_notes
|
||
run: |
|
||
TAG_NAME="${{ steps.version.outputs.tag_name }}"
|
||
PREV_TAG=$(git tag --sort=-creatordate | grep '^v' | sed -n '2p')
|
||
if [ -n "$PREV_TAG" ]; then
|
||
CHANGES=$(git log "${PREV_TAG}..HEAD" --pretty=format:"- %s (%h)" --no-merges)
|
||
else
|
||
CHANGES=$(git log --pretty=format:"- %s (%h)" --no-merges -20)
|
||
fi
|
||
{
|
||
echo "notes<<EOF"
|
||
echo "## ${APP_NAME} ${TAG_NAME}"
|
||
echo ""
|
||
echo "### 更新内容"
|
||
echo ""
|
||
echo "${CHANGES}"
|
||
echo ""
|
||
echo "---"
|
||
echo "构建编号: #${GITHUB_RUN_NUMBER}"
|
||
echo "EOF"
|
||
} >> $GITHUB_OUTPUT
|
||
|
||
- name: Upload artifact (dev / stage)
|
||
if: steps.env.outputs.env != 'prod'
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: app-expo-web-${{ steps.env.outputs.env }}
|
||
path: app-expo/dist
|
||
retention-days: ${{ steps.env.outputs.env == 'dev' && '14' || '30' }}
|
||
|
||
- name: Upload artifact (prod)
|
||
if: steps.env.outputs.env == 'prod'
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: ${{ env.APP_NAME }}-v${{ steps.version.outputs.version }}-web
|
||
path: app-expo/${{ env.APP_NAME }}-v${{ steps.version.outputs.version }}-web.zip
|
||
retention-days: 90
|
||
|
||
- name: Create GitHub Release (prod)
|
||
if: steps.env.outputs.env == 'prod'
|
||
uses: softprops/action-gh-release@v2
|
||
with:
|
||
tag_name: ${{ steps.version.outputs.tag_name }}
|
||
name: "${{ env.APP_NAME }} ${{ steps.version.outputs.tag_name }}"
|
||
body: ${{ steps.release_notes.outputs.notes || 'Release' }}
|
||
draft: false
|
||
prerelease: false
|
||
files: app-expo/${{ env.APP_NAME }}-v${{ steps.version.outputs.version }}-web.zip
|
||
env:
|
||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
permissions:
|
||
contents: write
|