Blind 75: Array Product Excluding Current #187
Workflow file for this run
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: Code Quality & Analysis | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review, reopened, labeled] | |
| branches: [main, develop] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| checks: write | |
| issues: write | |
| jobs: | |
| analyze-changed-files: | |
| runs-on: ubuntu-latest | |
| name: Analyze Changed Files | |
| if: github.event_name == 'pull_request' && github.actor == 'pertrai1' && contains(github.event.pull_request.labels.*.name, 'code challenge') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Get changed files | |
| id: changed-files | |
| run: | | |
| # Get files changed in this PR | |
| git fetch origin ${{ github.base_ref }} | |
| CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.(js|ts)$' | tr '\n' ' ') | |
| echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT | |
| echo "Changed files: $CHANGED_FILES" | |
| - name: Analyze changed files with ESLint | |
| if: steps.changed-files.outputs.files != '' | |
| run: | | |
| FILES="${{ steps.changed-files.outputs.files }}" | |
| if [ -n "$FILES" ]; then | |
| echo "Running ESLint on: $FILES" | |
| # Run ESLint and capture exit code | |
| if npx eslint $FILES --format=json --output-file=eslint-report.json; then | |
| echo "✅ ESLint passed - no errors found" | |
| else | |
| eslint_exit_code=$? | |
| echo "⚠️ ESLint found issues (exit code: $eslint_exit_code)" | |
| # Also run with default formatter for readable output in logs | |
| echo "ESLint issues found in changed files:" | |
| npx eslint $FILES || true | |
| fi | |
| else | |
| echo "No JavaScript/TypeScript files changed" | |
| echo "[]" > eslint-report.json | |
| fi | |
| - name: Format check on changed files | |
| if: steps.changed-files.outputs.files != '' | |
| run: | | |
| FILES="${{ steps.changed-files.outputs.files }}" | |
| if [ -n "$FILES" ]; then | |
| echo "Running Prettier check on: $FILES" | |
| if npx prettier --check $FILES; then | |
| echo "✅ Prettier check passed - all files properly formatted" | |
| else | |
| echo "⚠️ Prettier found formatting issues in changed files" | |
| echo "Run 'npm run format' locally to fix formatting issues" | |
| fi | |
| fi | |
| - name: Run complexity analysis on changed files | |
| if: steps.changed-files.outputs.files != '' | |
| run: | | |
| FILES="${{ steps.changed-files.outputs.files }}" | |
| mkdir -p docs/analysis | |
| mkdir -p analysis-results | |
| # Check if complexity analyzer exists | |
| if [ ! -f "scripts/complexity-analyzer.js" ]; then | |
| echo "⚠️ Warning: Complexity analyzer script not found at scripts/complexity-analyzer.js" | |
| echo "Skipping complexity analysis step" | |
| echo "# Complexity Analysis Unavailable" > analysis-results/analysis-error.md | |
| echo "The complexity analyzer script was not found in this repository." >> analysis-results/analysis-error.md | |
| echo "Please ensure \`scripts/complexity-analyzer.js\` exists to enable algorithm analysis." >> analysis-results/analysis-error.md | |
| exit 0 | |
| fi | |
| if [ -n "$FILES" ]; then | |
| echo "Running complexity analysis on changed files..." | |
| analysis_success=0 | |
| analysis_total=0 | |
| analysis_files_created="" | |
| for file in $FILES; do | |
| if [ -f "$file" ]; then | |
| analysis_total=$((analysis_total + 1)) | |
| echo "Analyzing: $file" | |
| # Extract problem name from file path for proper naming | |
| # Examples: leetcode/easy/0205-isomorphic-strings/isomorphic-strings.js -> isomorphic-strings | |
| # Examples: greatfrontend/blind-75/two-sum/solution.js -> two-sum | |
| echo "Checking file pattern for: $file" | |
| if [[ "$file" =~ (leetcode|greatfrontend)/[^/]+/[0-9]+-([^/]+)/([^/]+)\.(js|ts)$ ]]; then | |
| problem_name="${BASH_REMATCH[2]}" | |
| analysis_file="docs/analysis/${problem_name}-analysis.md" | |
| echo "✅ Matched numbered problem pattern. Problem: $problem_name" | |
| elif [[ "$file" =~ (leetcode|greatfrontend)/[^/]+/([^/]+)/([^/]+)\.(js|ts)$ ]]; then | |
| problem_name="${BASH_REMATCH[2]}" | |
| analysis_file="docs/analysis/${problem_name}-analysis.md" | |
| echo "✅ Matched platform pattern. Problem: $problem_name" | |
| echo "Creating analysis file: $analysis_file" | |
| # Run analysis and save to docs/analysis with proper naming | |
| if node scripts/complexity-analyzer.js "$file" > "$analysis_file" 2>&1; then | |
| echo "✅ Successfully analyzed: $file -> $analysis_file" | |
| analysis_success=$((analysis_success + 1)) | |
| analysis_files_created="$analysis_files_created $analysis_file" | |
| # Also create a copy in analysis-results for PR comment | |
| cp "$analysis_file" "analysis-results/${problem_name}-analysis.md" | |
| else | |
| echo "❌ Failed to analyze: $file" | |
| # Create error report for this file | |
| cat > "$analysis_file" << EOF | |
| # Analysis Failed for \`$file\` | |
| ❌ **Error**: The complexity analysis failed for this file. | |
| **Possible causes:** | |
| - Syntax errors in the code | |
| - Unsupported language constructs | |
| - File encoding issues | |
| **Recommendation**: Check the workflow logs for detailed error information. | |
| EOF | |
| analysis_files_created="$analysis_files_created $analysis_file" | |
| fi | |
| else | |
| echo "⚠️ File does not match expected pattern: $file" | |
| # For non-standard files, use the original logic | |
| base_name=$(basename "$file") | |
| output_name="${base_name%.*}" | |
| if node scripts/complexity-analyzer.js "$file" > "analysis-results/${output_name}.md" 2>&1; then | |
| echo "✅ Successfully analyzed: $file" | |
| analysis_success=$((analysis_success + 1)) | |
| else | |
| echo "❌ Failed to analyze: $file" | |
| fi | |
| fi | |
| else | |
| echo "⚠️ File not found: $file" | |
| fi | |
| done | |
| echo "📊 Analysis Summary: $analysis_success/$analysis_total files analyzed successfully" | |
| echo "analysis_files_created=$analysis_files_created" >> $GITHUB_ENV | |
| else | |
| echo "No files to analyze" | |
| fi | |
| - name: Commit and push analysis files | |
| if: steps.changed-files.outputs.files != '' && env.analysis_files_created != '' | |
| run: | | |
| # Configure git | |
| git config --local user.email "[email protected]" | |
| git config --local user.name "GitHub Action" | |
| # Check if there are any changes to commit | |
| if [ -n "$(git status --porcelain docs/analysis/)" ]; then | |
| echo "📝 Committing analysis files to docs/analysis/" | |
| # Stage only the analysis files we created | |
| git add docs/analysis/ | |
| # Commit with descriptive message | |
| git commit -m "📊 Add automated complexity analysis for PR changes | |
| - Generated analysis files for changed solutions | |
| - Files: ${{ steps.changed-files.outputs.files }} | |
| - Timestamp: $(date -u +"%Y-%m-%d %H:%M:%S UTC") | |
| [skip ci]" | |
| # Push to the PR branch | |
| git push origin HEAD:${{ github.head_ref }} | |
| echo "✅ Analysis files committed and pushed successfully" | |
| else | |
| echo "ℹ️ No analysis files to commit" | |
| fi | |
| - name: Generate solution summary | |
| if: steps.changed-files.outputs.files != '' | |
| run: | | |
| cat > solution-analysis.md << 'EOF' | |
| # 🧮 Solution Analysis | |
| **PR:** ${{ github.event.pull_request.title }} | |
| **Files Changed:** ${{ steps.changed-files.outputs.files }} | |
| ## 📊 Code Quality Results | |
| ### ESLint Analysis | |
| EOF | |
| # Add ESLint results | |
| if [ -f eslint-report.json ]; then | |
| node -e " | |
| const report = JSON.parse(require('fs').readFileSync('eslint-report.json', 'utf8')); | |
| if (report.length === 0) { | |
| console.log('✅ **No ESLint issues found**'); | |
| } else { | |
| const totalErrors = report.reduce((sum, file) => sum + file.errorCount, 0); | |
| const totalWarnings = report.reduce((sum, file) => sum + file.warningCount, 0); | |
| console.log(\`- **Errors:** \${totalErrors}\`); | |
| console.log(\`- **Warnings:** \${totalWarnings}\`); | |
| if (totalErrors > 0 || totalWarnings > 0) { | |
| console.log('\\n**Issues by file:**'); | |
| report.forEach(file => { | |
| if (file.errorCount > 0 || file.warningCount > 0) { | |
| console.log(\`- \${file.filePath}: \${file.errorCount} errors, \${file.warningCount} warnings\`); | |
| } | |
| }); | |
| } | |
| } | |
| " >> solution-analysis.md | |
| fi | |
| echo "" >> solution-analysis.md | |
| echo "### 🔍 Complexity Analysis" >> solution-analysis.md | |
| echo "" >> solution-analysis.md | |
| # Add complexity analysis for each changed file | |
| for file in analysis-results/*.md; do | |
| if [ -f "$file" ]; then | |
| echo "#### $(basename "$file" .md)" >> solution-analysis.md | |
| echo "" >> solution-analysis.md | |
| cat "$file" >> solution-analysis.md | |
| echo "" >> solution-analysis.md | |
| fi | |
| done | |
| # Add tips section | |
| cat >> solution-analysis.md << 'EOF' | |
| ## 💡 Analysis Tips | |
| - **Time Complexity**: Focus on the dominant operation in loops | |
| - **Space Complexity**: Consider auxiliary data structures | |
| - **Optimization**: Look for opportunities to improve efficiency | |
| - **Edge Cases**: Ensure your solution handles empty inputs, null/undefined, edge conditions | |
| ## 📁 Analysis Files Created | |
| Detailed analysis files have been automatically generated and committed to `docs/analysis/` for future reference. | |
| ## 🎯 Next Steps | |
| 1. Review any ESLint errors/warnings above | |
| 2. Consider the complexity analysis - is this the optimal approach? | |
| 3. Test with edge cases mentioned in the problem description | |
| 4. Add comments explaining complex logic | |
| 5. Check the `docs/analysis/` directory for detailed complexity analysis files | |
| --- | |
| *Analysis generated for PR files only* | |
| EOF | |
| - name: Comment PR with analysis | |
| if: steps.changed-files.outputs.files != '' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| // Read the analysis report | |
| let analysisContent = 'Analysis report not available'; | |
| try { | |
| analysisContent = fs.readFileSync('solution-analysis.md', 'utf8'); | |
| } catch (e) { | |
| console.log('Could not read analysis report:', e.message); | |
| analysisContent = `## 🧮 Solution Analysis | |
| ❌ Analysis could not be completed. Please check the workflow logs. | |
| **Files attempted:** ${{ steps.changed-files.outputs.files }}`; | |
| } | |
| // Check if we already commented on this PR | |
| 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.login === 'github-actions[bot]' && | |
| comment.body.includes('🧮 Solution Analysis') | |
| ); | |
| if (botComment) { | |
| // Update existing comment | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: analysisContent | |
| }); | |
| console.log('Updated existing PR comment'); | |
| } else { | |
| // Create new comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: analysisContent | |
| }); | |
| console.log('Created new PR comment'); | |
| } | |
| - name: Upload detailed analysis | |
| if: steps.changed-files.outputs.files != '' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: solution-analysis-detailed | |
| path: | | |
| solution-analysis.md | |
| analysis-results/ | |
| eslint-report.json | |
| retention-days: 30 |