Do not ivalidate the cache entirely on lock file change (#744)
* Do not ivalidate the cache entirely on yarn3 lock file change * Use cache prefix if all sub-projects are yarn managed * Rename functions & add e2e tests
This commit is contained in:
parent
c6722d36aa
commit
e33196f742
84
.github/workflows/e2e-cache.yml
vendored
84
.github/workflows/e2e-cache.yml
vendored
@ -146,7 +146,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: prepare sub-projects
|
- name: prepare sub-projects
|
||||||
run: __tests__/prepare-subprojects.sh
|
run: __tests__/prepare-yarn-subprojects.sh yarn1
|
||||||
|
|
||||||
# expect
|
# expect
|
||||||
# - no errors
|
# - no errors
|
||||||
@ -161,3 +161,85 @@ jobs:
|
|||||||
cache-dependency-path: |
|
cache-dependency-path: |
|
||||||
**/*.lock
|
**/*.lock
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
|
||||||
|
yarn-subprojects-berry-local:
|
||||||
|
name: Test yarn subprojects all locally managed
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [12, 14, 16]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: prepare sub-projects
|
||||||
|
run: __tests__/prepare-yarn-subprojects.sh
|
||||||
|
|
||||||
|
# expect
|
||||||
|
# - no errors
|
||||||
|
# - log
|
||||||
|
# ##[info]All dependencies are managed locally by yarn3, the previous cache can be used
|
||||||
|
# ##[debug]["node-cache-Linux-yarn-401024703386272f1a950c9f014cbb1bb79a7a5b6e1fb00e8b90d06734af41ee","node-cache-Linux-yarn"]
|
||||||
|
- name: Setup Node
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: 'yarn'
|
||||||
|
cache-dependency-path: |
|
||||||
|
sub2/*.lock
|
||||||
|
sub3/*.lock
|
||||||
|
|
||||||
|
yarn-subprojects-berry-global:
|
||||||
|
name: Test yarn subprojects some locally managed
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [12, 14, 16]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: prepare sub-projects
|
||||||
|
run: __tests__/prepare-yarn-subprojects.sh global
|
||||||
|
|
||||||
|
# expect
|
||||||
|
# - no errors
|
||||||
|
# - log must
|
||||||
|
# ##[debug]"/home/runner/work/setup-node-test/setup-node-test/sub2" dependencies are managed by yarn 3 locally
|
||||||
|
# ##[debug]"/home/runner/work/setup-node-test/setup-node-test/sub3" dependencies are not managed by yarn 3 locally
|
||||||
|
- name: Setup Node
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: 'yarn'
|
||||||
|
cache-dependency-path: |
|
||||||
|
sub2/*.lock
|
||||||
|
sub3/*.lock
|
||||||
|
|
||||||
|
yarn-subprojects-berry-git:
|
||||||
|
name: Test yarn subprojects managed by git
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [12, 14, 16]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: prepare sub-projects
|
||||||
|
run: /bin/bash __tests__/prepare-yarn-subprojects.sh keepcache
|
||||||
|
|
||||||
|
# expect
|
||||||
|
# - no errors
|
||||||
|
# - log
|
||||||
|
# [debug]"/home/runner/work/setup-node-test/setup-node-test/sub2" has .yarn/cache - dependencies are kept in the repository
|
||||||
|
# [debug]"/home/runner/work/setup-node-test/setup-node-test/sub3" has .yarn/cache - dependencies are kept in the repository
|
||||||
|
# [debug]["node-cache-Linux-yarn-401024703386272f1a950c9f014cbb1bb79a7a5b6e1fb00e8b90d06734af41ee"]
|
||||||
|
- name: Setup Node
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: 'yarn'
|
||||||
|
cache-dependency-path: |
|
||||||
|
sub2/*.lock
|
||||||
|
sub3/*.lock
|
||||||
|
@ -6,7 +6,8 @@ import {
|
|||||||
PackageManagerInfo,
|
PackageManagerInfo,
|
||||||
isCacheFeatureAvailable,
|
isCacheFeatureAvailable,
|
||||||
supportedPackageManagers,
|
supportedPackageManagers,
|
||||||
getCommandOutput
|
getCommandOutput,
|
||||||
|
resetProjectDirectoriesMemoized
|
||||||
} from '../src/cache-utils';
|
} from '../src/cache-utils';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import * as cacheUtils from '../src/cache-utils';
|
import * as cacheUtils from '../src/cache-utils';
|
||||||
@ -103,6 +104,8 @@ describe('cache-utils', () => {
|
|||||||
(pattern: string): Promise<Globber> =>
|
(pattern: string): Promise<Globber> =>
|
||||||
MockGlobber.create(['/foo', '/bar'])
|
MockGlobber.create(['/foo', '/bar'])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
resetProjectDirectoriesMemoized();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -32,9 +32,19 @@ cat <<EOT >package.json
|
|||||||
EOT
|
EOT
|
||||||
yarn set version 3.5.1
|
yarn set version 3.5.1
|
||||||
yarn install
|
yarn install
|
||||||
|
if [ x$1 = 'xglobal' ];then
|
||||||
|
echo enableGlobalCache
|
||||||
|
echo 'enableGlobalCache: true' >> .yarnrc.yml
|
||||||
|
fi
|
||||||
|
|
||||||
echo "create yarn1 project in the root"
|
|
||||||
cd ..
|
cd ..
|
||||||
|
if [ x$1 != 'xkeepcache' -a x$2 != 'xkeepcache' ]; then
|
||||||
|
rm -rf sub2/.yarn/cache
|
||||||
|
rm -rf sub3/.yarn/cache
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x$1 = 'xyarn1' ];then
|
||||||
|
echo "create yarn1 project in the root"
|
||||||
cat <<EOT >package.json
|
cat <<EOT >package.json
|
||||||
{
|
{
|
||||||
"name": "subproject",
|
"name": "subproject",
|
||||||
@ -46,3 +56,4 @@ cat <<EOT >package.json
|
|||||||
EOT
|
EOT
|
||||||
yarn set version 1.22.19
|
yarn set version 1.22.19
|
||||||
yarn install
|
yarn install
|
||||||
|
fi
|
71
dist/cache-save/index.js
vendored
71
dist/cache-save/index.js
vendored
@ -60434,7 +60434,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.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectories = exports.getPackageManagerInfo = exports.getCommandOutputNotEmpty = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
|
exports.isCacheFeatureAvailable = exports.isGhes = exports.repoHasYarnBerryManagedDependencies = exports.getCacheDirectories = exports.resetProjectDirectoriesMemoized = exports.getPackageManagerInfo = exports.getCommandOutputNotEmpty = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const exec = __importStar(__nccwpck_require__(1514));
|
const exec = __importStar(__nccwpck_require__(1514));
|
||||||
const cache = __importStar(__nccwpck_require__(7799));
|
const cache = __importStar(__nccwpck_require__(7799));
|
||||||
@ -60503,6 +60503,19 @@ const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
exports.getPackageManagerInfo = getPackageManagerInfo;
|
exports.getPackageManagerInfo = getPackageManagerInfo;
|
||||||
|
/**
|
||||||
|
* getProjectDirectoriesFromCacheDependencyPath is called twice during `restoreCache`
|
||||||
|
* - first through `getCacheDirectories`
|
||||||
|
* - second from `repoHasYarn3ManagedCache`
|
||||||
|
*
|
||||||
|
* it contains expensive IO operation and thus should be memoized
|
||||||
|
*/
|
||||||
|
let projectDirectoriesMemoized = null;
|
||||||
|
/**
|
||||||
|
* unit test must reset memoized variables
|
||||||
|
*/
|
||||||
|
const resetProjectDirectoriesMemoized = () => (projectDirectoriesMemoized = null);
|
||||||
|
exports.resetProjectDirectoriesMemoized = resetProjectDirectoriesMemoized;
|
||||||
/**
|
/**
|
||||||
* Expands (converts) the string input `cache-dependency-path` to list of directories that
|
* Expands (converts) the string input `cache-dependency-path` to list of directories that
|
||||||
* may be project roots
|
* may be project roots
|
||||||
@ -60511,6 +60524,9 @@ exports.getPackageManagerInfo = getPackageManagerInfo;
|
|||||||
* @return list of directories and possible
|
* @return list of directories and possible
|
||||||
*/
|
*/
|
||||||
const getProjectDirectoriesFromCacheDependencyPath = (cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
const getProjectDirectoriesFromCacheDependencyPath = (cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (projectDirectoriesMemoized !== null) {
|
||||||
|
return projectDirectoriesMemoized;
|
||||||
|
}
|
||||||
const globber = yield glob.create(cacheDependencyPath);
|
const globber = yield glob.create(cacheDependencyPath);
|
||||||
const cacheDependenciesPaths = yield globber.glob();
|
const cacheDependenciesPaths = yield globber.glob();
|
||||||
const existingDirectories = cacheDependenciesPaths
|
const existingDirectories = cacheDependenciesPaths
|
||||||
@ -60519,6 +60535,7 @@ const getProjectDirectoriesFromCacheDependencyPath = (cacheDependencyPath) => __
|
|||||||
.filter(directory => fs_1.default.lstatSync(directory).isDirectory());
|
.filter(directory => fs_1.default.lstatSync(directory).isDirectory());
|
||||||
if (!existingDirectories.length)
|
if (!existingDirectories.length)
|
||||||
core.warning(`No existing directories found containing cache-dependency-path="${cacheDependencyPath}"`);
|
core.warning(`No existing directories found containing cache-dependency-path="${cacheDependencyPath}"`);
|
||||||
|
projectDirectoriesMemoized = existingDirectories;
|
||||||
return existingDirectories;
|
return existingDirectories;
|
||||||
});
|
});
|
||||||
/**
|
/**
|
||||||
@ -60531,7 +60548,7 @@ const getProjectDirectoriesFromCacheDependencyPath = (cacheDependencyPath) => __
|
|||||||
const getCacheDirectoriesFromCacheDependencyPath = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
const getCacheDirectoriesFromCacheDependencyPath = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const projectDirectories = yield getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath);
|
const projectDirectories = yield getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath);
|
||||||
const cacheFoldersPaths = yield Promise.all(projectDirectories.map((projectDirectory) => __awaiter(void 0, void 0, void 0, function* () {
|
const cacheFoldersPaths = yield Promise.all(projectDirectories.map((projectDirectory) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const cacheFolderPath = packageManagerInfo.getCacheFolderPath(projectDirectory);
|
const cacheFolderPath = yield packageManagerInfo.getCacheFolderPath(projectDirectory);
|
||||||
core.debug(`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"`);
|
core.debug(`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"`);
|
||||||
return cacheFolderPath;
|
return cacheFolderPath;
|
||||||
})));
|
})));
|
||||||
@ -60565,6 +60582,56 @@ const getCacheDirectories = (packageManagerInfo, cacheDependencyPath) => __await
|
|||||||
return getCacheDirectoriesForRootProject(packageManagerInfo);
|
return getCacheDirectoriesForRootProject(packageManagerInfo);
|
||||||
});
|
});
|
||||||
exports.getCacheDirectories = getCacheDirectories;
|
exports.getCacheDirectories = getCacheDirectories;
|
||||||
|
/**
|
||||||
|
* A function to check if the directory is a yarn project configured to manage
|
||||||
|
* obsolete dependencies in the local cache
|
||||||
|
* @param directory - a path to the folder
|
||||||
|
* @return - true if the directory's project is yarn managed
|
||||||
|
* - if there's .yarn/cache folder do not mess with the dependencies kept in the repo, return false
|
||||||
|
* - global cache is not managed by yarn @see https://yarnpkg.com/features/offline-cache, return false
|
||||||
|
* - if local cache is not explicitly enabled (not yarn3), return false
|
||||||
|
* - return true otherwise
|
||||||
|
*/
|
||||||
|
const projectHasYarnBerryManagedDependencies = (directory) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const workDir = directory || process.env.GITHUB_WORKSPACE || '.';
|
||||||
|
core.debug(`check if "${workDir}" has locally managed yarn3 dependencies`);
|
||||||
|
// if .yarn/cache directory exists the cache is managed by version control system
|
||||||
|
const yarnCacheFile = path_1.default.join(workDir, '.yarn', 'cache');
|
||||||
|
if (fs_1.default.existsSync(yarnCacheFile) &&
|
||||||
|
fs_1.default.lstatSync(yarnCacheFile).isDirectory()) {
|
||||||
|
core.debug(`"${workDir}" has .yarn/cache - dependencies are kept in the repository`);
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
// NOTE: yarn1 returns 'undefined' with return code = 0
|
||||||
|
const enableGlobalCache = yield exports.getCommandOutput('yarn config get enableGlobalCache', workDir);
|
||||||
|
// only local cache is not managed by yarn
|
||||||
|
const managed = enableGlobalCache.includes('false');
|
||||||
|
if (managed) {
|
||||||
|
core.debug(`"${workDir}" dependencies are managed by yarn 3 locally`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug(`"${workDir}" dependencies are not managed by yarn 3 locally`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* A function to report the repo contains Yarn managed projects
|
||||||
|
* @param packageManagerInfo - used to make sure current package manager is yarn
|
||||||
|
* @param cacheDependencyPath - either a single string or multiline string with possible glob patterns
|
||||||
|
* expected to be the result of `core.getInput('cache-dependency-path')`
|
||||||
|
* @return - true if all project directories configured to be Yarn managed
|
||||||
|
*/
|
||||||
|
const repoHasYarnBerryManagedDependencies = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (packageManagerInfo.name !== 'yarn')
|
||||||
|
return false;
|
||||||
|
const yarnDirs = cacheDependencyPath
|
||||||
|
? yield getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath)
|
||||||
|
: [''];
|
||||||
|
const isManagedList = yield Promise.all(yarnDirs.map(projectHasYarnBerryManagedDependencies));
|
||||||
|
return isManagedList.every(Boolean);
|
||||||
|
});
|
||||||
|
exports.repoHasYarnBerryManagedDependencies = repoHasYarnBerryManagedDependencies;
|
||||||
function isGhes() {
|
function isGhes() {
|
||||||
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
||||||
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
||||||
|
84
dist/setup/index.js
vendored
84
dist/setup/index.js
vendored
@ -71153,10 +71153,19 @@ const restoreCache = (packageManager, cacheDependencyPath) => __awaiter(void 0,
|
|||||||
if (!fileHash) {
|
if (!fileHash) {
|
||||||
throw new Error('Some specified paths were not resolved, unable to cache dependencies.');
|
throw new Error('Some specified paths were not resolved, unable to cache dependencies.');
|
||||||
}
|
}
|
||||||
const primaryKey = `node-cache-${platform}-${packageManager}-${fileHash}`;
|
const keyPrefix = `node-cache-${platform}-${packageManager}`;
|
||||||
|
const primaryKey = `${keyPrefix}-${fileHash}`;
|
||||||
core.debug(`primary key is ${primaryKey}`);
|
core.debug(`primary key is ${primaryKey}`);
|
||||||
core.saveState(constants_1.State.CachePrimaryKey, primaryKey);
|
core.saveState(constants_1.State.CachePrimaryKey, primaryKey);
|
||||||
const cacheKey = yield cache.restoreCache(cachePaths, primaryKey);
|
const isManagedByYarnBerry = yield cache_utils_1.repoHasYarnBerryManagedDependencies(packageManagerInfo, cacheDependencyPath);
|
||||||
|
let cacheKey;
|
||||||
|
if (isManagedByYarnBerry) {
|
||||||
|
core.info('All dependencies are managed locally by yarn3, the previous cache can be used');
|
||||||
|
cacheKey = yield cache.restoreCache(cachePaths, primaryKey, [keyPrefix]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cacheKey = yield cache.restoreCache(cachePaths, primaryKey);
|
||||||
|
}
|
||||||
core.setOutput('cache-hit', Boolean(cacheKey));
|
core.setOutput('cache-hit', Boolean(cacheKey));
|
||||||
if (!cacheKey) {
|
if (!cacheKey) {
|
||||||
core.info(`${packageManager} cache is not found`);
|
core.info(`${packageManager} cache is not found`);
|
||||||
@ -71217,7 +71226,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.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectories = exports.getPackageManagerInfo = exports.getCommandOutputNotEmpty = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
|
exports.isCacheFeatureAvailable = exports.isGhes = exports.repoHasYarnBerryManagedDependencies = exports.getCacheDirectories = exports.resetProjectDirectoriesMemoized = exports.getPackageManagerInfo = exports.getCommandOutputNotEmpty = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const exec = __importStar(__nccwpck_require__(1514));
|
const exec = __importStar(__nccwpck_require__(1514));
|
||||||
const cache = __importStar(__nccwpck_require__(7799));
|
const cache = __importStar(__nccwpck_require__(7799));
|
||||||
@ -71286,6 +71295,19 @@ const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
exports.getPackageManagerInfo = getPackageManagerInfo;
|
exports.getPackageManagerInfo = getPackageManagerInfo;
|
||||||
|
/**
|
||||||
|
* getProjectDirectoriesFromCacheDependencyPath is called twice during `restoreCache`
|
||||||
|
* - first through `getCacheDirectories`
|
||||||
|
* - second from `repoHasYarn3ManagedCache`
|
||||||
|
*
|
||||||
|
* it contains expensive IO operation and thus should be memoized
|
||||||
|
*/
|
||||||
|
let projectDirectoriesMemoized = null;
|
||||||
|
/**
|
||||||
|
* unit test must reset memoized variables
|
||||||
|
*/
|
||||||
|
const resetProjectDirectoriesMemoized = () => (projectDirectoriesMemoized = null);
|
||||||
|
exports.resetProjectDirectoriesMemoized = resetProjectDirectoriesMemoized;
|
||||||
/**
|
/**
|
||||||
* Expands (converts) the string input `cache-dependency-path` to list of directories that
|
* Expands (converts) the string input `cache-dependency-path` to list of directories that
|
||||||
* may be project roots
|
* may be project roots
|
||||||
@ -71294,6 +71316,9 @@ exports.getPackageManagerInfo = getPackageManagerInfo;
|
|||||||
* @return list of directories and possible
|
* @return list of directories and possible
|
||||||
*/
|
*/
|
||||||
const getProjectDirectoriesFromCacheDependencyPath = (cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
const getProjectDirectoriesFromCacheDependencyPath = (cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (projectDirectoriesMemoized !== null) {
|
||||||
|
return projectDirectoriesMemoized;
|
||||||
|
}
|
||||||
const globber = yield glob.create(cacheDependencyPath);
|
const globber = yield glob.create(cacheDependencyPath);
|
||||||
const cacheDependenciesPaths = yield globber.glob();
|
const cacheDependenciesPaths = yield globber.glob();
|
||||||
const existingDirectories = cacheDependenciesPaths
|
const existingDirectories = cacheDependenciesPaths
|
||||||
@ -71302,6 +71327,7 @@ const getProjectDirectoriesFromCacheDependencyPath = (cacheDependencyPath) => __
|
|||||||
.filter(directory => fs_1.default.lstatSync(directory).isDirectory());
|
.filter(directory => fs_1.default.lstatSync(directory).isDirectory());
|
||||||
if (!existingDirectories.length)
|
if (!existingDirectories.length)
|
||||||
core.warning(`No existing directories found containing cache-dependency-path="${cacheDependencyPath}"`);
|
core.warning(`No existing directories found containing cache-dependency-path="${cacheDependencyPath}"`);
|
||||||
|
projectDirectoriesMemoized = existingDirectories;
|
||||||
return existingDirectories;
|
return existingDirectories;
|
||||||
});
|
});
|
||||||
/**
|
/**
|
||||||
@ -71314,7 +71340,7 @@ const getProjectDirectoriesFromCacheDependencyPath = (cacheDependencyPath) => __
|
|||||||
const getCacheDirectoriesFromCacheDependencyPath = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
const getCacheDirectoriesFromCacheDependencyPath = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const projectDirectories = yield getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath);
|
const projectDirectories = yield getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath);
|
||||||
const cacheFoldersPaths = yield Promise.all(projectDirectories.map((projectDirectory) => __awaiter(void 0, void 0, void 0, function* () {
|
const cacheFoldersPaths = yield Promise.all(projectDirectories.map((projectDirectory) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const cacheFolderPath = packageManagerInfo.getCacheFolderPath(projectDirectory);
|
const cacheFolderPath = yield packageManagerInfo.getCacheFolderPath(projectDirectory);
|
||||||
core.debug(`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"`);
|
core.debug(`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"`);
|
||||||
return cacheFolderPath;
|
return cacheFolderPath;
|
||||||
})));
|
})));
|
||||||
@ -71348,6 +71374,56 @@ const getCacheDirectories = (packageManagerInfo, cacheDependencyPath) => __await
|
|||||||
return getCacheDirectoriesForRootProject(packageManagerInfo);
|
return getCacheDirectoriesForRootProject(packageManagerInfo);
|
||||||
});
|
});
|
||||||
exports.getCacheDirectories = getCacheDirectories;
|
exports.getCacheDirectories = getCacheDirectories;
|
||||||
|
/**
|
||||||
|
* A function to check if the directory is a yarn project configured to manage
|
||||||
|
* obsolete dependencies in the local cache
|
||||||
|
* @param directory - a path to the folder
|
||||||
|
* @return - true if the directory's project is yarn managed
|
||||||
|
* - if there's .yarn/cache folder do not mess with the dependencies kept in the repo, return false
|
||||||
|
* - global cache is not managed by yarn @see https://yarnpkg.com/features/offline-cache, return false
|
||||||
|
* - if local cache is not explicitly enabled (not yarn3), return false
|
||||||
|
* - return true otherwise
|
||||||
|
*/
|
||||||
|
const projectHasYarnBerryManagedDependencies = (directory) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const workDir = directory || process.env.GITHUB_WORKSPACE || '.';
|
||||||
|
core.debug(`check if "${workDir}" has locally managed yarn3 dependencies`);
|
||||||
|
// if .yarn/cache directory exists the cache is managed by version control system
|
||||||
|
const yarnCacheFile = path_1.default.join(workDir, '.yarn', 'cache');
|
||||||
|
if (fs_1.default.existsSync(yarnCacheFile) &&
|
||||||
|
fs_1.default.lstatSync(yarnCacheFile).isDirectory()) {
|
||||||
|
core.debug(`"${workDir}" has .yarn/cache - dependencies are kept in the repository`);
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
// NOTE: yarn1 returns 'undefined' with return code = 0
|
||||||
|
const enableGlobalCache = yield exports.getCommandOutput('yarn config get enableGlobalCache', workDir);
|
||||||
|
// only local cache is not managed by yarn
|
||||||
|
const managed = enableGlobalCache.includes('false');
|
||||||
|
if (managed) {
|
||||||
|
core.debug(`"${workDir}" dependencies are managed by yarn 3 locally`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug(`"${workDir}" dependencies are not managed by yarn 3 locally`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* A function to report the repo contains Yarn managed projects
|
||||||
|
* @param packageManagerInfo - used to make sure current package manager is yarn
|
||||||
|
* @param cacheDependencyPath - either a single string or multiline string with possible glob patterns
|
||||||
|
* expected to be the result of `core.getInput('cache-dependency-path')`
|
||||||
|
* @return - true if all project directories configured to be Yarn managed
|
||||||
|
*/
|
||||||
|
const repoHasYarnBerryManagedDependencies = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (packageManagerInfo.name !== 'yarn')
|
||||||
|
return false;
|
||||||
|
const yarnDirs = cacheDependencyPath
|
||||||
|
? yield getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath)
|
||||||
|
: [''];
|
||||||
|
const isManagedList = yield Promise.all(yarnDirs.map(projectHasYarnBerryManagedDependencies));
|
||||||
|
return isManagedList.every(Boolean);
|
||||||
|
});
|
||||||
|
exports.repoHasYarnBerryManagedDependencies = repoHasYarnBerryManagedDependencies;
|
||||||
function isGhes() {
|
function isGhes() {
|
||||||
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
||||||
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
||||||
|
@ -8,6 +8,7 @@ import {State} from './constants';
|
|||||||
import {
|
import {
|
||||||
getCacheDirectories,
|
getCacheDirectories,
|
||||||
getPackageManagerInfo,
|
getPackageManagerInfo,
|
||||||
|
repoHasYarnBerryManagedDependencies,
|
||||||
PackageManagerInfo
|
PackageManagerInfo
|
||||||
} from './cache-utils';
|
} from './cache-utils';
|
||||||
|
|
||||||
@ -37,12 +38,26 @@ export const restoreCache = async (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const primaryKey = `node-cache-${platform}-${packageManager}-${fileHash}`;
|
const keyPrefix = `node-cache-${platform}-${packageManager}`;
|
||||||
|
const primaryKey = `${keyPrefix}-${fileHash}`;
|
||||||
core.debug(`primary key is ${primaryKey}`);
|
core.debug(`primary key is ${primaryKey}`);
|
||||||
|
|
||||||
core.saveState(State.CachePrimaryKey, primaryKey);
|
core.saveState(State.CachePrimaryKey, primaryKey);
|
||||||
|
|
||||||
const cacheKey = await cache.restoreCache(cachePaths, primaryKey);
|
const isManagedByYarnBerry = await repoHasYarnBerryManagedDependencies(
|
||||||
|
packageManagerInfo,
|
||||||
|
cacheDependencyPath
|
||||||
|
);
|
||||||
|
let cacheKey: string | undefined;
|
||||||
|
if (isManagedByYarnBerry) {
|
||||||
|
core.info(
|
||||||
|
'All dependencies are managed locally by yarn3, the previous cache can be used'
|
||||||
|
);
|
||||||
|
cacheKey = await cache.restoreCache(cachePaths, primaryKey, [keyPrefix]);
|
||||||
|
} else {
|
||||||
|
cacheKey = await cache.restoreCache(cachePaths, primaryKey);
|
||||||
|
}
|
||||||
|
|
||||||
core.setOutput('cache-hit', Boolean(cacheKey));
|
core.setOutput('cache-hit', Boolean(cacheKey));
|
||||||
|
|
||||||
if (!cacheKey) {
|
if (!cacheKey) {
|
||||||
|
@ -110,6 +110,20 @@ export const getPackageManagerInfo = async (packageManager: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getProjectDirectoriesFromCacheDependencyPath is called twice during `restoreCache`
|
||||||
|
* - first through `getCacheDirectories`
|
||||||
|
* - second from `repoHasYarn3ManagedCache`
|
||||||
|
*
|
||||||
|
* it contains expensive IO operation and thus should be memoized
|
||||||
|
*/
|
||||||
|
|
||||||
|
let projectDirectoriesMemoized: string[] | null = null;
|
||||||
|
/**
|
||||||
|
* unit test must reset memoized variables
|
||||||
|
*/
|
||||||
|
export const resetProjectDirectoriesMemoized = () =>
|
||||||
|
(projectDirectoriesMemoized = null);
|
||||||
/**
|
/**
|
||||||
* Expands (converts) the string input `cache-dependency-path` to list of directories that
|
* Expands (converts) the string input `cache-dependency-path` to list of directories that
|
||||||
* may be project roots
|
* may be project roots
|
||||||
@ -120,6 +134,10 @@ export const getPackageManagerInfo = async (packageManager: string) => {
|
|||||||
const getProjectDirectoriesFromCacheDependencyPath = async (
|
const getProjectDirectoriesFromCacheDependencyPath = async (
|
||||||
cacheDependencyPath: string
|
cacheDependencyPath: string
|
||||||
): Promise<string[]> => {
|
): Promise<string[]> => {
|
||||||
|
if (projectDirectoriesMemoized !== null) {
|
||||||
|
return projectDirectoriesMemoized;
|
||||||
|
}
|
||||||
|
|
||||||
const globber = await glob.create(cacheDependencyPath);
|
const globber = await glob.create(cacheDependencyPath);
|
||||||
const cacheDependenciesPaths = await globber.glob();
|
const cacheDependenciesPaths = await globber.glob();
|
||||||
|
|
||||||
@ -133,6 +151,7 @@ const getProjectDirectoriesFromCacheDependencyPath = async (
|
|||||||
`No existing directories found containing cache-dependency-path="${cacheDependencyPath}"`
|
`No existing directories found containing cache-dependency-path="${cacheDependencyPath}"`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
projectDirectoriesMemoized = existingDirectories;
|
||||||
return existingDirectories;
|
return existingDirectories;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -152,8 +171,9 @@ const getCacheDirectoriesFromCacheDependencyPath = async (
|
|||||||
);
|
);
|
||||||
const cacheFoldersPaths = await Promise.all(
|
const cacheFoldersPaths = await Promise.all(
|
||||||
projectDirectories.map(async projectDirectory => {
|
projectDirectories.map(async projectDirectory => {
|
||||||
const cacheFolderPath =
|
const cacheFolderPath = await packageManagerInfo.getCacheFolderPath(
|
||||||
packageManagerInfo.getCacheFolderPath(projectDirectory);
|
projectDirectory
|
||||||
|
);
|
||||||
core.debug(
|
core.debug(
|
||||||
`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"`
|
`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"`
|
||||||
);
|
);
|
||||||
@ -202,6 +222,74 @@ export const getCacheDirectories = async (
|
|||||||
return getCacheDirectoriesForRootProject(packageManagerInfo);
|
return getCacheDirectoriesForRootProject(packageManagerInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to check if the directory is a yarn project configured to manage
|
||||||
|
* obsolete dependencies in the local cache
|
||||||
|
* @param directory - a path to the folder
|
||||||
|
* @return - true if the directory's project is yarn managed
|
||||||
|
* - if there's .yarn/cache folder do not mess with the dependencies kept in the repo, return false
|
||||||
|
* - global cache is not managed by yarn @see https://yarnpkg.com/features/offline-cache, return false
|
||||||
|
* - if local cache is not explicitly enabled (not yarn3), return false
|
||||||
|
* - return true otherwise
|
||||||
|
*/
|
||||||
|
const projectHasYarnBerryManagedDependencies = async (
|
||||||
|
directory: string
|
||||||
|
): Promise<boolean> => {
|
||||||
|
const workDir = directory || process.env.GITHUB_WORKSPACE || '.';
|
||||||
|
core.debug(`check if "${workDir}" has locally managed yarn3 dependencies`);
|
||||||
|
|
||||||
|
// if .yarn/cache directory exists the cache is managed by version control system
|
||||||
|
const yarnCacheFile = path.join(workDir, '.yarn', 'cache');
|
||||||
|
if (
|
||||||
|
fs.existsSync(yarnCacheFile) &&
|
||||||
|
fs.lstatSync(yarnCacheFile).isDirectory()
|
||||||
|
) {
|
||||||
|
core.debug(
|
||||||
|
`"${workDir}" has .yarn/cache - dependencies are kept in the repository`
|
||||||
|
);
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: yarn1 returns 'undefined' with return code = 0
|
||||||
|
const enableGlobalCache = await getCommandOutput(
|
||||||
|
'yarn config get enableGlobalCache',
|
||||||
|
workDir
|
||||||
|
);
|
||||||
|
// only local cache is not managed by yarn
|
||||||
|
const managed = enableGlobalCache.includes('false');
|
||||||
|
if (managed) {
|
||||||
|
core.debug(`"${workDir}" dependencies are managed by yarn 3 locally`);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
core.debug(`"${workDir}" dependencies are not managed by yarn 3 locally`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to report the repo contains Yarn managed projects
|
||||||
|
* @param packageManagerInfo - used to make sure current package manager is yarn
|
||||||
|
* @param cacheDependencyPath - either a single string or multiline string with possible glob patterns
|
||||||
|
* expected to be the result of `core.getInput('cache-dependency-path')`
|
||||||
|
* @return - true if all project directories configured to be Yarn managed
|
||||||
|
*/
|
||||||
|
export const repoHasYarnBerryManagedDependencies = async (
|
||||||
|
packageManagerInfo: PackageManagerInfo,
|
||||||
|
cacheDependencyPath: string
|
||||||
|
): Promise<boolean> => {
|
||||||
|
if (packageManagerInfo.name !== 'yarn') return false;
|
||||||
|
|
||||||
|
const yarnDirs = cacheDependencyPath
|
||||||
|
? await getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath)
|
||||||
|
: [''];
|
||||||
|
|
||||||
|
const isManagedList = await Promise.all(
|
||||||
|
yarnDirs.map(projectHasYarnBerryManagedDependencies)
|
||||||
|
);
|
||||||
|
|
||||||
|
return isManagedList.every(Boolean);
|
||||||
|
};
|
||||||
|
|
||||||
export function isGhes(): boolean {
|
export function isGhes(): boolean {
|
||||||
const ghUrl = new URL(
|
const ghUrl = new URL(
|
||||||
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
||||||
|
Loading…
Reference in New Issue
Block a user