UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

143 lines 4.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AbstractGithubGraphqlCacheStrategy = void 0; const dequal_1 = require("dequal"); const luxon_1 = require("luxon"); const util_1 = require("../util"); /** * Cache strategy handles the caching Github GraphQL items * and reconciling them with newly obtained ones from paginated queries. */ class AbstractGithubGraphqlCacheStrategy { cacheNs; cacheKey; /** * Time period after which a cache record is considered expired. */ static cacheTTLDays = 30; /** * The time which is used during single cache access cycle. */ now = luxon_1.DateTime.now().toUTC(); /** * Set of all versions which were reconciled * during the current cache access cycle. */ reconciledVersions; /** * These fields will be persisted. */ items; createdAt = this.now; /** * This flag indicates whether there is any new or updated items */ hasNovelty = false; constructor(cacheNs, cacheKey) { this.cacheNs = cacheNs; this.cacheKey = cacheKey; } /** * Load data previously persisted by this strategy * for given `cacheNs` and `cacheKey`. */ async getItems() { if (this.items) { return this.items; } let result = { items: {}, createdAt: this.createdAt.toISO(), }; const storedData = await this.load(); if (storedData) { const cacheTTLDuration = { hours: AbstractGithubGraphqlCacheStrategy.cacheTTLDays * 24, }; if (!(0, util_1.isDateExpired)(this.now, storedData.createdAt, cacheTTLDuration)) { result = storedData; } } this.createdAt = luxon_1.DateTime.fromISO(result.createdAt).toUTC(); this.items = result.items; return this.items; } /** * If package release exists longer than this cache can exist, * we assume it won't updated/removed on the Github side. */ isStabilized(item) { const unstableDuration = { hours: AbstractGithubGraphqlCacheStrategy.cacheTTLDays * 24, }; return (0, util_1.isDateExpired)(this.now, item.releaseTimestamp, unstableDuration); } /** * Process items received from GraphQL page * ordered by `releaseTimestamp` in descending order * (fresh versions go first). */ async reconcile(items) { const cachedItems = await this.getItems(); let isPaginationDone = false; for (const item of items) { const { version } = item; const oldItem = cachedItems[version]; // If we reached previously stored item that is stabilized, // we assume the further pagination will not yield any new items. // // However, we don't break the loop here, allowing to reconcile // the entire page of items. This protects us from unusual cases // when release authors intentionally break the timeline. Therefore, // while it feels appealing to break early, please don't do that. if (oldItem && this.isStabilized(oldItem)) { isPaginationDone = true; } // Check if item is new or updated if (!oldItem || !(0, dequal_1.dequal)(oldItem, item)) { this.hasNovelty = true; } cachedItems[version] = item; this.reconciledVersions ??= new Set(); this.reconciledVersions.add(version); } this.items = cachedItems; return isPaginationDone; } /** * Handle removed items for packages that are not stabilized * and return the list of all items. */ async finalizeAndReturn() { const cachedItems = await this.getItems(); let resultItems; let hasDeletedItems = false; if (this.reconciledVersions) { resultItems = {}; for (const [version, item] of Object.entries(cachedItems)) { if (this.reconciledVersions.has(version) || this.isStabilized(item)) { resultItems[version] = item; } else { hasDeletedItems = true; } } } else { resultItems = cachedItems; } if (this.hasNovelty || hasDeletedItems) { await this.store(resultItems); } return Object.values(resultItems); } async store(cachedItems) { const cacheRecord = { items: cachedItems, createdAt: this.createdAt.toISO(), }; await this.persist(cacheRecord); } } exports.AbstractGithubGraphqlCacheStrategy = AbstractGithubGraphqlCacheStrategy; //# sourceMappingURL=abstract-cache-strategy.js.map