Add CI workflow to check assets:precompile output for failures #4
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: Assets Precompile Check | |
| on: | |
| push: | |
| branches: | |
| - 'master' | |
| pull_request: | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - 'react_on_rails_pro/**' | |
| workflow_dispatch: | |
| inputs: | |
| force_run: | |
| description: 'Force run all jobs (bypass detect-changes)' | |
| required: false | |
| type: boolean | |
| default: false | |
| jobs: | |
| detect-changes: | |
| permissions: | |
| contents: read | |
| actions: read | |
| runs-on: ubuntu-22.04 | |
| outputs: | |
| docs_only: ${{ steps.detect.outputs.docs_only }} | |
| run_dummy_tests: ${{ steps.detect.outputs.run_dummy_tests }} | |
| has_full_ci_label: ${{ steps.check-label.outputs.result }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 50 | |
| persist-credentials: false | |
| - name: Check for full-ci label | |
| id: check-label | |
| uses: ./.github/actions/check-full-ci-label | |
| - name: Detect relevant changes | |
| id: detect | |
| run: | | |
| if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then | |
| echo "run_dummy_tests=true" >> "$GITHUB_OUTPUT" | |
| echo "docs_only=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| BASE_REF="${{ github.event.pull_request.base.sha || github.event.before || 'origin/master' }}" | |
| script/ci-changes-detector "$BASE_REF" | |
| shell: bash | |
| - name: Guard docs-only master pushes | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| uses: ./.github/actions/ensure-master-docs-safety | |
| with: | |
| docs-only: ${{ steps.detect.outputs.docs_only }} | |
| previous-sha: ${{ github.event.before }} | |
| precompile-check: | |
| needs: detect-changes | |
| # Skip only if: master push AND docs-only changes | |
| # Otherwise run if: on master OR workflow_dispatch OR dummy tests needed | |
| if: | | |
| !( | |
| github.event_name == 'push' && | |
| github.ref == 'refs/heads/master' && | |
| needs.detect-changes.outputs.docs_only == 'true' | |
| ) && ( | |
| github.ref == 'refs/heads/master' || | |
| github.event_name == 'workflow_dispatch' || | |
| needs.detect-changes.outputs.run_dummy_tests == 'true' | |
| ) | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.4' | |
| bundler: 2.5.9 | |
| # libyaml-dev is needed for psych v5 | |
| - name: Fix dependency for libyaml-dev | |
| run: sudo apt install libyaml-dev | |
| - name: Setup Node | |
| uses: ./.github/actions/setup-node-with-retry | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_ENV" | |
| - name: Setup pnpm cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Print system information | |
| run: | | |
| echo "Linux release: "; cat /etc/issue | |
| echo "Current user: "; whoami | |
| echo "Current directory: "; pwd | |
| echo "Ruby version: "; ruby -v | |
| echo "Node version: "; node -v | |
| echo "pnpm version: "; pnpm --version | |
| echo "Bundler version: "; bundle --version | |
| - name: Install Node modules with pnpm for renderer package | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm add -g yalc | |
| - name: yalc publish for react-on-rails | |
| run: cd packages/react-on-rails && yalc publish | |
| - name: yalc add react-on-rails | |
| run: cd react_on_rails/spec/dummy && yalc add react-on-rails | |
| - name: Install Node modules with pnpm for dummy app | |
| run: cd react_on_rails/spec/dummy && pnpm install --ignore-workspace | |
| - name: Save dummy app ruby gems to cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: react_on_rails/spec/dummy/vendor/bundle | |
| key: dummy-app-gem-cache-${{ hashFiles('react_on_rails/spec/dummy/Gemfile.lock') }}-precompile | |
| - name: Install Ruby Gems for dummy app | |
| run: | | |
| cd react_on_rails/spec/dummy | |
| bundle lock --add-platform 'x86_64-linux' | |
| if ! bundle check --path=vendor/bundle; then | |
| bundle _2.5.9_ install --path=vendor/bundle --jobs=4 --retry=3 | |
| fi | |
| - name: Build ReScript files | |
| run: cd react_on_rails/spec/dummy && pnpm run build:rescript | |
| - name: Generate file system-based packs | |
| run: cd react_on_rails/spec/dummy && RAILS_ENV=production bundle exec rake react_on_rails:generate_packs | |
| - name: Run assets:precompile and check output | |
| run: | | |
| cd react_on_rails/spec/dummy | |
| echo "Running RAILS_ENV=production bin/rake assets:precompile..." | |
| echo "==========================================" | |
| # Run precompile and capture both stdout and stderr | |
| # Use pipefail to catch rake failures even when piped through tee | |
| set -o pipefail | |
| RAILS_ENV=production bin/rake assets:precompile 2>&1 | tee precompile_output.txt | |
| PRECOMPILE_EXIT=${PIPESTATUS[0]} | |
| echo "==========================================" | |
| echo "Precompile finished. Checking output for known issues..." | |
| echo "" | |
| # Check for known failure patterns | |
| FAILURES_FOUND=0 | |
| # Check if rake command itself failed | |
| if [ "$PRECOMPILE_EXIT" -ne 0 ]; then | |
| echo "::error::Precompile command failed with exit code $PRECOMPILE_EXIT" | |
| FAILURES_FOUND=1 | |
| fi | |
| # Pattern 1: Duplicate webpack compilation (indicates rake tasks running twice) | |
| # Look for webpack's "Compiled successfully" message which appears once per compilation | |
| if grep -q "Compiled successfully" precompile_output.txt; then | |
| COMPILE_SUCCESS_COUNT=$(grep -c "Compiled successfully" precompile_output.txt || true) | |
| if [ "$COMPILE_SUCCESS_COUNT" -gt 1 ]; then | |
| echo "::error::FAILURE: Detected $COMPILE_SUCCESS_COUNT webpack compilations (expected 1). Tasks may be running twice." | |
| echo " Matching lines:" | |
| grep -n "Compiled successfully" precompile_output.txt | head -5 | |
| FAILURES_FOUND=1 | |
| fi | |
| fi | |
| # Pattern 2: Duplicate task execution messages | |
| if grep -q "react_on_rails:generate_packs" precompile_output.txt; then | |
| GENERATE_PACKS_COUNT=$(grep -c "react_on_rails:generate_packs" precompile_output.txt || true) | |
| if [ "$GENERATE_PACKS_COUNT" -gt 1 ]; then | |
| echo "::error::FAILURE: react_on_rails:generate_packs task ran $GENERATE_PACKS_COUNT times (should only run once)." | |
| echo " Matching lines:" | |
| grep -n "react_on_rails:generate_packs" precompile_output.txt | |
| FAILURES_FOUND=1 | |
| fi | |
| fi | |
| # Pattern 3: Module not found errors | |
| if grep -Ei "module not found|cannot find module|can't resolve" precompile_output.txt; then | |
| echo "::error::FAILURE: Module resolution errors detected in precompile output." | |
| echo " Sample matching lines:" | |
| grep -Ei "module not found|cannot find module|can't resolve" precompile_output.txt | head -3 | |
| FAILURES_FOUND=1 | |
| fi | |
| # Pattern 4: Webpack build errors (use specific webpack error markers) | |
| if grep -Ei "webpack.*error|failed to compile|compilation failed|ERROR in" precompile_output.txt; then | |
| echo "::error::FAILURE: Webpack compilation errors detected." | |
| echo " Sample matching lines:" | |
| grep -Ei "webpack.*error|failed to compile|compilation failed|ERROR in" precompile_output.txt | head -3 | |
| FAILURES_FOUND=1 | |
| fi | |
| # Pattern 5: Ruby/Rails errors during precompile (match error class format) | |
| if grep -E "(NameError|LoadError|NoMethodError|SyntaxError):" precompile_output.txt; then | |
| echo "::error::FAILURE: Ruby errors detected during precompile." | |
| echo " Sample matching lines:" | |
| grep -E "(NameError|LoadError|NoMethodError|SyntaxError):" precompile_output.txt | head -3 | |
| FAILURES_FOUND=1 | |
| fi | |
| # Pattern 6: Asset pipeline errors | |
| if grep -Ei "Sprockets::FileNotFound|Asset.*was not declared" precompile_output.txt; then | |
| echo "::error::FAILURE: Asset pipeline errors detected." | |
| echo " Sample matching lines:" | |
| grep -Ei "Sprockets::FileNotFound|Asset.*was not declared" precompile_output.txt | head -3 | |
| FAILURES_FOUND=1 | |
| fi | |
| # Pattern 7: Memory issues | |
| if grep -Ei "javascript heap out of memory|killed|out of memory" precompile_output.txt; then | |
| echo "::error::FAILURE: Memory-related errors detected." | |
| echo " Sample matching lines:" | |
| grep -Ei "javascript heap out of memory|killed|out of memory" precompile_output.txt | head -3 | |
| FAILURES_FOUND=1 | |
| fi | |
| # Pattern 8: Check for warnings that might indicate problems | |
| WARNING_COUNT=$(grep -ci "warning" precompile_output.txt || true) | |
| if [ "$WARNING_COUNT" -gt 10 ]; then | |
| echo "::warning::High number of warnings detected: $WARNING_COUNT warnings found. Please review." | |
| echo " Sample warnings:" | |
| grep -i "warning" precompile_output.txt | head -5 | |
| fi | |
| if [ "$FAILURES_FOUND" -eq 1 ]; then | |
| echo "" | |
| echo "==========================================" | |
| echo "PRECOMPILE CHECK FAILED" | |
| echo "==========================================" | |
| echo "Review the output above for details." | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "==========================================" | |
| echo "PRECOMPILE CHECK PASSED" | |
| echo "==========================================" | |
| echo "No known failure patterns detected in precompile output." | |
| - name: Upload precompile output | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: precompile-output-${{ github.run_id }} | |
| path: react_on_rails/spec/dummy/precompile_output.txt | |
| retention-days: 7 |