Skip to content

Generate Database Types For Schema Changes #39

Generate Database Types For Schema Changes

Generate Database Types For Schema Changes #39

name: Generate Database Types For Schema Changes
on:
pull_request:
paths:
- apps/backend/db/db_setup.sql
workflow_run:
workflows: ["Lambda README Generation"]
types: [completed]
workflow_dispatch:
permissions:
contents: write
pull-requests: write
env:
NODE_VERSION: '23'
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb
jobs:
regenerate-types:
name: Auto-regenerate DB Types
runs-on: ubuntu-latest
if: >
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_branch || github.ref }}
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: |
echo "Installing project dependencies"
npm ci --legacy-peer-deps
echo "Installing kysely-codegen globally"
npm install -g kysely-codegen
echo "Verifying kysely-codegen installation"
kysely-codegen --version || {
echo "Error: kysely-codegen installation failed"
exit 1
}
- name: Setup PostgreSQL
uses: ikalnytskyi/action-setup-postgres@v6
with:
username: postgres
password: postgres
database: testdb
port: 5432
id: postgres
- name: Verify PostgreSQL connection
run: |
echo "Testing PostgreSQL connection"
psql -h localhost -U postgres -d testdb -c "SELECT version();"
env:
PGPASSWORD: postgres
- name: Initialize database schema
run: |
echo "Applying database schema"
psql -h localhost -U postgres -d testdb -f apps/backend/db/db_setup.sql
echo "Verifying schema application"
psql -h localhost -U postgres -d testdb -c "\dt"
env:
PGPASSWORD: postgres
- name: Generate types with kysely-codegen
run: |
echo "Starting type generation..."
cd apps/backend/db
# Run kysely-codegen
kysely-codegen \
--url "$DATABASE_URL" \
--out-file db-types.d.ts \
--dialect postgres || {
echo "Error: kysely-codegen failed to generate types"
exit 1
}
# Verify the output file was created
if [ ! -f "db-types.d.ts" ]; then
echo "Error: db-types.d.ts was not generated"
exit 1
fi
echo "Type generation successful"
- name: Copy generated types to lambda functions
run: |
echo "Copying generated types to lambda functions"
SOURCE_FILE="apps/backend/db/db-types.d.ts"
# verify the source file exists
if [ ! -f "$SOURCE_FILE" ]; then
echo "Error: Generated types file not found at $SOURCE_FILE"
exit 1
fi
if [ ! -s "$SOURCE_FILE" ]; then
echo "Error: Generated types file is empty"
exit 1
fi
# Define target lambda directories
LAMBDA_DIRS=()
for dir in apps/backend/lambdas/*; do
if [ -d "$dir" ]; then
LAMBDA_DIRS+=("$dir")
echo " Found: $dir"
fi
done
if [ ${#LAMBDA_DIRS[@]} -eq 0 ]; then
echo "Error: No lambda directories found in apps/backend/lambdas/"
exit 1
fi
# Track success and failures
SUCCESS_COUNT=0
FAIL_COUNT=0
for dir in "${LAMBDA_DIRS[@]}"; do
if [ -d "$dir" ]; then
echo "Copying to $dir/db-types.d.ts"
cp "$SOURCE_FILE" "$dir/db-types.d.ts"
if [ $? -eq 0 ]; then
((SUCCESS_COUNT++))
else
echo "Failed to copy to $dir"
((FAIL_COUNT++))
fi
else
echo "Warning: Directory $dir does not exist"
((FAIL_COUNT++))
fi
done
echo ""
echo "Copy summary: $SUCCESS_COUNT succeeded, $FAIL_COUNT failed"
if [ $SUCCESS_COUNT -eq 0 ]; then
echo "Error: Failed to copy types to any lambda function"
exit 1
fi
- name: Verify TypeScript compilation
run: |
echo "Verifying TypeScript compilation"
# check if tsconfig.json exists
if [ ! -f "tsconfig.json" ]; then
echo "Warning: tsconfig.json not found in root, skipping full compilation check"
echo "Performing basic syntax check on generated types..."
# Ensure the file is valid TypeScript
for file in apps/backend/lambdas/*/db-types.d.ts; do
if [ -f "$file" ]; then
npx tsc --noEmit --skipLibCheck "$file" || {
echo "Error: $file contains TypeScript errors"
exit 1
}
fi
done
else
npx tsc --noEmit --skipLibCheck || {
echo "Error: TypeScript compilation failed"
echo "The generated database types may be incompatible with the codebase."
exit 1
}
fi
echo "TypeScript compilation successful"
- name: Check for changes
id: git-check
run: |
git add -N apps/backend/lambdas/*/db-types.d.ts
if git diff --exit-code apps/backend/lambdas/*/db-types.d.ts; then
echo "changes=false" >> $GITHUB_OUTPUT
echo "No changes detected in generated types"
else
echo "changes=true" >> $GITHUB_OUTPUT
echo "Changes detected in generated types"
echo "Changed files:"
git diff --name-only apps/backend/lambdas/*/db-types.d.ts
fi
- name: Get PR author information
if: steps.git-check.outputs.changes == 'true'
id: pr-author
run: |
# username
PR_AUTHOR_NAME="${{ github.event.pull_request.user.login }}"
PR_AUTHOR_EMAIL="${{ github.event.pull_request.user.login }}@users.noreply.github.com"
REAL_EMAIL=$(gh api /users/${{ github.event.pull_request.user.login }} --jq '.email' 2>/dev/null || echo "")
if [ -n "$REAL_EMAIL" ] && [ "$REAL_EMAIL" != "null" ]; then
PR_AUTHOR_EMAIL="$REAL_EMAIL"
fi
echo "name=$PR_AUTHOR_NAME" >> $GITHUB_OUTPUT
echo "email=$PR_AUTHOR_EMAIL" >> $GITHUB_OUTPUT
echo "PR Author: $PR_AUTHOR_NAME <$PR_AUTHOR_EMAIL>"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit and push changes
if: steps.git-check.outputs.changes == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add apps/backend/lambdas/*/db-types.d.ts
COMMIT_MESSAGE="chore: auto-regenerate database types from schema changes"
if [ -n "${{ steps.pr-author.outputs.name }}" ]; then
COMMIT_MESSAGE="${COMMIT_MESSAGE}
Co-authored-by: ${{ steps.pr-author.outputs.name }} <${{ steps.pr-author.outputs.email }}>"
fi
git commit -m "$COMMIT_MESSAGE"
git push origin HEAD:${{ github.head_ref }}
echo "Changes committed + pushed successfully"
- name: Comment on PR
if: steps.git-check.outputs.changes == 'true'
uses: actions/github-script@v7
with:
script: |
const { execSync } = require('child_process');
const files = execSync('git diff --name-only apps/backend/lambdas/*/db-types.d.ts')
.toString()
.trim()
.split('\n')
.filter(f => f)
.map(f => `- \`${f}\``)
.join('\n');
const comment = `**Database Types Auto-Regenerated**
The database schema has changed and the Typescript definitions for these lambda functions were regenerated:
${files}
The updated types are now in sync with schema changes.`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
- name: Comment on PR if no changes
if: steps.git-check.outputs.changes != 'true'
uses: actions/github-script@v7
with:
script: |
const comment = `**Database Types Check Complete**
The database schema files were modified, but the regenerated TypeScript types are identical to the existing ones.
No changes were needed and the type definitions are already up to date.`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
- name: Workflow summary
if: always()
run: |
echo "## 🔄 Database Type Regeneration Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.git-check.outputs.changes }}" == "true" ]; then
echo "### Status: Types Regenerated Successfully" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The following files were updated and committed:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
for file in apps/backend/lambdas/*/db-types.d.ts; do
if [ -f "$file" ]; then
echo "- \`$file\`" >> $GITHUB_STEP_SUMMARY
fi
done
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Next Steps:** The changes have been automatically committed to this PR. Review the updated types and merge when ready." >> $GITHUB_STEP_SUMMARY
else
echo "### Status: No Changes Needed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The regenerated types are identical to the existing ones." >> $GITHUB_STEP_SUMMARY
echo "Your type definitions are already in sync with the schema." >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Workflow Trigger:** Schema change detected in:" >> $GITHUB_STEP_SUMMARY
echo "- \`apps/backend/db/db_setup.sql\`" >> $GITHUB_STEP_SUMMARY