mirror of
				https://github.com/actions/setup-node.git
				synced 2025-10-31 23:43:33 +00:00 
			
		
		
		
	Cache fallback with rolling time based expiration
This commit is contained in:
		
							parent
							
								
									c2ac33f2c6
								
							
						
					
					
						commit
						f01118b9a5
					
				| @ -126,6 +126,8 @@ The action defaults to search for the dependency file (`package-lock.json`, `npm | ||||
| 
 | ||||
| **Note:** The action does not cache `node_modules` | ||||
| 
 | ||||
| Use `cache-invalidate-after-days` to change the default fallback cache invalidation of every 120 days. Set to 0 to deactivate. | ||||
| 
 | ||||
| See the examples of using cache for `yarn`/`pnpm` and `cache-dependency-path` input in the [Advanced usage](docs/advanced-usage.md#caching-packages-data) guide. | ||||
| 
 | ||||
| **Caching npm dependencies:** | ||||
|  | ||||
| @ -132,13 +132,13 @@ describe('cache-restore', () => { | ||||
|           } | ||||
|         }); | ||||
| 
 | ||||
|         await restoreCache(packageManager, ''); | ||||
|         await restoreCache(packageManager, '', '0'); | ||||
|         expect(hashFilesSpy).toHaveBeenCalled(); | ||||
|         expect(infoSpy).toHaveBeenCalledWith( | ||||
|           `Cache restored from key: node-cache-${platform}-${packageManager}-${fileHash}` | ||||
|           `Cache restored from key: ${platform}-0-setup-node-${packageManager}-${fileHash}` | ||||
|         ); | ||||
|         expect(infoSpy).not.toHaveBeenCalledWith( | ||||
|           `${packageManager} cache is not found` | ||||
|           `Cache not found for input keys: ${platform}-0-setup-node-${packageManager}-${fileHash}, ${platform}-0-setup-node-${packageManager}-` | ||||
|         ); | ||||
|         expect(setOutputSpy).toHaveBeenCalledWith('cache-hit', true); | ||||
|       } | ||||
| @ -163,10 +163,10 @@ describe('cache-restore', () => { | ||||
|         }); | ||||
| 
 | ||||
|         restoreCacheSpy.mockImplementationOnce(() => undefined); | ||||
|         await restoreCache(packageManager, ''); | ||||
|         await restoreCache(packageManager, '', '0'); | ||||
|         expect(hashFilesSpy).toHaveBeenCalled(); | ||||
|         expect(infoSpy).toHaveBeenCalledWith( | ||||
|           `${packageManager} cache is not found` | ||||
|           `Cache not found for input keys: ${platform}-0-setup-node-${packageManager}-${fileHash}, ${platform}-0-setup-node-${packageManager}-` | ||||
|         ); | ||||
|         expect(setOutputSpy).toHaveBeenCalledWith('cache-hit', false); | ||||
|       } | ||||
|  | ||||
| @ -25,6 +25,8 @@ inputs: | ||||
|     description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm.' | ||||
|   cache-dependency-path: | ||||
|     description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.' | ||||
|   cache-invalidate-after-days: | ||||
|     description: 'Used to control how often the fallback cache is invalidated automatically.' | ||||
| # TODO: add input to control forcing to pull from cloud or dist. | ||||
| #       escape valve for someone having issues or needing the absolute latest which isn't cached yet | ||||
| outputs: | ||||
|  | ||||
							
								
								
									
										21
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							| @ -93090,7 +93090,7 @@ const path_1 = __importDefault(__nccwpck_require__(1017)); | ||||
| const fs_1 = __importDefault(__nccwpck_require__(7147)); | ||||
| const constants_1 = __nccwpck_require__(9042); | ||||
| const cache_utils_1 = __nccwpck_require__(1678); | ||||
| const restoreCache = (packageManager, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () { | ||||
| const restoreCache = (packageManager, cacheDependencyPath, cacheInvalidateAfterDays) => __awaiter(void 0, void 0, void 0, function* () { | ||||
|     const packageManagerInfo = yield (0, cache_utils_1.getPackageManagerInfo)(packageManager); | ||||
|     if (!packageManagerInfo) { | ||||
|         throw new Error(`Caching for '${packageManager}' is not supported`); | ||||
| @ -93105,22 +93105,30 @@ const restoreCache = (packageManager, cacheDependencyPath) => __awaiter(void 0, | ||||
|     if (!fileHash) { | ||||
|         throw new Error('Some specified paths were not resolved, unable to cache dependencies.'); | ||||
|     } | ||||
|     const keyPrefix = `node-cache-${platform}-${packageManager}`; | ||||
|     const numericCacheInvalidateAfterDays = cacheInvalidateAfterDays && cacheInvalidateAfterDays === '0' | ||||
|         ? 0 | ||||
|         : (parseInt(cacheInvalidateAfterDays || '', 10) || 120); | ||||
|     const timedInvalidationPrefix = numericCacheInvalidateAfterDays | ||||
|         ? Math.floor(Date.now() / (1000 * 60 * 60 * 24 * numericCacheInvalidateAfterDays)) % 1000 // % 1000 to get a rolling prefix between 0 and 999 rather than a possibly infinitely large
 | ||||
|         : 0; | ||||
|     const keyPrefixBase = `node-cache-${platform}-${packageManager}`; | ||||
|     const keyPrefix = `${keyPrefixBase}-${timedInvalidationPrefix}`; | ||||
|     const primaryKey = `${keyPrefix}-${fileHash}`; | ||||
|     const restoreKeys = [`${keyPrefix}-`]; | ||||
|     core.debug(`primary key is ${primaryKey}`); | ||||
|     core.saveState(constants_1.State.CachePrimaryKey, primaryKey); | ||||
|     const isManagedByYarnBerry = yield (0, 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]); | ||||
|         cacheKey = yield cache.restoreCache(cachePaths, primaryKey, [keyPrefixBase]); | ||||
|     } | ||||
|     else { | ||||
|         cacheKey = yield cache.restoreCache(cachePaths, primaryKey); | ||||
|         cacheKey = yield cache.restoreCache(cachePaths, primaryKey, restoreKeys); | ||||
|     } | ||||
|     core.setOutput('cache-hit', Boolean(cacheKey)); | ||||
|     if (!cacheKey) { | ||||
|         core.info(`${packageManager} cache is not found`); | ||||
|         core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(', ')}`); | ||||
|         return; | ||||
|     } | ||||
|     core.saveState(constants_1.State.CacheMatchedKey, cacheKey); | ||||
| @ -94251,7 +94259,8 @@ function run() { | ||||
|             if (cache && (0, cache_utils_1.isCacheFeatureAvailable)()) { | ||||
|                 core.saveState(constants_1.State.CachePackageManager, cache); | ||||
|                 const cacheDependencyPath = core.getInput('cache-dependency-path'); | ||||
|                 yield (0, cache_restore_1.restoreCache)(cache, cacheDependencyPath); | ||||
|                 const cacheInvalidateAfterDays = core.getInput('cache-invalidate-after-days'); | ||||
|                 yield (0, cache_restore_1.restoreCache)(cache, cacheDependencyPath, cacheInvalidateAfterDays); | ||||
|             } | ||||
|             const matchersPath = path.join(__dirname, '../..', '.github'); | ||||
|             core.info(`##[add-matcher]${path.join(matchersPath, 'tsc.json')}`); | ||||
|  | ||||
| @ -14,7 +14,8 @@ import { | ||||
| 
 | ||||
| export const restoreCache = async ( | ||||
|   packageManager: string, | ||||
|   cacheDependencyPath: string | ||||
|   cacheDependencyPath: string, | ||||
|   cacheInvalidateAfterDays?: string | ||||
| ) => { | ||||
|   const packageManagerInfo = await getPackageManagerInfo(packageManager); | ||||
|   if (!packageManagerInfo) { | ||||
| @ -37,9 +38,17 @@ export const restoreCache = async ( | ||||
|       'Some specified paths were not resolved, unable to cache dependencies.' | ||||
|     ); | ||||
|   } | ||||
|   const numericCacheInvalidateAfterDays = cacheInvalidateAfterDays && cacheInvalidateAfterDays === '0' | ||||
|     ? 0 | ||||
|     : (parseInt(cacheInvalidateAfterDays || '', 10) || 120) | ||||
|   const timedInvalidationPrefix = numericCacheInvalidateAfterDays | ||||
|     ? Math.floor(Date.now() / (1000 * 60 * 60 * 24 * numericCacheInvalidateAfterDays)) % 1000 // % 1000 to get a rolling prefix between 0 and 999 rather than a possibly infinitely large
 | ||||
|     : 0; | ||||
| 
 | ||||
|   const keyPrefix = `node-cache-${platform}-${packageManager}`; | ||||
|   const keyPrefixBase = `node-cache-${platform}-${packageManager}`; | ||||
|   const keyPrefix = `${keyPrefixBase}-${timedInvalidationPrefix}`; | ||||
|   const primaryKey = `${keyPrefix}-${fileHash}`; | ||||
|   const restoreKeys = [`${keyPrefix}-`]; | ||||
|   core.debug(`primary key is ${primaryKey}`); | ||||
| 
 | ||||
|   core.saveState(State.CachePrimaryKey, primaryKey); | ||||
| @ -53,15 +62,15 @@ export const restoreCache = async ( | ||||
|     core.info( | ||||
|       'All dependencies are managed locally by yarn3, the previous cache can be used' | ||||
|     ); | ||||
|     cacheKey = await cache.restoreCache(cachePaths, primaryKey, [keyPrefix]); | ||||
|     cacheKey = await cache.restoreCache(cachePaths, primaryKey, [keyPrefixBase]); | ||||
|   } else { | ||||
|     cacheKey = await cache.restoreCache(cachePaths, primaryKey); | ||||
|     cacheKey = await cache.restoreCache(cachePaths, primaryKey, restoreKeys); | ||||
|   } | ||||
| 
 | ||||
|   core.setOutput('cache-hit', Boolean(cacheKey)); | ||||
| 
 | ||||
|   if (!cacheKey) { | ||||
|     core.info(`${packageManager} cache is not found`); | ||||
|     core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(', ')}`); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -62,7 +62,8 @@ export async function run() { | ||||
|     if (cache && isCacheFeatureAvailable()) { | ||||
|       core.saveState(State.CachePackageManager, cache); | ||||
|       const cacheDependencyPath = core.getInput('cache-dependency-path'); | ||||
|       await restoreCache(cache, cacheDependencyPath); | ||||
|       const cacheInvalidateAfterDays = core.getInput('cache-invalidate-after-days'); | ||||
|       await restoreCache(cache, cacheDependencyPath, cacheInvalidateAfterDays); | ||||
|     } | ||||
| 
 | ||||
|     const matchersPath = path.join(__dirname, '../..', '.github'); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user