Skip to content

Commit 1dfe7d5

Browse files
authored
ci(cli): publish pkg.pr.new previews after preview builds (#5420)
## Summary Adds pkg.pr.new preview publishing for internal PRs after the normal Test workflow passes. The preview workflow resolves the current PR head, skips draft/fork/stale runs, builds the legacy release-shaped CLI artifacts, publishes all platform wrapper packages plus apps/cli to pkg.pr.new, verifies the PR-scoped npx command, and updates a single PR comment with the latest preview command. Extracts the shared CLI artifact build into a reusable workflow so production releases, manual release smoke tests, and PR previews all build the same packages/dist artifact shape. Release publishing still runs the full smoke matrix before npm/GitHub/Homebrew/Scoop publication, while manual release smoke is available through a dedicated dry-run workflow. Adds pkg-pr-new as a root dev dependency and keeps the Windows release smoke coverage aligned with the published artifacts by checking the native wrapper, release tarball, and Scoop install paths. ## Reviewer Notes The preview flow intentionally posts its own pkg.pr.new comment because it runs after Test via workflow_run and needs to publish the stable PR-scoped command, not a commit-SHA-only command.
1 parent 83e5b94 commit 1dfe7d5

8 files changed

Lines changed: 413 additions & 125 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: Build CLI Artifacts
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
version:
7+
description: CLI package version to build
8+
required: true
9+
type: string
10+
shell:
11+
description: CLI shell to package as the shipped supabase binary
12+
required: true
13+
type: string
14+
ref:
15+
description: Optional git ref or SHA to check out before building
16+
required: false
17+
type: string
18+
default: ""
19+
secrets:
20+
SENTRY_DSN:
21+
required: false
22+
POSTHOG_API_KEY:
23+
required: false
24+
POSTHOG_ENDPOINT:
25+
required: false
26+
27+
permissions:
28+
contents: read
29+
30+
jobs:
31+
build:
32+
name: Build CLI artifacts
33+
runs-on: blacksmith-32vcpu-ubuntu-2404
34+
env:
35+
BUN_SHELL: ${{ inputs.shell }}
36+
VERSION: ${{ inputs.version }}
37+
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
38+
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
39+
POSTHOG_ENDPOINT: ${{ secrets.POSTHOG_ENDPOINT }}
40+
steps:
41+
- name: Checkout
42+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
43+
with:
44+
ref: ${{ inputs.ref }}
45+
persist-credentials: false
46+
47+
- name: Setup
48+
uses: ./.github/actions/setup
49+
50+
- name: Setup Go
51+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
52+
with:
53+
go-version-file: apps/cli-go/go.mod
54+
cache: true
55+
cache-dependency-path: apps/cli-go/go.sum
56+
57+
- name: Pre-download Go modules
58+
working-directory: apps/cli-go
59+
run: go mod download -x
60+
61+
- name: Install nfpm
62+
run: |
63+
echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list
64+
sudo apt-get update
65+
sudo apt-get install -y nfpm
66+
67+
- name: Sync versions
68+
run: pnpm exec bun apps/cli/scripts/sync-versions.ts --version "${VERSION}"
69+
70+
- name: Build selected shell
71+
run: pnpm exec bun apps/cli/scripts/build.ts --version "${VERSION}" --shell "${BUN_SHELL}"
72+
73+
- name: Verify build artifacts
74+
run: |
75+
for pkg in cli-darwin-arm64 cli-darwin-x64 cli-linux-arm64 cli-linux-arm64-musl cli-linux-x64 cli-linux-x64-musl cli-windows-arm64 cli-windows-x64; do
76+
echo "Checking packages/$pkg/bin/..."
77+
ls -la "packages/$pkg/bin/"
78+
done
79+
echo "Checking dist/..."
80+
ls -la dist/
81+
82+
- name: Upload build artifacts
83+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
84+
with:
85+
name: cli-build-${{ inputs.shell }}-${{ inputs.version }}
86+
path: |
87+
packages/cli-*/bin/
88+
dist/
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
name: Publish Preview CLI Packages
2+
3+
on:
4+
workflow_run:
5+
workflows:
6+
- Test
7+
types:
8+
- completed
9+
10+
permissions:
11+
actions: read
12+
contents: read
13+
pull-requests: read
14+
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_sha || github.run_id }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
resolve:
21+
if: >-
22+
github.event.workflow_run.event == 'pull_request' &&
23+
github.event.workflow_run.conclusion == 'success'
24+
name: Resolve preview build context
25+
runs-on: ubuntu-latest
26+
env:
27+
GH_TOKEN: ${{ github.token }}
28+
REPOSITORY: ${{ github.repository }}
29+
outputs:
30+
should_build: ${{ steps.context.outputs.should_build }}
31+
pr_number: ${{ steps.context.outputs.pr_number }}
32+
pr_head_sha: ${{ steps.context.outputs.pr_head_sha }}
33+
preview_version: ${{ steps.context.outputs.preview_version }}
34+
steps:
35+
- name: Resolve PR context
36+
id: context
37+
run: |
38+
set -euo pipefail
39+
40+
should_build=false
41+
pr_number="$(jq -r '.workflow_run.pull_requests[0].number // ""' "$GITHUB_EVENT_PATH")"
42+
pr_head_sha="$(jq -r '.workflow_run.head_sha // ""' "$GITHUB_EVENT_PATH")"
43+
pr_head_branch="$(jq -r '.workflow_run.head_branch // ""' "$GITHUB_EVENT_PATH")"
44+
45+
if [[ -z "${pr_head_sha}" ]]; then
46+
echo "Workflow run has no head SHA; skipping."
47+
echo "should_build=false" >> "$GITHUB_OUTPUT"
48+
exit 0
49+
fi
50+
51+
if [[ -z "${pr_number}" && -n "${pr_head_branch}" ]]; then
52+
pr_number="$(
53+
gh pr list \
54+
--repo "${REPOSITORY}" \
55+
--head "${pr_head_branch}" \
56+
--state open \
57+
--json number,headRefOid \
58+
--jq 'map(select(.headRefOid == "'"${pr_head_sha}"'")) | .[0].number // ""'
59+
)"
60+
fi
61+
62+
if [[ -z "${pr_number}" ]]; then
63+
echo "Test run is not associated with an open pull request; skipping."
64+
echo "should_build=false" >> "$GITHUB_OUTPUT"
65+
exit 0
66+
fi
67+
68+
pr_json="$(gh api "repos/${REPOSITORY}/pulls/${pr_number}")"
69+
current_head_sha="$(jq -r '.head.sha' <<< "${pr_json}")"
70+
state="$(jq -r '.state' <<< "${pr_json}")"
71+
draft="$(jq -r '.draft' <<< "${pr_json}")"
72+
head_repo="$(jq -r '.head.repo.full_name' <<< "${pr_json}")"
73+
base_repo="$(jq -r '.base.repo.full_name' <<< "${pr_json}")"
74+
75+
if [[ "${state}" != "open" ]]; then
76+
echo "PR #${pr_number} is ${state}; skipping."
77+
echo "should_build=false" >> "$GITHUB_OUTPUT"
78+
exit 0
79+
fi
80+
81+
if [[ "${draft}" == "true" ]]; then
82+
echo "PR #${pr_number} is draft; skipping."
83+
echo "should_build=false" >> "$GITHUB_OUTPUT"
84+
exit 0
85+
fi
86+
87+
if [[ "${head_repo}" != "${base_repo}" ]]; then
88+
echo "PR #${pr_number} comes from fork ${head_repo}; skipping."
89+
echo "should_build=false" >> "$GITHUB_OUTPUT"
90+
exit 0
91+
fi
92+
93+
if [[ "${pr_head_sha}" != "${current_head_sha}" ]]; then
94+
echo "Test SHA ${pr_head_sha} is stale; current PR head is ${current_head_sha}. Skipping."
95+
echo "should_build=false" >> "$GITHUB_OUTPUT"
96+
exit 0
97+
fi
98+
99+
preview_version="0.0.0-pr.${pr_number}"
100+
should_build=true
101+
102+
{
103+
echo "should_build=${should_build}"
104+
echo "pr_number=${pr_number}"
105+
echo "pr_head_sha=${pr_head_sha}"
106+
echo "preview_version=${preview_version}"
107+
} >> "$GITHUB_OUTPUT"
108+
109+
build:
110+
needs: resolve
111+
if: needs.resolve.outputs.should_build == 'true'
112+
name: Build preview CLI packages
113+
uses: ./.github/workflows/build-cli-artifacts.yml
114+
with:
115+
version: ${{ needs.resolve.outputs.preview_version }}
116+
shell: legacy
117+
ref: ${{ needs.resolve.outputs.pr_head_sha }}
118+
119+
publish:
120+
needs: [resolve, build]
121+
if: needs.resolve.outputs.should_build == 'true' && needs.build.result == 'success'
122+
name: Publish preview package
123+
runs-on: ubuntu-latest
124+
permissions:
125+
actions: read
126+
contents: read
127+
issues: write
128+
pull-requests: read
129+
env:
130+
GH_TOKEN: ${{ github.token }}
131+
PREVIEW_VERSION: ${{ needs.resolve.outputs.preview_version }}
132+
PR_HEAD_SHA: ${{ needs.resolve.outputs.pr_head_sha }}
133+
PR_NUMBER: ${{ needs.resolve.outputs.pr_number }}
134+
REPOSITORY: ${{ github.repository }}
135+
steps:
136+
- name: Checkout
137+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
138+
with:
139+
ref: ${{ needs.resolve.outputs.pr_head_sha }}
140+
persist-credentials: false
141+
142+
- name: Setup
143+
uses: ./.github/actions/setup
144+
145+
- name: Download preview build artifacts
146+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
147+
with:
148+
name: cli-build-legacy-${{ needs.resolve.outputs.preview_version }}
149+
150+
- name: Prepare package files
151+
run: |
152+
set -euo pipefail
153+
pnpm exec bun apps/cli/scripts/sync-versions.ts --version "${PREVIEW_VERSION}"
154+
pnpm --dir apps/cli build:shim
155+
find packages -path '*/bin/supabase*' -type f -exec chmod +x {} +
156+
157+
- name: Publish preview package
158+
run: |
159+
pnpm exec pkg-pr-new publish \
160+
--pnpm \
161+
--bin \
162+
--comment=off \
163+
--json pkg-pr-new.json \
164+
--no-template \
165+
'./packages/cli-darwin-arm64' \
166+
'./packages/cli-darwin-x64' \
167+
'./packages/cli-linux-arm64' \
168+
'./packages/cli-linux-arm64-musl' \
169+
'./packages/cli-linux-x64' \
170+
'./packages/cli-linux-x64-musl' \
171+
'./packages/cli-windows-arm64' \
172+
'./packages/cli-windows-x64' \
173+
'./apps/cli'
174+
175+
- name: Smoke test preview command
176+
run: |
177+
set -euo pipefail
178+
preview_url="https://pkg.pr.new/supabase@${PR_NUMBER}"
179+
npx --yes "${preview_url}" --version
180+
181+
- name: Update PR comment
182+
run: |
183+
set -euo pipefail
184+
preview_url="https://pkg.pr.new/supabase@${PR_NUMBER}"
185+
short_sha="${PR_HEAD_SHA:0:7}"
186+
marker="<!-- pkg-pr-new-preview -->"
187+
cat > comment.md <<EOF
188+
${marker}
189+
## pkg.pr.new preview
190+
191+
Published version \`${PREVIEW_VERSION}\` from commit [\`${short_sha}\`](https://github.com/${REPOSITORY}/commit/${PR_HEAD_SHA}) after tests passed.
192+
193+
\`\`\`sh
194+
npx ${preview_url}
195+
\`\`\`
196+
197+
\`\`\`sh
198+
npx ${preview_url} --version
199+
\`\`\`
200+
EOF
201+
202+
jq -n --rawfile body comment.md '{ body: $body }' > comment.json
203+
comment_id="$(
204+
gh api "repos/${REPOSITORY}/issues/${PR_NUMBER}/comments" \
205+
--paginate \
206+
--jq '.[] | select(.body | contains("'"${marker}"'")) | .id' \
207+
| head -n1
208+
)"
209+
210+
if [[ -n "${comment_id}" ]]; then
211+
gh api --method PATCH "repos/${REPOSITORY}/issues/comments/${comment_id}" --input comment.json >/dev/null
212+
else
213+
gh api --method POST "repos/${REPOSITORY}/issues/${PR_NUMBER}/comments" --input comment.json >/dev/null
214+
fi

.github/workflows/release-shared.yml

Lines changed: 12 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -53,75 +53,27 @@ on:
5353
required: false
5454
jobs:
5555
build:
56-
runs-on: blacksmith-32vcpu-ubuntu-2404
57-
env:
58-
BUN_SHELL: ${{ inputs.shell }}
59-
VERSION: ${{ inputs.version }}
56+
name: Build CLI artifacts
57+
uses: ./.github/workflows/build-cli-artifacts.yml
58+
with:
59+
version: ${{ inputs.version }}
60+
shell: ${{ inputs.shell }}
61+
secrets:
6062
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
6163
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
6264
POSTHOG_ENDPOINT: ${{ secrets.POSTHOG_ENDPOINT }}
63-
steps:
64-
- name: Checkout
65-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
66-
with:
67-
persist-credentials: false
68-
69-
- name: Setup
70-
uses: ./.github/actions/setup
71-
72-
- name: Setup Go
73-
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
74-
with:
75-
go-version-file: apps/cli-go/go.mod
76-
cache: true
77-
cache-dependency-path: apps/cli-go/go.sum
78-
79-
- name: Pre-download Go modules
80-
working-directory: apps/cli-go
81-
run: go mod download -x
82-
83-
- name: Install nfpm
84-
run: |
85-
echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list
86-
sudo apt-get update
87-
sudo apt-get install -y nfpm
88-
89-
- name: Sync versions
90-
run: pnpm exec bun apps/cli/scripts/sync-versions.ts --version "${VERSION}"
91-
92-
- name: Build selected shell
93-
run: pnpm exec bun apps/cli/scripts/build.ts --version "${VERSION}" --shell "${BUN_SHELL}"
94-
95-
- name: Verify build artifacts
96-
run: |
97-
for pkg in cli-darwin-arm64 cli-darwin-x64 cli-linux-arm64 cli-linux-arm64-musl cli-linux-x64 cli-linux-x64-musl cli-windows-arm64 cli-windows-x64; do
98-
echo "Checking packages/$pkg/bin/..."
99-
ls -la "packages/$pkg/bin/"
100-
done
101-
echo "Checking dist/..."
102-
ls -la dist/
103-
104-
- name: Upload build artifacts
105-
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
106-
with:
107-
name: cli-build-${{ inputs.shell }}-${{ inputs.version }}
108-
path: |
109-
packages/cli-*/bin/
110-
dist/
11165

11266
smoke-test:
11367
needs: build
11468
strategy:
11569
fail-fast: false
116-
# macos-15-intel is the slowest smoke leg and the only one not on
117-
# Blacksmith (Blacksmith macOS is ARM-only). Drop it from the matrix
118-
# on prereleases (PR smoke + develop -> beta) so beta wall-clock isn't
119-
# gated by it; stable releases on main still run the full matrix.
120-
# The matrix list is built via fromJSON because GitHub Actions does
121-
# not allow the `matrix` context in a job-level `if:` (matrix
122-
# expansion happens after job conditions are evaluated).
12370
matrix:
124-
runner: ${{ fromJSON(inputs.prerelease && '["blacksmith-8vcpu-ubuntu-2404","blacksmith-6vcpu-macos-latest","blacksmith-8vcpu-windows-2025"]' || '["blacksmith-8vcpu-ubuntu-2404","blacksmith-6vcpu-macos-latest","macos-15-intel","blacksmith-8vcpu-windows-2025"]') }}
71+
runner:
72+
- blacksmith-8vcpu-ubuntu-2404
73+
- blacksmith-6vcpu-macos-latest
74+
- macos-15-intel
75+
- blacksmith-8vcpu-windows-2025
76+
- windows-11-arm
12577
runs-on: ${{ matrix.runner }}
12678
env:
12779
NPM_TAG: ${{ inputs.npm_tag }}

0 commit comments

Comments
 (0)