|
19365
|
14201
|
6
|
5
|
551c4d2e9b42cd14481ec48c3b2e2526cab4d58c
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776173495
|
1776173487
|
1776173495
|
|
0
|
|
0
|
Edit
Delete
|
|
19375
|
14202
|
6
|
5
|
551c4d2e9b42cd14481ec48c3b2e2526cab4d58c
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
16484
|
4
|
1776173510
|
1776173510
|
1776173496
|
1776173511
|
|
1
|
|
0
|
Edit
Delete
|
|
19571
|
14348
|
6
|
5
|
110abcc02b429bfac3ebe16a02a876c0ba2f4f62
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776215622
|
1776215542
|
1776215622
|
|
0
|
|
0
|
Edit
Delete
|
|
19589
|
14351
|
6
|
5
|
110abcc02b429bfac3ebe16a02a876c0ba2f4f62
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776215626
|
1776215623
|
1776215626
|
|
0
|
|
0
|
Edit
Delete
|
|
19599
|
14352
|
6
|
5
|
110abcc02b429bfac3ebe16a02a876c0ba2f4f62
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776215629
|
1776215627
|
1776215629
|
|
0
|
|
0
|
Edit
Delete
|
|
19609
|
14353
|
6
|
5
|
110abcc02b429bfac3ebe16a02a876c0ba2f4f62
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
16679
|
4
|
1776215644
|
1776215645
|
1776215630
|
1776215645
|
|
1
|
|
0
|
Edit
Delete
|
|
19728
|
14429
|
6
|
5
|
fd1878b707f31b05ee314173ac91491adb28bc30
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776237054
|
1776236986
|
1776237054
|
|
0
|
|
0
|
Edit
Delete
|
|
19743
|
14432
|
6
|
5
|
fd1878b707f31b05ee314173ac91491adb28bc30
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776237060
|
1776237055
|
1776237060
|
|
0
|
|
0
|
Edit
Delete
|
|
19753
|
14433
|
6
|
5
|
fd1878b707f31b05ee314173ac91491adb28bc30
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
16795
|
4
|
1776237076
|
1776237076
|
1776237061
|
1776237076
|
|
1
|
|
0
|
Edit
Delete
|
|
20322
|
14945
|
6
|
5
|
7b47df3186db279cfc071517a6c034aa213d926d
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776388769
|
1776388658
|
1776388769
|
|
0
|
|
0
|
Edit
Delete
|
|
20336
|
14947
|
6
|
5
|
7b47df3186db279cfc071517a6c034aa213d926d
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776388773
|
1776388770
|
1776388773
|
|
0
|
|
0
|
Edit
Delete
|
|
20346
|
14948
|
6
|
5
|
7b47df3186db279cfc071517a6c034aa213d926d
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
permissions:
contents: read
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
17360
|
4
|
1776388789
|
1776388789
|
1776388774
|
1776388789
|
|
1
|
|
0
|
Edit
Delete
|
|
18384
|
13575
|
6
|
5
|
2e3188c85a6cfc38ac7d3643b1cbbfc2e3e850d0
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1776001251
|
1776001296
|
|
1
|
|
0
|
Edit
Delete
|
|
18488
|
13615
|
6
|
5
|
98cc8da660b8d4dba9887432490471d976c03f5f
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1776011085
|
1776011126
|
|
1
|
|
0
|
Edit
Delete
|
|
18762
|
13812
|
6
|
5
|
d2c68b13960de626f7a8d496bf1977d263eb7931
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1776066083
|
1776066123
|
|
1
|
|
0
|
Edit
Delete
|
|
19192
|
14171
|
6
|
5
|
7c66dac1fd83d4b9dc05198d7589827309ba5922
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776170075
|
1776170068
|
1776170075
|
|
0
|
|
0
|
Edit
Delete
|
|
19226
|
14174
|
6
|
5
|
204e3356f50776130b4976cf96f4deedfe36ab5f
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776170151
|
1776170076
|
1776170151
|
|
0
|
|
0
|
Edit
Delete
|
|
19271
|
14179
|
6
|
5
|
551c4d2e9b42cd14481ec48c3b2e2526cab4d58c
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1776170151
|
1776170995
|
|
1
|
|
0
|
Edit
Delete
|
|
19526
|
14342
|
6
|
5
|
110abcc02b429bfac3ebe16a02a876c0ba2f4f62
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1776215056
|
1776215099
|
|
1
|
|
0
|
Edit
Delete
|
|
19684
|
14424
|
6
|
5
|
fd1878b707f31b05ee314173ac91491adb28bc30
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1776236458
|
1776236493
|
|
1
|
|
0
|
Edit
Delete
|
|
20274
|
14936
|
6
|
5
|
7b47df3186db279cfc071517a6c034aa213d926d
|
0
|
Unit Tests
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
permissions:
contents: read
...
|
test
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1776387183
|
1776387245
|
|
1
|
|
0
|
Edit
Delete
|
|
18383
|
13575
|
6
|
5
|
2e3188c85a6cfc38ac7d3643b1cbbfc2e3e850d0
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
15676
|
2
|
1776001279
|
1776001294
|
1776001251
|
1776001294
|
|
0
|
|
0
|
Edit
Delete
|
|
18487
|
13615
|
6
|
5
|
98cc8da660b8d4dba9887432490471d976c03f5f
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
15752
|
2
|
1776011108
|
1776011123
|
1776011085
|
1776011123
|
|
0
|
|
0
|
Edit
Delete
|
|
18761
|
13812
|
6
|
5
|
d2c68b13960de626f7a8d496bf1977d263eb7931
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
15999
|
2
|
1776066105
|
1776066120
|
1776066083
|
1776066121
|
|
0
|
|
0
|
Edit
Delete
|
|
19191
|
14171
|
6
|
5
|
7c66dac1fd83d4b9dc05198d7589827309ba5922
|
0
|
Lint & Type Check
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776170075
|
1776170068
|
1776170075
|
|
0
|
|
0
|
Edit
Delete
|
|
19225
|
14174
|
6
|
5
|
204e3356f50776130b4976cf96f4deedfe36ab5f
|
0
|
Lint & Type Check
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776170150
|
1776170076
|
1776170150
|
|
0
|
|
0
|
Edit
Delete
|
|
19270
|
14179
|
6
|
5
|
551c4d2e9b42cd14481ec48c3b2e2526cab4d58c
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
16417
|
2
|
1776170978
|
1776170993
|
1776170151
|
1776170994
|
|
0
|
|
0
|
Edit
Delete
|
|
19525
|
14342
|
6
|
5
|
110abcc02b429bfac3ebe16a02a876c0ba2f4f62
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
16634
|
2
|
1776215080
|
1776215096
|
1776215056
|
1776215096
|
|
0
|
|
0
|
Edit
Delete
|
|
19683
|
14424
|
6
|
5
|
fd1878b707f31b05ee314173ac91491adb28bc30
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
16753
|
2
|
1776236476
|
1776236492
|
1776236458
|
1776236492
|
|
0
|
|
0
|
Edit
Delete
|
|
20273
|
14936
|
6
|
5
|
7b47df3186db279cfc071517a6c034aa213d926d
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint || true
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
17315
|
2
|
1776387220
|
1776387239
|
1776387183
|
1776387239
|
|
0
|
|
0
|
Edit
Delete
|
|
18382
|
13575
|
6
|
5
|
2e3188c85a6cfc38ac7d3643b1cbbfc2e3e850d0
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
15675
|
2
|
1776001252
|
1776001279
|
1776001251
|
1776001279
|
|
0
|
|
0
|
Edit
Delete
|
|
18486
|
13615
|
6
|
5
|
98cc8da660b8d4dba9887432490471d976c03f5f
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
15751
|
2
|
1776011087
|
1776011107
|
1776011085
|
1776011108
|
|
0
|
|
0
|
Edit
Delete
|
|
18760
|
13812
|
6
|
5
|
d2c68b13960de626f7a8d496bf1977d263eb7931
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
15998
|
2
|
1776066084
|
1776066104
|
1776066083
|
1776066105
|
|
0
|
|
0
|
Edit
Delete
|
|
19190
|
14171
|
6
|
5
|
7c66dac1fd83d4b9dc05198d7589827309ba5922
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
16400
|
3
|
1776170068
|
1776170075
|
1776170068
|
1776170075
|
|
0
|
|
0
|
Edit
Delete
|
|
19224
|
14174
|
6
|
5
|
204e3356f50776130b4976cf96f4deedfe36ab5f
|
0
|
Frontend Type Check
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776170150
|
1776170076
|
1776170150
|
|
0
|
|
0
|
Edit
Delete
|
|
19269
|
14179
|
6
|
5
|
551c4d2e9b42cd14481ec48c3b2e2526cab4d58c
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
16416
|
2
|
1776170955
|
1776170978
|
1776170151
|
1776170978
|
|
0
|
|
0
|
Edit
Delete
|
|
19524
|
14342
|
6
|
5
|
110abcc02b429bfac3ebe16a02a876c0ba2f4f62
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
16633
|
2
|
1776215057
|
1776215080
|
1776215056
|
1776215080
|
|
0
|
|
0
|
Edit
Delete
|
|
19682
|
14424
|
6
|
5
|
fd1878b707f31b05ee314173ac91491adb28bc30
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
16752
|
2
|
1776236458
|
1776236476
|
1776236458
|
1776236476
|
|
0
|
|
0
|
Edit
Delete
|
|
20272
|
14936
|
6
|
5
|
7b47df3186db279cfc071517a6c034aa213d926d
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
17314
|
2
|
1776387184
|
1776387214
|
1776387183
|
1776387215
|
|
0
|
|
0
|
Edit
Delete
|
|
18385
|
13575
|
6
|
5
|
2e3188c85a6cfc38ac7d3643b1cbbfc2e3e850d0
|
0
|
Build Docker Images
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
15686
|
4
|
1776007227
|
1776007227
|
1776001251
|
1776007228
|
|
1
|
|
0
|
Edit
Delete
|
|
18489
|
13615
|
6
|
5
|
98cc8da660b8d4dba9887432490471d976c03f5f
|
0
|
Build Docker Images
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
15762
|
4
|
1776011733
|
1776011733
|
1776011085
|
1776011734
|
|
1
|
|
0
|
Edit
Delete
|
|
18763
|
13812
|
6
|
5
|
d2c68b13960de626f7a8d496bf1977d263eb7931
|
0
|
Build Docker Images
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
16009
|
4
|
1776066559
|
1776066559
|
1776066083
|
1776066559
|
|
1
|
|
0
|
Edit
Delete
|
|
19193
|
14171
|
6
|
5
|
7c66dac1fd83d4b9dc05198d7589827309ba5922
|
0
|
Build Docker Images
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776170076
|
1776170068
|
1776170076
|
|
0
|
|
0
|
Edit
Delete
|
|
19227
|
14174
|
6
|
5
|
204e3356f50776130b4976cf96f4deedfe36ab5f
|
0
|
Build Docker Images
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1776170151
|
1776170076
|
1776170151
|
|
0
|
|
0
|
Edit
Delete
|
|
19272
|
14179
|
6
|
5
|
551c4d2e9b42cd14481ec48c3b2e2526cab4d58c
|
0
|
Build Docker Images
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
16434
|
4
|
1776173379
|
1776173380
|
1776170151
|
1776173380
|
|
1
|
|
0
|
Edit
Delete
|
|
19527
|
14342
|
6
|
5
|
110abcc02b429bfac3ebe16a02a876c0ba2f4f62
|
0
|
Build Docker Images
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
16644
|
4
|
1776215542
|
1776215543
|
1776215056
|
1776215544
|
|
1
|
|
0
|
Edit
Delete
|
|
19685
|
14424
|
6
|
5
|
fd1878b707f31b05ee314173ac91491adb28bc30
|
0
|
Build Docker Images
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
16763
|
4
|
1776236987
|
1776236987
|
1776236458
|
1776236987
|
|
1
|
|
0
|
Edit
Delete
|
|
20275
|
14936
|
6
|
5
|
7b47df3186db279cfc071517a6c034aa213d926d
|
0
|
Build Docker Images
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
build:
name: Build Docker Images
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build API image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: backend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-api:latest
ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- name: Build Frontend image
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: frontend/Dockerfile
load: "true"
push: "false"
tags: |
ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- id: trivy-api
name: Trivy 扫描 API 镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output: trivy-api-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- id: trivy-frontend
if: always()
name: Trivy 扫描前端镜像
uses: aquasecurity/trivy-action@0.28.0
with:
exit-code: "1"
format: sarif
image-ref: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output: trivy-frontend-results.sarif
severity: MEDIUM,HIGH,CRITICAL
- if: always()
name: 上传 API 镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-api-image
sarif_file: trivy-api-results.sarif
- if: always()
name: 上传前端镜像安全扫描报告到 GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
category: trivy-frontend-image
sarif_file: trivy-frontend-results.sarif
- id: trivy-gate
if: always()
name: 检查 Trivy 扫描结果
run: |
# 任一镜像扫描失败则阻断后续推送
if [ "${{ steps.trivy-api.outcome }}" != "success" ] || [ "${{ steps.trivy-frontend.outcome }}" != "success" ]; then
echo "scan_passed=false" >> $GITHUB_OUTPUT
echo "::error::Trivy 安全扫描未通过,阻断镜像推送"
else
echo "scan_passed=true" >> $GITHUB_OUTPUT
fi
- if: always()
name: 生成 API 镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-api
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
output-file: sbom-api.spdx.json
- if: always()
name: 生成前端镜像 SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom-frontend
format: spdx-json
image: ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
output-file: sbom-frontend.spdx.json
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push API image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-api:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed == 'true'
name: Push Frontend image
run: |
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:latest
docker push ghcr.io/${{ github.repository_owner }}/juhi-frontend:${{ github.sha }}
- if: steps.trivy-gate.outputs.scan_passed != 'true'
name: 扫描未通过时终止流水线
run: |
echo "Trivy 扫描发现安全漏洞,镜像未推送"
exit 1
permissions:
contents: read
packages: write
security-events: write # 上传 SARIF 安全报告所需权限
...
|
build
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck","test"]...
|
["ubuntu-latest"]
|
17325
|
4
|
1776388660
|
1776388660
|
1776387183
|
1776388660
|
|
1
|
|
0
|
Edit
Delete
|
|
2430
|
1687
|
14
|
5
|
6bcd0f0b608c7161cdf8589d556a56257ee178bd
|
0
|
Frontend (TypeScript + Build)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
frontend:
name: Frontend (TypeScript + Build)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: "9"
- uses: actions/setup-node@v4
with:
cache: pnpm
cache-dependency-path: frontend/pnpm-lock.yaml
node-version: "20"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: TypeScript check
run: pnpm tsc --noEmit
- name: Build
run: pnpm build
- if: github.ref == 'refs/heads/main'
name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: frontend-dist
path: frontend/dist
retention-days: "7"
defaults:
run:
working-directory: frontend
...
|
frontend
|
null
|
["ubuntu-latest"]
|
1663
|
2
|
1772339824
|
1772339864
|
1772339824
|
1772339864
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
2432
|
1687
|
14
|
5
|
6bcd0f0b608c7161cdf8589d556a56257ee178bd
|
0
|
Docker Build Validation
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
docker-build:
name: Docker Build Validation
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Download frontend dist
uses: actions/download-artifact@v4
with:
name: frontend-dist
path: frontend/dist
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build PHP image
uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: .
file: docker/php/Dockerfile
push: "false"
tags: ops-php:${{ github.sha }}
...
|
docker-build
|
["frontend","backend"]
|
["ubuntu-latest"]
|
0
|
4
|
0
|
0
|
1772339824
|
1772340576
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|