Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85c8b8252f | ||
|
|
948fd1aec0 | ||
|
|
213a6fbf71 | ||
|
|
c089e392a9 | ||
|
|
387fa91a19 | ||
|
|
bde04d3ec6 | ||
|
|
ce7dceac93 | ||
|
|
18832c2f0d | ||
|
|
3fdcd6b1fa | ||
|
|
2b564ea543 | ||
|
|
6b62acfc40 | ||
|
|
62411c0bbf | ||
|
|
c10ebdc85f | ||
|
|
1b00b76bc1 | ||
|
|
8ffb34e4db | ||
|
|
81ce706243 | ||
|
|
a96679dfee | ||
|
|
0c659577d4 | ||
|
|
ea41e77287 | ||
|
|
ca51c3f430 | ||
|
|
5716c6246f | ||
|
|
f6edf885b4 | ||
|
|
4acaa728bb | ||
|
|
331d2daf96 | ||
|
|
174b246d44 | ||
|
|
0bf83955a9 | ||
|
|
69c6091ee4 | ||
|
|
cf02ab960f | ||
|
|
b50d1ab2d1 | ||
|
|
ba9054e8d5 | ||
|
|
7e9cc01c54 | ||
|
|
0f52c861db |
63
HISTORY.md
63
HISTORY.md
@@ -1,5 +1,68 @@
|
||||
# Changelog
|
||||
|
||||
# [37.5.1](https://github.com/tj-actions/changed-files/compare/v37.5.0...v37.5.1) - (2023-07-28)
|
||||
|
||||
## <!-- 26 -->🔄 Update
|
||||
|
||||
- Update README.md ([ca51c3f](https://github.com/tj-actions/changed-files/commit/ca51c3f4304b9cd96adebaa47025a2014040eb61)) - (Tonye Jack)
|
||||
- Update README.md ([5716c62](https://github.com/tj-actions/changed-files/commit/5716c6246fcfd7031340a7be53243a6a6b689c3e)) - (Tonye Jack)
|
||||
- Update README.md ([f6edf88](https://github.com/tj-actions/changed-files/commit/f6edf885b4a59cd97f396367b3e6fe4f26454601)) - (Tonye Jack)
|
||||
- Update README.md ([331d2da](https://github.com/tj-actions/changed-files/commit/331d2daf96995ca6711e07b13681faa6a55bda62)) - (Tonye Jack)
|
||||
- Updated README.md ([#1412](https://github.com/tj-actions/changed-files/issues/1412))
|
||||
|
||||
Co-authored-by: jackton1 <jackton1@users.noreply.github.com> ([174b246](https://github.com/tj-actions/changed-files/commit/174b246d44adb53ce1a125fc589734fce01e47eb)) - (tj-actions[bot])
|
||||
- Update README.md ([0bf8395](https://github.com/tj-actions/changed-files/commit/0bf83955a913aa99abe90724dc460e86708af650)) - (Tonye Jack)
|
||||
- Update README.md ([69c6091](https://github.com/tj-actions/changed-files/commit/69c6091ee4f562b2c6509ded97c4e5330ac95b09)) - (Tonye Jack)
|
||||
- Update README.md ([ba9054e](https://github.com/tj-actions/changed-files/commit/ba9054e8d5ffe1537ded23c6a65348cb9b78e8c4)) - (Tonye Jack)
|
||||
- Update README.md ([7e9cc01](https://github.com/tj-actions/changed-files/commit/7e9cc01c5474ea22e06e55ea8a296c8653e64d0c)) - (Tonye Jack)
|
||||
|
||||
## <!-- 7 -->⚙️ Miscellaneous Tasks
|
||||
|
||||
- **deps:** Update dependency eslint to v8.46.0 ([#1417](https://github.com/tj-actions/changed-files/issues/1417)) ([a96679d](https://github.com/tj-actions/changed-files/commit/a96679dfee2a1e64b1db5a210c0ffaf1f2cb24ce)) - (renovate[bot])
|
||||
- **deps:** Lock file maintenance ([#1416](https://github.com/tj-actions/changed-files/issues/1416)) ([0c65957](https://github.com/tj-actions/changed-files/commit/0c659577d4b26faf3f99868ea9cabd2775f9b3cb)) - (renovate[bot])
|
||||
- **deps:** Update dependency jest to v29.6.2 ([#1415](https://github.com/tj-actions/changed-files/issues/1415)) ([ea41e77](https://github.com/tj-actions/changed-files/commit/ea41e772876ff19a8d86e3315c52ceff3dae1941)) - (renovate[bot])
|
||||
- **deps:** Update dependency @types/lodash to v4.14.196 ([#1413](https://github.com/tj-actions/changed-files/issues/1413)) ([4acaa72](https://github.com/tj-actions/changed-files/commit/4acaa728bbc362e0ced57dad81204885d253a0e6)) - (renovate[bot])
|
||||
- **deps:** Update dependency @types/node to v20.4.5 ([#1409](https://github.com/tj-actions/changed-files/issues/1409)) ([cf02ab9](https://github.com/tj-actions/changed-files/commit/cf02ab960fc3dee58fc4911fac2c6946f4f64552)) - (renovate[bot])
|
||||
- **deps:** Lock file maintenance ([#1408](https://github.com/tj-actions/changed-files/issues/1408)) ([b50d1ab](https://github.com/tj-actions/changed-files/commit/b50d1ab2d1388e35e9163a8eb2ae8b903e62ca8e)) - (renovate[bot])
|
||||
|
||||
## <!-- 9 -->⬆️ Upgrades
|
||||
|
||||
- Upgraded to v37.5.0 ([#1407](https://github.com/tj-actions/changed-files/issues/1407))
|
||||
|
||||
Co-authored-by: jackton1 <jackton1@users.noreply.github.com> ([0f52c86](https://github.com/tj-actions/changed-files/commit/0f52c861db7764988bb85cbb66a0b166787f586b)) - (tj-actions[bot])
|
||||
|
||||
# [37.5.0](https://github.com/tj-actions/changed-files/compare/v37.4.0...v37.5.0) - (2023-07-24)
|
||||
|
||||
## <!-- 0 -->🚀 Features
|
||||
|
||||
- Add support to detect changes for merge group event ([#1404](https://github.com/tj-actions/changed-files/issues/1404)) ([b8e577a](https://github.com/tj-actions/changed-files/commit/b8e577a27496ebc04ffb8b3bbca1b30a145001b1)) - (Tonye Jack)
|
||||
|
||||
## <!-- 1 -->🐛 Bug Fixes
|
||||
|
||||
- Error fetch more history for release events ([#1403](https://github.com/tj-actions/changed-files/issues/1403)) ([fc3c551](https://github.com/tj-actions/changed-files/commit/fc3c551a67c6151b4b7746c157a9c0914f18e129)) - (Tonye Jack)
|
||||
|
||||
## <!-- 26 -->🔄 Update
|
||||
|
||||
- Update package.json ([73d266f](https://github.com/tj-actions/changed-files/commit/73d266fe29bbb01958506ffe53b575269d8f2b13)) - (Tonye Jack)
|
||||
- Update package.json ([e1ddf02](https://github.com/tj-actions/changed-files/commit/e1ddf02aff6c4d9a624216633291c52df6630421)) - (Tonye Jack)
|
||||
- Update README.md ([f543980](https://github.com/tj-actions/changed-files/commit/f5439803c2c02cdb10b325d247c8ccc66cbc2203)) - (Tonye Jack)
|
||||
- Update README.md ([a0a0be0](https://github.com/tj-actions/changed-files/commit/a0a0be0376b580745f0bd13a6b7ee4e98d028bf3)) - (Tonye Jack)
|
||||
|
||||
## <!-- 7 -->⚙️ Miscellaneous Tasks
|
||||
|
||||
- **deps:** Lock file maintenance ([#1406](https://github.com/tj-actions/changed-files/issues/1406)) ([920e7b9](https://github.com/tj-actions/changed-files/commit/920e7b9ae1d45913fc81f86c956fee89c77d2e5e)) - (renovate[bot])
|
||||
- **deps:** Update typescript-eslint monorepo to v6.2.0 ([#1402](https://github.com/tj-actions/changed-files/issues/1402)) ([797a722](https://github.com/tj-actions/changed-files/commit/797a7222448d90d32258966774780cfb39ee4f44)) - (renovate[bot])
|
||||
- **deps:** Lock file maintenance ([#1401](https://github.com/tj-actions/changed-files/issues/1401)) ([44790ad](https://github.com/tj-actions/changed-files/commit/44790ad9d8b0716d28defa47199281f484931e31)) - (renovate[bot])
|
||||
- Update package.json ([66d62c9](https://github.com/tj-actions/changed-files/commit/66d62c97d57b2c770a365925793a1e8eb2b1dcd0)) - (Tonye Jack)
|
||||
- **deps:** Update dependency @types/node to v20.4.4 ([#1400](https://github.com/tj-actions/changed-files/issues/1400)) ([d44a61e](https://github.com/tj-actions/changed-files/commit/d44a61ef339541580efca1a47286b8b9e3b69311)) - (renovate[bot])
|
||||
- **deps:** Update dependency @types/node to v20.4.3 ([#1399](https://github.com/tj-actions/changed-files/issues/1399)) ([ef59201](https://github.com/tj-actions/changed-files/commit/ef59201f02fa40b09640c053d97cdf5c5dc65391)) - (renovate[bot])
|
||||
|
||||
## <!-- 9 -->⬆️ Upgrades
|
||||
|
||||
- Upgraded to v37.4.0 ([#1397](https://github.com/tj-actions/changed-files/issues/1397))
|
||||
|
||||
Co-authored-by: jackton1 <jackton1@users.noreply.github.com> ([48ce584](https://github.com/tj-actions/changed-files/commit/48ce5846c9a7c7c959b6c60e3afc80aaba4e6b0c)) - (tj-actions[bot])
|
||||
|
||||
# [37.4.0](https://github.com/tj-actions/changed-files/compare/v37.3.0...v37.4.0) - (2023-07-20)
|
||||
|
||||
## <!-- 0 -->🚀 Features
|
||||
|
||||
30
README.md
30
README.md
@@ -13,10 +13,6 @@
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
<div align="center">
|
||||
<img width="auto" alt="Screen Shot 2021-11-19 at 4 59 21 PM" src="https://user-images.githubusercontent.com/17484350/229027815-eee0bf22-f3e5-444d-9d90-6409c68a0dc9.png">
|
||||
</div>
|
||||
|
||||
## changed-files
|
||||
|
||||
Effortlessly track all changed files and directories relative to a target branch, preceding commit or the last remote commit returning **relative paths** from the project root using this GitHub action.
|
||||
@@ -48,6 +44,7 @@ Effortlessly track all changed files and directories relative to a target branch
|
||||
* Facilitates easy debugging.
|
||||
* Scales to handle large repositories.
|
||||
* Supports Git submodules.
|
||||
* Supports [merge queues](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) for pull reequests.
|
||||
* Generates escaped JSON output for running matrix jobs based on changed files.
|
||||
* Lists changed directories.
|
||||
* Limits matching changed directories to a specified maximum depth.
|
||||
@@ -65,7 +62,7 @@ Effortlessly track all changed files and directories relative to a target branch
|
||||
* Between the last remote branch commit and the current HEAD.
|
||||
* Restricts change detection to a subset of files and directories:
|
||||
* Provides boolean output indicating changes in specific files.
|
||||
* Uses [Glob pattern](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet) matching.
|
||||
* Uses [Glob pattern](https://codepen.io/mrmlnc/pen/OXQjMe) matching.
|
||||
* Supports Globstar.
|
||||
* Supports brace expansion.
|
||||
* Supports negation.
|
||||
@@ -79,11 +76,13 @@ And many more.
|
||||
|
||||
> **Warning**:
|
||||
>
|
||||
> * **IMPORTANT:** For `push` events when configuring [`actions/checkout`](https://github.com/actions/checkout#usage) the `fetch-depth` should be set to either `fetch-depth: 0` **OR** `fetch-depth: 2` depending on your use case.
|
||||
> * For monorepos where pulling all the branch history might not be desired, you can omit [`actions/checkout`](https://github.com/actions/checkout#usage) - `fetch-depth` for `pull_request` events.
|
||||
> * All multiline inputs should not use double or single quotes since the value is already a string separated by a newline character. See [Examples](#examples) for more information.
|
||||
> * Ensure that `persist-credentials` is set to `true` when configuring [`actions/checkout`](https://github.com/actions/checkout#usage) if `fetch-depth` isn't set to `0`.
|
||||
> * For repositories that have PRs generated from forks when configuring [`actions/checkout`](https://github.com/actions/checkout#usage) set the `repository` to `${{ github.event.pull_request.head.repo.full_name }}`. See: [Example](https://github.com/tj-actions/changed-files/blob/main/.github/workflows/test.yml#L47-L51)
|
||||
> * For `push` events: When configuring [`actions/checkout`](https://github.com/actions/checkout#usage), make sure to set [`fetch-depth`](https://github.com/actions/checkout#usage) to either `0` or `2`, depending on your use case.
|
||||
> * For mono repositories where pulling all branch history might not be desired, you can still use the default [`fetch-depth`](https://github.com/actions/checkout#usage), which is set to `1` for `pull_request` events.
|
||||
> * Avoid using single or double quotes for multiline inputs, as the value is already a string separated by a newline character. See [Examples](#examples) for more information.
|
||||
> * If [`fetch-depth`](https://github.com/actions/checkout#usage) isn't set to `0`, ensure that `persist-credentials` is set to `true` when configuring [`actions/checkout`](https://github.com/actions/checkout#usage).
|
||||
> * For repositories that have PRs generated from forks, when configuring [`actions/checkout`](https://github.com/actions/checkout#usage), set the [`repository`](https://github.com/actions/checkout#usage) to `${{ github.event.pull_request.head.repo.full_name }}`. See [Example](https://github.com/tj-actions/changed-files/blob/main/.github/workflows/test.yml#L47-L51).
|
||||
|
||||
Visit the [discussions for more information](https://github.com/tj-actions/changed-files/discussions) or [create a new discussion](https://github.com/tj-actions/changed-files/discussions/new/choose) for usage-related questions.
|
||||
|
||||
### On `pull_request`
|
||||
|
||||
@@ -127,7 +126,8 @@ jobs:
|
||||
# Optionally set `files_yaml_from_source_file` to read the YAML from a file. e.g `files_yaml_from_source_file: .github/changed-files.yml`
|
||||
|
||||
- name: Run step if test file(s) change
|
||||
if: steps.changed-files-yaml.outputs.test_any_changed == 'true'
|
||||
# NOTE: The key has to start with the same key used above e.g. `test_(...)` | `doc_(...)` | `src_(...)` when trying to access the `any_changed` output.
|
||||
if: steps.changed-files-yaml.outputs.test_any_changed == 'true'
|
||||
run: |
|
||||
echo "One or more test file(s) has changed."
|
||||
echo "List all the files that have changed: ${{ steps.changed-files-yaml.outputs.test_all_changed_files }}"
|
||||
@@ -222,7 +222,9 @@ on:
|
||||
# - cron: '0 0 * * *'
|
||||
#
|
||||
# release:
|
||||
# types: [published]
|
||||
# types: [...]
|
||||
#
|
||||
# workflow_dispatch:
|
||||
#
|
||||
# push:
|
||||
# tags:
|
||||
@@ -294,6 +296,10 @@ Support this project with a :star:
|
||||
| U | Unmerged |
|
||||
| X | Unknown |
|
||||
|
||||
> **Warning**:
|
||||
>
|
||||
> * When using `files_yaml*` inputs ensure all outputs are prefixed by the key `test_{...}` e.g. `test_added_files`, `test_any_changed`
|
||||
|
||||
## Outputs
|
||||
|
||||
<!-- AUTO-DOC-OUTPUT:START - Do not remove or modify this section -->
|
||||
|
||||
149
dist/index.js
generated
vendored
149
dist/index.js
generated
vendored
@@ -153,16 +153,16 @@ exports.getAllDiffFiles = getAllDiffFiles;
|
||||
function* getChangeTypeFilesGenerator({ inputs, changedFiles, changeTypes }) {
|
||||
for (const changeType of changeTypes) {
|
||||
const files = changedFiles[changeType] || [];
|
||||
for (const file of files) {
|
||||
for (const filePath of files) {
|
||||
if (inputs.dirNames) {
|
||||
yield (0, utils_1.getDirnameMaxDepth)({
|
||||
pathStr: file,
|
||||
relativePath: filePath,
|
||||
dirNamesMaxDepth: inputs.dirNamesMaxDepth,
|
||||
excludeCurrentDir: inputs.dirNamesExcludeCurrentDir
|
||||
});
|
||||
}
|
||||
else {
|
||||
yield file;
|
||||
yield filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,16 +184,16 @@ const getChangeTypeFiles = ({ inputs, changedFiles, changeTypes }) => __awaiter(
|
||||
});
|
||||
exports.getChangeTypeFiles = getChangeTypeFiles;
|
||||
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) {
|
||||
yield (0, utils_1.getDirnameMaxDepth)({
|
||||
pathStr: file,
|
||||
relativePath: filePath,
|
||||
dirNamesMaxDepth: inputs.dirNamesMaxDepth,
|
||||
excludeCurrentDir: inputs.dirNamesExcludeCurrentDir
|
||||
});
|
||||
}
|
||||
else {
|
||||
yield file;
|
||||
yield filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1642,7 +1642,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
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*/
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const exec = __importStar(__nccwpck_require__(1514));
|
||||
@@ -1654,16 +1654,19 @@ const path = __importStar(__nccwpck_require__(1017));
|
||||
const readline_1 = __nccwpck_require__(4521);
|
||||
const yaml_1 = __nccwpck_require__(4083);
|
||||
const changedFiles_1 = __nccwpck_require__(7358);
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
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
|
||||
* @param p file path
|
||||
* Normalize file path separators to '/' on Linux/macOS and '\\' on Windows
|
||||
* @param p - file path
|
||||
* @returns file path with normalized separators
|
||||
*/
|
||||
const normalizeSeparators = (p) => {
|
||||
// Windows
|
||||
if (IS_WINDOWS) {
|
||||
if ((0, exports.isWindows)()) {
|
||||
// Convert slashes on Windows
|
||||
p = p.replace(/\//g, '\\');
|
||||
// Remove redundant slashes
|
||||
@@ -1673,9 +1676,18 @@ const normalizeSeparators = (p) => {
|
||||
// Remove redundant slashes
|
||||
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
|
||||
* @param p file path
|
||||
* @param p - file path
|
||||
* @returns file path without unnecessary trailing slash
|
||||
*/
|
||||
const safeTrimTrailingSeparator = (p) => {
|
||||
@@ -1684,7 +1696,7 @@ const safeTrimTrailingSeparator = (p) => {
|
||||
return '';
|
||||
}
|
||||
// Normalize separators
|
||||
p = normalizeSeparators(p);
|
||||
p = (0, exports.normalizeSeparators)(p);
|
||||
// No trailing slash
|
||||
if (!p.endsWith(path.sep)) {
|
||||
return p;
|
||||
@@ -1694,31 +1706,51 @@ const safeTrimTrailingSeparator = (p) => {
|
||||
return p;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
// Trim trailing slash
|
||||
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
|
||||
p = safeTrimTrailingSeparator(p);
|
||||
// Windows UNC root, e.g. \\hello or \\hello\world
|
||||
if (IS_WINDOWS && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) {
|
||||
if ((0, exports.isWindows)() && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) {
|
||||
return p;
|
||||
}
|
||||
// Get dirname
|
||||
let result = path.dirname(p);
|
||||
// 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);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
exports.getDirname = getDirname;
|
||||
/**
|
||||
* Converts the version string to a number
|
||||
* @param version - version string
|
||||
* @returns version number
|
||||
*/
|
||||
const versionToNumber = (version) => {
|
||||
const [major, minor, patch] = version.split('.').map(Number);
|
||||
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 { exitCode, stdout, stderr } = yield exec.getExecOutput('git', ['--version'], { silent: !core.isDebug() });
|
||||
if (exitCode !== 0) {
|
||||
@@ -1730,6 +1762,11 @@ const verifyMinimumGitVersion = () => __awaiter(void 0, void 0, void 0, function
|
||||
}
|
||||
});
|
||||
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* () {
|
||||
try {
|
||||
yield fs_1.promises.access(filePath);
|
||||
@@ -1739,6 +1776,11 @@ const exists = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
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 }) {
|
||||
return __asyncGenerator(this, arguments, function* lineOfFileGenerator_1() {
|
||||
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* () {
|
||||
var _b, e_2, _c, _d;
|
||||
const lines = [];
|
||||
@@ -1802,6 +1849,12 @@ const getFilesFromSourceFile = ({ filePaths, excludedFiles = false }) => __await
|
||||
}
|
||||
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 { exitCode, stderr } = yield exec.getExecOutput('git', ['config', '--global', name, value], {
|
||||
ignoreReturnCode: true,
|
||||
@@ -1813,6 +1866,11 @@ const updateGitGlobalConfig = ({ name, value }) => __awaiter(void 0, void 0, voi
|
||||
}
|
||||
});
|
||||
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 { stdout } = yield exec.getExecOutput('git', ['rev-parse', '--is-shallow-repository'], {
|
||||
cwd,
|
||||
@@ -1821,6 +1879,11 @@ const isRepoShallow = ({ cwd }) => __awaiter(void 0, void 0, void 0, function* (
|
||||
return stdout.trim() === 'true';
|
||||
});
|
||||
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 { stdout, exitCode, stderr } = yield exec.getExecOutput('git', ['submodule', 'status'], {
|
||||
cwd,
|
||||
@@ -1834,6 +1897,11 @@ const submoduleExists = ({ cwd }) => __awaiter(void 0, void 0, void 0, function*
|
||||
return stdout.trim() !== '';
|
||||
});
|
||||
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 { exitCode } = yield exec.getExecOutput('git', ['fetch', '-q', ...args], {
|
||||
cwd,
|
||||
@@ -1843,6 +1911,11 @@ const gitFetch = ({ args, cwd }) => __awaiter(void 0, void 0, void 0, function*
|
||||
return exitCode;
|
||||
});
|
||||
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 { exitCode, stderr } = yield exec.getExecOutput('git', ['submodule', 'foreach', 'git', 'fetch', '-q', ...args], {
|
||||
cwd,
|
||||
@@ -1855,9 +1928,10 @@ const gitFetchSubmodules = ({ args, cwd }) => __awaiter(void 0, void 0, void 0,
|
||||
}
|
||||
});
|
||||
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 { exitCode, stdout, stderr } = yield exec.getExecOutput('git', ['submodule', 'status'], {
|
||||
cwd,
|
||||
@@ -1874,9 +1948,17 @@ const getSubmodulePath = ({ cwd }) => __awaiter(void 0, void 0, void 0, function
|
||||
.map((line) => normalizePath(line.trim().split(' ')[1]));
|
||||
});
|
||||
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* () {
|
||||
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,
|
||||
silent: !core.isDebug()
|
||||
});
|
||||
@@ -1930,6 +2012,16 @@ const gitRenamedFiles = ({ cwd, sha1, sha2, diff, oldNewSeparator, isSubmodule =
|
||||
});
|
||||
});
|
||||
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 { exitCode, stdout, stderr } = yield exec.getExecOutput('git', [
|
||||
'diff',
|
||||
@@ -1988,6 +2080,11 @@ const getAllChangedFiles = ({ cwd, sha1, sha2, diff, isSubmodule = false, parent
|
||||
return changedFiles;
|
||||
});
|
||||
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 changedFiles = {
|
||||
[changedFiles_1.ChangeTypeEnum.Added]: [],
|
||||
@@ -2005,7 +2102,7 @@ const getFilteredChangedFiles = ({ allDiffFiles, filePatterns }) => __awaiter(vo
|
||||
if (hasFilePatterns) {
|
||||
changedFiles[changeType] = (0, micromatch_1.default)(files, filePatterns, {
|
||||
dot: true,
|
||||
windows: IS_WINDOWS,
|
||||
windows: (0, exports.isWindows)(),
|
||||
noext: true
|
||||
});
|
||||
}
|
||||
@@ -2113,8 +2210,8 @@ const canDiffCommits = ({ cwd, sha1, sha2, diff }) => __awaiter(void 0, void 0,
|
||||
return true;
|
||||
});
|
||||
exports.canDiffCommits = canDiffCommits;
|
||||
const getDirnameMaxDepth = ({ pathStr, dirNamesMaxDepth, excludeCurrentDir }) => {
|
||||
const pathArr = dirname(pathStr).split(path.sep);
|
||||
const getDirnameMaxDepth = ({ relativePath, dirNamesMaxDepth, excludeCurrentDir }) => {
|
||||
const pathArr = (0, exports.getDirname)(relativePath).split(path.sep);
|
||||
const maxDepth = Math.min(dirNamesMaxDepth || pathArr.length, pathArr.length);
|
||||
let output = pathArr[0];
|
||||
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}`);
|
||||
filePatterns = filePatterns.concat('\n', filesIgnoreFromSourceFiles);
|
||||
}
|
||||
if (IS_WINDOWS) {
|
||||
if ((0, exports.isWindows)()) {
|
||||
filePatterns = filePatterns.replace(/\r\n/g, '\n');
|
||||
filePatterns = filePatterns.replace(/\r/g, '\n');
|
||||
}
|
||||
@@ -2358,7 +2455,7 @@ const recoverDeletedFiles = ({ inputs, workingDirectory, deletedFiles, recoverPa
|
||||
if (recoverPatterns.length > 0) {
|
||||
recoverableDeletedFiles = (0, micromatch_1.default)(deletedFiles, recoverPatterns, {
|
||||
dot: true,
|
||||
windows: IS_WINDOWS,
|
||||
windows: (0, exports.isWindows)(),
|
||||
noext: true
|
||||
});
|
||||
core.debug(`filtered recoverable deleted files: ${recoverableDeletedFiles}`);
|
||||
|
||||
2
dist/index.js.map
generated
vendored
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
425
src/__tests__/utils.test.ts
Normal 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'
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -166,15 +166,15 @@ function* getChangeTypeFilesGenerator({
|
||||
}): Generator<string> {
|
||||
for (const changeType of changeTypes) {
|
||||
const files = changedFiles[changeType] || []
|
||||
for (const file of files) {
|
||||
for (const filePath of files) {
|
||||
if (inputs.dirNames) {
|
||||
yield getDirnameMaxDepth({
|
||||
pathStr: file,
|
||||
relativePath: filePath,
|
||||
dirNamesMaxDepth: inputs.dirNamesMaxDepth,
|
||||
excludeCurrentDir: inputs.dirNamesExcludeCurrentDir
|
||||
})
|
||||
} else {
|
||||
yield file
|
||||
yield filePath
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,15 +213,15 @@ function* getAllChangeTypeFilesGenerator({
|
||||
inputs: Inputs
|
||||
changedFiles: ChangedFiles
|
||||
}): Generator<string> {
|
||||
for (const file of flatten(Object.values(changedFiles))) {
|
||||
for (const filePath of flatten(Object.values(changedFiles))) {
|
||||
if (inputs.dirNames) {
|
||||
yield getDirnameMaxDepth({
|
||||
pathStr: file,
|
||||
relativePath: filePath,
|
||||
dirNamesMaxDepth: inputs.dirNamesMaxDepth,
|
||||
excludeCurrentDir: inputs.dirNamesExcludeCurrentDir
|
||||
})
|
||||
} else {
|
||||
yield file
|
||||
yield filePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
137
src/utils.ts
137
src/utils.ts
@@ -12,17 +12,20 @@ import {ChangedFiles, ChangeTypeEnum} from './changedFiles'
|
||||
|
||||
import {Inputs} from './inputs'
|
||||
|
||||
const IS_WINDOWS = process.platform === 'win32'
|
||||
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
|
||||
* @param p file path
|
||||
* Normalize file path separators to '/' on Linux/macOS and '\\' on Windows
|
||||
* @param p - file path
|
||||
* @returns file path with normalized separators
|
||||
*/
|
||||
const normalizeSeparators = (p: string): string => {
|
||||
export const normalizeSeparators = (p: string): string => {
|
||||
// Windows
|
||||
if (IS_WINDOWS) {
|
||||
if (isWindows()) {
|
||||
// Convert slashes on Windows
|
||||
p = p.replace(/\//g, '\\')
|
||||
|
||||
@@ -35,9 +38,18 @@ const normalizeSeparators = (p: string): string => {
|
||||
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
|
||||
* @param p file path
|
||||
* @param p - file path
|
||||
* @returns file path without unnecessary trailing slash
|
||||
*/
|
||||
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
|
||||
if (IS_WINDOWS && /^[A-Z]:\\$/i.test(p)) {
|
||||
if (isWindows() && /^[A-Z]:\\$/i.test(p)) {
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -68,12 +80,18 @@ const safeTrimTrailingSeparator = (p: string): string => {
|
||||
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
|
||||
p = safeTrimTrailingSeparator(p)
|
||||
|
||||
// Windows UNC root, e.g. \\hello or \\hello\world
|
||||
if (IS_WINDOWS && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) {
|
||||
if (isWindows() && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) {
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -81,18 +99,31 @@ const dirname = (p: string): string => {
|
||||
let result = path.dirname(p)
|
||||
|
||||
// Trim trailing slash for Windows UNC root, e.g. \\hello\world\
|
||||
if (IS_WINDOWS && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) {
|
||||
if (isWindows() && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) {
|
||||
result = safeTrimTrailingSeparator(result)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the version string to a number
|
||||
* @param version - version string
|
||||
* @returns version number
|
||||
*/
|
||||
const versionToNumber = (version: string): number => {
|
||||
const [major, minor, patch] = version.split('.').map(Number)
|
||||
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> => {
|
||||
const {exitCode, stdout, stderr} = await exec.getExecOutput(
|
||||
'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> => {
|
||||
try {
|
||||
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({
|
||||
filePath,
|
||||
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 ({
|
||||
filePaths,
|
||||
excludedFiles = false
|
||||
@@ -169,6 +215,12 @@ const getFilesFromSourceFile = async ({
|
||||
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 ({
|
||||
name,
|
||||
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> => {
|
||||
const {stdout} = await exec.getExecOutput(
|
||||
'git',
|
||||
@@ -204,6 +261,11 @@ export const isRepoShallow = async ({cwd}: {cwd: string}): Promise<boolean> => {
|
||||
return stdout.trim() === 'true'
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a submodule exists
|
||||
* @param cwd - working directory
|
||||
* @returns submodule exists
|
||||
*/
|
||||
export const submoduleExists = async ({
|
||||
cwd
|
||||
}: {
|
||||
@@ -227,6 +289,11 @@ export const submoduleExists = async ({
|
||||
return stdout.trim() !== ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the git repository
|
||||
* @param args - arguments for fetch command
|
||||
* @param cwd - working directory
|
||||
*/
|
||||
export const gitFetch = async ({
|
||||
args,
|
||||
cwd
|
||||
@@ -243,6 +310,11 @@ export const gitFetch = async ({
|
||||
return exitCode
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the git repository submodules
|
||||
* @param args - arguments for fetch command
|
||||
* @param cwd - working directory
|
||||
*/
|
||||
export const gitFetchSubmodules = async ({
|
||||
args,
|
||||
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 ({
|
||||
cwd
|
||||
}: {
|
||||
@@ -296,6 +368,14 @@ export const getSubmodulePath = async ({
|
||||
.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 ({
|
||||
cwd,
|
||||
parentSha1,
|
||||
@@ -311,7 +391,7 @@ export const gitSubmoduleDiffSHA = async ({
|
||||
}): Promise<{previousSha?: string; currentSha?: string}> => {
|
||||
const {stdout} = await exec.getExecOutput(
|
||||
'git',
|
||||
['diff', parentSha1, parentSha2, '--', submodulePath],
|
||||
['diff', `${parentSha1}${diff}${parentSha2}`, '--', submodulePath],
|
||||
{
|
||||
cwd,
|
||||
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 ({
|
||||
cwd,
|
||||
sha1,
|
||||
@@ -494,6 +584,11 @@ export const getAllChangedFiles = async ({
|
||||
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 ({
|
||||
allDiffFiles,
|
||||
filePatterns
|
||||
@@ -518,7 +613,7 @@ export const getFilteredChangedFiles = async ({
|
||||
if (hasFilePatterns) {
|
||||
changedFiles[changeType as ChangeTypeEnum] = mm(files, filePatterns, {
|
||||
dot: true,
|
||||
windows: IS_WINDOWS,
|
||||
windows: isWindows(),
|
||||
noext: true
|
||||
})
|
||||
} else {
|
||||
@@ -710,15 +805,15 @@ export const canDiffCommits = async ({
|
||||
}
|
||||
|
||||
export const getDirnameMaxDepth = ({
|
||||
pathStr,
|
||||
relativePath,
|
||||
dirNamesMaxDepth,
|
||||
excludeCurrentDir
|
||||
}: {
|
||||
pathStr: string
|
||||
relativePath: string
|
||||
dirNamesMaxDepth?: number
|
||||
excludeCurrentDir?: boolean
|
||||
}): string => {
|
||||
const pathArr = dirname(pathStr).split(path.sep)
|
||||
const pathArr = getDirname(relativePath).split(path.sep)
|
||||
const maxDepth = Math.min(dirNamesMaxDepth || pathArr.length, pathArr.length)
|
||||
let output = pathArr[0]
|
||||
|
||||
@@ -815,7 +910,7 @@ export const getFilePatterns = async ({
|
||||
filePatterns = filePatterns.concat('\n', filesIgnoreFromSourceFiles)
|
||||
}
|
||||
|
||||
if (IS_WINDOWS) {
|
||||
if (isWindows()) {
|
||||
filePatterns = filePatterns.replace(/\r\n/g, '\n')
|
||||
filePatterns = filePatterns.replace(/\r/g, '\n')
|
||||
}
|
||||
@@ -1129,7 +1224,7 @@ export const recoverDeletedFiles = async ({
|
||||
if (recoverPatterns.length > 0) {
|
||||
recoverableDeletedFiles = mm(deletedFiles, recoverPatterns, {
|
||||
dot: true,
|
||||
windows: IS_WINDOWS,
|
||||
windows: isWindows(),
|
||||
noext: true
|
||||
})
|
||||
core.debug(`filtered recoverable deleted files: ${recoverableDeletedFiles}`)
|
||||
|
||||
Reference in New Issue
Block a user