chore(deps): update python dependencies #1792
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI | |
on: | |
push: | |
branches: [main] | |
pull_request: | |
release: | |
types: [published] | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref }} | |
cancel-in-progress: true | |
jobs: | |
test: | |
name: Test | |
runs-on: ubuntu-latest | |
outputs: | |
environment: ${{ steps.setVersion.outputs.environment }} | |
version: ${{ steps.setVersion.outputs.version }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Set timezone | |
run: sudo timedatectl set-timezone 'Asia/Shanghai' | |
- name: Setup uv | |
uses: astral-sh/setup-uv@v5 | |
with: | |
enable-cache: true | |
- name: Run tests | |
run: uv run poe test | |
env: | |
TZ: Asia/Shanghai | |
- name: Upload test results to Codecov | |
if: ${{ !cancelled() }} | |
uses: codecov/test-results-action@v1 | |
with: | |
token: ${{ secrets.CODECOV_TOKEN }} | |
- name: Upload coverage to Codecov | |
uses: codecov/codecov-action@v5 | |
with: | |
token: ${{ secrets.CODECOV_TOKEN }} | |
- name: Set build version | |
id: setVersion | |
run: | | |
VERSION=$(uvx --from=toml-cli toml get --toml-path=pyproject.toml project.version) | |
COMMIT_ID=$(git rev-parse --short HEAD) | |
if [[ "${{github.event_name}}" == "release" && "${{github.event.action}}" == "published" ]]; then | |
echo "environment=prod" >> $GITHUB_OUTPUT | |
echo "version=$VERSION" >> $GITHUB_OUTPUT | |
else | |
echo "environment=dev" >> $GITHUB_OUTPUT | |
echo "version=$VERSION-git.$COMMIT_ID" >> $GITHUB_OUTPUT | |
fi | |
docker: | |
name: Docker | |
runs-on: ubuntu-latest | |
needs: test | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Login to DockerHub | |
if: github.event_name != 'pull_request' | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKER_USERNAME }} | |
password: ${{ secrets.DOCKER_PASSWORD }} | |
- name: Docker meta | |
if: github.event_name != 'pull_request' | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: he0119/coolqbot | |
- name: Cache buildkit | |
uses: actions/cache@v4 | |
id: cache | |
with: | |
path: | | |
var-cache-apt | |
var-lib-apt | |
root-cache-uv | |
key: cache-${{ hashFiles('Dockerfile') }} | |
- name: Inject cache into docker | |
uses: reproducible-containers/buildkit-cache-dance@v3.1.2 | |
with: | |
cache-map: | | |
{ | |
"var-cache-apt": "/var/cache/apt", | |
"var-lib-apt": "/var/lib/apt", | |
"root-cache-uv": "/root/.cache/uv" | |
} | |
skip-extraction: ${{ steps.cache.outputs.cache-hit }} | |
- name: Build and push | |
if: github.event_name != 'pull_request' | |
uses: docker/build-push-action@v6 | |
with: | |
context: . | |
push: true | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
build-args: | | |
VERSION=${{ needs.test.outputs.version }} | |
- name: Build for test | |
if: github.event_name == 'pull_request' | |
uses: docker/build-push-action@v6 | |
with: | |
context: . | |
push: false | |
load: true | |
tags: he0119/coolqbot:test | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
build-args: | | |
VERSION=${{ needs.test.outputs.version }} | |
- name: Test Image | |
if: github.event_name == 'pull_request' | |
run: | | |
cleanup_container() { | |
docker rm -f test-docker-container > /dev/null 2>&1 || true | |
} | |
check_container() { | |
CONTAINER_STATE=$(docker ps -f name=test-docker-container -a --format '{{.State}}') | |
HEALTH_STATUS=$(docker inspect --format='{{.State.Health.Status}}' test-docker-container 2>/dev/null || echo "unknown") | |
echo "状态: $CONTAINER_STATE, 健康状态: $HEALTH_STATUS" | |
} | |
# 启动容器 | |
echo "正在启动容器..." | |
docker run --name test-docker-container -d he0119/coolqbot:test > /dev/null | |
TIMEOUT=60 | |
ELAPSED=0 | |
INTERVAL=5 | |
while [ $ELAPSED -lt $TIMEOUT ]; do | |
check_container | |
if [[ $CONTAINER_STATE = "running" && $HEALTH_STATUS = "healthy" ]]; then | |
echo "✅ 容器健康检查通过" | |
cleanup_container | |
exit 0 | |
fi | |
if [[ $CONTAINER_STATE != "running" ]]; then | |
echo "❌ 容器异常停止" | |
docker logs test-docker-container | |
cleanup_container | |
exit 1 | |
fi | |
echo "⏳ 等待健康检查... (${ELAPSED}/${TIMEOUT}s)" | |
sleep $INTERVAL | |
ELAPSED=$((ELAPSED + INTERVAL)) | |
done | |
echo "❌ 健康检查超时" | |
docker logs test-docker-container | |
cleanup_container | |
exit 1 | |
deploy_dev: | |
name: Deploy Dev | |
runs-on: ubuntu-latest | |
environment: dev | |
needs: docker | |
if: github.event_name != 'pull_request' | |
steps: | |
- name: Tailscale | |
uses: tailscale/github-action@v3 | |
with: | |
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} | |
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} | |
tags: tag:ci | |
- name: Deploy to server | |
run: tailscale ssh ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} ${{ secrets.DEPLOY_SCRIPT }} | |
deploy_prod: | |
name: Deploy Prod | |
runs-on: ubuntu-latest | |
environment: prod | |
needs: docker | |
if: ${{ github.event_name == 'release' && github.event.action == 'published' }} | |
steps: | |
- name: Tailscale | |
uses: tailscale/github-action@v3 | |
with: | |
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} | |
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} | |
tags: tag:ci | |
- name: Deploy to server | |
run: tailscale ssh ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} ${{ secrets.DEPLOY_SCRIPT }} | |
sentry_release: | |
name: Sentry Release | |
runs-on: ubuntu-latest | |
needs: [test, docker] | |
if: github.event_name != 'pull_request' | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Create Sentry release | |
uses: getsentry/action-release@v1 | |
env: | |
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
SENTRY_ORG: ${{ secrets.SENTRY_ORG }} | |
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} | |
with: | |
environment: ${{ needs.test.outputs.environment }} | |
version: ${{ needs.test.outputs.version }} |