diff --git a/dist/index.js b/dist/index.js index 1fe9710..24d3dae 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4547,6 +4547,1229 @@ exports.Pattern = Pattern; /***/ ((__unused_webpack_module, exports) => { +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.SearchState = void 0; +class SearchState { + constructor(path, level) { + this.path = path; + this.level = level; + } +} +exports.SearchState = SearchState; +//# sourceMappingURL=internal-search-state.js.map + +/***/ }), + +/***/ 8505: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + + +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 })); +exports.hashFiles = exports.create = void 0; +const internal_globber_1 = __nccwpck_require__(2460); +const internal_hash_files_1 = __nccwpck_require__(7233); +/** + * Constructs a globber + * + * @param patterns Patterns separated by newlines + * @param options Glob options + */ +function create(patterns, options) { + return __awaiter(this, void 0, void 0, function* () { + return yield internal_globber_1.DefaultGlobber.create(patterns, options); + }); +} +exports.create = create; +/** + * Computes the sha256 hash of a glob + * + * @param patterns Patterns separated by newlines + * @param currentWorkspace Workspace used when matching files + * @param options Glob options + * @param verbose Enables verbose logging + */ +function hashFiles(patterns, currentWorkspace = '', options, verbose = false) { + return __awaiter(this, void 0, void 0, function* () { + let followSymbolicLinks = true; + if (options && typeof options.followSymbolicLinks === 'boolean') { + followSymbolicLinks = options.followSymbolicLinks; + } + const globber = yield create(patterns, { followSymbolicLinks }); + return (0, internal_hash_files_1.hashFiles)(globber, currentWorkspace, verbose); + }); +} +exports.hashFiles = hashFiles; +//# sourceMappingURL=glob.js.map + +/***/ }), + +/***/ 9911: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + + +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.getOptions = void 0; +const core = __importStar(__nccwpck_require__(9999)); +/** + * Returns a copy with defaults filled in. + */ +function getOptions(copy) { + const result = { + followSymbolicLinks: true, + implicitDescendants: true, + matchDirectories: true, + omitBrokenSymbolicLinks: true, + excludeHiddenFiles: false + }; + if (copy) { + if (typeof copy.followSymbolicLinks === 'boolean') { + result.followSymbolicLinks = copy.followSymbolicLinks; + core.debug(`followSymbolicLinks '${result.followSymbolicLinks}'`); + } + if (typeof copy.implicitDescendants === 'boolean') { + result.implicitDescendants = copy.implicitDescendants; + core.debug(`implicitDescendants '${result.implicitDescendants}'`); + } + if (typeof copy.matchDirectories === 'boolean') { + result.matchDirectories = copy.matchDirectories; + core.debug(`matchDirectories '${result.matchDirectories}'`); + } + if (typeof copy.omitBrokenSymbolicLinks === 'boolean') { + result.omitBrokenSymbolicLinks = copy.omitBrokenSymbolicLinks; + core.debug(`omitBrokenSymbolicLinks '${result.omitBrokenSymbolicLinks}'`); + } + if (typeof copy.excludeHiddenFiles === 'boolean') { + result.excludeHiddenFiles = copy.excludeHiddenFiles; + core.debug(`excludeHiddenFiles '${result.excludeHiddenFiles}'`); + } + } + return result; +} +exports.getOptions = getOptions; +//# sourceMappingURL=internal-glob-options-helper.js.map + +/***/ }), + +/***/ 2460: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + + +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()); + }); +}; +var __asyncValues = (this && this.__asyncValues) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +}; +var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } +var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.DefaultGlobber = void 0; +const core = __importStar(__nccwpck_require__(9999)); +const fs = __importStar(__nccwpck_require__(9896)); +const globOptionsHelper = __importStar(__nccwpck_require__(9911)); +const path = __importStar(__nccwpck_require__(6928)); +const patternHelper = __importStar(__nccwpck_require__(6857)); +const internal_match_kind_1 = __nccwpck_require__(6401); +const internal_pattern_1 = __nccwpck_require__(8109); +const internal_search_state_1 = __nccwpck_require__(6187); +const IS_WINDOWS = process.platform === 'win32'; +class DefaultGlobber { + constructor(options) { + this.patterns = []; + this.searchPaths = []; + this.options = globOptionsHelper.getOptions(options); + } + getSearchPaths() { + // Return a copy + return this.searchPaths.slice(); + } + glob() { + var _a, e_1, _b, _c; + return __awaiter(this, void 0, void 0, function* () { + const result = []; + try { + for (var _d = true, _e = __asyncValues(this.globGenerator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) { + _c = _f.value; + _d = false; + const itemPath = _c; + result.push(itemPath); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (!_d && !_a && (_b = _e.return)) yield _b.call(_e); + } + finally { if (e_1) throw e_1.error; } + } + return result; + }); + } + globGenerator() { + return __asyncGenerator(this, arguments, function* globGenerator_1() { + // Fill in defaults options + const options = globOptionsHelper.getOptions(this.options); + // Implicit descendants? + const patterns = []; + for (const pattern of this.patterns) { + patterns.push(pattern); + if (options.implicitDescendants && + (pattern.trailingSeparator || + pattern.segments[pattern.segments.length - 1] !== '**')) { + patterns.push(new internal_pattern_1.Pattern(pattern.negate, true, pattern.segments.concat('**'))); + } + } + // Push the search paths + const stack = []; + for (const searchPath of patternHelper.getSearchPaths(patterns)) { + core.debug(`Search path '${searchPath}'`); + // Exists? + try { + // Intentionally using lstat. Detection for broken symlink + // will be performed later (if following symlinks). + yield __await(fs.promises.lstat(searchPath)); + } + catch (err) { + if (err.code === 'ENOENT') { + continue; + } + throw err; + } + stack.unshift(new internal_search_state_1.SearchState(searchPath, 1)); + } + // Search + const traversalChain = []; // used to detect cycles + while (stack.length) { + // Pop + const item = stack.pop(); + // Match? + const match = patternHelper.match(patterns, item.path); + const partialMatch = !!match || patternHelper.partialMatch(patterns, item.path); + if (!match && !partialMatch) { + continue; + } + // Stat + const stats = yield __await(DefaultGlobber.stat(item, options, traversalChain) + // Broken symlink, or symlink cycle detected, or no longer exists + ); + // Broken symlink, or symlink cycle detected, or no longer exists + if (!stats) { + continue; + } + // Hidden file or directory? + if (options.excludeHiddenFiles && path.basename(item.path).match(/^\./)) { + continue; + } + // Directory + if (stats.isDirectory()) { + // Matched + if (match & internal_match_kind_1.MatchKind.Directory && options.matchDirectories) { + yield yield __await(item.path); + } + // Descend? + else if (!partialMatch) { + continue; + } + // Push the child items in reverse + const childLevel = item.level + 1; + const childItems = (yield __await(fs.promises.readdir(item.path))).map(x => new internal_search_state_1.SearchState(path.join(item.path, x), childLevel)); + stack.push(...childItems.reverse()); + } + // File + else if (match & internal_match_kind_1.MatchKind.File) { + yield yield __await(item.path); + } + } + }); + } + /** + * Constructs a DefaultGlobber + */ + static create(patterns, options) { + return __awaiter(this, void 0, void 0, function* () { + const result = new DefaultGlobber(options); + if (IS_WINDOWS) { + patterns = patterns.replace(/\r\n/g, '\n'); + patterns = patterns.replace(/\r/g, '\n'); + } + const lines = patterns.split('\n').map(x => x.trim()); + for (const line of lines) { + // Empty or comment + if (!line || line.startsWith('#')) { + continue; + } + // Pattern + else { + result.patterns.push(new internal_pattern_1.Pattern(line)); + } + } + result.searchPaths.push(...patternHelper.getSearchPaths(result.patterns)); + return result; + }); + } + static stat(item, options, traversalChain) { + return __awaiter(this, void 0, void 0, function* () { + // Note: + // `stat` returns info about the target of a symlink (or symlink chain) + // `lstat` returns info about a symlink itself + let stats; + if (options.followSymbolicLinks) { + try { + // Use `stat` (following symlinks) + stats = yield fs.promises.stat(item.path); + } + catch (err) { + if (err.code === 'ENOENT') { + if (options.omitBrokenSymbolicLinks) { + core.debug(`Broken symlink '${item.path}'`); + return undefined; + } + throw new Error(`No information found for the path '${item.path}'. This may indicate a broken symbolic link.`); + } + throw err; + } + } + else { + // Use `lstat` (not following symlinks) + stats = yield fs.promises.lstat(item.path); + } + // Note, isDirectory() returns false for the lstat of a symlink + if (stats.isDirectory() && options.followSymbolicLinks) { + // Get the realpath + const realPath = yield fs.promises.realpath(item.path); + // Fixup the traversal chain to match the item level + while (traversalChain.length >= item.level) { + traversalChain.pop(); + } + // Test for a cycle + if (traversalChain.some((x) => x === realPath)) { + core.debug(`Symlink cycle detected for path '${item.path}' and realpath '${realPath}'`); + return undefined; + } + // Update the traversal chain + traversalChain.push(realPath); + } + return stats; + }); + } +} +exports.DefaultGlobber = DefaultGlobber; +//# sourceMappingURL=internal-globber.js.map + +/***/ }), + +/***/ 7233: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + + +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()); + }); +}; +var __asyncValues = (this && this.__asyncValues) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.hashFiles = void 0; +const crypto = __importStar(__nccwpck_require__(6982)); +const core = __importStar(__nccwpck_require__(9999)); +const fs = __importStar(__nccwpck_require__(9896)); +const stream = __importStar(__nccwpck_require__(2203)); +const util = __importStar(__nccwpck_require__(9023)); +const path = __importStar(__nccwpck_require__(6928)); +function hashFiles(globber, currentWorkspace, verbose = false) { + var _a, e_1, _b, _c; + var _d; + return __awaiter(this, void 0, void 0, function* () { + const writeDelegate = verbose ? core.info : core.debug; + let hasMatch = false; + const githubWorkspace = currentWorkspace + ? currentWorkspace + : (_d = process.env['GITHUB_WORKSPACE']) !== null && _d !== void 0 ? _d : process.cwd(); + const result = crypto.createHash('sha256'); + let count = 0; + try { + for (var _e = true, _f = __asyncValues(globber.globGenerator()), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) { + _c = _g.value; + _e = false; + const file = _c; + writeDelegate(file); + if (!file.startsWith(`${githubWorkspace}${path.sep}`)) { + writeDelegate(`Ignore '${file}' since it is not under GITHUB_WORKSPACE.`); + continue; + } + if (fs.statSync(file).isDirectory()) { + writeDelegate(`Skip directory '${file}'.`); + continue; + } + const hash = crypto.createHash('sha256'); + const pipeline = util.promisify(stream.pipeline); + yield pipeline(fs.createReadStream(file), hash); + result.write(hash.digest()); + count++; + if (!hasMatch) { + hasMatch = true; + } + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (!_e && !_a && (_b = _f.return)) yield _b.call(_f); + } + finally { if (e_1) throw e_1.error; } + } + result.end(); + if (hasMatch) { + writeDelegate(`Found ${count} files to hash.`); + return result.digest('hex'); + } + else { + writeDelegate(`No matches found for glob`); + return ''; + } + }); +} +exports.hashFiles = hashFiles; +//# sourceMappingURL=internal-hash-files.js.map + +/***/ }), + +/***/ 6401: +/***/ ((__unused_webpack_module, exports) => { + + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MatchKind = void 0; +/** + * Indicates whether a pattern matches a path + */ +var MatchKind; +(function (MatchKind) { + /** Not matched */ + MatchKind[MatchKind["None"] = 0] = "None"; + /** Matched if the path is a directory */ + MatchKind[MatchKind["Directory"] = 1] = "Directory"; + /** Matched if the path is a regular file */ + MatchKind[MatchKind["File"] = 2] = "File"; + /** Matched */ + MatchKind[MatchKind["All"] = 3] = "All"; +})(MatchKind || (exports.MatchKind = MatchKind = {})); +//# sourceMappingURL=internal-match-kind.js.map + +/***/ }), + +/***/ 9445: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + + +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 __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.safeTrimTrailingSeparator = exports.normalizeSeparators = exports.hasRoot = exports.hasAbsoluteRoot = exports.ensureAbsoluteRoot = exports.dirname = void 0; +const path = __importStar(__nccwpck_require__(6928)); +const assert_1 = __importDefault(__nccwpck_require__(2613)); +const IS_WINDOWS = process.platform === 'win32'; +/** + * Similar to path.dirname except normalizes the path separators and slightly better handling for Windows UNC paths. + * + * For example, on Linux/macOS: + * - `/ => /` + * - `/hello => /` + * + * For example, on Windows: + * - `C:\ => C:\` + * - `C:\hello => C:\` + * - `C: => C:` + * - `C:hello => C:` + * - `\ => \` + * - `\hello => \` + * - `\\hello => \\hello` + * - `\\hello\world => \\hello\world` + */ +function dirname(p) { + // Normalize slashes and trim unnecessary trailing slash + p = safeTrimTrailingSeparator(p); + // Windows UNC root, e.g. \\hello or \\hello\world + if (IS_WINDOWS && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) { + return p; + } + // Get dirname + let result = path.dirname(p); + // Trim trailing slash for Windows UNC root, e.g. \\hello\world\ + if (IS_WINDOWS && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) { + result = safeTrimTrailingSeparator(result); + } + return result; +} +exports.dirname = dirname; +/** + * Roots the path if not already rooted. On Windows, relative roots like `\` + * or `C:` are expanded based on the current working directory. + */ +function ensureAbsoluteRoot(root, itemPath) { + (0, assert_1.default)(root, `ensureAbsoluteRoot parameter 'root' must not be empty`); + (0, assert_1.default)(itemPath, `ensureAbsoluteRoot parameter 'itemPath' must not be empty`); + // Already rooted + if (hasAbsoluteRoot(itemPath)) { + return itemPath; + } + // Windows + if (IS_WINDOWS) { + // Check for itemPath like C: or C:foo + if (itemPath.match(/^[A-Z]:[^\\/]|^[A-Z]:$/i)) { + let cwd = process.cwd(); + (0, assert_1.default)(cwd.match(/^[A-Z]:\\/i), `Expected current directory to start with an absolute drive root. Actual '${cwd}'`); + // Drive letter matches cwd? Expand to cwd + if (itemPath[0].toUpperCase() === cwd[0].toUpperCase()) { + // Drive only, e.g. C: + if (itemPath.length === 2) { + // Preserve specified drive letter case (upper or lower) + return `${itemPath[0]}:\\${cwd.substr(3)}`; + } + // Drive + path, e.g. C:foo + else { + if (!cwd.endsWith('\\')) { + cwd += '\\'; + } + // Preserve specified drive letter case (upper or lower) + return `${itemPath[0]}:\\${cwd.substr(3)}${itemPath.substr(2)}`; + } + } + // Different drive + else { + return `${itemPath[0]}:\\${itemPath.substr(2)}`; + } + } + // Check for itemPath like \ or \foo + else if (normalizeSeparators(itemPath).match(/^\\$|^\\[^\\]/)) { + const cwd = process.cwd(); + (0, assert_1.default)(cwd.match(/^[A-Z]:\\/i), `Expected current directory to start with an absolute drive root. Actual '${cwd}'`); + return `${cwd[0]}:\\${itemPath.substr(1)}`; + } + } + (0, assert_1.default)(hasAbsoluteRoot(root), `ensureAbsoluteRoot parameter 'root' must have an absolute root`); + // Otherwise ensure root ends with a separator + if (root.endsWith('/') || (IS_WINDOWS && root.endsWith('\\'))) { + // Intentionally empty + } + else { + // Append separator + root += path.sep; + } + return root + itemPath; +} +exports.ensureAbsoluteRoot = ensureAbsoluteRoot; +/** + * On Linux/macOS, true if path starts with `/`. On Windows, true for paths like: + * `\\hello\share` and `C:\hello` (and using alternate separator). + */ +function hasAbsoluteRoot(itemPath) { + (0, assert_1.default)(itemPath, `hasAbsoluteRoot parameter 'itemPath' must not be empty`); + // Normalize separators + itemPath = normalizeSeparators(itemPath); + // Windows + if (IS_WINDOWS) { + // E.g. \\hello\share or C:\hello + return itemPath.startsWith('\\\\') || /^[A-Z]:\\/i.test(itemPath); + } + // E.g. /hello + return itemPath.startsWith('/'); +} +exports.hasAbsoluteRoot = hasAbsoluteRoot; +/** + * On Linux/macOS, true if path starts with `/`. On Windows, true for paths like: + * `\`, `\hello`, `\\hello\share`, `C:`, and `C:\hello` (and using alternate separator). + */ +function hasRoot(itemPath) { + (0, assert_1.default)(itemPath, `isRooted parameter 'itemPath' must not be empty`); + // Normalize separators + itemPath = normalizeSeparators(itemPath); + // Windows + if (IS_WINDOWS) { + // E.g. \ or \hello or \\hello + // E.g. C: or C:\hello + return itemPath.startsWith('\\') || /^[A-Z]:/i.test(itemPath); + } + // E.g. /hello + return itemPath.startsWith('/'); +} +exports.hasRoot = hasRoot; +/** + * Removes redundant slashes and converts `/` to `\` on Windows + */ +function normalizeSeparators(p) { + p = p || ''; + // Windows + if (IS_WINDOWS) { + // Convert slashes on Windows + p = p.replace(/\//g, '\\'); + // Remove redundant slashes + const isUnc = /^\\\\+[^\\]/.test(p); // e.g. \\hello + return (isUnc ? '\\' : '') + p.replace(/\\\\+/g, '\\'); // preserve leading \\ for UNC + } + // Remove redundant slashes + return p.replace(/\/\/+/g, '/'); +} +exports.normalizeSeparators = normalizeSeparators; +/** + * Normalizes the path separators and trims the trailing separator (when safe). + * For example, `/foo/ => /foo` but `/ => /` + */ +function safeTrimTrailingSeparator(p) { + // Short-circuit if empty + if (!p) { + return ''; + } + // Normalize separators + p = normalizeSeparators(p); + // No trailing slash + if (!p.endsWith(path.sep)) { + return p; + } + // Check '/' on Linux/macOS and '\' on Windows + if (p === path.sep) { + return p; + } + // On Windows check if drive root. E.g. C:\ + if (IS_WINDOWS && /^[A-Z]:\\$/i.test(p)) { + return p; + } + // Otherwise trim trailing slash + return p.substr(0, p.length - 1); +} +exports.safeTrimTrailingSeparator = safeTrimTrailingSeparator; +//# sourceMappingURL=internal-path-helper.js.map + +/***/ }), + +/***/ 5588: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + + +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 __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Path = void 0; +const path = __importStar(__nccwpck_require__(6928)); +const pathHelper = __importStar(__nccwpck_require__(9445)); +const assert_1 = __importDefault(__nccwpck_require__(2613)); +const IS_WINDOWS = process.platform === 'win32'; +/** + * Helper class for parsing paths into segments + */ +class Path { + /** + * Constructs a Path + * @param itemPath Path or array of segments + */ + constructor(itemPath) { + this.segments = []; + // String + if (typeof itemPath === 'string') { + (0, assert_1.default)(itemPath, `Parameter 'itemPath' must not be empty`); + // Normalize slashes and trim unnecessary trailing slash + itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); + // Not rooted + if (!pathHelper.hasRoot(itemPath)) { + this.segments = itemPath.split(path.sep); + } + // Rooted + else { + // Add all segments, while not at the root + let remaining = itemPath; + let dir = pathHelper.dirname(remaining); + while (dir !== remaining) { + // Add the segment + const basename = path.basename(remaining); + this.segments.unshift(basename); + // Truncate the last segment + remaining = dir; + dir = pathHelper.dirname(remaining); + } + // Remainder is the root + this.segments.unshift(remaining); + } + } + // Array + else { + // Must not be empty + (0, assert_1.default)(itemPath.length > 0, `Parameter 'itemPath' must not be an empty array`); + // Each segment + for (let i = 0; i < itemPath.length; i++) { + let segment = itemPath[i]; + // Must not be empty + (0, assert_1.default)(segment, `Parameter 'itemPath' must not contain any empty segments`); + // Normalize slashes + segment = pathHelper.normalizeSeparators(itemPath[i]); + // Root segment + if (i === 0 && pathHelper.hasRoot(segment)) { + segment = pathHelper.safeTrimTrailingSeparator(segment); + (0, assert_1.default)(segment === pathHelper.dirname(segment), `Parameter 'itemPath' root segment contains information for multiple segments`); + this.segments.push(segment); + } + // All other segments + else { + // Must not contain slash + (0, assert_1.default)(!segment.includes(path.sep), `Parameter 'itemPath' contains unexpected path separators`); + this.segments.push(segment); + } + } + } + } + /** + * Converts the path to it's string representation + */ + toString() { + // First segment + let result = this.segments[0]; + // All others + let skipSlash = result.endsWith(path.sep) || (IS_WINDOWS && /^[A-Z]:$/i.test(result)); + for (let i = 1; i < this.segments.length; i++) { + if (skipSlash) { + skipSlash = false; + } + else { + result += path.sep; + } + result += this.segments[i]; + } + return result; + } +} +exports.Path = Path; +//# sourceMappingURL=internal-path.js.map + +/***/ }), + +/***/ 6857: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + + +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.partialMatch = exports.match = exports.getSearchPaths = void 0; +const pathHelper = __importStar(__nccwpck_require__(9445)); +const internal_match_kind_1 = __nccwpck_require__(6401); +const IS_WINDOWS = process.platform === 'win32'; +/** + * Given an array of patterns, returns an array of paths to search. + * Duplicates and paths under other included paths are filtered out. + */ +function getSearchPaths(patterns) { + // Ignore negate patterns + patterns = patterns.filter(x => !x.negate); + // Create a map of all search paths + const searchPathMap = {}; + for (const pattern of patterns) { + const key = IS_WINDOWS + ? pattern.searchPath.toUpperCase() + : pattern.searchPath; + searchPathMap[key] = 'candidate'; + } + const result = []; + for (const pattern of patterns) { + // Check if already included + const key = IS_WINDOWS + ? pattern.searchPath.toUpperCase() + : pattern.searchPath; + if (searchPathMap[key] === 'included') { + continue; + } + // Check for an ancestor search path + let foundAncestor = false; + let tempKey = key; + let parent = pathHelper.dirname(tempKey); + while (parent !== tempKey) { + if (searchPathMap[parent]) { + foundAncestor = true; + break; + } + tempKey = parent; + parent = pathHelper.dirname(tempKey); + } + // Include the search pattern in the result + if (!foundAncestor) { + result.push(pattern.searchPath); + searchPathMap[key] = 'included'; + } + } + return result; +} +exports.getSearchPaths = getSearchPaths; +/** + * Matches the patterns against the path + */ +function match(patterns, itemPath) { + let result = internal_match_kind_1.MatchKind.None; + for (const pattern of patterns) { + if (pattern.negate) { + result &= ~pattern.match(itemPath); + } + else { + result |= pattern.match(itemPath); + } + } + return result; +} +exports.match = match; +/** + * Checks whether to descend further into the directory + */ +function partialMatch(patterns, itemPath) { + return patterns.some(x => !x.negate && x.partialMatch(itemPath)); +} +exports.partialMatch = partialMatch; +//# sourceMappingURL=internal-pattern-helper.js.map + +/***/ }), + +/***/ 8109: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + + +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 __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Pattern = void 0; +const os = __importStar(__nccwpck_require__(857)); +const path = __importStar(__nccwpck_require__(6928)); +const pathHelper = __importStar(__nccwpck_require__(9445)); +const assert_1 = __importDefault(__nccwpck_require__(2613)); +const minimatch_1 = __nccwpck_require__(6274); +const internal_match_kind_1 = __nccwpck_require__(6401); +const internal_path_1 = __nccwpck_require__(5588); +const IS_WINDOWS = process.platform === 'win32'; +class Pattern { + constructor(patternOrNegate, isImplicitPattern = false, segments, homedir) { + /** + * Indicates whether matches should be excluded from the result set + */ + this.negate = false; + // Pattern overload + let pattern; + if (typeof patternOrNegate === 'string') { + pattern = patternOrNegate.trim(); + } + // Segments overload + else { + // Convert to pattern + segments = segments || []; + (0, assert_1.default)(segments.length, `Parameter 'segments' must not empty`); + const root = Pattern.getLiteral(segments[0]); + (0, assert_1.default)(root && pathHelper.hasAbsoluteRoot(root), `Parameter 'segments' first element must be a root path`); + pattern = new internal_path_1.Path(segments).toString().trim(); + if (patternOrNegate) { + pattern = `!${pattern}`; + } + } + // Negate + while (pattern.startsWith('!')) { + this.negate = !this.negate; + pattern = pattern.substr(1).trim(); + } + // Normalize slashes and ensures absolute root + pattern = Pattern.fixupPattern(pattern, homedir); + // Segments + this.segments = new internal_path_1.Path(pattern).segments; + // Trailing slash indicates the pattern should only match directories, not regular files + this.trailingSeparator = pathHelper + .normalizeSeparators(pattern) + .endsWith(path.sep); + pattern = pathHelper.safeTrimTrailingSeparator(pattern); + // Search path (literal path prior to the first glob segment) + let foundGlob = false; + const searchSegments = this.segments + .map(x => Pattern.getLiteral(x)) + .filter(x => !foundGlob && !(foundGlob = x === '')); + this.searchPath = new internal_path_1.Path(searchSegments).toString(); + // Root RegExp (required when determining partial match) + this.rootRegExp = new RegExp(Pattern.regExpEscape(searchSegments[0]), IS_WINDOWS ? 'i' : ''); + this.isImplicitPattern = isImplicitPattern; + // Create minimatch + const minimatchOptions = { + dot: true, + nobrace: true, + nocase: IS_WINDOWS, + nocomment: true, + noext: true, + nonegate: true + }; + pattern = IS_WINDOWS ? pattern.replace(/\\/g, '/') : pattern; + this.minimatch = new minimatch_1.Minimatch(pattern, minimatchOptions); + } + /** + * Matches the pattern against the specified path + */ + match(itemPath) { + // Last segment is globstar? + if (this.segments[this.segments.length - 1] === '**') { + // Normalize slashes + itemPath = pathHelper.normalizeSeparators(itemPath); + // Append a trailing slash. Otherwise Minimatch will not match the directory immediately + // preceding the globstar. For example, given the pattern `/foo/**`, Minimatch returns + // false for `/foo` but returns true for `/foo/`. Append a trailing slash to handle that quirk. + if (!itemPath.endsWith(path.sep) && this.isImplicitPattern === false) { + // Note, this is safe because the constructor ensures the pattern has an absolute root. + // For example, formats like C: and C:foo on Windows are resolved to an absolute root. + itemPath = `${itemPath}${path.sep}`; + } + } + else { + // Normalize slashes and trim unnecessary trailing slash + itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); + } + // Match + if (this.minimatch.match(itemPath)) { + return this.trailingSeparator ? internal_match_kind_1.MatchKind.Directory : internal_match_kind_1.MatchKind.All; + } + return internal_match_kind_1.MatchKind.None; + } + /** + * Indicates whether the pattern may match descendants of the specified path + */ + partialMatch(itemPath) { + // Normalize slashes and trim unnecessary trailing slash + itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); + // matchOne does not handle root path correctly + if (pathHelper.dirname(itemPath) === itemPath) { + return this.rootRegExp.test(itemPath); + } + return this.minimatch.matchOne(itemPath.split(IS_WINDOWS ? /\\+/ : /\/+/), this.minimatch.set[0], true); + } + /** + * Escapes glob patterns within a path + */ + static globEscape(s) { + return (IS_WINDOWS ? s : s.replace(/\\/g, '\\\\')) // escape '\' on Linux/macOS + .replace(/(\[)(?=[^/]+\])/g, '[[]') // escape '[' when ']' follows within the path segment + .replace(/\?/g, '[?]') // escape '?' + .replace(/\*/g, '[*]'); // escape '*' + } + /** + * Normalizes slashes and ensures absolute root + */ + static fixupPattern(pattern, homedir) { + // Empty + (0, assert_1.default)(pattern, 'pattern cannot be empty'); + // Must not contain `.` segment, unless first segment + // Must not contain `..` segment + const literalSegments = new internal_path_1.Path(pattern).segments.map(x => Pattern.getLiteral(x)); + (0, assert_1.default)(literalSegments.every((x, i) => (x !== '.' || i === 0) && x !== '..'), `Invalid pattern '${pattern}'. Relative pathing '.' and '..' is not allowed.`); + // Must not contain globs in root, e.g. Windows UNC path \\foo\b*r + (0, assert_1.default)(!pathHelper.hasRoot(pattern) || literalSegments[0], `Invalid pattern '${pattern}'. Root segment must not contain globs.`); + // Normalize slashes + pattern = pathHelper.normalizeSeparators(pattern); + // Replace leading `.` segment + if (pattern === '.' || pattern.startsWith(`.${path.sep}`)) { + pattern = Pattern.globEscape(process.cwd()) + pattern.substr(1); + } + // Replace leading `~` segment + else if (pattern === '~' || pattern.startsWith(`~${path.sep}`)) { + homedir = homedir || os.homedir(); + (0, assert_1.default)(homedir, 'Unable to determine HOME directory'); + (0, assert_1.default)(pathHelper.hasAbsoluteRoot(homedir), `Expected HOME directory to be a rooted path. Actual '${homedir}'`); + pattern = Pattern.globEscape(homedir) + pattern.substr(1); + } + // Replace relative drive root, e.g. pattern is C: or C:foo + else if (IS_WINDOWS && + (pattern.match(/^[A-Z]:$/i) || pattern.match(/^[A-Z]:[^\\]/i))) { + let root = pathHelper.ensureAbsoluteRoot('C:\\dummy-root', pattern.substr(0, 2)); + if (pattern.length > 2 && !root.endsWith('\\')) { + root += '\\'; + } + pattern = Pattern.globEscape(root) + pattern.substr(2); + } + // Replace relative root, e.g. pattern is \ or \foo + else if (IS_WINDOWS && (pattern === '\\' || pattern.match(/^\\[^\\]/))) { + let root = pathHelper.ensureAbsoluteRoot('C:\\dummy-root', '\\'); + if (!root.endsWith('\\')) { + root += '\\'; + } + pattern = Pattern.globEscape(root) + pattern.substr(1); + } + // Otherwise ensure absolute root + else { + pattern = pathHelper.ensureAbsoluteRoot(Pattern.globEscape(process.cwd()), pattern); + } + return pathHelper.normalizeSeparators(pattern); + } + /** + * Attempts to unescape a pattern segment to create a literal path segment. + * Otherwise returns empty string. + */ + static getLiteral(segment) { + let literal = ''; + for (let i = 0; i < segment.length; i++) { + const c = segment[i]; + // Escape + if (c === '\\' && !IS_WINDOWS && i + 1 < segment.length) { + literal += segment[++i]; + continue; + } + // Wildcard + else if (c === '*' || c === '?') { + return ''; + } + // Character set + else if (c === '[' && i + 1 < segment.length) { + let set = ''; + let closed = -1; + for (let i2 = i + 1; i2 < segment.length; i2++) { + const c2 = segment[i2]; + // Escape + if (c2 === '\\' && !IS_WINDOWS && i2 + 1 < segment.length) { + set += segment[++i2]; + continue; + } + // Closed + else if (c2 === ']') { + closed = i2; + break; + } + // Otherwise + else { + set += c2; + } + } + // Closed? + if (closed >= 0) { + // Cannot convert + if (set.length > 1) { + return ''; + } + // Convert to literal + if (set) { + literal += set; + i = closed; + continue; + } + } + // Otherwise fall thru + } + // Append + literal += c; + } + return literal; + } + /** + * Escapes regexp special characters + * https://javascript.info/regexp-escaping + */ + static regExpEscape(s) { + return s.replace(/[[\\^$.|?*+()]/g, '\\$&'); + } +} +exports.Pattern = Pattern; +//# sourceMappingURL=internal-pattern.js.map + +/***/ }), + +/***/ 6187: +/***/ ((__unused_webpack_module, exports) => { + + Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SearchState = void 0; class SearchState { @@ -76053,6 +77276,8 @@ var external_node_os_ = __nccwpck_require__(8161); const external_node_path_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:path"); // EXTERNAL MODULE: ./node_modules/.pnpm/tail@2.2.6/node_modules/tail/lib/tail.js var tail = __nccwpck_require__(5408); +// EXTERNAL MODULE: ./node_modules/.pnpm/@actions+glob@0.5.0/node_modules/@actions/glob/lib/glob.js +var glob = __nccwpck_require__(8505); ;// CONCATENATED MODULE: external "node:fs" const external_node_fs_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:fs"); // EXTERNAL MODULE: external "node:util" @@ -84832,6 +86057,63 @@ async function flakeHubLogin(netrc) { core.info("Logged in to FlakeHub."); } +// src/mnc-warn.ts + + + + +async function warnOnMnc() { + const cwd = process.cwd(); + const patterns = [ + ".github/actions/*.yaml", + ".github/actions/*.yml", + ".github/workflows/*.yaml", + ".github/workflows/*.yml" + ]; + const globber = await glob.create(patterns.join("\n")); + const files = await globber.glob(); + for (const file of files) { + try { + const relativeFilePath = file.replace(cwd, "."); + const lines = (await promises_namespaceObject.readFile(file, { encoding: "utf8" })).split("\n"); + for (const lineIdx of lines.keys()) { + const line = lines[lineIdx]; + if (line.toLowerCase().includes("determinatesystems/magic-nix-cache-action")) { + const actionPosition = line.toLowerCase().indexOf("determinatesystems/magic-nix-cache-action"); + const actionPositionEnd = actionPosition + "determinatesystems/magic-nix-cache-action".length; + const newLine = line.replace( + /DeterminateSystems\/magic-nix-cache-action/gi, + "DeterminateSystems/flakehub-cache-action" + ); + core.warning( + [ + "Magic Nix Cache has been deprecated due to a change in the underlying GitHub APIs and will stop working on 1 February 2025.", + "To continue caching Nix builds in GitHub Actions, use FlakeHub Cache instead.", + "", + "Replace...", + line, + "", + "...with...", + newLine, + "", + "For more details: https://dtr.mn/magic-nix-cache-eol" + ].join("\n"), + { + title: "Magic Nix Cache is deprecated", + file: relativeFilePath, + startLine: lineIdx + 1, + startColumn: actionPosition, + endColumn: actionPositionEnd + } + ); + } + } + } catch (err) { + core.debug(stringifyError(err)); + } + } +} + // src/index.ts @@ -84903,6 +86185,9 @@ var MagicNixCacheAction = class extends DetSysAction { core.warning(TEXT_ALREADY_RUNNING); return; } + if (this.getFeature("warn-magic-nix-cache-eol")?.variant === true) { + await warnOnMnc(); + } if (this.nixStoreTrust === "untrusted") { core.warning(TEXT_TRUST_UNTRUSTED); return; diff --git a/dist/index.js.map b/dist/index.js.map index 675f83e..48eab39 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/helpers.ts","../src/index.ts"],"sourcesContent":["import * as actionsCore from \"@actions/core\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport path from \"node:path\";\nimport { Tail } from \"tail\";\n\nexport function getTrinaryInput(\n name: string,\n): \"enabled\" | \"disabled\" | \"no-preference\" {\n const trueValue = [\"true\", \"True\", \"TRUE\", \"enabled\"];\n const falseValue = [\"false\", \"False\", \"FALSE\", \"disabled\"];\n const noPreferenceValue = [\"\", \"null\", \"no-preference\"];\n\n const val = actionsCore.getInput(name);\n if (trueValue.includes(val)) {\n return \"enabled\";\n }\n if (falseValue.includes(val)) {\n return \"disabled\";\n }\n if (noPreferenceValue.includes(val)) {\n return \"no-preference\";\n }\n\n const possibleValues = trueValue\n .concat(falseValue)\n .concat(noPreferenceValue)\n .join(\" | \");\n throw new TypeError(\n `Input ${name} does not look like a trinary, which requires one of:\\n${possibleValues}`,\n );\n}\n\nexport function tailLog(daemonDir: string): Tail {\n const log = new Tail(path.join(daemonDir, \"daemon.log\"));\n actionsCore.debug(`tailing daemon.log...`);\n log.on(\"line\", (line) => {\n actionsCore.info(line);\n });\n return log;\n}\n\nexport async function netrcPath(): Promise {\n const expectedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] ?? os.tmpdir(),\n \"determinate-nix-installer-netrc\",\n );\n try {\n await fs.access(expectedNetrcPath);\n return expectedNetrcPath;\n } catch {\n // `nix-installer` was not used, the user may be registered with FlakeHub though.\n const destinedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] ?? os.tmpdir(),\n \"magic-nix-cache-netrc\",\n );\n try {\n await flakeHubLogin(destinedNetrcPath);\n } catch (e) {\n actionsCore.info(\n \"FlakeHub Cache is disabled due to missing or invalid token\",\n );\n actionsCore.info(\n `If you're signed up for FlakeHub Cache, make sure that your Actions config has a \\`permissions\\` block with \\`id-token\\` set to \"write\" and \\`contents\\` set to \"read\"`,\n );\n actionsCore.debug(`Error while logging into FlakeHub: ${e}`);\n }\n return destinedNetrcPath;\n }\n}\n\nasync function flakeHubLogin(netrc: string): Promise {\n const jwt = await actionsCore.getIDToken(\"api.flakehub.com\");\n\n await fs.writeFile(\n netrc,\n [\n `machine api.flakehub.com login flakehub password ${jwt}`,\n `machine flakehub.com login flakehub password ${jwt}`,\n `machine cache.flakehub.com login flakehub password ${jwt}`,\n ].join(\"\\n\"),\n );\n\n actionsCore.info(\"Logged in to FlakeHub.\");\n}\n","import { getTrinaryInput, netrcPath, tailLog } from \"./helpers.js\";\nimport * as actionsCore from \"@actions/core\";\nimport { DetSysAction, inputs, stringifyError } from \"detsys-ts\";\nimport got, { Got, Response } from \"got\";\nimport * as http from \"http\";\nimport { SpawnOptions, spawn } from \"node:child_process\";\nimport { mkdirSync, openSync, readFileSync } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { setTimeout } from \"node:timers/promises\";\n\n// The ENV_DAEMON_DIR is intended to determine if we \"own\" the daemon or not,\n// in the case that a user has put the magic nix cache into their workflow\n// twice.\nconst ENV_DAEMON_DIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\n\nconst FACT_ENV_VARS_PRESENT = \"required_env_vars_present\";\nconst FACT_SENT_SIGTERM = \"sent_sigterm\";\nconst FACT_DIFF_STORE_ENABLED = \"diff_store\";\nconst FACT_ALREADY_RUNNING = \"noop_mode\";\n\nconst STATE_DAEMONDIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\nconst STATE_ERROR_IN_MAIN = \"ERROR_IN_MAIN\";\nconst STATE_STARTED = \"MAGIC_NIX_CACHE_STARTED\";\nconst STARTED_HINT = \"true\";\n\nconst TEXT_ALREADY_RUNNING =\n \"Magic Nix Cache is already running, this workflow job is in noop mode. Is the Magic Nix Cache in the workflow twice?\";\nconst TEXT_TRUST_UNTRUSTED =\n \"The Nix daemon does not consider the user running this workflow to be trusted. Magic Nix Cache is disabled.\";\nconst TEXT_TRUST_UNKNOWN =\n \"The Nix daemon may not consider the user running this workflow to be trusted. Magic Nix Cache may not start correctly.\";\n\nclass MagicNixCacheAction extends DetSysAction {\n private hostAndPort: string;\n private diffStore: boolean;\n private httpClient: Got;\n private daemonDir: string;\n private daemonStarted: boolean;\n\n // This is set to `true` if the MNC is already running, in which case the\n // workflow will use the existing process rather than starting a new one.\n private alreadyRunning: boolean;\n\n constructor() {\n super({\n name: \"magic-nix-cache\",\n fetchStyle: \"gh-env-style\",\n idsProjectName: \"magic-nix-cache-closure\",\n requireNix: \"warn\",\n diagnosticsSuffix: \"perf\",\n });\n\n this.hostAndPort = inputs.getString(\"listen\");\n this.diffStore = inputs.getBool(\"diff-store\");\n\n this.addFact(FACT_DIFF_STORE_ENABLED, this.diffStore);\n\n this.httpClient = got.extend({\n retry: {\n limit: 1,\n methods: [\"POST\", \"GET\", \"PUT\", \"HEAD\", \"DELETE\", \"OPTIONS\", \"TRACE\"],\n },\n hooks: {\n beforeRetry: [\n (error, retryCount) => {\n actionsCore.info(\n `Retrying after error ${error.code}, retry #: ${retryCount}`,\n );\n },\n ],\n },\n });\n\n this.daemonStarted = actionsCore.getState(STATE_STARTED) === STARTED_HINT;\n\n if (actionsCore.getState(STATE_DAEMONDIR) !== \"\") {\n this.daemonDir = actionsCore.getState(STATE_DAEMONDIR);\n } else {\n this.daemonDir = this.getTemporaryName();\n mkdirSync(this.daemonDir);\n actionsCore.saveState(STATE_DAEMONDIR, this.daemonDir);\n }\n\n if (process.env[ENV_DAEMON_DIR] === undefined) {\n this.alreadyRunning = false;\n actionsCore.exportVariable(ENV_DAEMON_DIR, this.daemonDir);\n } else {\n this.alreadyRunning = process.env[ENV_DAEMON_DIR] !== this.daemonDir;\n }\n this.addFact(FACT_ALREADY_RUNNING, this.alreadyRunning);\n\n this.stapleFile(\"daemon.log\", path.join(this.daemonDir, \"daemon.log\"));\n }\n\n async main(): Promise {\n if (this.alreadyRunning) {\n actionsCore.warning(TEXT_ALREADY_RUNNING);\n return;\n }\n\n if (this.nixStoreTrust === \"untrusted\") {\n actionsCore.warning(TEXT_TRUST_UNTRUSTED);\n return;\n } else if (this.nixStoreTrust === \"unknown\") {\n actionsCore.info(TEXT_TRUST_UNKNOWN);\n }\n\n await this.setUpAutoCache();\n await this.notifyAutoCache();\n }\n\n async post(): Promise {\n // If strict mode is off and there was an error in main, such as the daemon not starting,\n // then the post phase is skipped with a warning.\n if (!this.strictMode && this.errorInMain) {\n actionsCore.warning(\n `skipping post phase due to error in main phase: ${this.errorInMain}`,\n );\n return;\n }\n\n if (this.alreadyRunning) {\n actionsCore.debug(TEXT_ALREADY_RUNNING);\n return;\n }\n\n if (this.nixStoreTrust === \"untrusted\") {\n actionsCore.debug(TEXT_TRUST_UNTRUSTED);\n return;\n } else if (this.nixStoreTrust === \"unknown\") {\n actionsCore.debug(TEXT_TRUST_UNKNOWN);\n }\n\n await this.tearDownAutoCache();\n }\n\n async setUpAutoCache(): Promise {\n const requiredEnv = [\n \"ACTIONS_CACHE_URL\",\n \"ACTIONS_RUNTIME_URL\",\n \"ACTIONS_RUNTIME_TOKEN\",\n ];\n\n let anyMissing = false;\n for (const n of requiredEnv) {\n if (!process.env.hasOwnProperty(n)) {\n anyMissing = true;\n actionsCore.warning(\n `Disabling automatic caching since required environment ${n} isn't available`,\n );\n }\n }\n\n this.addFact(FACT_ENV_VARS_PRESENT, !anyMissing);\n if (anyMissing) {\n return;\n }\n\n if (this.daemonStarted) {\n actionsCore.debug(\"Already started.\");\n return;\n }\n\n actionsCore.debug(\n `GitHub Action Cache URL: ${process.env[\"ACTIONS_CACHE_URL\"]}`,\n );\n\n const daemonBin = await this.unpackClosure(\"magic-nix-cache\");\n\n let runEnv;\n if (actionsCore.isDebug()) {\n runEnv = {\n RUST_LOG: \"debug,magic_nix_cache=trace,gha_cache=trace\",\n RUST_BACKTRACE: \"full\",\n ...process.env,\n };\n } else {\n runEnv = process.env;\n }\n\n const notifyPort = inputs.getString(\"startup-notification-port\");\n\n const notifyPromise = new Promise>((resolveListening) => {\n const promise = new Promise(async (resolveQuit) => {\n const notifyServer = http.createServer((req, res) => {\n if (req.method === \"POST\" && req.url === \"/\") {\n actionsCore.debug(`Notify server shutting down.`);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n notifyServer.close(() => {\n resolveQuit();\n });\n }\n });\n\n notifyServer.listen(notifyPort, () => {\n actionsCore.debug(`Notify server running.`);\n resolveListening(promise);\n });\n });\n });\n\n // Start tailing the daemon log.\n const outputPath = `${this.daemonDir}/daemon.log`;\n const output = openSync(outputPath, \"a\");\n const log = tailLog(this.daemonDir);\n const netrc = await netrcPath();\n const nixConfPath = `${process.env[\"HOME\"]}/.config/nix/nix.conf`;\n const upstreamCache = inputs.getString(\"upstream-cache\");\n const useFlakeHub = getTrinaryInput(\"use-flakehub\");\n const flakeHubCacheServer = inputs.getString(\"flakehub-cache-server\");\n const flakeHubApiServer = inputs.getString(\"flakehub-api-server\");\n const flakeHubFlakeName = inputs.getString(\"flakehub-flake-name\");\n const useGhaCache = getTrinaryInput(\"use-gha-cache\");\n\n const daemonCliFlags: string[] = [\n \"--startup-notification-url\",\n `http://127.0.0.1:${notifyPort}`,\n \"--listen\",\n this.hostAndPort,\n \"--upstream\",\n upstreamCache,\n \"--diagnostic-endpoint\",\n (await this.getDiagnosticsUrl())?.toString() ?? \"\",\n \"--nix-conf\",\n nixConfPath,\n \"--use-gha-cache\",\n useGhaCache,\n \"--use-flakehub\",\n useFlakeHub,\n ]\n .concat(this.diffStore ? [\"--diff-store\"] : [])\n .concat(\n useFlakeHub !== \"disabled\"\n ? [\n \"--flakehub-cache-server\",\n flakeHubCacheServer,\n \"--flakehub-api-server\",\n flakeHubApiServer,\n \"--flakehub-api-server-netrc\",\n netrc,\n \"--flakehub-flake-name\",\n flakeHubFlakeName,\n ]\n : [],\n );\n\n const opts: SpawnOptions = {\n stdio: [\"ignore\", output, output],\n env: runEnv,\n detached: true,\n };\n\n // Display the final command for debugging purposes\n actionsCore.debug(\"Full daemon start command:\");\n actionsCore.debug(`${daemonBin} ${daemonCliFlags.join(\" \")}`);\n\n // Start the server. Once it is ready, it will notify us via the notification server.\n const daemon = spawn(daemonBin, daemonCliFlags, opts);\n\n this.daemonStarted = true;\n actionsCore.saveState(STATE_STARTED, STARTED_HINT);\n\n const pidFile = path.join(this.daemonDir, \"daemon.pid\");\n await fs.writeFile(pidFile, `${daemon.pid}`);\n\n actionsCore.info(\"Waiting for magic-nix-cache to start...\");\n\n await new Promise((resolve) => {\n notifyPromise\n // eslint-disable-next-line github/no-then\n .then((_value) => {\n resolve();\n })\n // eslint-disable-next-line github/no-then\n .catch((e: unknown) => {\n this.exitMain(`Error in notifyPromise: ${stringifyError(e)}`);\n });\n\n daemon.on(\"exit\", async (code, signal) => {\n let msg: string;\n if (signal) {\n msg = `Daemon was killed by signal ${signal}`;\n } else if (code) {\n msg = `Daemon exited with code ${code}`;\n } else {\n msg = \"Daemon unexpectedly exited\";\n }\n\n this.exitMain(msg);\n });\n });\n\n daemon.unref();\n\n actionsCore.info(\"Launched Magic Nix Cache\");\n\n log.unwatch();\n }\n\n private async notifyAutoCache(): Promise {\n if (!this.daemonStarted) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n try {\n actionsCore.debug(`Indicating workflow start`);\n const res: Response = await this.httpClient.post(\n `http://${this.hostAndPort}/api/workflow-start`,\n );\n\n actionsCore.debug(\n `Response from POST to /api/workflow-start: (status: ${res.statusCode}, body: ${res.body})`,\n );\n\n if (res.statusCode !== 200) {\n throw new Error(\n `Failed to trigger workflow start hook; expected status 200 but got (status: ${res.statusCode}, body: ${res.body})`,\n );\n }\n\n actionsCore.debug(`back from post: ${res.body}`);\n } catch (e: unknown) {\n this.exitMain(`Error starting the Magic Nix Cache: ${stringifyError(e)}`);\n }\n }\n\n async tearDownAutoCache(): Promise {\n if (!this.daemonStarted) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n const pidFile = path.join(this.daemonDir, \"daemon.pid\");\n const pid = parseInt(await fs.readFile(pidFile, { encoding: \"ascii\" }));\n actionsCore.debug(`found daemon pid: ${pid}`);\n if (!pid) {\n throw new Error(\"magic-nix-cache did not start successfully\");\n }\n\n const log = tailLog(this.daemonDir);\n\n try {\n actionsCore.debug(`about to post to localhost`);\n const res: Response = await this.httpClient.post(\n `http://${this.hostAndPort}/api/workflow-finish`,\n );\n\n actionsCore.debug(\n `Response from POST to /api/workflow-finish: (status: ${res.statusCode}, body: ${res.body})`,\n );\n\n if (res.statusCode !== 200) {\n throw new Error(\n `Failed to trigger workflow finish hook; expected status 200 but got (status: ${res.statusCode}, body: ${res.body})`,\n );\n }\n } finally {\n actionsCore.debug(`unwatching the daemon log`);\n log.unwatch();\n }\n\n actionsCore.debug(`killing daemon process ${pid}`);\n\n try {\n // Repeatedly signal 0 the daemon to test if it is up.\n // If it exits, kill will raise an exception which breaks us out of this control flow and skips the sigterm.\n // If magic-nix-cache doesn't exit in 30s, we SIGTERM it.\n for (let i = 0; i < 30 * 10; i++) {\n process.kill(pid, 0);\n await setTimeout(100);\n }\n\n this.addFact(FACT_SENT_SIGTERM, true);\n actionsCore.info(`Sending Magic Nix Cache a SIGTERM`);\n process.kill(pid, \"SIGTERM\");\n } catch {\n // Perfectly normal to get an exception here, because the process shut down.\n }\n\n if (actionsCore.isDebug()) {\n actionsCore.info(\"Entire log:\");\n const entireLog = readFileSync(path.join(this.daemonDir, \"daemon.log\"));\n actionsCore.info(entireLog.toString());\n }\n }\n\n // Exit the workflow during the main phase. If strict mode is set, fail; if not, save the error\n // message to the workflow's state and exit successfully.\n private exitMain(msg: string): void {\n if (this.strictMode) {\n actionsCore.setFailed(msg);\n } else {\n actionsCore.saveState(STATE_ERROR_IN_MAIN, msg);\n process.exit(0);\n }\n }\n\n // If the main phase threw an error (not in strict mode), this will be a non-empty\n // string available in the post phase.\n private get errorInMain(): string | undefined {\n const state = actionsCore.getState(STATE_ERROR_IN_MAIN);\n return state !== \"\" ? state : undefined;\n }\n}\n\nfunction main(): void {\n new MagicNixCacheAction().execute();\n}\n\nmain();\n"],"mappings":"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","names":["actionsCore","fs","path"]} \ No newline at end of file +{"version":3,"sources":["../src/helpers.ts","../src/mnc-warn.ts","../src/index.ts"],"sourcesContent":["import * as actionsCore from \"@actions/core\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport path from \"node:path\";\nimport { Tail } from \"tail\";\n\nexport function getTrinaryInput(\n name: string,\n): \"enabled\" | \"disabled\" | \"no-preference\" {\n const trueValue = [\"true\", \"True\", \"TRUE\", \"enabled\"];\n const falseValue = [\"false\", \"False\", \"FALSE\", \"disabled\"];\n const noPreferenceValue = [\"\", \"null\", \"no-preference\"];\n\n const val = actionsCore.getInput(name);\n if (trueValue.includes(val)) {\n return \"enabled\";\n }\n if (falseValue.includes(val)) {\n return \"disabled\";\n }\n if (noPreferenceValue.includes(val)) {\n return \"no-preference\";\n }\n\n const possibleValues = trueValue\n .concat(falseValue)\n .concat(noPreferenceValue)\n .join(\" | \");\n throw new TypeError(\n `Input ${name} does not look like a trinary, which requires one of:\\n${possibleValues}`,\n );\n}\n\nexport function tailLog(daemonDir: string): Tail {\n const log = new Tail(path.join(daemonDir, \"daemon.log\"));\n actionsCore.debug(`tailing daemon.log...`);\n log.on(\"line\", (line) => {\n actionsCore.info(line);\n });\n return log;\n}\n\nexport async function netrcPath(): Promise {\n const expectedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] ?? os.tmpdir(),\n \"determinate-nix-installer-netrc\",\n );\n try {\n await fs.access(expectedNetrcPath);\n return expectedNetrcPath;\n } catch {\n // `nix-installer` was not used, the user may be registered with FlakeHub though.\n const destinedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] ?? os.tmpdir(),\n \"magic-nix-cache-netrc\",\n );\n try {\n await flakeHubLogin(destinedNetrcPath);\n } catch (e) {\n actionsCore.info(\n \"FlakeHub Cache is disabled due to missing or invalid token\",\n );\n actionsCore.info(\n `If you're signed up for FlakeHub Cache, make sure that your Actions config has a \\`permissions\\` block with \\`id-token\\` set to \"write\" and \\`contents\\` set to \"read\"`,\n );\n actionsCore.debug(`Error while logging into FlakeHub: ${e}`);\n }\n return destinedNetrcPath;\n }\n}\n\nasync function flakeHubLogin(netrc: string): Promise {\n const jwt = await actionsCore.getIDToken(\"api.flakehub.com\");\n\n await fs.writeFile(\n netrc,\n [\n `machine api.flakehub.com login flakehub password ${jwt}`,\n `machine flakehub.com login flakehub password ${jwt}`,\n `machine cache.flakehub.com login flakehub password ${jwt}`,\n ].join(\"\\n\"),\n );\n\n actionsCore.info(\"Logged in to FlakeHub.\");\n}\n","import actionsCore from \"@actions/core\";\nimport glob from \"@actions/glob\";\nimport { stringifyError } from \"detsys-ts\";\nimport * as fs from \"node:fs/promises\";\n\nexport async function warnOnMnc(): Promise {\n const cwd = process.cwd();\n\n const patterns = [\n \".github/actions/*.yaml\",\n \".github/actions/*.yml\",\n \".github/workflows/*.yaml\",\n \".github/workflows/*.yml\",\n ];\n const globber = await glob.create(patterns.join(\"\\n\"));\n const files = await globber.glob();\n\n for (const file of files) {\n try {\n const relativeFilePath = file.replace(cwd, \".\");\n const lines = (await fs.readFile(file, { encoding: \"utf8\" })).split(\"\\n\");\n\n for (const lineIdx of lines.keys()) {\n const line = lines[lineIdx];\n\n if (\n line\n .toLowerCase()\n .includes(\"determinatesystems/magic-nix-cache-action\")\n ) {\n const actionPosition = line\n .toLowerCase()\n .indexOf(\"determinatesystems/magic-nix-cache-action\");\n const actionPositionEnd =\n actionPosition + \"determinatesystems/magic-nix-cache-action\".length;\n\n const newLine = line.replace(\n /DeterminateSystems\\/magic-nix-cache-action/gi,\n \"DeterminateSystems/flakehub-cache-action\",\n );\n actionsCore.warning(\n [\n \"Magic Nix Cache has been deprecated due to a change in the underlying GitHub APIs and will stop working on 1 February 2025.\",\n \"To continue caching Nix builds in GitHub Actions, use FlakeHub Cache instead.\",\n \"\",\n \"Replace...\",\n line,\n \"\",\n \"...with...\",\n newLine,\n \"\",\n \"For more details: https://dtr.mn/magic-nix-cache-eol\",\n ].join(\"\\n\"),\n {\n title: \"Magic Nix Cache is deprecated\",\n file: relativeFilePath,\n startLine: lineIdx + 1,\n startColumn: actionPosition,\n endColumn: actionPositionEnd,\n },\n );\n }\n }\n } catch (err) {\n actionsCore.debug(stringifyError(err));\n }\n }\n}\n","import { getTrinaryInput, netrcPath, tailLog } from \"./helpers.js\";\nimport { warnOnMnc } from \"./mnc-warn.js\";\nimport * as actionsCore from \"@actions/core\";\nimport { DetSysAction, inputs, stringifyError } from \"detsys-ts\";\nimport got, { Got, Response } from \"got\";\nimport * as http from \"http\";\nimport { SpawnOptions, spawn } from \"node:child_process\";\nimport { mkdirSync, openSync, readFileSync } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { setTimeout } from \"node:timers/promises\";\n\n// The ENV_DAEMON_DIR is intended to determine if we \"own\" the daemon or not,\n// in the case that a user has put the magic nix cache into their workflow\n// twice.\nconst ENV_DAEMON_DIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\n\nconst FACT_ENV_VARS_PRESENT = \"required_env_vars_present\";\nconst FACT_SENT_SIGTERM = \"sent_sigterm\";\nconst FACT_DIFF_STORE_ENABLED = \"diff_store\";\nconst FACT_ALREADY_RUNNING = \"noop_mode\";\n\nconst STATE_DAEMONDIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\nconst STATE_ERROR_IN_MAIN = \"ERROR_IN_MAIN\";\nconst STATE_STARTED = \"MAGIC_NIX_CACHE_STARTED\";\nconst STARTED_HINT = \"true\";\n\nconst TEXT_ALREADY_RUNNING =\n \"Magic Nix Cache is already running, this workflow job is in noop mode. Is the Magic Nix Cache in the workflow twice?\";\nconst TEXT_TRUST_UNTRUSTED =\n \"The Nix daemon does not consider the user running this workflow to be trusted. Magic Nix Cache is disabled.\";\nconst TEXT_TRUST_UNKNOWN =\n \"The Nix daemon may not consider the user running this workflow to be trusted. Magic Nix Cache may not start correctly.\";\n\nclass MagicNixCacheAction extends DetSysAction {\n private hostAndPort: string;\n private diffStore: boolean;\n private httpClient: Got;\n private daemonDir: string;\n private daemonStarted: boolean;\n\n // This is set to `true` if the MNC is already running, in which case the\n // workflow will use the existing process rather than starting a new one.\n private alreadyRunning: boolean;\n\n constructor() {\n super({\n name: \"magic-nix-cache\",\n fetchStyle: \"gh-env-style\",\n idsProjectName: \"magic-nix-cache-closure\",\n requireNix: \"warn\",\n diagnosticsSuffix: \"perf\",\n });\n\n this.hostAndPort = inputs.getString(\"listen\");\n this.diffStore = inputs.getBool(\"diff-store\");\n\n this.addFact(FACT_DIFF_STORE_ENABLED, this.diffStore);\n\n this.httpClient = got.extend({\n retry: {\n limit: 1,\n methods: [\"POST\", \"GET\", \"PUT\", \"HEAD\", \"DELETE\", \"OPTIONS\", \"TRACE\"],\n },\n hooks: {\n beforeRetry: [\n (error, retryCount) => {\n actionsCore.info(\n `Retrying after error ${error.code}, retry #: ${retryCount}`,\n );\n },\n ],\n },\n });\n\n this.daemonStarted = actionsCore.getState(STATE_STARTED) === STARTED_HINT;\n\n if (actionsCore.getState(STATE_DAEMONDIR) !== \"\") {\n this.daemonDir = actionsCore.getState(STATE_DAEMONDIR);\n } else {\n this.daemonDir = this.getTemporaryName();\n mkdirSync(this.daemonDir);\n actionsCore.saveState(STATE_DAEMONDIR, this.daemonDir);\n }\n\n if (process.env[ENV_DAEMON_DIR] === undefined) {\n this.alreadyRunning = false;\n actionsCore.exportVariable(ENV_DAEMON_DIR, this.daemonDir);\n } else {\n this.alreadyRunning = process.env[ENV_DAEMON_DIR] !== this.daemonDir;\n }\n this.addFact(FACT_ALREADY_RUNNING, this.alreadyRunning);\n\n this.stapleFile(\"daemon.log\", path.join(this.daemonDir, \"daemon.log\"));\n }\n\n async main(): Promise {\n if (this.alreadyRunning) {\n actionsCore.warning(TEXT_ALREADY_RUNNING);\n return;\n }\n\n if (this.getFeature(\"warn-magic-nix-cache-eol\")?.variant === true) {\n await warnOnMnc();\n }\n\n if (this.nixStoreTrust === \"untrusted\") {\n actionsCore.warning(TEXT_TRUST_UNTRUSTED);\n return;\n } else if (this.nixStoreTrust === \"unknown\") {\n actionsCore.info(TEXT_TRUST_UNKNOWN);\n }\n\n await this.setUpAutoCache();\n await this.notifyAutoCache();\n }\n\n async post(): Promise {\n // If strict mode is off and there was an error in main, such as the daemon not starting,\n // then the post phase is skipped with a warning.\n if (!this.strictMode && this.errorInMain) {\n actionsCore.warning(\n `skipping post phase due to error in main phase: ${this.errorInMain}`,\n );\n return;\n }\n\n if (this.alreadyRunning) {\n actionsCore.debug(TEXT_ALREADY_RUNNING);\n return;\n }\n\n if (this.nixStoreTrust === \"untrusted\") {\n actionsCore.debug(TEXT_TRUST_UNTRUSTED);\n return;\n } else if (this.nixStoreTrust === \"unknown\") {\n actionsCore.debug(TEXT_TRUST_UNKNOWN);\n }\n\n await this.tearDownAutoCache();\n }\n\n async setUpAutoCache(): Promise {\n const requiredEnv = [\n \"ACTIONS_CACHE_URL\",\n \"ACTIONS_RUNTIME_URL\",\n \"ACTIONS_RUNTIME_TOKEN\",\n ];\n\n let anyMissing = false;\n for (const n of requiredEnv) {\n if (!process.env.hasOwnProperty(n)) {\n anyMissing = true;\n actionsCore.warning(\n `Disabling automatic caching since required environment ${n} isn't available`,\n );\n }\n }\n\n this.addFact(FACT_ENV_VARS_PRESENT, !anyMissing);\n if (anyMissing) {\n return;\n }\n\n if (this.daemonStarted) {\n actionsCore.debug(\"Already started.\");\n return;\n }\n\n actionsCore.debug(\n `GitHub Action Cache URL: ${process.env[\"ACTIONS_CACHE_URL\"]}`,\n );\n\n const daemonBin = await this.unpackClosure(\"magic-nix-cache\");\n\n let runEnv;\n if (actionsCore.isDebug()) {\n runEnv = {\n RUST_LOG: \"debug,magic_nix_cache=trace,gha_cache=trace\",\n RUST_BACKTRACE: \"full\",\n ...process.env,\n };\n } else {\n runEnv = process.env;\n }\n\n const notifyPort = inputs.getString(\"startup-notification-port\");\n\n const notifyPromise = new Promise>((resolveListening) => {\n const promise = new Promise(async (resolveQuit) => {\n const notifyServer = http.createServer((req, res) => {\n if (req.method === \"POST\" && req.url === \"/\") {\n actionsCore.debug(`Notify server shutting down.`);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n notifyServer.close(() => {\n resolveQuit();\n });\n }\n });\n\n notifyServer.listen(notifyPort, () => {\n actionsCore.debug(`Notify server running.`);\n resolveListening(promise);\n });\n });\n });\n\n // Start tailing the daemon log.\n const outputPath = `${this.daemonDir}/daemon.log`;\n const output = openSync(outputPath, \"a\");\n const log = tailLog(this.daemonDir);\n const netrc = await netrcPath();\n const nixConfPath = `${process.env[\"HOME\"]}/.config/nix/nix.conf`;\n const upstreamCache = inputs.getString(\"upstream-cache\");\n const useFlakeHub = getTrinaryInput(\"use-flakehub\");\n const flakeHubCacheServer = inputs.getString(\"flakehub-cache-server\");\n const flakeHubApiServer = inputs.getString(\"flakehub-api-server\");\n const flakeHubFlakeName = inputs.getString(\"flakehub-flake-name\");\n const useGhaCache = getTrinaryInput(\"use-gha-cache\");\n\n const daemonCliFlags: string[] = [\n \"--startup-notification-url\",\n `http://127.0.0.1:${notifyPort}`,\n \"--listen\",\n this.hostAndPort,\n \"--upstream\",\n upstreamCache,\n \"--diagnostic-endpoint\",\n (await this.getDiagnosticsUrl())?.toString() ?? \"\",\n \"--nix-conf\",\n nixConfPath,\n \"--use-gha-cache\",\n useGhaCache,\n \"--use-flakehub\",\n useFlakeHub,\n ]\n .concat(this.diffStore ? [\"--diff-store\"] : [])\n .concat(\n useFlakeHub !== \"disabled\"\n ? [\n \"--flakehub-cache-server\",\n flakeHubCacheServer,\n \"--flakehub-api-server\",\n flakeHubApiServer,\n \"--flakehub-api-server-netrc\",\n netrc,\n \"--flakehub-flake-name\",\n flakeHubFlakeName,\n ]\n : [],\n );\n\n const opts: SpawnOptions = {\n stdio: [\"ignore\", output, output],\n env: runEnv,\n detached: true,\n };\n\n // Display the final command for debugging purposes\n actionsCore.debug(\"Full daemon start command:\");\n actionsCore.debug(`${daemonBin} ${daemonCliFlags.join(\" \")}`);\n\n // Start the server. Once it is ready, it will notify us via the notification server.\n const daemon = spawn(daemonBin, daemonCliFlags, opts);\n\n this.daemonStarted = true;\n actionsCore.saveState(STATE_STARTED, STARTED_HINT);\n\n const pidFile = path.join(this.daemonDir, \"daemon.pid\");\n await fs.writeFile(pidFile, `${daemon.pid}`);\n\n actionsCore.info(\"Waiting for magic-nix-cache to start...\");\n\n await new Promise((resolve) => {\n notifyPromise\n // eslint-disable-next-line github/no-then\n .then((_value) => {\n resolve();\n })\n // eslint-disable-next-line github/no-then\n .catch((e: unknown) => {\n this.exitMain(`Error in notifyPromise: ${stringifyError(e)}`);\n });\n\n daemon.on(\"exit\", async (code, signal) => {\n let msg: string;\n if (signal) {\n msg = `Daemon was killed by signal ${signal}`;\n } else if (code) {\n msg = `Daemon exited with code ${code}`;\n } else {\n msg = \"Daemon unexpectedly exited\";\n }\n\n this.exitMain(msg);\n });\n });\n\n daemon.unref();\n\n actionsCore.info(\"Launched Magic Nix Cache\");\n\n log.unwatch();\n }\n\n private async notifyAutoCache(): Promise {\n if (!this.daemonStarted) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n try {\n actionsCore.debug(`Indicating workflow start`);\n const res: Response = await this.httpClient.post(\n `http://${this.hostAndPort}/api/workflow-start`,\n );\n\n actionsCore.debug(\n `Response from POST to /api/workflow-start: (status: ${res.statusCode}, body: ${res.body})`,\n );\n\n if (res.statusCode !== 200) {\n throw new Error(\n `Failed to trigger workflow start hook; expected status 200 but got (status: ${res.statusCode}, body: ${res.body})`,\n );\n }\n\n actionsCore.debug(`back from post: ${res.body}`);\n } catch (e: unknown) {\n this.exitMain(`Error starting the Magic Nix Cache: ${stringifyError(e)}`);\n }\n }\n\n async tearDownAutoCache(): Promise {\n if (!this.daemonStarted) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n const pidFile = path.join(this.daemonDir, \"daemon.pid\");\n const pid = parseInt(await fs.readFile(pidFile, { encoding: \"ascii\" }));\n actionsCore.debug(`found daemon pid: ${pid}`);\n if (!pid) {\n throw new Error(\"magic-nix-cache did not start successfully\");\n }\n\n const log = tailLog(this.daemonDir);\n\n try {\n actionsCore.debug(`about to post to localhost`);\n const res: Response = await this.httpClient.post(\n `http://${this.hostAndPort}/api/workflow-finish`,\n );\n\n actionsCore.debug(\n `Response from POST to /api/workflow-finish: (status: ${res.statusCode}, body: ${res.body})`,\n );\n\n if (res.statusCode !== 200) {\n throw new Error(\n `Failed to trigger workflow finish hook; expected status 200 but got (status: ${res.statusCode}, body: ${res.body})`,\n );\n }\n } finally {\n actionsCore.debug(`unwatching the daemon log`);\n log.unwatch();\n }\n\n actionsCore.debug(`killing daemon process ${pid}`);\n\n try {\n // Repeatedly signal 0 the daemon to test if it is up.\n // If it exits, kill will raise an exception which breaks us out of this control flow and skips the sigterm.\n // If magic-nix-cache doesn't exit in 30s, we SIGTERM it.\n for (let i = 0; i < 30 * 10; i++) {\n process.kill(pid, 0);\n await setTimeout(100);\n }\n\n this.addFact(FACT_SENT_SIGTERM, true);\n actionsCore.info(`Sending Magic Nix Cache a SIGTERM`);\n process.kill(pid, \"SIGTERM\");\n } catch {\n // Perfectly normal to get an exception here, because the process shut down.\n }\n\n if (actionsCore.isDebug()) {\n actionsCore.info(\"Entire log:\");\n const entireLog = readFileSync(path.join(this.daemonDir, \"daemon.log\"));\n actionsCore.info(entireLog.toString());\n }\n }\n\n // Exit the workflow during the main phase. If strict mode is set, fail; if not, save the error\n // message to the workflow's state and exit successfully.\n private exitMain(msg: string): void {\n if (this.strictMode) {\n actionsCore.setFailed(msg);\n } else {\n actionsCore.saveState(STATE_ERROR_IN_MAIN, msg);\n process.exit(0);\n }\n }\n\n // If the main phase threw an error (not in strict mode), this will be a non-empty\n // string available in the post phase.\n private get errorInMain(): string | undefined {\n const state = actionsCore.getState(STATE_ERROR_IN_MAIN);\n return state !== \"\" ? state : undefined;\n }\n}\n\nfunction main(): void {\n new MagicNixCacheAction().execute();\n}\n\nmain();\n"],"mappings":"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","names":["actionsCore","fs","actionsCore","stringifyError","fs","path"]} \ No newline at end of file diff --git a/package.json b/package.json index d8f4302..840ec65 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "dependencies": { "@actions/core": "^1.11.1", "@actions/exec": "^1.1.1", + "@actions/glob": "^0.5.0", "detsys-ts": "github:DeterminateSystems/detsys-ts", "got": "^14.4.5", "tail": "^2.2.6" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 053fba9..e9f61c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ dependencies: '@actions/exec': specifier: ^1.1.1 version: 1.1.1 + '@actions/glob': + specifier: ^0.5.0 + version: 0.5.0 detsys-ts: specifier: github:DeterminateSystems/detsys-ts version: github.com/DeterminateSystems/detsys-ts/eb87094f35072ac911526ad052c3437c9e0c42d6 @@ -104,6 +107,13 @@ packages: minimatch: 3.1.2 dev: false + /@actions/glob@0.5.0: + resolution: {integrity: sha512-tST2rjPvJLRZLuT9NMUtyBjvj9Yo0MiJS3ow004slMvm8GFM+Zv9HvMJ7HWzfUyJnGrJvDsYkWBaaG3YKXRtCw==} + dependencies: + '@actions/core': 1.11.1 + minimatch: 3.1.2 + dev: false + /@actions/http-client@2.2.3: resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==} dependencies: diff --git a/src/index.ts b/src/index.ts index b3bb3bf..3eb95a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import { getTrinaryInput, netrcPath, tailLog } from "./helpers.js"; +import { warnOnMnc } from "./mnc-warn.js"; import * as actionsCore from "@actions/core"; import { DetSysAction, inputs, stringifyError } from "detsys-ts"; import got, { Got, Response } from "got"; @@ -99,6 +100,10 @@ class MagicNixCacheAction extends DetSysAction { return; } + if (this.getFeature("warn-magic-nix-cache-eol")?.variant === true) { + await warnOnMnc(); + } + if (this.nixStoreTrust === "untrusted") { actionsCore.warning(TEXT_TRUST_UNTRUSTED); return; diff --git a/src/mnc-warn.ts b/src/mnc-warn.ts new file mode 100644 index 0000000..d431c80 --- /dev/null +++ b/src/mnc-warn.ts @@ -0,0 +1,68 @@ +import actionsCore from "@actions/core"; +import glob from "@actions/glob"; +import { stringifyError } from "detsys-ts"; +import * as fs from "node:fs/promises"; + +export async function warnOnMnc(): Promise { + const cwd = process.cwd(); + + const patterns = [ + ".github/actions/*.yaml", + ".github/actions/*.yml", + ".github/workflows/*.yaml", + ".github/workflows/*.yml", + ]; + const globber = await glob.create(patterns.join("\n")); + const files = await globber.glob(); + + for (const file of files) { + try { + const relativeFilePath = file.replace(cwd, "."); + const lines = (await fs.readFile(file, { encoding: "utf8" })).split("\n"); + + for (const lineIdx of lines.keys()) { + const line = lines[lineIdx]; + + if ( + line + .toLowerCase() + .includes("determinatesystems/magic-nix-cache-action") + ) { + const actionPosition = line + .toLowerCase() + .indexOf("determinatesystems/magic-nix-cache-action"); + const actionPositionEnd = + actionPosition + "determinatesystems/magic-nix-cache-action".length; + + const newLine = line.replace( + /DeterminateSystems\/magic-nix-cache-action/gi, + "DeterminateSystems/flakehub-cache-action", + ); + actionsCore.warning( + [ + "Magic Nix Cache has been deprecated due to a change in the underlying GitHub APIs and will stop working on 1 February 2025.", + "To continue caching Nix builds in GitHub Actions, use FlakeHub Cache instead.", + "", + "Replace...", + line, + "", + "...with...", + newLine, + "", + "For more details: https://dtr.mn/magic-nix-cache-eol", + ].join("\n"), + { + title: "Magic Nix Cache is deprecated", + file: relativeFilePath, + startLine: lineIdx + 1, + startColumn: actionPosition, + endColumn: actionPositionEnd, + }, + ); + } + } + } catch (err) { + actionsCore.debug(stringifyError(err)); + } + } +}