mirror of
				https://github.com/actions/cache.git
				synced 2025-11-04 03:04:01 +00:00 
			
		
		
		
	feat: Adding "always-save" flag that allows to save the new cache over the old cache.
This commit is contained in:
		
							parent
							
								
									baed3516c3
								
							
						
					
					
						commit
						5ab49b24e0
					
				@ -31,6 +31,7 @@ If you are using this inside a container, a POSIX-compliant `tar` needs to be in
 | 
				
			|||||||
* `key` - An explicit key for restoring and saving the cache
 | 
					* `key` - An explicit key for restoring and saving the cache
 | 
				
			||||||
* `restore-keys` - An ordered list of keys to use for restoring stale cache if no cache hit occurred for key. Note
 | 
					* `restore-keys` - An ordered list of keys to use for restoring stale cache if no cache hit occurred for key. Note
 | 
				
			||||||
`cache-hit` returns false in this case.
 | 
					`cache-hit` returns false in this case.
 | 
				
			||||||
 | 
					* `always-save` - Flag indicating that it the cache should always be written
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Outputs
 | 
					### Outputs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -293,6 +293,41 @@ test("restore with restore keys and no cache found", async () => {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("restore with always-save", async () => {
 | 
				
			||||||
 | 
					    const path = "node_modules";
 | 
				
			||||||
 | 
					    const key = "node-test";
 | 
				
			||||||
 | 
					    testUtils.setInputs({
 | 
				
			||||||
 | 
					        path: path,
 | 
				
			||||||
 | 
					        key,
 | 
				
			||||||
 | 
					        alwaysSave: true
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const infoMock = jest.spyOn(core, "info");
 | 
				
			||||||
 | 
					    const failedMock = jest.spyOn(core, "setFailed");
 | 
				
			||||||
 | 
					    const stateMock = jest.spyOn(core, "saveState");
 | 
				
			||||||
 | 
					    const restoreCacheMock = jest
 | 
				
			||||||
 | 
					        .spyOn(cache, "restoreCache")
 | 
				
			||||||
 | 
					        .mockImplementationOnce(() => {
 | 
				
			||||||
 | 
					            return Promise.resolve(undefined);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    process.env['GITHUB_RUN_ID'] = '1234'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    process.env['GITHUB_RUN_ID'] = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(restoreCacheMock).toHaveBeenCalledTimes(1);
 | 
				
			||||||
 | 
					    expect(restoreCacheMock).toHaveBeenCalledWith([path], `${key}-1234`, [`${key}-`]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", `${key}-1234`);
 | 
				
			||||||
 | 
					    expect(failedMock).toHaveBeenCalledTimes(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(infoMock).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					        `Cache not found for input keys: ${key}-1234, ${key}-`
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("restore with cache found for key", async () => {
 | 
					test("restore with cache found for key", async () => {
 | 
				
			||||||
    const path = "node_modules";
 | 
					    const path = "node_modules";
 | 
				
			||||||
    const key = "node-test";
 | 
					    const key = "node-test";
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,12 @@ beforeAll(() => {
 | 
				
			|||||||
        return jest.requireActual("@actions/core").getInput(name, options);
 | 
					        return jest.requireActual("@actions/core").getInput(name, options);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    jest.spyOn(core, "getBooleanInput").mockImplementation((name, options) => {
 | 
				
			||||||
 | 
					        return jest
 | 
				
			||||||
 | 
					            .requireActual("@actions/core")
 | 
				
			||||||
 | 
					            .getBooleanInput(name, options);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    jest.spyOn(actionUtils, "getCacheState").mockImplementation(() => {
 | 
					    jest.spyOn(actionUtils, "getCacheState").mockImplementation(() => {
 | 
				
			||||||
        return jest.requireActual("../src/utils/actionUtils").getCacheState();
 | 
					        return jest.requireActual("../src/utils/actionUtils").getCacheState();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,9 @@ inputs:
 | 
				
			|||||||
  upload-chunk-size:
 | 
					  upload-chunk-size:
 | 
				
			||||||
    description: 'The chunk size used to split up large files during upload, in bytes'
 | 
					    description: 'The chunk size used to split up large files during upload, in bytes'
 | 
				
			||||||
    required: false
 | 
					    required: false
 | 
				
			||||||
 | 
					  always-save:
 | 
				
			||||||
 | 
					    description: 'Flag indicating that it the cache should always be written'
 | 
				
			||||||
 | 
					    required: false
 | 
				
			||||||
outputs:
 | 
					outputs:
 | 
				
			||||||
  cache-hit:
 | 
					  cache-hit:
 | 
				
			||||||
    description: 'A boolean value to indicate an exact match was found for the primary key'
 | 
					    description: 'A boolean value to indicate an exact match was found for the primary key'
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,8 @@ export enum Inputs {
 | 
				
			|||||||
    Key = "key",
 | 
					    Key = "key",
 | 
				
			||||||
    Path = "path",
 | 
					    Path = "path",
 | 
				
			||||||
    RestoreKeys = "restore-keys",
 | 
					    RestoreKeys = "restore-keys",
 | 
				
			||||||
    UploadChunkSize = "upload-chunk-size"
 | 
					    UploadChunkSize = "upload-chunk-size",
 | 
				
			||||||
 | 
					    AlwaysSave = "always-save"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum Outputs {
 | 
					export enum Outputs {
 | 
				
			||||||
 | 
				
			|||||||
@ -21,10 +21,20 @@ async function run(): Promise<void> {
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const primaryKey = core.getInput(Inputs.Key, { required: true });
 | 
					        let primaryKey = core.getInput(Inputs.Key, { required: true });
 | 
				
			||||||
        core.saveState(State.CachePrimaryKey, primaryKey);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const restoreKeys = utils.getInputAsArray(Inputs.RestoreKeys);
 | 
					        const restoreKeys = utils.getInputAsArray(Inputs.RestoreKeys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // https://github.com/actions/toolkit/issues/844
 | 
				
			||||||
 | 
					        let alwaysSave = false;
 | 
				
			||||||
 | 
					        if (core.getInput(Inputs.AlwaysSave)) {
 | 
				
			||||||
 | 
					            alwaysSave = core.getBooleanInput(Inputs.AlwaysSave);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (alwaysSave) {
 | 
				
			||||||
 | 
					            restoreKeys.push(`${primaryKey}-`);
 | 
				
			||||||
 | 
					            primaryKey = `${primaryKey}-${process.env['GITHUB_RUN_ID'] ?? Date.now()}`;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        core.saveState(State.CachePrimaryKey, primaryKey);
 | 
				
			||||||
        const cachePaths = utils.getInputAsArray(Inputs.Path, {
 | 
					        const cachePaths = utils.getInputAsArray(Inputs.Path, {
 | 
				
			||||||
            required: true
 | 
					            required: true
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ async function run(): Promise<void> {
 | 
				
			|||||||
        const state = utils.getCacheState();
 | 
					        const state = utils.getCacheState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Inputs are re-evaluted before the post action, so we want the original key used for restore
 | 
					        // Inputs are re-evaluted before the post action, so we want the original key used for restore
 | 
				
			||||||
        const primaryKey = core.getState(State.CachePrimaryKey);
 | 
					        let primaryKey = core.getState(State.CachePrimaryKey);
 | 
				
			||||||
        if (!primaryKey) {
 | 
					        if (!primaryKey) {
 | 
				
			||||||
            utils.logWarning(`Error retrieving key from state.`);
 | 
					            utils.logWarning(`Error retrieving key from state.`);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ interface CacheInput {
 | 
				
			|||||||
    path: string;
 | 
					    path: string;
 | 
				
			||||||
    key: string;
 | 
					    key: string;
 | 
				
			||||||
    restoreKeys?: string[];
 | 
					    restoreKeys?: string[];
 | 
				
			||||||
 | 
					    alwaysSave?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function setInputs(input: CacheInput): void {
 | 
					export function setInputs(input: CacheInput): void {
 | 
				
			||||||
@ -20,6 +21,7 @@ export function setInputs(input: CacheInput): void {
 | 
				
			|||||||
    setInput(Inputs.Key, input.key);
 | 
					    setInput(Inputs.Key, input.key);
 | 
				
			||||||
    input.restoreKeys &&
 | 
					    input.restoreKeys &&
 | 
				
			||||||
        setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n"));
 | 
					        setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n"));
 | 
				
			||||||
 | 
					    setInput(Inputs.AlwaysSave, input.alwaysSave ? "true" : "");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function clearInputs(): void {
 | 
					export function clearInputs(): void {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user