Skip to content

chore: publish new package versions (#4766) #2314

chore: publish new package versions (#4766)

chore: publish new package versions (#4766) #2314

name: Deploy Examples
on:
push:
branches: ['main']
# pull_request:
# paths: ['examples/*/**']
concurrency:
group: ${{ github.event_name == 'push' && 'prod-deploy-group' || format('examples-pr-{0}', github.event.number) }}
jobs:
example-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.create-example-matrix.outputs.matrix }}
has_examples: ${{ steps.create-example-matrix.outputs.has_examples }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create example matrix
id: create-example-matrix
env:
BASE_SHA: ${{ github.event.before }}
run: node scripts/ci/example-matrix.mjs changed-deployable
deploy:
name: Deploy ${{ matrix.example.name }}
environment: ${{ github.event_name == 'push' && 'Production' || 'Pull request' }}
runs-on: ubuntu-latest
continue-on-error: true
needs: example-matrix
if: ${{ needs.example-matrix.outputs.has_examples == 'true' }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.example-matrix.outputs.matrix) }}
outputs:
yjs: ${{ steps.deploy.outputs.yjs }}
linearlite-read-only: ${{ steps.deploy.outputs.linearlite-read-only }}
write-patterns: ${{ steps.deploy.outputs.write-patterns }}
nextjs: ${{ steps.deploy.outputs.nextjs }}
todo-app: ${{ steps.deploy.outputs.todo-app }}
proxy-auth: ${{ steps.deploy.outputs.proxy-auth }}
phoenix-liveview: ${{ steps.deploy.outputs.phoenix-liveview }}
tanstack: ${{ steps.deploy.outputs.tanstack }}
remix: ${{ steps.deploy.outputs.remix }}
react: ${{ steps.deploy.outputs.react }}
burn: ${{ steps.deploy.outputs.burn }}
tanstack-db-web-starter: ${{ steps.deploy.outputs.tanstack-db-web-starter }}
env:
DEPLOY_ENV: ${{ github.event_name == 'push' && 'production' || format('pr-{0}', github.event.number) }}
PULUMI_LOG_LEVEL: debug
SST_DEBUG: '1'
SHARED_INFRA_VPC_ID: ${{ vars.SHARED_INFRA_VPC_ID }}
SHARED_INFRA_CLUSTER_ARN: ${{ vars.SHARED_INFRA_CLUSTER_ARN }}
SHARED_EXAMPLES_DATABASE_URI: ${{ secrets.SHARED_EXAMPLES_DATABASE_URI }}
SHARED_EXAMPLES_POOLED_DATABASE_URI: ${{ secrets.SHARED_EXAMPLES_POOLED_DATABASE_URI }}
SHARED_EXAMPLES_SOURCE_ID: ${{ vars.SHARED_EXAMPLES_SOURCE_ID }}
SHARED_EXAMPLES_SOURCE_SECRET: ${{ secrets.SHARED_EXAMPLES_SOURCE_SECRET }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_DEFAULT_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_DEFAULT_ACCOUNT_ID }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
NEON_API_KEY: ${{ secrets.NEON_API_KEY }}
NEON_PROJECT_ID: ${{ secrets.NEON_PROJECT_ID }}
ELECTRIC_API: ${{ secrets.ELECTRIC_API }}
ELECTRIC_ADMIN_API: ${{ secrets.ELECTRIC_ADMIN_API }}
ELECTRIC_TEAM_ID: ${{ secrets.ELECTRIC_TEAM_ID }}
ELECTRIC_ADMIN_API_AUTH_TOKEN: ${{ secrets.ELECTRIC_ADMIN_API_AUTH_TOKEN }}
SECRET_KEY_BASE: ${{ secrets.LIVEVIEW_EXAMPLE_SECRET_KEY_BASE }}
ANTHROPIC_KEY: ${{ secrets.ANTHROPIC_KEY }}
QUICKSTART_DATABASE_URI: ${{ secrets.QUICKSTART_DATABASE_URI }}
QUICKSTART_POOLED_DATABASE_URI: ${{ secrets.QUICKSTART_POOLED_DATABASE_URI }}
QUICKSTART_SOURCE_ID: ${{ vars.QUICKSTART_SOURCE_ID }}
QUICKSTART_SOURCE_SECRET: ${{ secrets.QUICKSTART_SOURCE_SECRET }}
BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }}
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.tool-versions'
cache: 'pnpm'
- name: Install dependencies
run: |
if [ -f "${{ matrix.example.path }}/package.json" ]; then
pnpm --filter "$(jq -r .name "${{ matrix.example.path }}/package.json")..." --filter @electric-examples/shared --filter @electric-sql/client --filter @electric-sql/experimental --filter @electric-sql/react install --frozen-lockfile
else
pnpm install --frozen-lockfile
fi
- name: Cache SST state
uses: actions/cache@v4
with:
path: .sst
key: sst-cache-${{ matrix.example.name }}-${{ runner.os }}
restore-keys: |
sst-cache-${{ matrix.example.name }}-${{ runner.os }}
- name: Deploy
id: deploy
working-directory: ./${{ matrix.example.path }}
run: |
pnpm --filter @electric-sql/client --filter @electric-sql/experimental --filter @electric-sql/react run build
pnpm sst deploy --stage ${{ env.DEPLOY_ENV }}
if [ -f ".sst/outputs.json" ]; then
website=$(jq -r '.website' .sst/outputs.json)
echo "${{ matrix.example.name }}=$website" >> $GITHUB_OUTPUT
echo "website=$website" >> $GITHUB_OUTPUT
else
echo "sst outputs file not found. Exiting."
exit 123
fi
- name: Test deployed example
if: ${{ matrix.example.deploy_test_folder != '' }}
uses: ./.github/actions/test-example
with:
test_folder: ${{ matrix.example.deploy_test_folder }}
example_url: ${{ steps.deploy.outputs.website }}
comment:
if: github.event_name == 'pull_request' && needs.example-matrix.outputs.has_examples == 'true'
needs: [example-matrix, deploy]
runs-on: ubuntu-latest
steps:
- name: Create PR comment with deployment URLs
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// Get the matrix of examples that were deployed
const matrix = JSON.parse(${{ toJSON(needs.example-matrix.outputs.matrix) }})
const urls = {
yjs: "${{ needs.deploy.outputs.yjs }}",
"linearlite-read-only": "${{ needs.deploy.outputs.linearlite-read-only }}",
"write-patterns": "${{ needs.deploy.outputs.write-patterns }}",
nextjs: "${{ needs.deploy.outputs.nextjs }}",
"todo-app": "${{ needs.deploy.outputs.todo-app }}",
"proxy-auth": "${{ needs.deploy.outputs.proxy-auth }}",
"phoenix-liveview": "${{ needs.deploy.outputs.phoenix-liveview }}",
"tanstack": "${{ needs.deploy.outputs.tanstack }}",
"remix": "${{ needs.deploy.outputs.remix }}",
"react": "${{ needs.deploy.outputs.react }}",
"tanstack-db-web-starter": "${{ needs.deploy.outputs.tanstack-db-web-starter }}"
}
// Create deployments array only for examples that were deployed
const deployments = matrix.example.map(example => ({
name: example.name,
url: urls[example.name]
}))
const commentBody = [
"## Examples",
...deployments.map(d => `- ${d.name}: ${d.url || '*deploy failed*'}`),
].join('\n')
const prNumber = context.issue.number
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
})
const existingComment = comments.find(comment => comment.user.login ==='github-actions[bot]' && comment.body.startsWith("## Examples"))
if (existingComment) {
// Update the existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body: commentBody,
})
} else {
// Create a new comment if none exists
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: commentBody,
})
}