prebid/Prebid.js

View on GitHub
.github/workflows/linter.yml

Summary

Maintainability
Test Coverage
name: Check for linter warnings / exceptions

on:
  pull_request_target:
    branches:
      - master

jobs:
  check-linter:
    runs-on: ubuntu-latest

    steps:
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          ref: ${{ github.event.pull_request.base.sha }}

      - name: Fetch base and target branches
        run: |
          git fetch origin +refs/heads/${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}
          git fetch origin +refs/pull/${{ github.event.pull_request.number }}/merge:refs/remotes/pull/${{ github.event.pull_request.number }}/merge

      - name: Install dependencies
        run: npm ci

      - name: Get the diff
        run: git diff --name-only origin/${{ github.event.pull_request.base.ref }}...refs/remotes/pull/${{ github.event.pull_request.number }}/merge | grep '^\(modules\|src\|libraries\|creative\)/.*\.js$' > __changed_files.txt || true

      - name: Run linter on base branch
        run: npx eslint --no-inline-config --format json $(cat __changed_files.txt | xargs stat --printf '%n\n' 2> /dev/null) > __base.json || true

      - name: Check out PR
        run: git checkout ${{ github.event.pull_request.head.sha }}

      - name: Install dependencies
        run: npm ci

      - name: Run linter on PR
        run: npx eslint --no-inline-config --format json $(cat __changed_files.txt | xargs stat --printf '%n\n' 2> /dev/null) > __pr.json || true

      - name: Compare them and post comment if necessary
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const path = require('path');
            const process = require('process');
            
            function parse(fn) {
              return JSON.parse(fs.readFileSync(fn)).reduce((memo, data) => {
                const file = path.relative(process.cwd(), data.filePath);
                if (!memo.hasOwnProperty(file)) { memo[file] = { errors: 0, warnings: 0} }
                data.messages.forEach(({severity}) => {
                  memo[file][severity > 1 ? 'errors' : 'warnings']++;
                });
                return memo;
              }, {})
            }
            
            function mkDiff(old, new_) {
              const files = Object.fromEntries(
                Object.entries(new_)
                  .map(([file, {errors, warnings}]) => {
                    const {errors: oldErrors, warnings: oldWarnings} = old[file] || {};
                    return [file, {errors: Math.max(0, errors - (oldErrors ?? 0)), warnings: Math.max(0, warnings - (oldWarnings ?? 0))}]
                  })
                  .filter(([_, {errors, warnings}]) => errors > 0 || warnings > 0)
              )
              return Object.values(files).reduce((memo, {warnings, errors}) => {
                memo.errors += errors;
                memo.warnings += warnings;
                return memo;
              }, {errors: 0, warnings: 0, files})
            }
            
            function mkComment({errors, warnings, files}) {
              function pl(noun, number) {
                return noun + (number === 1 ? '' : 's')
              }
              if (errors === 0 && warnings === 0) return;
              const summary = [];
              if (errors) summary.push(`**${errors}** linter ${pl('error', errors)}`)
              if (warnings) summary.push(`**${warnings}** linter ${pl('warning', warnings)}`)
              let cm = `Tread carefully! This PR adds ${summary.join(' and ')} (possibly disabled through directives):\n\n`;
              Object.entries(files).forEach(([file, {errors, warnings}]) => {
                const summary = [];
                if (errors) summary.push(`+${errors} ${pl('error', errors)}`);
                if (warnings) summary.push(`+${warnings} ${pl('warning', warnings)}`)
                cm += ` * \`${file}\` (${summary.join(', ')})\n`
              })
              return cm;
            }
            
            const [base, pr] = ['__base.json', '__pr.json'].map(parse);
            const comment = mkComment(mkDiff(base, pr));
            
            if (comment) {
              github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body: comment
              });
            }