diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 54b6fa8..7fbff69 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -878,6 +878,29 @@ jobs: exit 1 fi + test-cache-python-missing-managed-install-dir: + runs-on: ubuntu-latest + env: + UV_PYTHON_INSTALL_DIR: /tmp/missing-uv-python + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Setup uv with cache and python cache enabled + uses: ./ + with: + enable-cache: true + cache-python: true + python-version: "3.12" + cache-local-path: /tmp/setup-uv-cache + cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-cache-python-missing-managed-install-dir + - name: Ensure uv cache dir exists so only python-cache behavior is tested + run: uv sync + working-directory: __tests__/fixtures/uv-project + shell: bash + - name: Ensure managed Python install dir does not exist and this does not break caching + run: rm -rf "$UV_PYTHON_INSTALL_DIR" + test-cache-python-installs: runs-on: ubuntu-latest steps: @@ -1029,6 +1052,7 @@ jobs: - test-relative-path - test-cache-prune-force - test-cache-dir-from-file + - test-cache-python-missing-managed-install-dir - test-cache-python-installs - test-restore-python-installs - test-python-install-dir diff --git a/dist/save-cache/index.js b/dist/save-cache/index.js index 23586bd..758f403 100644 --- a/dist/save-cache/index.js +++ b/dist/save-cache/index.js @@ -90852,11 +90852,25 @@ async function saveCache() { await pruneCache(); } const actualCachePath = getUvCachePath(); - await saveCacheToKey(cacheKey, actualCachePath, restore_cache_1.STATE_CACHE_MATCHED_KEY, "uv cache", `Cache path ${actualCachePath} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`); + if (!fs.existsSync(actualCachePath)) { + if (inputs_1.ignoreNothingToCache) { + core.info("No cacheable uv cache paths were found. Ignoring because ignore-nothing-to-cache is enabled."); + } + else { + throw new Error(`Cache path ${actualCachePath} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`); + } + } + else { + await saveCacheToKey(cacheKey, actualCachePath, restore_cache_1.STATE_CACHE_MATCHED_KEY, "uv cache"); + } } if (inputs_1.cachePython) { + if (!fs.existsSync(inputs_1.pythonDir)) { + core.warning(`Python cache path ${inputs_1.pythonDir} does not exist on disk. Skipping Python cache save because no managed Python installation was found. If you want uv to install managed Python instead of using a system interpreter, set UV_PYTHON_PREFERENCE=only-managed.`); + return; + } const pythonCacheKey = `${cacheKey}-python`; - await saveCacheToKey(pythonCacheKey, inputs_1.pythonDir, restore_cache_1.STATE_PYTHON_CACHE_MATCHED_KEY, "Python cache", `Python cache path ${inputs_1.pythonDir} does not exist on disk. This likely indicates that there are no Python installations to cache. Consider disabling the cache input if it is not needed.`); + await saveCacheToKey(pythonCacheKey, inputs_1.pythonDir, restore_cache_1.STATE_PYTHON_CACHE_MATCHED_KEY, "Python cache"); } } async function pruneCache() { @@ -90883,30 +90897,15 @@ function getUvCachePath() { } return inputs_1.cacheLocalPath.path; } -async function saveCacheToKey(cacheKey, cachePath, stateKey, cacheName, pathNotExistErrorMessage) { +async function saveCacheToKey(cacheKey, cachePath, stateKey, cacheName) { const matchedKey = core.getState(stateKey); if (matchedKey === cacheKey) { core.info(`${cacheName} hit occurred on key ${cacheKey}, not saving cache.`); return; } core.info(`Including ${cacheName} path: ${cachePath}`); - if (!fs.existsSync(cachePath) && !inputs_1.ignoreNothingToCache) { - throw new Error(pathNotExistErrorMessage); - } - try { - await cache.saveCache([cachePath], cacheKey); - core.info(`${cacheName} saved with key: ${cacheKey}`); - } - catch (e) { - if (e instanceof Error && - e.message === - "Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.") { - core.info(`No cacheable ${cacheName} paths were found. Ignoring because ignore-nothing-to-save is enabled.`); - } - else { - throw e; - } - } + await cache.saveCache([cachePath], cacheKey); + core.info(`${cacheName} saved with key: ${cacheKey}`); } run(); diff --git a/docs/caching.md b/docs/caching.md index 64350ad..82063d2 100644 --- a/docs/caching.md +++ b/docs/caching.md @@ -199,6 +199,10 @@ By default, the Python install dir (`uv python dir` / `UV_PYTHON_INSTALL_DIR`) i for the same reason that the dependency cache is pruned. If you want to cache Python installs along with your dependencies, set the `cache-python` input to `true`. +Note that this only caches Python versions that uv actually installs into `UV_PYTHON_INSTALL_DIR` +(i.e. managed Python installs). If uv uses a system Python, there may be nothing to cache. +To force managed Python installs, set `UV_PYTHON_PREFERENCE=only-managed`. + ```yaml - name: Cache Python installs uses: astral-sh/setup-uv@v7 diff --git a/src/save-cache.ts b/src/save-cache.ts index 2f0b370..3872ae9 100644 --- a/src/save-cache.ts +++ b/src/save-cache.ts @@ -59,23 +59,40 @@ async function saveCache(): Promise { } const actualCachePath = getUvCachePath(); - await saveCacheToKey( - cacheKey, - actualCachePath, - STATE_CACHE_MATCHED_KEY, - "uv cache", - `Cache path ${actualCachePath} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`, - ); + if (!fs.existsSync(actualCachePath)) { + if (ignoreNothingToCache) { + core.info( + "No cacheable uv cache paths were found. Ignoring because ignore-nothing-to-cache is enabled.", + ); + } else { + throw new Error( + `Cache path ${actualCachePath} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`, + ); + } + } else { + await saveCacheToKey( + cacheKey, + actualCachePath, + STATE_CACHE_MATCHED_KEY, + "uv cache", + ); + } } if (cachePython) { + if (!fs.existsSync(pythonDir)) { + core.warning( + `Python cache path ${pythonDir} does not exist on disk. Skipping Python cache save because no managed Python installation was found. If you want uv to install managed Python instead of using a system interpreter, set UV_PYTHON_PREFERENCE=only-managed.`, + ); + return; + } + const pythonCacheKey = `${cacheKey}-python`; await saveCacheToKey( pythonCacheKey, pythonDir, STATE_PYTHON_CACHE_MATCHED_KEY, "Python cache", - `Python cache path ${pythonDir} does not exist on disk. This likely indicates that there are no Python installations to cache. Consider disabling the cache input if it is not needed.`, ); } } @@ -119,7 +136,6 @@ async function saveCacheToKey( cachePath: string, stateKey: string, cacheName: string, - pathNotExistErrorMessage: string, ): Promise { const matchedKey = core.getState(stateKey); @@ -131,26 +147,8 @@ async function saveCacheToKey( } core.info(`Including ${cacheName} path: ${cachePath}`); - if (!fs.existsSync(cachePath) && !ignoreNothingToCache) { - throw new Error(pathNotExistErrorMessage); - } - - try { - await cache.saveCache([cachePath], cacheKey); - core.info(`${cacheName} saved with key: ${cacheKey}`); - } catch (e) { - if ( - e instanceof Error && - e.message === - "Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved." - ) { - core.info( - `No cacheable ${cacheName} paths were found. Ignoring because ignore-nothing-to-save is enabled.`, - ); - } else { - throw e; - } - } + await cache.saveCache([cachePath], cacheKey); + core.info(`${cacheName} saved with key: ${cacheKey}`); } run();