Compare commits
3 Commits
bishal/out
...
bishal-pdM
Author | SHA1 | Date | |
---|---|---|---|
619517aa29 | |||
dc097e3bb9 | |||
fb86cbf360 |
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Node.js & TypeScript",
|
|
||||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:16-bullseye",
|
|
||||||
// Features to add to the dev container. More info: https://containers.dev/implementors/features.
|
|
||||||
// "features": {},
|
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
||||||
// "forwardPorts": [],
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
|
||||||
"postCreateCommand": "npm install && npm run build"
|
|
||||||
// Configure tool-specific properties.
|
|
||||||
// "customizations": {},
|
|
||||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
|
||||||
// "remoteUser": "root"
|
|
||||||
}
|
|
@ -102,7 +102,7 @@ test("restore on GHES with AC available ", async () => {
|
|||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
const failedMock = jest.spyOn(core, "setFailed");
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
const stateMock = jest.spyOn(core, "saveState");
|
const stateMock = jest.spyOn(core, "saveState");
|
||||||
const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
|
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
||||||
const restoreCacheMock = jest
|
const restoreCacheMock = jest
|
||||||
.spyOn(cache, "restoreCache")
|
.spyOn(cache, "restoreCache")
|
||||||
.mockImplementationOnce(() => {
|
.mockImplementationOnce(() => {
|
||||||
@ -116,7 +116,7 @@ test("restore on GHES with AC available ", async () => {
|
|||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledWith("cache-hit", "true");
|
expect(setCacheHitOutputMock).toHaveBeenCalledWith(true);
|
||||||
|
|
||||||
expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`);
|
expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
@ -270,7 +270,7 @@ test("restore with cache found for key", async () => {
|
|||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
const failedMock = jest.spyOn(core, "setFailed");
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
const stateMock = jest.spyOn(core, "saveState");
|
const stateMock = jest.spyOn(core, "saveState");
|
||||||
const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
|
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
||||||
const restoreCacheMock = jest
|
const restoreCacheMock = jest
|
||||||
.spyOn(cache, "restoreCache")
|
.spyOn(cache, "restoreCache")
|
||||||
.mockImplementationOnce(() => {
|
.mockImplementationOnce(() => {
|
||||||
@ -284,7 +284,7 @@ test("restore with cache found for key", async () => {
|
|||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledWith("cache-hit", "true");
|
expect(setCacheHitOutputMock).toHaveBeenCalledWith(true);
|
||||||
|
|
||||||
expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`);
|
expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
@ -303,7 +303,7 @@ test("restore with cache found for restore key", async () => {
|
|||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
const failedMock = jest.spyOn(core, "setFailed");
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
const stateMock = jest.spyOn(core, "saveState");
|
const stateMock = jest.spyOn(core, "saveState");
|
||||||
const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
|
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
||||||
const restoreCacheMock = jest
|
const restoreCacheMock = jest
|
||||||
.spyOn(cache, "restoreCache")
|
.spyOn(cache, "restoreCache")
|
||||||
.mockImplementationOnce(() => {
|
.mockImplementationOnce(() => {
|
||||||
@ -317,7 +317,8 @@ test("restore with cache found for restore key", async () => {
|
|||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledWith("cache-hit", "false");
|
expect(setCacheHitOutputMock).toHaveBeenCalledWith(false);
|
||||||
|
|
||||||
expect(infoMock).toHaveBeenCalledWith(
|
expect(infoMock).toHaveBeenCalledWith(
|
||||||
`Cache restored from key: ${restoreKey}`
|
`Cache restored from key: ${restoreKey}`
|
||||||
);
|
);
|
||||||
|
@ -21,7 +21,7 @@ runs:
|
|||||||
using: 'node16'
|
using: 'node16'
|
||||||
main: 'dist/restore/index.js'
|
main: 'dist/restore/index.js'
|
||||||
post: 'dist/save/index.js'
|
post: 'dist/save/index.js'
|
||||||
post-if: success()
|
post-if: 'success()'
|
||||||
branding:
|
branding:
|
||||||
icon: 'archive'
|
icon: 'archive'
|
||||||
color: 'gray-dark'
|
color: 'gray-dark'
|
||||||
|
5407
dist/restore/index.js
vendored
5407
dist/restore/index.js
vendored
File diff suppressed because it is too large
Load Diff
252
dist/save/index.js
vendored
252
dist/save/index.js
vendored
@ -9344,76 +9344,7 @@ function expand(str, isTop) {
|
|||||||
/***/ }),
|
/***/ }),
|
||||||
/* 307 */,
|
/* 307 */,
|
||||||
/* 308 */,
|
/* 308 */,
|
||||||
/* 309 */
|
/* 309 */,
|
||||||
/***/ (function(__unusedmodule, exports, __webpack_require__) {
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.NullStateProvider = exports.StateProvider = void 0;
|
|
||||||
const core = __importStar(__webpack_require__(470));
|
|
||||||
const constants_1 = __webpack_require__(196);
|
|
||||||
class StateProviderBase {
|
|
||||||
constructor() {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
|
|
||||||
this.setState = (key, value) => { };
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
this.getState = (key) => "";
|
|
||||||
}
|
|
||||||
getCacheState() {
|
|
||||||
const cacheKey = this.getState(constants_1.State.CacheMatchedKey);
|
|
||||||
if (cacheKey) {
|
|
||||||
core.debug(`Cache state/key: ${cacheKey}`);
|
|
||||||
return cacheKey;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class StateProvider extends StateProviderBase {
|
|
||||||
constructor() {
|
|
||||||
super(...arguments);
|
|
||||||
//setOutput = core.setOutput;
|
|
||||||
this.setState = core.saveState;
|
|
||||||
this.getState = core.getState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.StateProvider = StateProvider;
|
|
||||||
class NullStateProvider extends StateProviderBase {
|
|
||||||
constructor() {
|
|
||||||
super(...arguments);
|
|
||||||
//setOutput = core.setOutput;
|
|
||||||
this.setState = core.setOutput;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
this.getState = (key) => "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.NullStateProvider = NullStateProvider;
|
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
|
||||||
/* 310 */,
|
/* 310 */,
|
||||||
/* 311 */,
|
/* 311 */,
|
||||||
/* 312 */
|
/* 312 */
|
||||||
@ -38491,7 +38422,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.isCacheFeatureAvailable = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.setCacheHitOutput = exports.isExactKeyMatch = exports.isGhes = void 0;
|
exports.isCacheFeatureAvailable = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.getCacheState = exports.setOutputAndState = exports.setCacheHitOutput = exports.setCacheState = exports.isExactKeyMatch = exports.isGhes = void 0;
|
||||||
const cache = __importStar(__webpack_require__(692));
|
const cache = __importStar(__webpack_require__(692));
|
||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
const constants_1 = __webpack_require__(196);
|
const constants_1 = __webpack_require__(196);
|
||||||
@ -38507,10 +38438,29 @@ function isExactKeyMatch(key, cacheKey) {
|
|||||||
}) === 0);
|
}) === 0);
|
||||||
}
|
}
|
||||||
exports.isExactKeyMatch = isExactKeyMatch;
|
exports.isExactKeyMatch = isExactKeyMatch;
|
||||||
|
function setCacheState(state) {
|
||||||
|
core.saveState(constants_1.State.CacheMatchedKey, state);
|
||||||
|
}
|
||||||
|
exports.setCacheState = setCacheState;
|
||||||
function setCacheHitOutput(isCacheHit) {
|
function setCacheHitOutput(isCacheHit) {
|
||||||
core.setOutput(constants_1.Outputs.CacheHit, isCacheHit.toString());
|
core.setOutput(constants_1.Outputs.CacheHit, isCacheHit.toString());
|
||||||
}
|
}
|
||||||
exports.setCacheHitOutput = setCacheHitOutput;
|
exports.setCacheHitOutput = setCacheHitOutput;
|
||||||
|
function setOutputAndState(key, cacheKey) {
|
||||||
|
setCacheHitOutput(isExactKeyMatch(key, cacheKey));
|
||||||
|
// Store the matched cache key if it exists
|
||||||
|
cacheKey && setCacheState(cacheKey);
|
||||||
|
}
|
||||||
|
exports.setOutputAndState = setOutputAndState;
|
||||||
|
function getCacheState() {
|
||||||
|
const cacheKey = core.getState(constants_1.State.CacheMatchedKey);
|
||||||
|
if (cacheKey) {
|
||||||
|
core.debug(`Cache state/key: ${cacheKey}`);
|
||||||
|
return cacheKey;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
exports.getCacheState = getCacheState;
|
||||||
function logWarning(message) {
|
function logWarning(message) {
|
||||||
const warningPrefix = "[warning]";
|
const warningPrefix = "[warning]";
|
||||||
core.info(`${warningPrefix}${message}`);
|
core.info(`${warningPrefix}${message}`);
|
||||||
@ -40942,96 +40892,7 @@ Object.defineProperty(exports, "toPlatformPath", { enumerable: true, get: functi
|
|||||||
//# sourceMappingURL=core.js.map
|
//# sourceMappingURL=core.js.map
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
/* 471 */
|
/* 471 */,
|
||||||
/***/ (function(__unusedmodule, exports, __webpack_require__) {
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const cache = __importStar(__webpack_require__(692));
|
|
||||||
const core = __importStar(__webpack_require__(470));
|
|
||||||
const constants_1 = __webpack_require__(196);
|
|
||||||
const utils = __importStar(__webpack_require__(443));
|
|
||||||
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
|
||||||
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
|
||||||
// throw an uncaught exception. Instead of failing this action, just warn.
|
|
||||||
process.on("uncaughtException", e => utils.logWarning(e.message));
|
|
||||||
function saveImpl(stateProvider) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
try {
|
|
||||||
if (!utils.isCacheFeatureAvailable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!utils.isValidEvent()) {
|
|
||||||
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If restore has stored a primary key in state, reuse that
|
|
||||||
// Else re-evaluate from inputs
|
|
||||||
const primaryKey = stateProvider.getState(constants_1.State.CachePrimaryKey) ||
|
|
||||||
core.getInput(constants_1.Inputs.Key);
|
|
||||||
if (!primaryKey) {
|
|
||||||
utils.logWarning(`Error retrieving key from state.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If matched restore key is same as primary key, then do not save cache
|
|
||||||
// NO-OP in case of SaveOnly action
|
|
||||||
const state = stateProvider.getCacheState();
|
|
||||||
if (utils.isExactKeyMatch(primaryKey, state)) {
|
|
||||||
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
|
||||||
required: true
|
|
||||||
});
|
|
||||||
const cacheId = yield cache.saveCache(cachePaths, primaryKey, {
|
|
||||||
uploadChunkSize: utils.getInputAsInt(constants_1.Inputs.UploadChunkSize)
|
|
||||||
});
|
|
||||||
if (cacheId != -1) {
|
|
||||||
core.info(`Cache saved with key: ${primaryKey}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
utils.logWarning(error.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.default = saveImpl;
|
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
|
||||||
/* 472 */,
|
/* 472 */,
|
||||||
/* 473 */,
|
/* 473 */,
|
||||||
/* 474 */,
|
/* 474 */,
|
||||||
@ -47407,6 +47268,29 @@ exports.default = _default;
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
@ -47416,15 +47300,49 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const saveImpl_1 = __importDefault(__webpack_require__(471));
|
const cache = __importStar(__webpack_require__(692));
|
||||||
const stateProvider_1 = __webpack_require__(309);
|
const core = __importStar(__webpack_require__(470));
|
||||||
|
const constants_1 = __webpack_require__(196);
|
||||||
|
const utils = __importStar(__webpack_require__(443));
|
||||||
|
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||||
|
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
||||||
|
// throw an uncaught exception. Instead of failing this action, just warn.
|
||||||
|
process.on("uncaughtException", e => utils.logWarning(e.message));
|
||||||
function run() {
|
function run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
yield (0, saveImpl_1.default)(new stateProvider_1.StateProvider());
|
try {
|
||||||
|
if (!utils.isCacheFeatureAvailable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!utils.isValidEvent()) {
|
||||||
|
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const state = utils.getCacheState();
|
||||||
|
// Inputs are re-evaluted before the post action, so we want the original key used for restore
|
||||||
|
const primaryKey = core.getState(constants_1.State.CachePrimaryKey);
|
||||||
|
if (!primaryKey) {
|
||||||
|
utils.logWarning(`Error retrieving key from state.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (utils.isExactKeyMatch(primaryKey, state)) {
|
||||||
|
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
||||||
|
required: true
|
||||||
|
});
|
||||||
|
const cacheId = yield cache.saveCache(cachePaths, primaryKey, {
|
||||||
|
uploadChunkSize: utils.getInputAsInt(constants_1.Inputs.UploadChunkSize)
|
||||||
|
});
|
||||||
|
if (cacheId != -1) {
|
||||||
|
core.info(`Cache saved with key: ${primaryKey}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
utils.logWarning(error.message);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
run();
|
run();
|
||||||
|
19
examples.md
19
examples.md
@ -309,14 +309,29 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
|
|||||||
For npm, cache files are stored in `~/.npm` on Posix, or `~\AppData\npm-cache` on Windows, but it's possible to use `npm config get cache` to find the path on any platform. See [the npm docs](https://docs.npmjs.com/cli/cache#cache) for more details.
|
For npm, cache files are stored in `~/.npm` on Posix, or `~\AppData\npm-cache` on Windows, but it's possible to use `npm config get cache` to find the path on any platform. See [the npm docs](https://docs.npmjs.com/cli/cache#cache) for more details.
|
||||||
|
|
||||||
If using `npm config` to retrieve the cache directory, ensure you run [actions/setup-node](https://github.com/actions/setup-node) first to ensure your `npm` version is correct.
|
If using `npm config` to retrieve the cache directory, ensure you run [actions/setup-node](https://github.com/actions/setup-node) first to ensure your `npm` version is correct.
|
||||||
|
After [deprecation](https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/) of save-state and set-output commands, the correct way to set output is using `${GITHUB_OUTPUT}`. For linux, we can use `${GITHUB_OUTPUT}` whereas for windows we need to use `${env:GITHUB_OUTPUT}` due to two different default shells in these two different OS ie `bash` and `pwsh` respectively.
|
||||||
|
|
||||||
>Note: It is not recommended to cache `node_modules`, as it can break across Node versions and won't work with `npm ci`
|
>Note: It is not recommended to cache `node_modules`, as it can break across Node versions and won't work with `npm ci`
|
||||||
|
|
||||||
|
### **Get npm cache directory using same shell**
|
||||||
|
### Bash shell
|
||||||
```yaml
|
```yaml
|
||||||
- name: Get npm cache directory
|
- name: Get npm cache directory
|
||||||
id: npm-cache-dir
|
id: npm-cache-dir
|
||||||
run: |
|
shell: bash
|
||||||
echo "::set-output name=dir::$(npm config get cache)"
|
run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT}
|
||||||
|
```
|
||||||
|
|
||||||
|
### PWSH shell
|
||||||
|
```yaml
|
||||||
|
- name: Get npm cache directory
|
||||||
|
id: npm-cache-dir
|
||||||
|
shell: pwsh
|
||||||
|
run: echo "dir=$(npm config get cache)" >> ${env:GITHUB_OUTPUT}
|
||||||
|
```
|
||||||
|
`Get npm cache directory` step can then be used with `actions/cache` as shown below
|
||||||
|
|
||||||
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
|
id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
name: 'Restore Cache'
|
|
||||||
description: 'Restore Cache artifacts like dependencies and build outputs to improve workflow execution time'
|
|
||||||
author: 'GitHub'
|
|
||||||
inputs:
|
|
||||||
path:
|
|
||||||
description: 'The same list of files, directories, and wildcard patterns to restore cache that were used while saving it'
|
|
||||||
required: true
|
|
||||||
key:
|
|
||||||
description: 'An explicit key for restoring the cache'
|
|
||||||
required: true
|
|
||||||
restore-keys:
|
|
||||||
description: '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.'
|
|
||||||
required: false
|
|
||||||
outputs:
|
|
||||||
cache-hit:
|
|
||||||
description: 'A boolean value to indicate an exact match was found for the primary key'
|
|
||||||
runs:
|
|
||||||
using: 'node16'
|
|
||||||
main: '../dist/restore/index.js'
|
|
||||||
branding:
|
|
||||||
icon: 'archive'
|
|
||||||
color: 'gray-dark'
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
|||||||
name: 'Save Cache'
|
|
||||||
description: 'Save Cache artifacts like dependencies and build outputs to improve workflow execution time'
|
|
||||||
author: 'GitHub'
|
|
||||||
inputs:
|
|
||||||
path:
|
|
||||||
description: 'A list of files, directories, and wildcard patterns to cache'
|
|
||||||
required: true
|
|
||||||
key:
|
|
||||||
description: 'An explicit key for saving the cache'
|
|
||||||
required: true
|
|
||||||
upload-chunk-size:
|
|
||||||
description: 'The chunk size used to split up large files during upload, in bytes'
|
|
||||||
required: false
|
|
||||||
runs:
|
|
||||||
using: 'node16'
|
|
||||||
main: '../dist/save/index.js'
|
|
||||||
branding:
|
|
||||||
icon: 'archive'
|
|
||||||
color: 'gray-dark'
|
|
@ -1,8 +1,60 @@
|
|||||||
import { StateProvider } from "./stateProvider";
|
import * as cache from "@actions/cache";
|
||||||
import restoreImpl from "./restoreImpl";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
|
import { Events, Inputs, State } from "./constants";
|
||||||
|
import * as utils from "./utils/actionUtils";
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
await restoreImpl(new StateProvider());
|
try {
|
||||||
|
if (!utils.isCacheFeatureAvailable()) {
|
||||||
|
utils.setCacheHitOutput(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate inputs, this can cause task failure
|
||||||
|
if (!utils.isValidEvent()) {
|
||||||
|
utils.logWarning(
|
||||||
|
`Event Validation Error: The event type ${
|
||||||
|
process.env[Events.Key]
|
||||||
|
} is not supported because it's not tied to a branch or tag ref.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const primaryKey = core.getInput(Inputs.Key, { required: true });
|
||||||
|
core.saveState(State.CachePrimaryKey, primaryKey);
|
||||||
|
|
||||||
|
const restoreKeys = utils.getInputAsArray(Inputs.RestoreKeys);
|
||||||
|
const cachePaths = utils.getInputAsArray(Inputs.Path, {
|
||||||
|
required: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const cacheKey = await cache.restoreCache(
|
||||||
|
cachePaths,
|
||||||
|
primaryKey,
|
||||||
|
restoreKeys
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!cacheKey) {
|
||||||
|
core.info(
|
||||||
|
`Cache not found for input keys: ${[
|
||||||
|
primaryKey,
|
||||||
|
...restoreKeys
|
||||||
|
].join(", ")}`
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the matched cache key
|
||||||
|
utils.setCacheState(cacheKey);
|
||||||
|
|
||||||
|
const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey);
|
||||||
|
utils.setCacheHitOutput(isExactKeyMatch);
|
||||||
|
core.info(`Cache restored from key: ${cacheKey}`);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
core.setFailed((error as Error).message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
import * as cache from "@actions/cache";
|
|
||||||
import * as core from "@actions/core";
|
|
||||||
|
|
||||||
import { Events, Inputs, Outputs, State } from "./constants";
|
|
||||||
import { IStateProvider } from "./stateProvider";
|
|
||||||
import * as utils from "./utils/actionUtils";
|
|
||||||
|
|
||||||
async function restoreImpl(stateProvider: IStateProvider): Promise<string | undefined> {
|
|
||||||
try {
|
|
||||||
if (!utils.isCacheFeatureAvailable()) {
|
|
||||||
utils.setCacheHitOutput(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate inputs, this can cause task failure
|
|
||||||
if (!utils.isValidEvent()) {
|
|
||||||
utils.logWarning(
|
|
||||||
`Event Validation Error: The event type ${
|
|
||||||
process.env[Events.Key]
|
|
||||||
} is not supported because it's not tied to a branch or tag ref.`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const primaryKey = core.getInput(Inputs.Key, { required: true });
|
|
||||||
stateProvider.setState(State.CachePrimaryKey, primaryKey);
|
|
||||||
|
|
||||||
const restoreKeys = utils.getInputAsArray(Inputs.RestoreKeys);
|
|
||||||
const cachePaths = utils.getInputAsArray(Inputs.Path, {
|
|
||||||
required: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const cacheKey = await cache.restoreCache(
|
|
||||||
cachePaths,
|
|
||||||
primaryKey,
|
|
||||||
restoreKeys
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!cacheKey) {
|
|
||||||
core.info(
|
|
||||||
`Cache not found for input keys: ${[
|
|
||||||
primaryKey,
|
|
||||||
...restoreKeys
|
|
||||||
].join(", ")}`
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the matched cache key in states
|
|
||||||
stateProvider.setState(State.CacheMatchedKey, cacheKey);
|
|
||||||
|
|
||||||
const isExactKeyMatch = utils.isExactKeyMatch(
|
|
||||||
core.getInput(Inputs.Key, { required: true }),
|
|
||||||
cacheKey
|
|
||||||
);
|
|
||||||
|
|
||||||
core.setOutput(Outputs.CacheHit, isExactKeyMatch.toString());
|
|
||||||
core.info(`Cache restored from key: ${cacheKey}`);
|
|
||||||
|
|
||||||
return cacheKey;
|
|
||||||
} catch (error: unknown) {
|
|
||||||
core.setFailed((error as Error).message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default restoreImpl;
|
|
@ -1,10 +0,0 @@
|
|||||||
import restoreImpl from "./restoreImpl";
|
|
||||||
import { NullStateProvider } from "./stateProvider";
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
|
||||||
await restoreImpl(new NullStateProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
|
|
||||||
export default run;
|
|
57
src/save.ts
57
src/save.ts
@ -1,8 +1,59 @@
|
|||||||
import saveImpl from "./saveImpl";
|
import * as cache from "@actions/cache";
|
||||||
import { StateProvider } from "./stateProvider";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
|
import { Events, Inputs, State } from "./constants";
|
||||||
|
import * as utils from "./utils/actionUtils";
|
||||||
|
|
||||||
|
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||||
|
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
||||||
|
// throw an uncaught exception. Instead of failing this action, just warn.
|
||||||
|
process.on("uncaughtException", e => utils.logWarning(e.message));
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
await saveImpl(new StateProvider());
|
try {
|
||||||
|
if (!utils.isCacheFeatureAvailable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!utils.isValidEvent()) {
|
||||||
|
utils.logWarning(
|
||||||
|
`Event Validation Error: The event type ${
|
||||||
|
process.env[Events.Key]
|
||||||
|
} is not supported because it's not tied to a branch or tag ref.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = utils.getCacheState();
|
||||||
|
|
||||||
|
// Inputs are re-evaluted before the post action, so we want the original key used for restore
|
||||||
|
const primaryKey = core.getState(State.CachePrimaryKey);
|
||||||
|
if (!primaryKey) {
|
||||||
|
utils.logWarning(`Error retrieving key from state.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils.isExactKeyMatch(primaryKey, state)) {
|
||||||
|
core.info(
|
||||||
|
`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachePaths = utils.getInputAsArray(Inputs.Path, {
|
||||||
|
required: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const cacheId = await cache.saveCache(cachePaths, primaryKey, {
|
||||||
|
uploadChunkSize: utils.getInputAsInt(Inputs.UploadChunkSize)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (cacheId != -1) {
|
||||||
|
core.info(`Cache saved with key: ${primaryKey}`);
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
utils.logWarning((error as Error).message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import * as cache from "@actions/cache";
|
|
||||||
import * as core from "@actions/core";
|
|
||||||
|
|
||||||
import { Events, Inputs, State } from "./constants";
|
|
||||||
import { IStateProvider } from "./stateProvider";
|
|
||||||
import * as utils from "./utils/actionUtils";
|
|
||||||
|
|
||||||
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
|
||||||
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
|
||||||
// throw an uncaught exception. Instead of failing this action, just warn.
|
|
||||||
process.on("uncaughtException", e => utils.logWarning(e.message));
|
|
||||||
|
|
||||||
async function saveImpl(stateProvider: IStateProvider): Promise<void> {
|
|
||||||
try {
|
|
||||||
if (!utils.isCacheFeatureAvailable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!utils.isValidEvent()) {
|
|
||||||
utils.logWarning(
|
|
||||||
`Event Validation Error: The event type ${
|
|
||||||
process.env[Events.Key]
|
|
||||||
} is not supported because it's not tied to a branch or tag ref.`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If restore has stored a primary key in state, reuse that
|
|
||||||
// Else re-evaluate from inputs
|
|
||||||
const primaryKey =
|
|
||||||
stateProvider.getState(State.CachePrimaryKey) ||
|
|
||||||
core.getInput(Inputs.Key);
|
|
||||||
|
|
||||||
if (!primaryKey) {
|
|
||||||
utils.logWarning(`Error retrieving key from state.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If matched restore key is same as primary key, then do not save cache
|
|
||||||
// NO-OP in case of SaveOnly action
|
|
||||||
const state = stateProvider.getCacheState();
|
|
||||||
if (utils.isExactKeyMatch(primaryKey, state)) {
|
|
||||||
core.info(
|
|
||||||
`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cachePaths = utils.getInputAsArray(Inputs.Path, {
|
|
||||||
required: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const cacheId = await cache.saveCache(cachePaths, primaryKey, {
|
|
||||||
uploadChunkSize: utils.getInputAsInt(Inputs.UploadChunkSize)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (cacheId != -1) {
|
|
||||||
core.info(`Cache saved with key: ${primaryKey}`);
|
|
||||||
}
|
|
||||||
} catch (error: unknown) {
|
|
||||||
utils.logWarning((error as Error).message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default saveImpl;
|
|
@ -1,10 +0,0 @@
|
|||||||
import saveImpl from "./saveImpl";
|
|
||||||
import { NullStateProvider } from "./stateProvider";
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
|
||||||
await saveImpl(new NullStateProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
|
|
||||||
export default run;
|
|
@ -1,42 +0,0 @@
|
|||||||
import * as core from "@actions/core";
|
|
||||||
|
|
||||||
import { State } from "./constants";
|
|
||||||
|
|
||||||
export interface IStateProvider {
|
|
||||||
//setOutput(key: string, value: string): void;
|
|
||||||
setState(key: string, value: string): void;
|
|
||||||
getState(key: string): string;
|
|
||||||
|
|
||||||
getCacheState(): string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
class StateProviderBase implements IStateProvider {
|
|
||||||
getCacheState(): string | undefined {
|
|
||||||
const cacheKey = this.getState(State.CacheMatchedKey);
|
|
||||||
if (cacheKey) {
|
|
||||||
core.debug(`Cache state/key: ${cacheKey}`);
|
|
||||||
return cacheKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
|
|
||||||
setState = (key: string, value: string) => {};
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
getState = (key: string) => "";
|
|
||||||
}
|
|
||||||
|
|
||||||
export class StateProvider extends StateProviderBase {
|
|
||||||
//setOutput = core.setOutput;
|
|
||||||
setState = core.saveState;
|
|
||||||
getState = core.getState;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NullStateProvider extends StateProviderBase {
|
|
||||||
//setOutput = core.setOutput;
|
|
||||||
setState = core.setOutput;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
getState = (key: string) => "";
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import * as cache from "@actions/cache";
|
import * as cache from "@actions/cache";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Outputs, RefKey } from "../constants";
|
import { Outputs, RefKey, State } from "../constants";
|
||||||
|
|
||||||
export function isGhes(): boolean {
|
export function isGhes(): boolean {
|
||||||
const ghUrl = new URL(
|
const ghUrl = new URL(
|
||||||
@ -19,10 +19,30 @@ export function isExactKeyMatch(key: string, cacheKey?: string): boolean {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setCacheState(state: string): void {
|
||||||
|
core.saveState(State.CacheMatchedKey, state);
|
||||||
|
}
|
||||||
|
|
||||||
export function setCacheHitOutput(isCacheHit: boolean): void {
|
export function setCacheHitOutput(isCacheHit: boolean): void {
|
||||||
core.setOutput(Outputs.CacheHit, isCacheHit.toString());
|
core.setOutput(Outputs.CacheHit, isCacheHit.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setOutputAndState(key: string, cacheKey?: string): void {
|
||||||
|
setCacheHitOutput(isExactKeyMatch(key, cacheKey));
|
||||||
|
// Store the matched cache key if it exists
|
||||||
|
cacheKey && setCacheState(cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCacheState(): string | undefined {
|
||||||
|
const cacheKey = core.getState(State.CacheMatchedKey);
|
||||||
|
if (cacheKey) {
|
||||||
|
core.debug(`Cache state/key: ${cacheKey}`);
|
||||||
|
return cacheKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function logWarning(message: string): void {
|
export function logWarning(message: string): void {
|
||||||
const warningPrefix = "[warning]";
|
const warningPrefix = "[warning]";
|
||||||
core.info(`${warningPrefix}${message}`);
|
core.info(`${warningPrefix}${message}`);
|
||||||
|
@ -14,7 +14,7 @@ A cache today is immutable and cannot be updated. But some use cases require the
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
primes-${{ runner.os }}
|
primes-${{ runner.os }}
|
||||||
```
|
```
|
||||||
Please note that this will create a new cache on every run and hence will consume the cache [quota](#cache-limits).
|
Please note that this will create a new cache on every run and hence will consume the cache [quota](./README.md#cache-limits).
|
||||||
|
|
||||||
## Use cache across feature branches
|
## Use cache across feature branches
|
||||||
Reusing cache across feature branches is not allowed today to provide cache [isolation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache). However if both feature branches are from the default branch, a good way to achieve this is to ensure that the default branch has a cache. This cache will then be consumable by both feature branches.
|
Reusing cache across feature branches is not allowed today to provide cache [isolation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache). However if both feature branches are from the default branch, a good way to achieve this is to ensure that the default branch has a cache. This cache will then be consumable by both feature branches.
|
||||||
@ -80,4 +80,4 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
Reference in New Issue
Block a user