diff --git a/.github/actions/lint-js-and-md/action.yml b/.github/actions/lint-js-and-md/action.yml new file mode 100644 index 000000000000..92cbdb1fc26f --- /dev/null +++ b/.github/actions/lint-js-and-md/action.yml @@ -0,0 +1,84 @@ +name: Lint JavaScript and Markdown +description: Restore ESLint results and run the JavaScript and Markdown linters +inputs: + node-version: + description: Node.js version used for linting + required: true + run-on-cache-miss: + description: Run the linters even when the ESLint cache cannot be restored + default: 'false' +outputs: + cache-restored: + description: Whether an ESLint cache was restored + value: ${{ steps.eslint-cache.outputs.cache-matched-key != '' }} +runs: + using: composite + steps: + - name: Use Node.js ${{ inputs.node-version }} + id: setup-node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: ${{ inputs.node-version }} + cache: npm + cache-dependency-path: | + tools/doc/package-lock.json + tools/eslint/package-lock.json + tools/lint-md/package-lock.json + - name: Cache ESLint results + id: eslint-cache + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + env: + # ESLint only invalidates its cache on config changes, so the key also + # covers the custom rules and the files they read. + cache-prefix: eslint-${{ runner.os }}-${{ steps.setup-node.outputs.node-version }}-${{ hashFiles('eslint.config.mjs', '*/eslint.config_partial.mjs', 'tools/eslint/*', 'tools/eslint-rules/**', 'doc/api/errors.md', 'doc/api/deprecations.md') }} + with: + path: .eslintcache + key: ${{ env.cache-prefix }}-${{ github.sha }} + restore-keys: ${{ env.cache-prefix }}- + - name: Lint JavaScript files + if: ${{ steps.eslint-cache.outputs.cache-matched-key != '' || inputs.run-on-cache-miss == 'true' }} + shell: bash + run: | + set +e + NODE=$(command -v node) make lint-js ESLINT_CACHE_FLAGS='--cache --cache-strategy content' + EXIT_CODE="$?" + if [ "$EXIT_CODE" != "0" ]; then + echo + echo 'ERROR: The JavaScript lint validation failed (the errors are logged above).' + echo ' Please fix the lint errors.' + if NODE=$(command -v node) make lint-js-fix > /dev/null 2>&1; then + echo ' Run:' + echo ' make lint-js-fix' + echo ' to fix the lint issues.' + git --no-pager diff + elif git diff --quiet --exit-code; then + echo ' None of the issue is auto-fixable, so manual fixes for' + echo ' all of the issues are required.' + else + echo ' Run:' + echo ' make lint-js-fix' + echo ' to fix the auto-fixable lint issues.' + echo ' Note that some manual fixes are also required.' + fi + echo + exit "$EXIT_CODE" + fi + - name: Get release version numbers + if: ${{ (steps.eslint-cache.outputs.cache-matched-key != '' || inputs.run-on-cache-miss == 'true') && github.event.pull_request && github.event.pull_request.base.ref == github.event.pull_request.base.repo.default_branch }} + id: get-released-versions + shell: bash + run: ./tools/lint-md/list-released-versions-from-changelogs.mjs >> $GITHUB_OUTPUT + - name: Lint markdown files + if: ${{ steps.eslint-cache.outputs.cache-matched-key != '' || inputs.run-on-cache-miss == 'true' }} + shell: bash + run: | + echo "::add-matcher::.github/workflows/remark-lint-problem-matcher.json" + NODE=$(command -v node) make lint-md ESLINT_CACHE_FLAGS='--cache --cache-strategy content' + env: + NODE_RELEASED_VERSIONS: ${{ steps.get-released-versions.outputs.NODE_RELEASED_VERSIONS }} + - name: Save ESLint results + if: ${{ (steps.eslint-cache.outputs.cache-matched-key != '' || inputs.run-on-cache-miss == 'true') && steps.eslint-cache.outputs.cache-matched-key != steps.eslint-cache.outputs.cache-primary-key }} + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: .eslintcache + key: ${{ steps.eslint-cache.outputs.cache-primary-key }} diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index f6945f9df517..63998007d897 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -96,69 +96,51 @@ jobs: echo 'to format the commits in your branch.' exit "$EXIT_CODE" fi - lint-js-and-md: + lint-js-and-md-slim: if: github.event.pull_request.draft == false runs-on: ubuntu-slim + outputs: + cache-restored: ${{ steps.lint.outputs.cache-restored }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - name: Use Node.js ${{ env.NODE_VERSION }} - id: setup-node - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: ./.github/actions/lint-js-and-md + id: lint with: node-version: ${{ env.NODE_VERSION }} - cache: npm - cache-dependency-path: | - tools/doc/package-lock.json - tools/eslint/package-lock.json - tools/lint-md/package-lock.json - - name: Cache ESLint results - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - env: - # ESLint only invalidates its cache on config changes, so the key also - # covers the custom rules and the files they read. - cache-prefix: eslint-${{ runner.os }}-${{ steps.setup-node.outputs.node-version }}-${{ hashFiles('eslint.config.mjs', '*/eslint.config_partial.mjs', 'tools/eslint/*', 'tools/eslint-rules/**', 'doc/api/errors.md', 'doc/api/deprecations.md') }} + + lint-js-and-md-fallback: + needs: lint-js-and-md-slim + if: needs.lint-js-and-md-slim.outputs.cache-restored == 'false' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - path: .eslintcache - key: ${{ env.cache-prefix }}-${{ github.sha }} - restore-keys: ${{ env.cache-prefix }}- - - name: Lint JavaScript files + persist-credentials: false + - uses: ./.github/actions/lint-js-and-md + with: + node-version: ${{ env.NODE_VERSION }} + run-on-cache-miss: 'true' + + lint-js-and-md: + needs: [lint-js-and-md-slim, lint-js-and-md-fallback] + if: ${{ always() && github.event.pull_request.draft == false }} + runs-on: ubuntu-slim + steps: + - name: Check lint results + env: + SLIM_RESULT: ${{ needs.lint-js-and-md-slim.result }} + CACHE_RESTORED: ${{ needs.lint-js-and-md-slim.outputs.cache-restored }} + FALLBACK_RESULT: ${{ needs.lint-js-and-md-fallback.result }} run: | - set +e - NODE=$(command -v node) make lint-js ESLINT_CACHE_FLAGS='--cache --cache-strategy content' - EXIT_CODE="$?" - if [ "$EXIT_CODE" != "0" ]; then - echo - echo 'ERROR: The JavaScript lint validation failed (the errors are logged above).' - echo ' Please fix the lint errors.' - if NODE=$(command -v node) make lint-js-fix > /dev/null 2>&1; then - echo ' Run:' - echo ' make lint-js-fix' - echo ' to fix the lint issues.' - git --no-pager diff - elif git diff --quiet --exit-code; then - echo ' None of the issue is auto-fixable, so manual fixes for' - echo ' all of the issues are required.' - else - echo ' Run:' - echo ' make lint-js-fix' - echo ' to fix the auto-fixable lint issues.' - echo ' Note that some manual fixes are also required.' - fi - echo - exit "$EXIT_CODE" + test "$SLIM_RESULT" = success + if [ "$CACHE_RESTORED" = true ]; then + test "$FALLBACK_RESULT" = skipped + else + test "$CACHE_RESTORED" = false + test "$FALLBACK_RESULT" = success fi - - name: Get release version numbers - if: ${{ github.event.pull_request && github.event.pull_request.base.ref == github.event.pull_request.base.repo.default_branch }} - id: get-released-versions - run: ./tools/lint-md/list-released-versions-from-changelogs.mjs >> $GITHUB_OUTPUT - - name: Lint markdown files - run: | - echo "::add-matcher::.github/workflows/remark-lint-problem-matcher.json" - NODE=$(command -v node) make lint-md ESLINT_CACHE_FLAGS='--cache --cache-strategy content' - env: - NODE_RELEASED_VERSIONS: ${{ steps.get-released-versions.outputs.NODE_RELEASED_VERSIONS }} lint-py: if: github.event.pull_request.draft == false