From 7dbc812f2042aa700624711a2dcfbf6fb7c8679c Mon Sep 17 00:00:00 2001 From: Naseem Date: Sat, 14 Aug 2021 23:36:52 -0400 Subject: [PATCH] add exclusionPatterns option --- README.md | 29 +++++++++++++++++++++------ action.yml | 9 ++++++--- package-lock.json | 50 +++++++++++++++++++++++++++++++++-------------- package.json | 10 ++++++---- src/index.ts | 18 +++++++++++++++-- 5 files changed, 86 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 7a1641b..8c28ae3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,19 @@ -## LFS-Warning action +# LFS-Warning action -This action scans files in commits of a Pull Request and compares it against the configured file size limit threshold. If the threshold is exceeded for any of the file, the action will mark the pull request as failed, add a `lfs-detected!` label and reply with an issue comment containing detected large file(s). +This action works to prevent both: + +- large files that are not LFS tracked +- files that are LFS tracked + +from being checked-in in non-pointer format/not stored in LFS. The latter happens if the client does not have git-lfs installed. + +## How it works + +This action scans files in commits of a pull request and will mark the pull request as failed, add a `lfs-detected!` label and reply with an issue comment if any of the following is true about any of the pull request files: + +- the file size is greater than the configured file size limit threshold. +- the file is tracked in LFS but is being checked-in as a regular file + - the current implementation of this check is that the file has git attribute `filter: lfs` but does not contain the string `version https://git-lfs.github.com/spec/v1'` ![pr-with-lfs-detected](https://user-images.githubusercontent.com/5770369/77542326-4cc7a400-6ea6-11ea-9d16-aa99be9b3240.png) @@ -10,17 +23,21 @@ Note: Remember to configure the branch protection rule and select the `LFS-warni ## Inputs -#### `filesizelimit ` +### `filesizelimit` Required, set's the file size limit threshold in bytes. Default "10MB". -#### `token ` +### `token` + +Optional. Takes a valid **GitHub Token** from the Repo by default. + +### `exclusionPatterns` -Optional. Takes a valid **GitHub Token** from the Repo by default. +Optional. A newline delimited list of glob patterns that match checked in files to exclude form LFS Warning. ## Outputs -#### `lfsFiles ` +### `lfsFiles` Returns an array of possible detected large file(s) diff --git a/action.yml b/action.yml index 2cd89db..dbebee6 100644 --- a/action.yml +++ b/action.yml @@ -5,12 +5,15 @@ inputs: required: false description: Token used to fetch the repository default: ${{ github.token }} - filesizelimit: # id of input + filesizelimit: # id of input description: 'file size limit threshold' required: true - default: '10485760' # 10 MB is 10485760 Bytes + default: '10485760' # 10 MB is 10485760 Bytes + exclusionPatterns: + required: false + description: A newline delimited list of glob patterns that match checked in files to exclude form LFS Warning outputs: - lfsFiles: # output will be available to future steps + lfsFiles: # output will be available to future steps description: 'Array of possible detected large file(s)' runs: using: 'node12' diff --git a/package-lock.json b/package-lock.json index 19ee31c..c175746 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,11 @@ "license": "MIT", "dependencies": { "@actions/core": "^1.4.0", - "@actions/github": "^5.0.0" + "@actions/github": "^5.0.0", + "micromatch": "^4.0.4" }, "devDependencies": { + "@types/micromatch": "^4.0.2", "@types/node": "^16.6.1", "@vercel/ncc": "^0.29.1", "eslint": "^7.32.0", @@ -1242,6 +1244,12 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/braces": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.1.tgz", + "integrity": "sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==", + "dev": true + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -1281,6 +1289,15 @@ "integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==", "dev": true }, + "node_modules/@types/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-oqXqVb0ci19GtH0vOA/U2TmHTcRY9kuZl4mqUxe0QmJAlIW13kzhuK5pi1i9+ngav8FjpSb9FVS/GE00GLX1VA==", + "dev": true, + "dependencies": { + "@types/braces": "*" + } + }, "node_modules/@types/minimist": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", @@ -1904,7 +1921,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -3115,7 +3131,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3754,7 +3769,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -4887,7 +4901,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, "dependencies": { "braces": "^3.0.1", "picomatch": "^2.2.3" @@ -5295,7 +5308,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -6231,7 +6243,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -7698,6 +7709,12 @@ "@babel/types": "^7.3.0" } }, + "@types/braces": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.1.tgz", + "integrity": "sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==", + "dev": true + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -7737,6 +7754,15 @@ "integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==", "dev": true }, + "@types/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-oqXqVb0ci19GtH0vOA/U2TmHTcRY9kuZl4mqUxe0QmJAlIW13kzhuK5pi1i9+ngav8FjpSb9FVS/GE00GLX1VA==", + "dev": true, + "requires": { + "@types/braces": "*" + } + }, "@types/minimist": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", @@ -8187,7 +8213,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -9113,7 +9138,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -9585,8 +9609,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-obj": { "version": "2.0.0", @@ -10467,7 +10490,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" @@ -10771,8 +10793,7 @@ "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, "pirates": { "version": "4.0.1", @@ -11476,7 +11497,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } diff --git a/package.json b/package.json index 40e4f7a..1daa267 100644 --- a/package.json +++ b/package.json @@ -31,14 +31,16 @@ "homepage": "https://github.com/ppremk/lfs-warning#readme", "dependencies": { "@actions/core": "^1.4.0", - "@actions/github": "^5.0.0" + "@actions/github": "^5.0.0", + "micromatch": "^4.0.4" }, "devDependencies": { + "@types/micromatch": "^4.0.2", + "@types/node": "^16.6.1", "@vercel/ncc": "^0.29.1", "eslint": "^7.32.0", - "jest": "^27.0.6", - "typescript": "^4.3.5", "gts": "^3.1.0", - "@types/node": "^16.6.1" + "jest": "^27.0.6", + "typescript": "^4.3.5" } } diff --git a/src/index.ts b/src/index.ts index 320e173..906244c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import * as core from '@actions/core'; import * as github from '@actions/github'; import {exec} from 'child_process'; +import * as micromatch from 'micromatch'; import {promisify} from 'util'; const execP = promisify(exec); const octokit = github.getOctokit(core.getInput('token')); @@ -51,11 +52,24 @@ async function run() { core.info(`The PR number is: ${pullRequestNumber}`); - const {data: files} = await octokit.rest.pulls.listFiles({ + const {data} = await octokit.rest.pulls.listFiles({ ...repo, pull_number: pullRequestNumber, }); + const exclusionPatterns = core.getMultilineInput('exclusionPatterns'); + + const files = + exclusionPatterns.length > 0 + ? data.filter(({filename}) => { + const match = micromatch.isMatch(filename, exclusionPatterns); + if (match === false) { + core.info(`${filename} has been excluded from LFS warning`); + } + return match; + }) + : data; + const prFilesWithBlobSize = await Promise.all( files.map(async file => { const {filename, sha, patch} = file; @@ -102,7 +116,7 @@ async function run() { const issueBaseProps = { ...repo, - issue_number: pullRequestNumber + issue_number: pullRequestNumber, }; if (lsfFiles.length > 0) {