Generate Database Types For Schema Changes #39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |