Skip to content

Commit

Permalink
Merge branch 'staging' into devex-no-floating-promises
Browse files Browse the repository at this point in the history
  • Loading branch information
zachrog authored Jan 17, 2024
2 parents 439e415 + d106f3b commit 5bb0536
Show file tree
Hide file tree
Showing 5 changed files with 449 additions and 97 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/typescript-untouched-files-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Typescript Untouched File Check

on:
pull_request:
push:

jobs:
CheckUntouchedFiles:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Determine Target Branch
id: target_branch
run: echo "::set-output name=target_branch::$(jq -r '.pull_request.base.ref' $GITHUB_EVENT_PATH)"

- name: Set Environment Variable
run: echo "TARGET_BRANCH=${{ steps.target_branch.outputs.target_branch }}" >> $GITHUB_ENV

- name: Checkout Target Branch
uses: actions/checkout@v3
with:
repository: ustaxcourt/ef-cms
ref: ${{ env.TARGET_BRANCH }}
path: targetBranch

- uses: actions/setup-node@v3
with:
node-version: '18.16.1'

- name: NPM Install in your branch
run: npm ci

- name: NPM Install in target branch
working-directory: ./targetBranch
run: npm ci

- name: Check untouched files
run: npx ts-node scripts/checkUntouchedFiles.ts
157 changes: 157 additions & 0 deletions scripts/checkUntouchedFiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { execSync, spawnSync } from 'child_process';

function runTypescriptCommand(cwd: string): { stdout: string } {
return spawnSync(
'npx',
['--node-options="--max-old-space-size=8192"', 'tsc', '--noEmit'],
{
cwd,
encoding: 'utf-8',
maxBuffer: 1024 * 5000,
},
);
}

function createTypescriptErrorMap(stdout: string): {
[fileName: string]: number;
} {
return stdout
.split('\n')
.map(line => line.trim())
.filter(line => line.includes(': error TS'))
.map(line => line.split('(')[0])
.reduce(
(accumulator, file) => {
accumulator[file] = (accumulator[file] || 0) + 1;
return accumulator;
},
{} as { [fileName: string]: number },
);
}

function getTypescriptErrorMap(cwd: string): { [fileName: string]: number } {
const { stdout } = runTypescriptCommand(cwd);
return createTypescriptErrorMap(stdout);
}

function getHashForDirectory(cwd: string) {
return spawnSync('git', ['log', '-n', '1', '--pretty=format:"%H"'], {
cwd,
encoding: 'utf-8',
}).stdout;
}

function getDifferencesBetweenHashes(
branchDirPath: string,
currentBranchHash: string,
targetBranchHash: string,
): { [fileName: string]: boolean } {
return execSync(
`git diff --name-only ${currentBranchHash} ${targetBranchHash}`,
{
cwd: branchDirPath,
encoding: 'utf-8',
},
)
.split('\n')
.map(line => line.trim())
.reduce(
(accumulator, fileName) => {
accumulator[fileName] = true;
return accumulator;
},
{} as { [fileName: string]: boolean },
);
}

function getModifiedFiles(
branchDirPath: string,
targetRepoPath: string,
): {
[fileName: string]: boolean;
} {
const currentBranchHash = getHashForDirectory(branchDirPath);
const targetBranchHash = getHashForDirectory(targetRepoPath);

return getDifferencesBetweenHashes(
branchDirPath,
currentBranchHash,
targetBranchHash,
);
}

function getFilesToCheck(
branchTypescriptErrorMap: { [fileName: string]: number },
targetTypescriptErrorMap: { [fileName: string]: number },
modifiedFiles: { [fileName: string]: boolean },
): {
[fileName: string]: {
targetCount: number;
branchCount: number;
};
} {
const fileToCheck: {
[fileName: string]: {
targetCount: number;
branchCount: number;
};
} = {};
Object.entries(branchTypescriptErrorMap).forEach(
([fileName, branchCount]) => {
if (modifiedFiles[fileName]) return;
const targetCount = targetTypescriptErrorMap[fileName] || 0;
if (targetCount < branchCount)
fileToCheck[fileName] = { branchCount, targetCount };
},
);
return fileToCheck;
}

const branchDirPath = './';
const targetDirPath = './targetBranch';
const branchTypescriptErrorMap = getTypescriptErrorMap(branchDirPath);
const targetTypescriptErrorMap = getTypescriptErrorMap(targetDirPath);
const modifiedFiles = getModifiedFiles(branchDirPath, targetDirPath);

const fileToCheck = getFilesToCheck(
branchTypescriptErrorMap,
targetTypescriptErrorMap,
modifiedFiles,
);

function logSmartTable(dataObject: {
[fileName: string]: {
targetCount: number;
branchCount: number;
};
}): void {
const tableData: {
'Branch Count': number;
'File Path': string;
'Target Count': number;
}[] = [];

Object.entries(dataObject).forEach(([filePath, counts]) => {
const { branchCount, targetCount } = counts;
const data = {
'Branch Count': branchCount,
'File Path': filePath,
'Target Count': targetCount,
};
tableData.push(data);
});

console.table(tableData, ['File Path', 'Target Count', 'Branch Count']);
}

const errorCount = Object.keys(fileToCheck);
if (errorCount.length) {
logSmartTable(fileToCheck);
console.log(
'\nHere are the files that your PR did not touch but increased in Typescript error count: ',
errorCount.length,
);
process.exit(1);
} else {
process.exit(0);
}
1 change: 1 addition & 0 deletions scripts/jest-scripts.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const config: Config = {
collectCoverageFrom: [
'**/*.{js,ts}',
'!circleci/*.ts',
'!checkUntouchedFiles.ts',
'!compareTypescriptErrors.ts',
'!coverage/**',
'!circleci/judge/bulkImportJudgeUsers.ts',
Expand Down
Loading

0 comments on commit 5bb0536

Please sign in to comment.