Skip to content

[Pro] Add RSC SSR synchrony regression tests: complete payload must render before setTimeout(0) #15178

[Pro] Add RSC SSR synchrony regression tests: complete payload must render before setTimeout(0)

[Pro] Add RSC SSR synchrony regression tests: complete payload must render before setTimeout(0) #15178

name: Lint JS and Ruby
permissions:
contents: read
on:
push:
branches:
- 'main'
- 'release/**'
# Always trigger on main/release branches; docs-only detection handles skipping heavy jobs
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
merge_group:
workflow_dispatch:
inputs:
force_full_hosted:
description: 'Force full hosted CI (bypass optimized detect-changes)'
required: false
type: boolean
default: false
pull_request_base_ref:
description: 'Pull request base branch for label/command dispatches'
required: false
type: string
pull_request_base_sha:
description: 'Pull request base SHA for label/command dispatches'
required: false
type: string
jobs:
detect-changes:
# Branch deletion push events have no checkoutable release ref.
if: github.event_name != 'push' || github.event.deleted != true
permissions:
contents: read
actions: read
issues: read
runs-on: ubuntu-22.04
outputs:
docs_only: ${{ steps.detect.outputs.docs_only }}
non_runtime_only: ${{ steps.detect.outputs.non_runtime_only }}
run_lint: ${{ steps.detect.outputs.run_lint }}
run_js_tests: ${{ steps.detect.outputs.run_js_tests }}
run_ruby_tests: ${{ steps.detect.outputs.run_ruby_tests }}
run_dummy_tests: ${{ steps.detect.outputs.run_dummy_tests }}
run_generators: ${{ steps.detect.outputs.run_generators }}
should_run_hosted_ci: ${{ steps.hosted-ci.outputs.should_run_hosted_ci }}
should_force_full_hosted_ci: ${{ steps.hosted-ci.outputs.should_force_full_hosted_ci }}
steps:
- uses: actions/checkout@v4
with:
# Full history is only needed for workflow_dispatch base-SHA reruns.
fetch-depth: ${{ github.event_name == 'workflow_dispatch' && '0' || '50' }}
persist-credentials: false
- name: Select hosted CI mode
id: hosted-ci
uses: ./.github/actions/hosted-ci-selectors
with:
force-full-hosted: ${{ inputs.force_full_hosted || false }}
base-ref: ${{ inputs.pull_request_base_ref || '' }}
- name: Detect relevant changes
id: detect
env:
DISPATCH_BASE_REF: ${{ inputs.pull_request_base_ref || '' }}
DISPATCH_BASE_SHA: ${{ inputs.pull_request_base_sha || '' }}
run: |
# Force-full hosted CI is the explicit escape hatch that bypasses
# optimized change selection. Hosted readiness alone stays path-based.
if [ "${{ steps.hosted-ci.outputs.should_force_full_hosted_ci }}" = "true" ]; then
{
echo "run_lint=true"
echo "run_js_tests=true"
echo "run_ruby_tests=true"
echo "run_dummy_tests=true"
echo "run_generators=true"
echo "docs_only=false"
echo "non_runtime_only=false"
} >> "$GITHUB_OUTPUT"
exit 0
fi
if [ -n "$DISPATCH_BASE_SHA" ]; then
export GITHUB_BASE_REF="$DISPATCH_BASE_REF"
BASE_REF="$DISPATCH_BASE_SHA"
else
BASE_REF="${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || 'origin/main' }}"
fi
script/ci-changes-detector "$BASE_REF"
shell: bash
- name: Guard docs-only main pushes
if: |
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
(github.event_name == 'merge_group' &&
github.event.merge_group.base_ref == 'refs/heads/main')
uses: ./.github/actions/ensure-main-docs-safety
with:
docs-only: ${{ steps.detect.outputs.docs_only }}
previous-sha: ${{ github.event.before || github.event.merge_group.base_sha }}
docs-format-check:
needs: detect-changes
if: |
github.event_name == 'pull_request' &&
needs.detect-changes.outputs.docs_only == 'true'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
# No need for history in lint job
fetch-depth: 1
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@v4
with:
# Latest Node comes from .tool-versions; pinned below the Node startup regression.
# https://github.com/nodejs/node/issues/56010
node-version-file: .tool-versions
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Install Node modules with pnpm
run: pnpm install --frozen-lockfile --ignore-scripts --filter='{.}'
- name: Check formatting
run: pnpm start format.listDifferent
build:
needs: detect-changes
# Run heavyweight lint only when hosted CI is allowed and the detector says
# this PR actually needs lint. Docs-only PRs get the focused check above.
if: |
needs.detect-changes.outputs.should_run_hosted_ci == 'true' &&
needs.detect-changes.outputs.run_lint == 'true'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
# No need for history in lint job
fetch-depth: 1
persist-credentials: false
- name: Read runtime versions
id: tool-versions
uses: ./.github/actions/read-tool-versions
- name: Setup Ruby
uses: ./.github/actions/setup-ruby
with:
ruby-version: ${{ steps.tool-versions.outputs.ruby-minor-version }}
- name: Setup Node
uses: actions/setup-node@v4
with:
# Latest Node comes from .tool-versions; pinned below the Node startup regression.
# https://github.com/nodejs/node/issues/56010
node-version-file: .tool-versions
- 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: Check Gemfile.lock platforms
run: ruby script/check-gemfile-lock-platforms
- name: Install Ruby Gems for root lint tools
uses: ./.github/actions/setup-bundle
with:
working-directory: .
ruby-version: ${{ steps.tool-versions.outputs.ruby-minor-version }}
install-libyaml: 'false'
- name: Install Ruby Gems for package
uses: ./.github/actions/setup-bundle
with:
working-directory: react_on_rails
ruby-version: ${{ steps.tool-versions.outputs.ruby-minor-version }}
install-libyaml: 'false'
- name: Install Node modules with pnpm
run: pnpm install --frozen-lockfile
# RuboCop is owned by the root Gemfile/Gemfile.lock so OSS and Pro use one
# locked lint version. Keep package bundles for package-specific tasks.
- name: Lint Ruby
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/Gemfile
run: cd react_on_rails && bundle exec rubocop
# The benchmarks/ scripts live outside the gem, so the package rubocop run
# above doesn't see them. Lint them from the repo root (root .rubocop.yml).
- name: Lint benchmark scripts
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/Gemfile
run: bundle exec rubocop benchmarks
- name: Validate RBS type signatures
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/react_on_rails/Gemfile
run: cd react_on_rails && bundle exec rake rbs:validate
# TODO: Re-enable Steep once RBS signatures are complete for all checked files
# Currently disabled because 374 type errors need to be fixed first
# - name: Run Steep type checker
# run: bundle exec rake rbs:steep
- name: Install Ruby Gems for dummy app
uses: ./.github/actions/setup-bundle
with:
working-directory: react_on_rails/spec/dummy
ruby-version: ${{ steps.tool-versions.outputs.ruby-minor-version }}
install-libyaml: 'false'
- name: generate file system-based packs
run: cd react_on_rails/spec/dummy && RAILS_ENV="test" bundle exec rake react_on_rails:generate_packs
- name: Detect dead code
run: |
pnpm exec knip
pnpm exec knip --production
- name: Lint JS
run: pnpm run eslint --report-unused-disable-directives
- name: Test GitHub Action helpers
run: node .github/actions/ensure-main-docs-safety/check-previous-main.test.cjs
- name: Test custom ESLint rules
run: pnpm run test:eslint-rules
- name: Check formatting
run: pnpm start format.listDifferent
- name: Lint SCSS with stylelint
run: pnpm run lint:scss
- name: Type-check TypeScript
run: pnpm run type-check
- name: Pack for attw and publint
run: cd packages/react-on-rails && pnpm pack
- name: Lint package types
# our package is ESM-only
# Exclude internal exports used for react-on-rails-pro communication
run: pnpm run attw packages/react-on-rails/react-on-rails-*.tgz --profile esm-only --exclude-entrypoints reactApis ReactDOMServer
- name: Lint package publishing
run: pnpm run publint --strict packages/react-on-rails/react-on-rails-*.tgz
# We only download and run Actionlint if there is any difference in GitHub Action workflows
# https://github.com/rhysd/actionlint/blob/main/docs/usage.md#on-github-actions