-
Notifications
You must be signed in to change notification settings - Fork 12
151 lines (137 loc) · 6.49 KB
/
deploy-staging.yml
File metadata and controls
151 lines (137 loc) · 6.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
name: Deploy Staging
# Triggers:
# 1. PR labeled with "deploy-staging" by a collaborator
# 2. Manual workflow_dispatch (team member specifies branch)
#
# Both update the staging apps to the target branch, then deploy.
on:
pull_request:
types: [labeled]
workflow_dispatch:
inputs:
ref:
description: "Branch or commit SHA to deploy to staging"
required: true
default: "main"
permissions:
contents: read
pull-requests: write
jobs:
deploy-staging:
# For label trigger: only run when the label is exactly "deploy-staging"
if: >
github.event_name == 'push' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' && github.event.label.name == 'deploy-staging')
runs-on: ubuntu-latest
env:
STAGING_STACK_UUID: fasbsube26s75ag6qus5bpi2
steps:
- name: Resolve target ref
id: ref
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "ref=${{ github.head_ref }}" >> "$GITHUB_OUTPUT"
elif [ "${{ github.event_name }}" = "push" ]; then
echo "ref=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
else
echo "ref=${{ inputs.ref }}" >> "$GITHUB_OUTPUT"
fi
- name: Check out target ref
uses: actions/checkout@v4
with:
ref: ${{ steps.ref.outputs.ref }}
- name: Resolve target commit
id: target
run: |
set -euo pipefail
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Assert repo staging compose contract
run: |
set -euo pipefail
grep -F "leon-home:/root/.leon" docker-compose.yml >/dev/null
grep -F "LEON_LOCAL_WORKSPACE_ROOT: /root/.leon/workspaces" docker-compose.yml >/dev/null
grep -F "volumes:" docker-compose.yml >/dev/null
- name: Update staging stack branch
run: |
set -euo pipefail
body="$(curl -sS --fail-with-body -X PATCH "${{ secrets.COOLIFY_URL }}/api/v1/applications/${STAGING_STACK_UUID}" \
-H "Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}" \
-H "Content-Type: application/json" \
-d "{\"git_branch\": \"${{ steps.ref.outputs.ref }}\"}")"
echo "$body"
printf '%s' "$body" | jq -e --arg uuid "$STAGING_STACK_UUID" '.uuid == $uuid' >/dev/null
- name: Deploy staging stack
id: deploy
run: |
set -euo pipefail
body="$(curl -sS --fail-with-body "${{ secrets.COOLIFY_URL }}/api/v1/deploy?uuid=${STAGING_STACK_UUID}&force=false" \
-H "Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}")"
echo "$body"
printf '%s' "$body" | jq -e --arg uuid "$STAGING_STACK_UUID" '.deployments[0].resource_uuid == $uuid' >/dev/null
echo "deployment_uuid=$(printf '%s' "$body" | jq -r '.deployments[0].deployment_uuid')" >> "$GITHUB_OUTPUT"
- name: Wait for staging deployment
run: |
set -euo pipefail
deployment_uuid="${{ steps.deploy.outputs.deployment_uuid }}"
for _ in $(seq 1 60); do
body="$(curl -sS --fail-with-body "${{ secrets.COOLIFY_URL }}/api/v1/deployments/${deployment_uuid}" \
-H "Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}")"
status="$(printf '%s' "$body" | jq -r '.status')"
echo "deployment status: $status"
if [ "$status" = "finished" ]; then
exit 0
fi
if [ "$status" != "queued" ] && [ "$status" != "in_progress" ]; then
echo "$body"
exit 1
fi
sleep 10
done
echo "Timed out waiting for staging deployment ${deployment_uuid}"
exit 1
- name: Verify Coolify staging contract
run: |
set -euo pipefail
body="$(curl -sS --fail-with-body "${{ secrets.COOLIFY_URL }}/api/v1/applications/${STAGING_STACK_UUID}" \
-H "Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}")"
echo "$body" | jq '{uuid,git_branch,docker_compose_location}'
printf '%s' "$body" | jq -e --arg ref "${{ steps.ref.outputs.ref }}" '.git_branch == $ref' >/dev/null
printf '%s' "$body" | jq -e '.docker_compose_raw | contains("leon-home:/root/.leon")' >/dev/null
printf '%s' "$body" | jq -e '.docker_compose_raw | contains("LEON_LOCAL_WORKSPACE_ROOT: /root/.leon/workspaces")' >/dev/null
printf '%s' "$body" | jq -e --arg volume "${STAGING_STACK_UUID}_leon-home:/root/.leon" '.docker_compose | contains($volume)' >/dev/null
printf '%s' "$body" | jq -e '.docker_compose | contains("LEON_LOCAL_WORKSPACE_ROOT=/root/.leon/workspaces") or contains("LEON_LOCAL_WORKSPACE_ROOT: /root/.leon/workspaces")' >/dev/null
printf '%s' "$body" | jq -e --arg sha "${{ steps.target.outputs.sha }}" '.docker_compose | contains($sha)' >/dev/null
- name: Verify staging OpenAPI contract
run: |
set -euo pipefail
for attempt in $(seq 1 18); do
status="$(curl -sS -o /tmp/staging-openapi.json -w '%{http_code}' "https://app.staging.mycel.nextmind.space/openapi.json")"
echo "openapi attempt ${attempt}: status=${status}"
if [ "$status" = "200" ]; then
cat /tmp/staging-openapi.json
jq -e '
.openapi
and .info.title == "Mycel Web Backend"
and (.paths | has("/api/runtime/inbox/wait"))
and (.components.schemas.SetChatWorkflowBody.properties | has("expected_state_version"))
and (.components.schemas.UpdateChatWorkflowEventBody.properties | has("expected_state_version"))
' /tmp/staging-openapi.json >/dev/null
exit 0
fi
cat /tmp/staging-openapi.json || true
sleep 10
done
echo "Staging OpenAPI contract did not become ready in time"
exit 1
- name: Comment on PR with staging URL
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `🚀 **预发部署已触发**\n\n- 共享 Staging: https://app.staging.mycel.nextmind.space\n- API(同域反代): https://app.staging.mycel.nextmind.space/api\n\n分支: \`${{ steps.ref.outputs.ref }}\``
})