fix: upload reliability, admin features, and recipe details page #41
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: PR Compliance Checks | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| branches: [main] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| conventional-commits: | |
| name: Validate Conventional Commits (Warning Only) | |
| runs-on: ubuntu-latest | |
| if: ${{ !github.event.pull_request.draft }} | |
| continue-on-error: true | |
| permissions: | |
| pull-requests: write | |
| issues: write | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate conventional commits | |
| uses: wagoid/commitlint-github-action@v6 | |
| with: | |
| configFile: .commitlintrc.warning.json | |
| continue-on-error: true | |
| - name: Add commit message guidance comment | |
| if: failure() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('Conventional Commit Format') | |
| ); | |
| if (!botComment) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: [ | |
| "## β οΈ Conventional Commit Format", | |
| "", | |
| "Your commit messages don't follow the conventional commit format, but **this won't block your PR from being merged**.", | |
| "", | |
| "### Expected Format:", | |
| "```", | |
| "<type>[optional scope]: <description>", | |
| "", | |
| "[optional body]", | |
| "", | |
| "[optional footer(s)]", | |
| "```", | |
| "", | |
| "### Examples:", | |
| "- `feat: add changelog generation support`", | |
| "- `fix: resolve login redirect issue`", | |
| "- `docs: update README with new instructions`", | |
| "- `chore: update dependencies`", | |
| "", | |
| "### Valid Types:", | |
| "`feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`", | |
| "", | |
| "This helps with:", | |
| "- π Automatic changelog generation", | |
| "- π Automated semantic versioning", | |
| "- π Better project history tracking", | |
| "", | |
| "*This is a non-blocking warning - your PR can still be merged without fixing this.*" | |
| ].join('\n') | |
| }); | |
| } | |
| code-quality: | |
| name: Code Quality Checks | |
| runs-on: ubuntu-latest | |
| if: ${{ !github.event.pull_request.draft }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run TypeScript type checking | |
| run: npm run build | |
| - name: Debug environment | |
| run: | | |
| echo "Node version: $(node --version)" | |
| echo "NPM version: $(npm --version)" | |
| echo "Current directory: $(pwd)" | |
| echo "Package.json type: $(node -p 'JSON.parse(require("fs").readFileSync("package.json", "utf8")).type')" | |
| ls -la node_modules/@nivo/ || echo "@nivo not found" | |
| ls -la node_modules/d3-interpolate/ || echo "d3-interpolate not found" | |
| - name: Run tests | |
| run: npm test -- --coverage --passWithNoTests --reporter=verbose | |
| env: | |
| VITE_OPENAI_API_KEY: test-key-for-ci | |
| NODE_OPTIONS: "--unhandled-rejections=strict" | |
| - name: Upload coverage reports | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| file: ./coverage/lcov.info | |
| fail_ci_if_error: false | |
| security-audit: | |
| name: Security Audit | |
| runs-on: ubuntu-latest | |
| if: ${{ !github.event.pull_request.draft }} | |
| permissions: | |
| security-events: write | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Fix vulnerabilities | |
| run: npm audit fix | |
| - name: Run npm audit | |
| run: npm audit --audit-level=moderate | |
| - name: Initialize CodeQL | |
| uses: github/codeql-action/init@v3 | |
| with: | |
| languages: javascript | |
| - name: Perform CodeQL Analysis | |
| uses: github/codeql-action/analyze@v3 | |
| bundle-size: | |
| name: Bundle Size Impact | |
| runs-on: ubuntu-latest | |
| if: ${{ !github.event.pull_request.draft }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build application | |
| run: npm run build | |
| - name: Analyze bundle size | |
| run: | | |
| echo "## Bundle Size Analysis" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Get bundle sizes | |
| if [ -d "dist" ]; then | |
| echo "### JavaScript Bundles:" >> $GITHUB_STEP_SUMMARY | |
| find dist -name "*.js" -not -name "*.map" -exec du -h {} \; | sort -hr | head -10 >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### CSS Bundles:" >> $GITHUB_STEP_SUMMARY | |
| find dist -name "*.css" -exec du -h {} \; | sort -hr >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Total Size:" >> $GITHUB_STEP_SUMMARY | |
| du -sh dist >> $GITHUB_STEP_SUMMARY | |
| # Check if bundle sizes are reasonable (warn if JS > 2MB) | |
| total_js_size=$(find dist -name "*.js" -not -name "*.map" -exec stat -c%s {} \; | awk '{sum+=$1} END {print sum}') | |
| if [ "$total_js_size" -gt 2097152 ]; then | |
| echo "β οΈ **Warning**: Total JavaScript bundle size is $(( total_js_size / 1024 / 1024 ))MB" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "β Bundle size looks good!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "β No dist folder found" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| file-validation: | |
| name: Required Files Check | |
| runs-on: ubuntu-latest | |
| if: ${{ !github.event.pull_request.draft }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Check required files | |
| run: | | |
| required_files=( | |
| "package.json" | |
| "README.md" | |
| "LICENSE" | |
| ".gitignore" | |
| "tsconfig.json" | |
| ) | |
| missing_files=() | |
| for file in "${required_files[@]}"; do | |
| if [[ ! -f "$file" ]]; then | |
| missing_files+=("$file") | |
| fi | |
| done | |
| if [[ ${#missing_files[@]} -gt 0 ]]; then | |
| echo "β Missing required files:" | |
| printf '%s\n' "${missing_files[@]}" | |
| exit 1 | |
| else | |
| echo "β All required files present" | |
| fi | |
| pr-labels: | |
| name: PR Label Management | |
| runs-on: ubuntu-latest | |
| if: ${{ !github.event.pull_request.draft }} | |
| permissions: | |
| pull-requests: write | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Auto-label PR based on changes | |
| uses: actions/labeler@v5 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| configuration-path: .github/pr-labeler.yml | |
| compliance-summary: | |
| name: Compliance Summary | |
| runs-on: ubuntu-latest | |
| needs: [conventional-commits, code-quality, security-audit, bundle-size, file-validation, pr-labels] | |
| if: always() && !github.event.pull_request.draft | |
| steps: | |
| - name: Check compliance status | |
| run: | | |
| echo "## π Compliance Check Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ needs.conventional-commits.result }}" == "success" ]]; then | |
| echo "β Conventional Commits: PASSED" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.conventional-commits.result }}" == "failure" ]]; then | |
| echo "β οΈ Conventional Commits: WARNING (non-blocking)" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "β Conventional Commits: SKIPPED" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.code-quality.result }}" == "success" ]]; then | |
| echo "β Code Quality: PASSED" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "β Code Quality: FAILED" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.security-audit.result }}" == "success" ]]; then | |
| echo "β Security Audit: PASSED" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "β Security Audit: FAILED" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.bundle-size.result }}" == "success" ]]; then | |
| echo "β Bundle Size: PASSED" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "β Bundle Size: FAILED" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.file-validation.result }}" == "success" ]]; then | |
| echo "β File Validation: PASSED" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "β File Validation: FAILED" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "π **Overall Status**: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY |