Skip to content

Commit 8b5b74f

Browse files
authored
ci: canary deploy process (#988)
* ci: canary deploy process * chore: upgrade a dep * chore: reword canary comment
1 parent 0300c49 commit 8b5b74f

File tree

5 files changed

+302
-138
lines changed

5 files changed

+302
-138
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: Update Canary PR Comment
2+
3+
permissions:
4+
pull-requests: write
5+
actions: read
6+
7+
on:
8+
workflow_run:
9+
workflows: ['Canary Deploy']
10+
types: [completed]
11+
12+
jobs:
13+
update-comment:
14+
# Only run on the correct repository
15+
if: github.repository == 'supabase/postgres-meta'
16+
runs-on: ubuntu-latest
17+
timeout-minutes: 5
18+
steps:
19+
# Get PR number from the workflow run
20+
- name: Get PR info
21+
id: pr-info
22+
uses: actions/github-script@v7
23+
with:
24+
script: |
25+
// Get the workflow run details
26+
const workflowRun = context.payload.workflow_run;
27+
28+
// Find associated PR
29+
const prs = await github.rest.pulls.list({
30+
owner: context.repo.owner,
31+
repo: context.repo.repo,
32+
state: 'open',
33+
head: `${workflowRun.head_repository.owner.login}:${workflowRun.head_branch}`
34+
});
35+
36+
if (prs.data.length > 0) {
37+
const pr = prs.data[0];
38+
core.setOutput('pr_number', pr.number);
39+
core.setOutput('found', 'true');
40+
console.log(`Found PR #${pr.number}`);
41+
} else {
42+
core.setOutput('found', 'false');
43+
console.log('No associated PR found');
44+
}
45+
46+
# Only continue if we found a PR and the workflow succeeded
47+
- name: Download canary info
48+
if: ${{ steps.pr-info.outputs.found == 'true' && github.event.workflow_run.conclusion == 'success' }}
49+
uses: actions/download-artifact@v4
50+
with:
51+
name: canary-info
52+
path: canary-info/
53+
run-id: ${{ github.event.workflow_run.id }}
54+
continue-on-error: true
55+
56+
- name: Read canary info
57+
if: ${{ steps.pr-info.outputs.found == 'true' && github.event.workflow_run.conclusion == 'success' }}
58+
id: canary-info
59+
run: |
60+
if [ -f "canary-info/canary-tags.txt" ]; then
61+
# Read the first tag (DockerHub) from the tags
62+
FIRST_TAG=$(head -n1 canary-info/canary-tags.txt)
63+
echo "tag=$FIRST_TAG" >> $GITHUB_OUTPUT
64+
echo "found=true" >> $GITHUB_OUTPUT
65+
echo "commit-sha=$(cat canary-info/commit-sha.txt)" >> $GITHUB_OUTPUT
66+
else
67+
echo "found=false" >> $GITHUB_OUTPUT
68+
fi
69+
continue-on-error: true
70+
71+
# Find existing comment
72+
- name: Find existing comment
73+
if: ${{ steps.pr-info.outputs.found == 'true' }}
74+
uses: peter-evans/find-comment@v3
75+
id: find-comment
76+
with:
77+
issue-number: ${{ steps.pr-info.outputs.pr_number }}
78+
comment-author: 'github-actions[bot]'
79+
body-includes: '<!-- postgres-meta-canary-status -->'
80+
81+
# Create or update comment based on workflow status
82+
- name: Create or update canary comment
83+
if: ${{ steps.pr-info.outputs.found == 'true' }}
84+
uses: peter-evans/create-or-update-comment@v4
85+
with:
86+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
87+
issue-number: ${{ steps.pr-info.outputs.pr_number }}
88+
body: |
89+
<!-- postgres-meta-canary-status -->
90+
## 🚀 Canary Deployment Status
91+
92+
${{ github.event.workflow_run.conclusion == 'success' && steps.canary-info.outputs.found == 'true' && format('✅ **Canary image deployed successfully!**
93+
94+
🐳 **Docker Image:** `{0}`
95+
📝 **Commit:** `{1}`
96+
97+
You can test this canary deployment by pulling the image:
98+
```bash
99+
docker pull {0}
100+
```
101+
102+
You can also set the version in a supabase local project by running:
103+
```bash
104+
echo "{0}" > supabase/.temp/pgmeta-version
105+
```
106+
107+
Or use it in your docker-compose.yml:
108+
```yaml
109+
services:
110+
postgres-meta:
111+
image: {0}
112+
# ... other configuration
113+
```
114+
115+
The canary image is available on:
116+
- 🐳 [Docker Hub](https://hub.docker.com/r/supabase/postgres-meta)
117+
- 📦 [GitHub Container Registry](https://ghcr.io/supabase/postgres-meta)
118+
- ☁️ [AWS ECR Public](https://gallery.ecr.aws/supabase/postgres-meta)
119+
', steps.canary-info.outputs.tag, steps.canary-info.outputs.commit-sha) || '' }}
120+
121+
${{ github.event.workflow_run.conclusion == 'failure' && '❌ **Canary deployment failed**
122+
123+
Please check the [workflow logs](' }}${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.html_url || '' }}${{ github.event.workflow_run.conclusion == 'failure' && ') for more details.
124+
125+
Make sure your PR has the `deploy-canary` label and targets the `master` branch.' || '' }}
126+
127+
---
128+
<sub>Last updated: ${{ github.event.workflow_run.updated_at }}</sub>
129+
edit-mode: replace
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
name: Canary Deploy
2+
3+
permissions:
4+
contents: read
5+
pull-requests: read
6+
packages: write
7+
id-token: write
8+
9+
on:
10+
pull_request:
11+
types: [opened, synchronize, labeled]
12+
paths:
13+
- 'src/**'
14+
- 'package.json'
15+
- 'package-lock.json'
16+
- 'tsconfig.json'
17+
- 'Dockerfile'
18+
19+
jobs:
20+
build-canary:
21+
# Only run if PR has the 'deploy-canary' label, is on the correct repository, and targets master branch
22+
if: |
23+
github.repository == 'supabase/postgres-meta' &&
24+
github.event.pull_request.base.ref == 'master' &&
25+
contains(github.event.pull_request.labels.*.name, 'deploy-canary')
26+
runs-on: ubuntu-22.04
27+
timeout-minutes: 30
28+
outputs:
29+
canary-tag: ${{ steps.meta.outputs.tags }}
30+
pr-number: ${{ github.event.pull_request.number }}
31+
steps:
32+
# Checkout fork code - safe because no secrets are available for building
33+
- name: Checkout code
34+
uses: actions/checkout@v5
35+
36+
# Log PR author for auditing
37+
- name: Log PR author
38+
run: |
39+
echo "Canary deploy triggered by: ${{ github.event.pull_request.user.login }}"
40+
echo "PR #${{ github.event.pull_request.number }} from fork: ${{ github.event.pull_request.head.repo.full_name }}"
41+
42+
- name: Setup Node.js
43+
uses: actions/setup-node@v4
44+
with:
45+
node-version-file: '.nvmrc'
46+
cache: 'npm'
47+
48+
- name: Install dependencies and build
49+
run: |
50+
npm clean-install
51+
npm run build
52+
53+
# Generate canary tag
54+
- id: meta
55+
uses: docker/metadata-action@v5
56+
with:
57+
images: |
58+
supabase/postgres-meta
59+
public.ecr.aws/supabase/postgres-meta
60+
ghcr.io/supabase/postgres-meta
61+
tags: |
62+
type=raw,value=canary-pr-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}
63+
type=raw,value=canary-pr-${{ github.event.pull_request.number }}
64+
65+
- uses: docker/setup-qemu-action@v3
66+
with:
67+
platforms: amd64,arm64
68+
- uses: docker/setup-buildx-action@v3
69+
70+
- name: Login to DockerHub
71+
uses: docker/login-action@v3
72+
with:
73+
username: ${{ secrets.DOCKER_USERNAME }}
74+
password: ${{ secrets.DOCKER_PASSWORD }}
75+
76+
- name: configure aws credentials
77+
uses: aws-actions/configure-aws-credentials@v4
78+
with:
79+
role-to-assume: ${{ secrets.PROD_AWS_ROLE }}
80+
aws-region: us-east-1
81+
82+
- name: Login to ECR
83+
uses: docker/login-action@v3
84+
with:
85+
registry: public.ecr.aws
86+
87+
- name: Login to GHCR
88+
uses: docker/login-action@v3
89+
with:
90+
registry: ghcr.io
91+
username: ${{ github.actor }}
92+
password: ${{ secrets.GITHUB_TOKEN }}
93+
94+
- name: Build and push canary image
95+
uses: docker/build-push-action@v6
96+
with:
97+
context: .
98+
push: true
99+
platforms: linux/amd64,linux/arm64
100+
tags: ${{ steps.meta.outputs.tags }}
101+
labels: |
102+
org.opencontainers.image.title=postgres-meta-canary
103+
org.opencontainers.image.description=Canary build for PR #${{ github.event.pull_request.number }}
104+
org.opencontainers.image.source=${{ github.event.pull_request.head.repo.html_url }}
105+
org.opencontainers.image.revision=${{ github.event.pull_request.head.sha }}
106+
canary.pr.number=${{ github.event.pull_request.number }}
107+
canary.pr.author=${{ github.event.pull_request.user.login }}
108+
109+
# Save canary info for the comment workflow
110+
- name: Save canary info
111+
run: |
112+
mkdir -p canary-info
113+
echo "${{ steps.meta.outputs.tags }}" > canary-info/canary-tags.txt
114+
echo "${{ github.event.pull_request.number }}" > canary-info/pr-number.txt
115+
echo "${{ github.event.pull_request.head.sha }}" > canary-info/commit-sha.txt
116+
echo "postgres-meta" > canary-info/package-name.txt
117+
118+
- name: Upload canary info
119+
uses: actions/upload-artifact@v4
120+
with:
121+
name: canary-info
122+
path: canary-info/
123+
retention-days: 7

CONTRIBUTING.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,27 @@
1111
2. Run the tests: `npm run test:run`
1212
3. Make changes in code (`/src`) and tests (`/test/lib` and `/test/server`)
1313
4. Run the tests again: `npm run test:run`
14-
5. Commit + PR
14+
5. Commit + PR
15+
16+
### Canary Deployments
17+
18+
For testing your changes when they impact other things (like type generation and postgrest-js), you can deploy a canary version of postgres-meta:
19+
20+
1. **Create a Pull Request** targeting the `master` branch
21+
2. **Add the `deploy-canary` label** to your PR
22+
3. **Wait for the canary build** - GitHub Actions will automatically build and push a canary Docker image
23+
4. **Use the canary image** - The bot will comment on your PR with the exact image tag and usage instructions
24+
25+
The canary image will be tagged as:
26+
27+
- `supabase/postgres-meta:canary-pr-{PR_NUMBER}-{COMMIT_SHA}`
28+
- `supabase/postgres-meta:canary-pr-{PR_NUMBER}`
29+
30+
Example usage:
31+
32+
```bash
33+
docker pull supabase/postgres-meta:canary-pr-123-abc1234
34+
echo "canary-pr-123-abc1234" > supabase/.temp/pgmeta-version
35+
```
36+
37+
**Note:** Only maintainers can add the `deploy-canary` label for security reasons. The canary deployment requires access to production Docker registries.

0 commit comments

Comments
 (0)