chore: improve test coverage (#1430)

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
This commit is contained in:
Tonye Jack 2023-08-03 13:25:35 -06:00 committed by GitHub
parent 948fd1aec0
commit 85c8b8252f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 671 additions and 54 deletions

149
dist/index.js generated vendored
View File

@ -153,16 +153,16 @@ exports.getAllDiffFiles = getAllDiffFiles;
function* getChangeTypeFilesGenerator({ inputs, changedFiles, changeTypes }) { function* getChangeTypeFilesGenerator({ inputs, changedFiles, changeTypes }) {
for (const changeType of changeTypes) { for (const changeType of changeTypes) {
const files = changedFiles[changeType] || []; const files = changedFiles[changeType] || [];
for (const file of files) { for (const filePath of files) {
if (inputs.dirNames) { if (inputs.dirNames) {
yield (0, utils_1.getDirnameMaxDepth)({ yield (0, utils_1.getDirnameMaxDepth)({
pathStr: file, relativePath: filePath,
dirNamesMaxDepth: inputs.dirNamesMaxDepth, dirNamesMaxDepth: inputs.dirNamesMaxDepth,
excludeCurrentDir: inputs.dirNamesExcludeCurrentDir excludeCurrentDir: inputs.dirNamesExcludeCurrentDir
}); });
} }
else { else {
yield file; yield filePath;
} }
} }
} }
@ -184,16 +184,16 @@ const getChangeTypeFiles = ({ inputs, changedFiles, changeTypes }) => __awaiter(
}); });
exports.getChangeTypeFiles = getChangeTypeFiles; exports.getChangeTypeFiles = getChangeTypeFiles;
function* getAllChangeTypeFilesGenerator({ inputs, changedFiles }) { function* getAllChangeTypeFilesGenerator({ inputs, changedFiles }) {
for (const file of (0, flatten_1.default)(Object.values(changedFiles))) { for (const filePath of (0, flatten_1.default)(Object.values(changedFiles))) {
if (inputs.dirNames) { if (inputs.dirNames) {
yield (0, utils_1.getDirnameMaxDepth)({ yield (0, utils_1.getDirnameMaxDepth)({
pathStr: file, relativePath: filePath,
dirNamesMaxDepth: inputs.dirNamesMaxDepth, dirNamesMaxDepth: inputs.dirNamesMaxDepth,
excludeCurrentDir: inputs.dirNamesExcludeCurrentDir excludeCurrentDir: inputs.dirNamesExcludeCurrentDir
}); });
} }
else { else {
yield file; yield filePath;
} }
} }
} }
@ -1642,7 +1642,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.hasLocalGitDirectory = exports.recoverDeletedFiles = exports.setOutput = exports.getRecoverFilePatterns = exports.getYamlFilePatterns = exports.getFilePatterns = exports.jsonOutput = exports.getDirnameMaxDepth = exports.canDiffCommits = exports.getPreviousGitTag = exports.verifyCommitSha = exports.getParentSha = exports.getRemoteBranchHeadSha = exports.isInsideWorkTree = exports.getHeadSha = exports.gitLog = exports.getFilteredChangedFiles = exports.getAllChangedFiles = exports.gitRenamedFiles = exports.gitSubmoduleDiffSHA = exports.getSubmodulePath = exports.gitFetchSubmodules = exports.gitFetch = exports.submoduleExists = exports.isRepoShallow = exports.updateGitGlobalConfig = exports.verifyMinimumGitVersion = void 0; exports.hasLocalGitDirectory = exports.recoverDeletedFiles = exports.setOutput = exports.getRecoverFilePatterns = exports.getYamlFilePatterns = exports.getFilePatterns = exports.jsonOutput = exports.getDirnameMaxDepth = exports.canDiffCommits = exports.getPreviousGitTag = exports.verifyCommitSha = exports.getParentSha = exports.getRemoteBranchHeadSha = exports.isInsideWorkTree = exports.getHeadSha = exports.gitLog = exports.getFilteredChangedFiles = exports.getAllChangedFiles = exports.gitRenamedFiles = exports.gitSubmoduleDiffSHA = exports.getSubmodulePath = exports.gitFetchSubmodules = exports.gitFetch = exports.submoduleExists = exports.isRepoShallow = exports.updateGitGlobalConfig = exports.verifyMinimumGitVersion = exports.getDirname = exports.normalizeSeparators = exports.isWindows = void 0;
/*global AsyncIterableIterator*/ /*global AsyncIterableIterator*/
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
const exec = __importStar(__nccwpck_require__(1514)); const exec = __importStar(__nccwpck_require__(1514));
@ -1654,16 +1654,19 @@ const path = __importStar(__nccwpck_require__(1017));
const readline_1 = __nccwpck_require__(4521); const readline_1 = __nccwpck_require__(4521);
const yaml_1 = __nccwpck_require__(4083); const yaml_1 = __nccwpck_require__(4083);
const changedFiles_1 = __nccwpck_require__(7358); const changedFiles_1 = __nccwpck_require__(7358);
const IS_WINDOWS = process.platform === 'win32';
const MINIMUM_GIT_VERSION = '2.18.0'; const MINIMUM_GIT_VERSION = '2.18.0';
const isWindows = () => {
return process.platform === 'win32';
};
exports.isWindows = isWindows;
/** /**
* Normalize file path separators to '/' on Windows and Linux/macOS * Normalize file path separators to '/' on Linux/macOS and '\\' on Windows
* @param p file path * @param p - file path
* @returns file path with normalized separators * @returns file path with normalized separators
*/ */
const normalizeSeparators = (p) => { const normalizeSeparators = (p) => {
// Windows // Windows
if (IS_WINDOWS) { if ((0, exports.isWindows)()) {
// Convert slashes on Windows // Convert slashes on Windows
p = p.replace(/\//g, '\\'); p = p.replace(/\//g, '\\');
// Remove redundant slashes // Remove redundant slashes
@ -1673,9 +1676,18 @@ const normalizeSeparators = (p) => {
// Remove redundant slashes // Remove redundant slashes
return p.replace(/\/\/+/g, '/'); return p.replace(/\/\/+/g, '/');
}; };
exports.normalizeSeparators = normalizeSeparators;
/**
* Normalize file path separators to '/' on all platforms
* @param p - file path
* @returns file path with normalized separators
*/
const normalizePath = (p) => {
return p.replace(/\\/g, '/');
};
/** /**
* Trims unnecessary trailing slash from file path * Trims unnecessary trailing slash from file path
* @param p file path * @param p - file path
* @returns file path without unnecessary trailing slash * @returns file path without unnecessary trailing slash
*/ */
const safeTrimTrailingSeparator = (p) => { const safeTrimTrailingSeparator = (p) => {
@ -1684,7 +1696,7 @@ const safeTrimTrailingSeparator = (p) => {
return ''; return '';
} }
// Normalize separators // Normalize separators
p = normalizeSeparators(p); p = (0, exports.normalizeSeparators)(p);
// No trailing slash // No trailing slash
if (!p.endsWith(path.sep)) { if (!p.endsWith(path.sep)) {
return p; return p;
@ -1694,31 +1706,51 @@ const safeTrimTrailingSeparator = (p) => {
return p; return p;
} }
// On Windows, avoid trimming the drive root, e.g. C:\ or \\hello // On Windows, avoid trimming the drive root, e.g. C:\ or \\hello
if (IS_WINDOWS && /^[A-Z]:\\$/i.test(p)) { if ((0, exports.isWindows)() && /^[A-Z]:\\$/i.test(p)) {
return p; return p;
} }
// Trim trailing slash // Trim trailing slash
return p.substring(0, p.length - 1); return p.substring(0, p.length - 1);
}; };
const dirname = (p) => { /**
* Gets the dirname of a path, similar to the Node.js path.dirname() function except that this function
* also works for Windows UNC root paths, e.g. \\hello\world
* @param p - file path
* @returns dirname of path
*/
const getDirname = (p) => {
// Normalize slashes and trim unnecessary trailing slash // Normalize slashes and trim unnecessary trailing slash
p = safeTrimTrailingSeparator(p); p = safeTrimTrailingSeparator(p);
// Windows UNC root, e.g. \\hello or \\hello\world // Windows UNC root, e.g. \\hello or \\hello\world
if (IS_WINDOWS && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) { if ((0, exports.isWindows)() && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) {
return p; return p;
} }
// Get dirname // Get dirname
let result = path.dirname(p); let result = path.dirname(p);
// Trim trailing slash for Windows UNC root, e.g. \\hello\world\ // Trim trailing slash for Windows UNC root, e.g. \\hello\world\
if (IS_WINDOWS && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) { if ((0, exports.isWindows)() && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) {
result = safeTrimTrailingSeparator(result); result = safeTrimTrailingSeparator(result);
} }
return result; return result;
}; };
exports.getDirname = getDirname;
/**
* Converts the version string to a number
* @param version - version string
* @returns version number
*/
const versionToNumber = (version) => { const versionToNumber = (version) => {
const [major, minor, patch] = version.split('.').map(Number); const [major, minor, patch] = version.split('.').map(Number);
return major * 1000000 + minor * 1000 + patch; return major * 1000000 + minor * 1000 + patch;
}; };
/**
* Verifies the minimum required git version
* @returns minimum required git version
* @throws Minimum git version requirement is not met
* @throws Git is not installed
* @throws Git is not found in PATH
* @throws An unexpected error occurred
*/
const verifyMinimumGitVersion = () => __awaiter(void 0, void 0, void 0, function* () { const verifyMinimumGitVersion = () => __awaiter(void 0, void 0, void 0, function* () {
const { exitCode, stdout, stderr } = yield exec.getExecOutput('git', ['--version'], { silent: !core.isDebug() }); const { exitCode, stdout, stderr } = yield exec.getExecOutput('git', ['--version'], { silent: !core.isDebug() });
if (exitCode !== 0) { if (exitCode !== 0) {
@ -1730,6 +1762,11 @@ const verifyMinimumGitVersion = () => __awaiter(void 0, void 0, void 0, function
} }
}); });
exports.verifyMinimumGitVersion = verifyMinimumGitVersion; exports.verifyMinimumGitVersion = verifyMinimumGitVersion;
/**
* Checks if a path exists
* @param filePath - path to check
* @returns path exists
*/
const exists = (filePath) => __awaiter(void 0, void 0, void 0, function* () { const exists = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
try { try {
yield fs_1.promises.access(filePath); yield fs_1.promises.access(filePath);
@ -1739,6 +1776,11 @@ const exists = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
return false; return false;
} }
}); });
/**
* Generates lines of a file as an async iterable iterator
* @param filePath - path of file to read
* @param excludedFiles - whether to exclude files
*/
function lineOfFileGenerator({ filePath, excludedFiles }) { function lineOfFileGenerator({ filePath, excludedFiles }) {
return __asyncGenerator(this, arguments, function* lineOfFileGenerator_1() { return __asyncGenerator(this, arguments, function* lineOfFileGenerator_1() {
var _a, e_1, _b, _c; var _a, e_1, _b, _c;
@ -1780,6 +1822,11 @@ function lineOfFileGenerator({ filePath, excludedFiles }) {
} }
}); });
} }
/**
* Gets the file patterns from a source file
* @param filePaths - paths of files to read
* @param excludedFiles - whether to exclude the file patterns
*/
const getFilesFromSourceFile = ({ filePaths, excludedFiles = false }) => __awaiter(void 0, void 0, void 0, function* () { const getFilesFromSourceFile = ({ filePaths, excludedFiles = false }) => __awaiter(void 0, void 0, void 0, function* () {
var _b, e_2, _c, _d; var _b, e_2, _c, _d;
const lines = []; const lines = [];
@ -1802,6 +1849,12 @@ const getFilesFromSourceFile = ({ filePaths, excludedFiles = false }) => __await
} }
return lines; return lines;
}); });
/**
* Sets the global git configs
* @param name - name of config
* @param value - value of config
* @throws Couldn't update git global config
*/
const updateGitGlobalConfig = ({ name, value }) => __awaiter(void 0, void 0, void 0, function* () { const updateGitGlobalConfig = ({ name, value }) => __awaiter(void 0, void 0, void 0, function* () {
const { exitCode, stderr } = yield exec.getExecOutput('git', ['config', '--global', name, value], { const { exitCode, stderr } = yield exec.getExecOutput('git', ['config', '--global', name, value], {
ignoreReturnCode: true, ignoreReturnCode: true,
@ -1813,6 +1866,11 @@ const updateGitGlobalConfig = ({ name, value }) => __awaiter(void 0, void 0, voi
} }
}); });
exports.updateGitGlobalConfig = updateGitGlobalConfig; exports.updateGitGlobalConfig = updateGitGlobalConfig;
/**
* Checks if a git repository is shallow
* @param cwd - working directory
* @returns repository is shallow
*/
const isRepoShallow = ({ cwd }) => __awaiter(void 0, void 0, void 0, function* () { const isRepoShallow = ({ cwd }) => __awaiter(void 0, void 0, void 0, function* () {
const { stdout } = yield exec.getExecOutput('git', ['rev-parse', '--is-shallow-repository'], { const { stdout } = yield exec.getExecOutput('git', ['rev-parse', '--is-shallow-repository'], {
cwd, cwd,
@ -1821,6 +1879,11 @@ const isRepoShallow = ({ cwd }) => __awaiter(void 0, void 0, void 0, function* (
return stdout.trim() === 'true'; return stdout.trim() === 'true';
}); });
exports.isRepoShallow = isRepoShallow; exports.isRepoShallow = isRepoShallow;
/**
* Checks if a submodule exists
* @param cwd - working directory
* @returns submodule exists
*/
const submoduleExists = ({ cwd }) => __awaiter(void 0, void 0, void 0, function* () { const submoduleExists = ({ cwd }) => __awaiter(void 0, void 0, void 0, function* () {
const { stdout, exitCode, stderr } = yield exec.getExecOutput('git', ['submodule', 'status'], { const { stdout, exitCode, stderr } = yield exec.getExecOutput('git', ['submodule', 'status'], {
cwd, cwd,
@ -1834,6 +1897,11 @@ const submoduleExists = ({ cwd }) => __awaiter(void 0, void 0, void 0, function*
return stdout.trim() !== ''; return stdout.trim() !== '';
}); });
exports.submoduleExists = submoduleExists; exports.submoduleExists = submoduleExists;
/**
* Fetches the git repository
* @param args - arguments for fetch command
* @param cwd - working directory
*/
const gitFetch = ({ args, cwd }) => __awaiter(void 0, void 0, void 0, function* () { const gitFetch = ({ args, cwd }) => __awaiter(void 0, void 0, void 0, function* () {
const { exitCode } = yield exec.getExecOutput('git', ['fetch', '-q', ...args], { const { exitCode } = yield exec.getExecOutput('git', ['fetch', '-q', ...args], {
cwd, cwd,
@ -1843,6 +1911,11 @@ const gitFetch = ({ args, cwd }) => __awaiter(void 0, void 0, void 0, function*
return exitCode; return exitCode;
}); });
exports.gitFetch = gitFetch; exports.gitFetch = gitFetch;
/**
* Fetches the git repository submodules
* @param args - arguments for fetch command
* @param cwd - working directory
*/
const gitFetchSubmodules = ({ args, cwd }) => __awaiter(void 0, void 0, void 0, function* () { const gitFetchSubmodules = ({ args, cwd }) => __awaiter(void 0, void 0, void 0, function* () {
const { exitCode, stderr } = yield exec.getExecOutput('git', ['submodule', 'foreach', 'git', 'fetch', '-q', ...args], { const { exitCode, stderr } = yield exec.getExecOutput('git', ['submodule', 'foreach', 'git', 'fetch', '-q', ...args], {
cwd, cwd,
@ -1855,9 +1928,10 @@ const gitFetchSubmodules = ({ args, cwd }) => __awaiter(void 0, void 0, void 0,
} }
}); });
exports.gitFetchSubmodules = gitFetchSubmodules; exports.gitFetchSubmodules = gitFetchSubmodules;
const normalizePath = (p) => { /**
return p.replace(/\\/g, '/'); * Retrieves all the submodule paths
}; * @param cwd - working directory
*/
const getSubmodulePath = ({ cwd }) => __awaiter(void 0, void 0, void 0, function* () { const getSubmodulePath = ({ cwd }) => __awaiter(void 0, void 0, void 0, function* () {
const { exitCode, stdout, stderr } = yield exec.getExecOutput('git', ['submodule', 'status'], { const { exitCode, stdout, stderr } = yield exec.getExecOutput('git', ['submodule', 'status'], {
cwd, cwd,
@ -1874,9 +1948,17 @@ const getSubmodulePath = ({ cwd }) => __awaiter(void 0, void 0, void 0, function
.map((line) => normalizePath(line.trim().split(' ')[1])); .map((line) => normalizePath(line.trim().split(' ')[1]));
}); });
exports.getSubmodulePath = getSubmodulePath; exports.getSubmodulePath = getSubmodulePath;
/**
* Retrieves commit sha of a submodule from a parent commit
* @param cwd - working directory
* @param parentSha1 - parent commit sha
* @param parentSha2 - parent commit sha
* @param submodulePath - path of submodule
* @param diff - diff type between parent commits (`..` or `...`)
*/
const gitSubmoduleDiffSHA = ({ cwd, parentSha1, parentSha2, submodulePath, diff }) => __awaiter(void 0, void 0, void 0, function* () { const gitSubmoduleDiffSHA = ({ cwd, parentSha1, parentSha2, submodulePath, diff }) => __awaiter(void 0, void 0, void 0, function* () {
var _h, _j, _k, _l; var _h, _j, _k, _l;
const { stdout } = yield exec.getExecOutput('git', ['diff', parentSha1, parentSha2, '--', submodulePath], { const { stdout } = yield exec.getExecOutput('git', ['diff', `${parentSha1}${diff}${parentSha2}`, '--', submodulePath], {
cwd, cwd,
silent: !core.isDebug() silent: !core.isDebug()
}); });
@ -1930,6 +2012,16 @@ const gitRenamedFiles = ({ cwd, sha1, sha2, diff, oldNewSeparator, isSubmodule =
}); });
}); });
exports.gitRenamedFiles = gitRenamedFiles; exports.gitRenamedFiles = gitRenamedFiles;
/**
* Retrieves all the changed files between two commits
* @param cwd - working directory
* @param sha1 - commit sha
* @param sha2 - commit sha
* @param diff - diff type between parent commits (`..` or `...`)
* @param isSubmodule - is the repo a submodule
* @param parentDir - parent directory of the submodule
* @param outputRenamedFilesAsDeletedAndAdded - output renamed files as deleted and added
*/
const getAllChangedFiles = ({ cwd, sha1, sha2, diff, isSubmodule = false, parentDir = '', outputRenamedFilesAsDeletedAndAdded = false }) => __awaiter(void 0, void 0, void 0, function* () { const getAllChangedFiles = ({ cwd, sha1, sha2, diff, isSubmodule = false, parentDir = '', outputRenamedFilesAsDeletedAndAdded = false }) => __awaiter(void 0, void 0, void 0, function* () {
const { exitCode, stdout, stderr } = yield exec.getExecOutput('git', [ const { exitCode, stdout, stderr } = yield exec.getExecOutput('git', [
'diff', 'diff',
@ -1988,6 +2080,11 @@ const getAllChangedFiles = ({ cwd, sha1, sha2, diff, isSubmodule = false, parent
return changedFiles; return changedFiles;
}); });
exports.getAllChangedFiles = getAllChangedFiles; exports.getAllChangedFiles = getAllChangedFiles;
/**
* Filters the changed files by the file patterns
* @param allDiffFiles - all the changed files
* @param filePatterns - file patterns to filter by
*/
const getFilteredChangedFiles = ({ allDiffFiles, filePatterns }) => __awaiter(void 0, void 0, void 0, function* () { const getFilteredChangedFiles = ({ allDiffFiles, filePatterns }) => __awaiter(void 0, void 0, void 0, function* () {
const changedFiles = { const changedFiles = {
[changedFiles_1.ChangeTypeEnum.Added]: [], [changedFiles_1.ChangeTypeEnum.Added]: [],
@ -2005,7 +2102,7 @@ const getFilteredChangedFiles = ({ allDiffFiles, filePatterns }) => __awaiter(vo
if (hasFilePatterns) { if (hasFilePatterns) {
changedFiles[changeType] = (0, micromatch_1.default)(files, filePatterns, { changedFiles[changeType] = (0, micromatch_1.default)(files, filePatterns, {
dot: true, dot: true,
windows: IS_WINDOWS, windows: (0, exports.isWindows)(),
noext: true noext: true
}); });
} }
@ -2113,8 +2210,8 @@ const canDiffCommits = ({ cwd, sha1, sha2, diff }) => __awaiter(void 0, void 0,
return true; return true;
}); });
exports.canDiffCommits = canDiffCommits; exports.canDiffCommits = canDiffCommits;
const getDirnameMaxDepth = ({ pathStr, dirNamesMaxDepth, excludeCurrentDir }) => { const getDirnameMaxDepth = ({ relativePath, dirNamesMaxDepth, excludeCurrentDir }) => {
const pathArr = dirname(pathStr).split(path.sep); const pathArr = (0, exports.getDirname)(relativePath).split(path.sep);
const maxDepth = Math.min(dirNamesMaxDepth || pathArr.length, pathArr.length); const maxDepth = Math.min(dirNamesMaxDepth || pathArr.length, pathArr.length);
let output = pathArr[0]; let output = pathArr[0];
for (let i = 1; i < maxDepth; i++) { for (let i = 1; i < maxDepth; i++) {
@ -2173,7 +2270,7 @@ const getFilePatterns = ({ inputs, workingDirectory }) => __awaiter(void 0, void
core.debug(`files ignore from source files patterns: ${filesIgnoreFromSourceFiles}`); core.debug(`files ignore from source files patterns: ${filesIgnoreFromSourceFiles}`);
filePatterns = filePatterns.concat('\n', filesIgnoreFromSourceFiles); filePatterns = filePatterns.concat('\n', filesIgnoreFromSourceFiles);
} }
if (IS_WINDOWS) { if ((0, exports.isWindows)()) {
filePatterns = filePatterns.replace(/\r\n/g, '\n'); filePatterns = filePatterns.replace(/\r\n/g, '\n');
filePatterns = filePatterns.replace(/\r/g, '\n'); filePatterns = filePatterns.replace(/\r/g, '\n');
} }
@ -2358,7 +2455,7 @@ const recoverDeletedFiles = ({ inputs, workingDirectory, deletedFiles, recoverPa
if (recoverPatterns.length > 0) { if (recoverPatterns.length > 0) {
recoverableDeletedFiles = (0, micromatch_1.default)(deletedFiles, recoverPatterns, { recoverableDeletedFiles = (0, micromatch_1.default)(deletedFiles, recoverPatterns, {
dot: true, dot: true,
windows: IS_WINDOWS, windows: (0, exports.isWindows)(),
noext: true noext: true
}); });
core.debug(`filtered recoverable deleted files: ${recoverableDeletedFiles}`); core.debug(`filtered recoverable deleted files: ${recoverableDeletedFiles}`);

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

425
src/__tests__/utils.test.ts Normal file
View File

@ -0,0 +1,425 @@
import {ChangeTypeEnum} from '../changedFiles'
import {
getDirname,
getDirnameMaxDepth,
getFilteredChangedFiles,
normalizeSeparators
} from '../utils'
const originalPlatform = process.platform
function mockedPlatform(platform: string): void {
Object.defineProperty(process, 'platform', {
value: platform
})
}
describe('utils test', () => {
afterEach(() => {
Object.defineProperty(process, 'platform', {
value: originalPlatform
})
})
describe('getDirnameMaxDepth_function', () => {
// Tests that the function returns the correct dirname when the relative path has multiple directories
it('test_multiple_directories', () => {
const result = getDirnameMaxDepth({
relativePath: 'path/to/some/file',
dirNamesMaxDepth: 2,
excludeCurrentDir: false
})
expect(result).toEqual('path/to')
})
// Tests that the function returns the correct dirname when the relative path has only one directory
it('test_single_directory', () => {
const result = getDirnameMaxDepth({
relativePath: 'path/to',
dirNamesMaxDepth: 1,
excludeCurrentDir: false
})
expect(result).toEqual('path')
})
// Tests that the function returns the correct dirname when the relative path has no directories
it('test_no_directories', () => {
const result = getDirnameMaxDepth({
relativePath: 'file.txt',
dirNamesMaxDepth: 1,
excludeCurrentDir: false
})
expect(result).toEqual('.')
})
// Tests that the function returns the correct dirname when dirNamesMaxDepth is set to a value less than the number of directories in the relative path
it('test_dirnames_max_depth_less_than_num_directories', () => {
const result = getDirnameMaxDepth({
relativePath: 'path/to/some/file',
dirNamesMaxDepth: 1,
excludeCurrentDir: false
})
expect(result).toEqual('path')
})
// Tests that the function returns an empty string when excludeCurrentDir is true and the output is '.'
it('test_exclude_current_dir_is_true_and_output_is_dot', () => {
const result = getDirnameMaxDepth({
relativePath: '.',
dirNamesMaxDepth: 1,
excludeCurrentDir: true
})
expect(result).toEqual('')
})
// Tests that the function returns the correct dirname when the relative path is a Windows drive root and excludeCurrentDir is true
it('test_windows_drive_root_and_exclude_current_dir_is_true', () => {
const result = getDirnameMaxDepth({
relativePath: 'C:\\',
dirNamesMaxDepth: 1,
excludeCurrentDir: true
})
expect(result).toEqual('')
})
// Tests that getDirnameMaxDepth handles a relative path with a trailing separator correctly
it('test_trailing_separator', () => {
const input = {
relativePath: 'path/to/dir/',
dirNamesMaxDepth: 2,
excludeCurrentDir: true
}
const expectedOutput = 'path/to'
const actualOutput = getDirnameMaxDepth(input)
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that getDirnameMaxDepth returns an empty string when excludeCurrentDir is true and the output is '.'
it('test_trailing_separator_exclude_current_dir', () => {
const input = {
relativePath: 'file',
excludeCurrentDir: true
}
const expectedOutput = ''
const actualOutput = getDirnameMaxDepth(input)
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that getDirnameMaxDepth returns the correct output for a Windows UNC root path
it('test_windows_unc_root', () => {
const input = {
relativePath: '\\hello',
dirNamesMaxDepth: 2,
excludeCurrentDir: true
}
const expectedOutput = ''
expect(getDirnameMaxDepth(input)).toEqual(expectedOutput)
})
// Tests that getDirnameMaxDepth returns an empty string when given a Windows UNC root and excludeCurrentDir is true
it('test_windows_unc_root_exclude_current_dir', () => {
const relativePath = '\\hello'
const result = getDirnameMaxDepth({
relativePath,
excludeCurrentDir: true
})
expect(result).toEqual('')
})
// Tests that getDirnameMaxDepth returns the correct dirname with a relative path that contains both forward and backward slashes
it('test_relative_path_with_slashes', () => {
const relativePath = 'path/to\file'
const expectedOutput = 'path'
const actualOutput = getDirnameMaxDepth({relativePath})
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that getDirnameMaxDepth returns the correct dirname for a relative path that contains special characters
it('test_special_characters', () => {
const relativePath =
'path/with/special/characters/!@#$%^&*()_+{}|:<>?[];,./'
const expectedDirname = 'path/with/special/characters'
const actualDirname = getDirnameMaxDepth({relativePath})
expect(actualDirname).toEqual(expectedDirname)
})
})
describe('getDirname_function', () => {
// Tests that the function returns the correct dirname for a valid path
it('test valid path', () => {
expect(getDirname('/path/to/file')).toEqual('/path/to')
})
// Tests that the function returns the correct dirname for a valid Windows UNC root path
it('test windows unc root path', () => {
expect(getDirname('\\helloworld')).toEqual('.')
})
// Tests that the function returns the correct dirname for a path with a trailing slash
it('test path with trailing slash', () => {
expect(getDirname('/path/to/file/')).toEqual('/path/to')
})
// Tests that the function returns the correct dirname for a Windows UNC root path with a trailing slash
it('test windows unc root path with trailing slash', () => {
expect(getDirname('\\hello\\world\\')).toEqual('.')
})
// Tests that the function returns the correct dirname for a path with multiple slashes
it('test path with multiple slashes', () => {
expect(getDirname('/path//to/file')).toEqual('/path/to')
})
// Tests that the function returns the correct dirname for a Windows UNC root path with multiple slashes
it('test windows unc root path with multiple slashes', () => {
expect(getDirname('\\hello\\world')).toEqual('.')
})
})
describe('normalizeSeparators_function', () => {
// Tests that forward slashes are normalized on Linux
it('test forward slashes linux', () => {
const input = 'path/to/file'
const expectedOutput = 'path/to/file'
const actualOutput = normalizeSeparators(input)
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that backslashes are normalized on Windows
it('test backslashes windows', () => {
mockedPlatform('win32')
const input = 'path\\to\\file'
const expectedOutput = 'path\\to\\file'
const actualOutput = normalizeSeparators(input)
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that mixed slashes are normalized on Windows
it('test mixed slashes windows', () => {
mockedPlatform('win32')
const input = 'path\\to/file'
const expectedOutput = 'path\\to\\file'
const actualOutput = normalizeSeparators(input)
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that an empty string returns an empty string
it('test empty string', () => {
const input = ''
const expectedOutput = ''
const actualOutput = normalizeSeparators(input)
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that multiple consecutive slashes are removed
it('test multiple consecutive slashes', () => {
const input = 'path//to//file'
const expectedOutput = 'path/to/file'
const actualOutput = normalizeSeparators(input)
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that UNC format is preserved on Windows
it('test unc format windows', () => {
const input = '\\\\hello\\world'
const expectedOutput = '\\\\hello\\world'
const actualOutput = normalizeSeparators(input)
expect(actualOutput).toEqual(expectedOutput)
})
// Tests that a drive root is preserved on Windows
it('test drive root windows', () => {
const input = 'C:\\'
const expectedOutput = 'C:\\'
const actualOutput = normalizeSeparators(input)
expect(actualOutput).toEqual(expectedOutput)
})
})
// Generated by CodiumAI
describe('getFilteredChangedFiles', () => {
// Tests that the function returns an empty object when allDiffFiles and filePatterns are empty
it('should return an empty object when allDiffFiles and filePatterns are empty', async () => {
const result = await getFilteredChangedFiles({
allDiffFiles: {
[ChangeTypeEnum.Added]: [],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
},
filePatterns: []
})
expect(result).toEqual({
[ChangeTypeEnum.Added]: [],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
})
})
// Tests that the function returns allDiffFiles when filePatterns is empty
it('should return allDiffFiles when filePatterns is empty', async () => {
const allDiffFiles = {
[ChangeTypeEnum.Added]: ['file1.txt'],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
}
const result = await getFilteredChangedFiles({
allDiffFiles,
filePatterns: []
})
expect(result).toEqual(allDiffFiles)
})
// Tests that the function returns an empty object when allDiffFiles is empty
it('should return an empty object when allDiffFiles is empty', async () => {
const result = await getFilteredChangedFiles({
allDiffFiles: {
[ChangeTypeEnum.Added]: [],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
},
filePatterns: ['*.txt']
})
expect(result).toEqual({
[ChangeTypeEnum.Added]: [],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
})
})
// Tests that the function returns only the files that match the file patterns
it('should return only the files that match the file patterns', async () => {
const allDiffFiles = {
[ChangeTypeEnum.Added]: ['file1.txt', 'file2.md', 'file3.txt'],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
}
const result = await getFilteredChangedFiles({
allDiffFiles,
filePatterns: ['*.txt']
})
expect(result).toEqual({
[ChangeTypeEnum.Added]: ['file1.txt', 'file3.txt'],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
})
})
// Tests that the function returns an empty object when there are no files that match the file patterns
it('should return an empty object when there are no files that match the file patterns', async () => {
const allDiffFiles = {
[ChangeTypeEnum.Added]: ['file1.md', 'file2.md', 'file3.md'],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
}
const result = await getFilteredChangedFiles({
allDiffFiles,
filePatterns: ['*.txt']
})
expect(result).toEqual({
[ChangeTypeEnum.Added]: [],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
})
})
// Tests that the function can handle file names with special characters
it('should handle file names with special characters', async () => {
const allDiffFiles = {
[ChangeTypeEnum.Added]: [
'file1.txt',
'file2 with spaces.txt',
'file3$$.txt'
],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
}
const result = await getFilteredChangedFiles({
allDiffFiles,
filePatterns: ['file2*.txt']
})
expect(result).toEqual({
[ChangeTypeEnum.Added]: ['file2 with spaces.txt'],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
})
})
// Tests that getFilteredChangedFiles correctly filters files using glob patterns
it('should filter files using glob patterns', async () => {
const allDiffFiles = {
[ChangeTypeEnum.Added]: ['test/migrations/test.sql'],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
}
const filePatterns = ['test/migrations/**']
const filteredFiles = await getFilteredChangedFiles({
allDiffFiles,
filePatterns
})
expect(filteredFiles[ChangeTypeEnum.Added]).toEqual([
'test/migrations/test.sql'
])
})
})
})

View File

@ -166,15 +166,15 @@ function* getChangeTypeFilesGenerator({
}): Generator<string> { }): Generator<string> {
for (const changeType of changeTypes) { for (const changeType of changeTypes) {
const files = changedFiles[changeType] || [] const files = changedFiles[changeType] || []
for (const file of files) { for (const filePath of files) {
if (inputs.dirNames) { if (inputs.dirNames) {
yield getDirnameMaxDepth({ yield getDirnameMaxDepth({
pathStr: file, relativePath: filePath,
dirNamesMaxDepth: inputs.dirNamesMaxDepth, dirNamesMaxDepth: inputs.dirNamesMaxDepth,
excludeCurrentDir: inputs.dirNamesExcludeCurrentDir excludeCurrentDir: inputs.dirNamesExcludeCurrentDir
}) })
} else { } else {
yield file yield filePath
} }
} }
} }
@ -213,15 +213,15 @@ function* getAllChangeTypeFilesGenerator({
inputs: Inputs inputs: Inputs
changedFiles: ChangedFiles changedFiles: ChangedFiles
}): Generator<string> { }): Generator<string> {
for (const file of flatten(Object.values(changedFiles))) { for (const filePath of flatten(Object.values(changedFiles))) {
if (inputs.dirNames) { if (inputs.dirNames) {
yield getDirnameMaxDepth({ yield getDirnameMaxDepth({
pathStr: file, relativePath: filePath,
dirNamesMaxDepth: inputs.dirNamesMaxDepth, dirNamesMaxDepth: inputs.dirNamesMaxDepth,
excludeCurrentDir: inputs.dirNamesExcludeCurrentDir excludeCurrentDir: inputs.dirNamesExcludeCurrentDir
}) })
} else { } else {
yield file yield filePath
} }
} }
} }

View File

@ -12,17 +12,20 @@ import {ChangedFiles, ChangeTypeEnum} from './changedFiles'
import {Inputs} from './inputs' import {Inputs} from './inputs'
const IS_WINDOWS = process.platform === 'win32'
const MINIMUM_GIT_VERSION = '2.18.0' const MINIMUM_GIT_VERSION = '2.18.0'
export const isWindows = (): boolean => {
return process.platform === 'win32'
}
/** /**
* Normalize file path separators to '/' on Windows and Linux/macOS * Normalize file path separators to '/' on Linux/macOS and '\\' on Windows
* @param p file path * @param p - file path
* @returns file path with normalized separators * @returns file path with normalized separators
*/ */
const normalizeSeparators = (p: string): string => { export const normalizeSeparators = (p: string): string => {
// Windows // Windows
if (IS_WINDOWS) { if (isWindows()) {
// Convert slashes on Windows // Convert slashes on Windows
p = p.replace(/\//g, '\\') p = p.replace(/\//g, '\\')
@ -35,9 +38,18 @@ const normalizeSeparators = (p: string): string => {
return p.replace(/\/\/+/g, '/') return p.replace(/\/\/+/g, '/')
} }
/**
* Normalize file path separators to '/' on all platforms
* @param p - file path
* @returns file path with normalized separators
*/
const normalizePath = (p: string): string => {
return p.replace(/\\/g, '/')
}
/** /**
* Trims unnecessary trailing slash from file path * Trims unnecessary trailing slash from file path
* @param p file path * @param p - file path
* @returns file path without unnecessary trailing slash * @returns file path without unnecessary trailing slash
*/ */
const safeTrimTrailingSeparator = (p: string): string => { const safeTrimTrailingSeparator = (p: string): string => {
@ -60,7 +72,7 @@ const safeTrimTrailingSeparator = (p: string): string => {
} }
// On Windows, avoid trimming the drive root, e.g. C:\ or \\hello // On Windows, avoid trimming the drive root, e.g. C:\ or \\hello
if (IS_WINDOWS && /^[A-Z]:\\$/i.test(p)) { if (isWindows() && /^[A-Z]:\\$/i.test(p)) {
return p return p
} }
@ -68,12 +80,18 @@ const safeTrimTrailingSeparator = (p: string): string => {
return p.substring(0, p.length - 1) return p.substring(0, p.length - 1)
} }
const dirname = (p: string): string => { /**
* Gets the dirname of a path, similar to the Node.js path.dirname() function except that this function
* also works for Windows UNC root paths, e.g. \\hello\world
* @param p - file path
* @returns dirname of path
*/
export const getDirname = (p: string): string => {
// Normalize slashes and trim unnecessary trailing slash // Normalize slashes and trim unnecessary trailing slash
p = safeTrimTrailingSeparator(p) p = safeTrimTrailingSeparator(p)
// Windows UNC root, e.g. \\hello or \\hello\world // Windows UNC root, e.g. \\hello or \\hello\world
if (IS_WINDOWS && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) { if (isWindows() && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) {
return p return p
} }
@ -81,18 +99,31 @@ const dirname = (p: string): string => {
let result = path.dirname(p) let result = path.dirname(p)
// Trim trailing slash for Windows UNC root, e.g. \\hello\world\ // Trim trailing slash for Windows UNC root, e.g. \\hello\world\
if (IS_WINDOWS && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) { if (isWindows() && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) {
result = safeTrimTrailingSeparator(result) result = safeTrimTrailingSeparator(result)
} }
return result return result
} }
/**
* Converts the version string to a number
* @param version - version string
* @returns version number
*/
const versionToNumber = (version: string): number => { const versionToNumber = (version: string): number => {
const [major, minor, patch] = version.split('.').map(Number) const [major, minor, patch] = version.split('.').map(Number)
return major * 1000000 + minor * 1000 + patch return major * 1000000 + minor * 1000 + patch
} }
/**
* Verifies the minimum required git version
* @returns minimum required git version
* @throws Minimum git version requirement is not met
* @throws Git is not installed
* @throws Git is not found in PATH
* @throws An unexpected error occurred
*/
export const verifyMinimumGitVersion = async (): Promise<void> => { export const verifyMinimumGitVersion = async (): Promise<void> => {
const {exitCode, stdout, stderr} = await exec.getExecOutput( const {exitCode, stdout, stderr} = await exec.getExecOutput(
'git', 'git',
@ -113,6 +144,11 @@ export const verifyMinimumGitVersion = async (): Promise<void> => {
} }
} }
/**
* Checks if a path exists
* @param filePath - path to check
* @returns path exists
*/
const exists = async (filePath: string): Promise<boolean> => { const exists = async (filePath: string): Promise<boolean> => {
try { try {
await fs.access(filePath) await fs.access(filePath)
@ -122,6 +158,11 @@ const exists = async (filePath: string): Promise<boolean> => {
} }
} }
/**
* Generates lines of a file as an async iterable iterator
* @param filePath - path of file to read
* @param excludedFiles - whether to exclude files
*/
async function* lineOfFileGenerator({ async function* lineOfFileGenerator({
filePath, filePath,
excludedFiles excludedFiles
@ -153,6 +194,11 @@ async function* lineOfFileGenerator({
} }
} }
/**
* Gets the file patterns from a source file
* @param filePaths - paths of files to read
* @param excludedFiles - whether to exclude the file patterns
*/
const getFilesFromSourceFile = async ({ const getFilesFromSourceFile = async ({
filePaths, filePaths,
excludedFiles = false excludedFiles = false
@ -169,6 +215,12 @@ const getFilesFromSourceFile = async ({
return lines return lines
} }
/**
* Sets the global git configs
* @param name - name of config
* @param value - value of config
* @throws Couldn't update git global config
*/
export const updateGitGlobalConfig = async ({ export const updateGitGlobalConfig = async ({
name, name,
value value
@ -191,6 +243,11 @@ export const updateGitGlobalConfig = async ({
} }
} }
/**
* Checks if a git repository is shallow
* @param cwd - working directory
* @returns repository is shallow
*/
export const isRepoShallow = async ({cwd}: {cwd: string}): Promise<boolean> => { export const isRepoShallow = async ({cwd}: {cwd: string}): Promise<boolean> => {
const {stdout} = await exec.getExecOutput( const {stdout} = await exec.getExecOutput(
'git', 'git',
@ -204,6 +261,11 @@ export const isRepoShallow = async ({cwd}: {cwd: string}): Promise<boolean> => {
return stdout.trim() === 'true' return stdout.trim() === 'true'
} }
/**
* Checks if a submodule exists
* @param cwd - working directory
* @returns submodule exists
*/
export const submoduleExists = async ({ export const submoduleExists = async ({
cwd cwd
}: { }: {
@ -227,6 +289,11 @@ export const submoduleExists = async ({
return stdout.trim() !== '' return stdout.trim() !== ''
} }
/**
* Fetches the git repository
* @param args - arguments for fetch command
* @param cwd - working directory
*/
export const gitFetch = async ({ export const gitFetch = async ({
args, args,
cwd cwd
@ -243,6 +310,11 @@ export const gitFetch = async ({
return exitCode return exitCode
} }
/**
* Fetches the git repository submodules
* @param args - arguments for fetch command
* @param cwd - working directory
*/
export const gitFetchSubmodules = async ({ export const gitFetchSubmodules = async ({
args, args,
cwd cwd
@ -266,10 +338,10 @@ export const gitFetchSubmodules = async ({
} }
} }
const normalizePath = (p: string): string => { /**
return p.replace(/\\/g, '/') * Retrieves all the submodule paths
} * @param cwd - working directory
*/
export const getSubmodulePath = async ({ export const getSubmodulePath = async ({
cwd cwd
}: { }: {
@ -296,6 +368,14 @@ export const getSubmodulePath = async ({
.map((line: string) => normalizePath(line.trim().split(' ')[1])) .map((line: string) => normalizePath(line.trim().split(' ')[1]))
} }
/**
* Retrieves commit sha of a submodule from a parent commit
* @param cwd - working directory
* @param parentSha1 - parent commit sha
* @param parentSha2 - parent commit sha
* @param submodulePath - path of submodule
* @param diff - diff type between parent commits (`..` or `...`)
*/
export const gitSubmoduleDiffSHA = async ({ export const gitSubmoduleDiffSHA = async ({
cwd, cwd,
parentSha1, parentSha1,
@ -311,7 +391,7 @@ export const gitSubmoduleDiffSHA = async ({
}): Promise<{previousSha?: string; currentSha?: string}> => { }): Promise<{previousSha?: string; currentSha?: string}> => {
const {stdout} = await exec.getExecOutput( const {stdout} = await exec.getExecOutput(
'git', 'git',
['diff', parentSha1, parentSha2, '--', submodulePath], ['diff', `${parentSha1}${diff}${parentSha2}`, '--', submodulePath],
{ {
cwd, cwd,
silent: !core.isDebug() silent: !core.isDebug()
@ -408,6 +488,16 @@ export const gitRenamedFiles = async ({
}) })
} }
/**
* Retrieves all the changed files between two commits
* @param cwd - working directory
* @param sha1 - commit sha
* @param sha2 - commit sha
* @param diff - diff type between parent commits (`..` or `...`)
* @param isSubmodule - is the repo a submodule
* @param parentDir - parent directory of the submodule
* @param outputRenamedFilesAsDeletedAndAdded - output renamed files as deleted and added
*/
export const getAllChangedFiles = async ({ export const getAllChangedFiles = async ({
cwd, cwd,
sha1, sha1,
@ -494,6 +584,11 @@ export const getAllChangedFiles = async ({
return changedFiles return changedFiles
} }
/**
* Filters the changed files by the file patterns
* @param allDiffFiles - all the changed files
* @param filePatterns - file patterns to filter by
*/
export const getFilteredChangedFiles = async ({ export const getFilteredChangedFiles = async ({
allDiffFiles, allDiffFiles,
filePatterns filePatterns
@ -518,7 +613,7 @@ export const getFilteredChangedFiles = async ({
if (hasFilePatterns) { if (hasFilePatterns) {
changedFiles[changeType as ChangeTypeEnum] = mm(files, filePatterns, { changedFiles[changeType as ChangeTypeEnum] = mm(files, filePatterns, {
dot: true, dot: true,
windows: IS_WINDOWS, windows: isWindows(),
noext: true noext: true
}) })
} else { } else {
@ -710,15 +805,15 @@ export const canDiffCommits = async ({
} }
export const getDirnameMaxDepth = ({ export const getDirnameMaxDepth = ({
pathStr, relativePath,
dirNamesMaxDepth, dirNamesMaxDepth,
excludeCurrentDir excludeCurrentDir
}: { }: {
pathStr: string relativePath: string
dirNamesMaxDepth?: number dirNamesMaxDepth?: number
excludeCurrentDir?: boolean excludeCurrentDir?: boolean
}): string => { }): string => {
const pathArr = dirname(pathStr).split(path.sep) const pathArr = getDirname(relativePath).split(path.sep)
const maxDepth = Math.min(dirNamesMaxDepth || pathArr.length, pathArr.length) const maxDepth = Math.min(dirNamesMaxDepth || pathArr.length, pathArr.length)
let output = pathArr[0] let output = pathArr[0]
@ -815,7 +910,7 @@ export const getFilePatterns = async ({
filePatterns = filePatterns.concat('\n', filesIgnoreFromSourceFiles) filePatterns = filePatterns.concat('\n', filesIgnoreFromSourceFiles)
} }
if (IS_WINDOWS) { if (isWindows()) {
filePatterns = filePatterns.replace(/\r\n/g, '\n') filePatterns = filePatterns.replace(/\r\n/g, '\n')
filePatterns = filePatterns.replace(/\r/g, '\n') filePatterns = filePatterns.replace(/\r/g, '\n')
} }
@ -1129,7 +1224,7 @@ export const recoverDeletedFiles = async ({
if (recoverPatterns.length > 0) { if (recoverPatterns.length > 0) {
recoverableDeletedFiles = mm(deletedFiles, recoverPatterns, { recoverableDeletedFiles = mm(deletedFiles, recoverPatterns, {
dot: true, dot: true,
windows: IS_WINDOWS, windows: isWindows(),
noext: true noext: true
}) })
core.debug(`filtered recoverable deleted files: ${recoverableDeletedFiles}`) core.debug(`filtered recoverable deleted files: ${recoverableDeletedFiles}`)